]> andersk Git - moira.git/blob - server/qsupport.qc
Case-insensitive stuff.
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qsupport_qc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include "query.h"
18 #include "mr_server.h"
19 #include <ctype.h>
20
21
22 extern char *whoami, *strsave();
23 extern int ingres_errno, mr_errcode;
24
25
26 /* Specialized Access Routines */
27
28 /* access_user - verify that client name equals specified login name
29  *
30  *  - since field validation routines are called first, a users_id is
31  *    now in argv[0] instead of the login name.
32  */
33
34 access_user(q, argv, cl)
35     struct query *q;
36     char *argv[];
37     client *cl;
38 {
39     if (cl->users_id != *(int *)argv[0])
40         return(MR_PERM);
41     else
42         return(MR_SUCCESS);
43 }
44
45     
46
47 /* access_login - verify that client name equals specified login name
48  *
49  *   argv[0...n] contain search info.  q->
50  */
51
52 access_login(q, argv, cl)
53     struct query *q;
54     char *argv[];
55     client *cl;
56 ##{
57 ##  int rowcount, id;
58 ##  char qual[256];
59
60     build_qual(q->qual, q->argc, argv, qual);
61 ##  range of u is users
62 ##  retrieve (id = u.users_id) where qual
63 ##  inquire_equel(rowcount = "rowcount")
64     if (rowcount != 1 || id != cl->users_id)
65         return(MR_PERM);
66     else
67         return(MR_SUCCESS);
68 ##}
69
70     
71
72 /* access_list - check access for most list operations
73  *
74  * Inputs: argv[0] - list_id
75  *          q - query name
76  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
77  *          argv[7] - group IID (only for query "ulis")
78  *          cl - client name
79  *
80  * - check that client is a member of the access control list
81  * - OR, if the query is add_member_to_list or delete_member_from_list
82  *      and the list is public, allow access if client = member
83  */ 
84
85 access_list(q, argv, cl)
86     struct query *q;
87     char *argv[];
88     client *cl;
89 ##{
90 ##  int list_id, acl_id, flags, rowcount, gid;
91 ##  char acl_type[9];
92     char *client_type;
93     int client_id, status;
94
95     list_id = *(int *)argv[0];
96 ##  repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
97 ##                   gid = list.#gid, flags = list.#public) 
98 ##         where list.#list_id = @list_id
99 ##  inquire_equel(rowcount = "rowcount")
100     if (rowcount != 1)
101       return(MR_INTERNAL);
102
103     /* parse client structure */
104     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
105         return(status);
106
107     /* if amtl or dmfl and list is public allow client to add or delete self */
108     if (((!strcmp("amtl", q->shortname) && flags) ||
109          (!strcmp("dmfl", q->shortname))) &&
110         (!strcmp("USER", argv[1]))) {
111         if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
112     /* if update_list, don't allow them to change the GID */
113     } else if (!strcmp("ulis", q->shortname)) {
114         if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
115             (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
116           return(MR_PERM);
117     }
118
119     /* check for client in access control list */
120     status = find_member(acl_type, acl_id, client_type, client_id, 0);
121     if (!status) return(MR_PERM);
122
123     return(MR_SUCCESS);
124 ##}
125
126
127 /* access_visible_list - allow access to list only if it is not hidden,
128  *      or if the client is on the ACL
129  *
130  * Inputs: argv[0] - list_id
131  *         cl - client identifier
132  */ 
133
134 access_visible_list(q, argv, cl)
135     struct query *q;
136     char *argv[];
137     client *cl;
138 ##{
139 ##  int list_id, acl_id, flags, rowcount;
140 ##  char acl_type[9];
141     char *client_type;
142     int client_id, status;
143
144     list_id = *(int *)argv[0];
145 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
146 ##      acl_type = list.#acl_type) where list.#list_id = @list_id
147 ##  inquire_equel(rowcount = "rowcount")
148     if (rowcount != 1)
149       return(MR_INTERNAL);
150     if (!flags)
151         return(MR_SUCCESS);
152
153
154     /* parse client structure */
155     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
156         return(status);
157
158     /* check for client in access control list */
159     status = find_member(acl_type, acl_id, client_type, client_id, 0);
160     if (!status)
161         return(MR_PERM);
162
163     return(MR_SUCCESS);
164 ##}
165
166
167 /* access_vis_list_by_name - allow access to list only if it is not hidden,
168  *      or if the client is on the ACL
169  *
170  * Inputs: argv[0] - list name
171  *         cl - client identifier
172  */ 
173
174 access_vis_list_by_name(q, argv, cl)
175     struct query *q;
176     char *argv[];
177     client *cl;
178 ##{
179 ##  int acl_id, flags, rowcount;
180 ##  char acl_type[9], *listname;
181     char *client_type;
182     int client_id, status;
183
184     listname = argv[0];
185 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
186 ##      acl_type = list.#acl_type) where list.#name = @listname
187 ##  inquire_equel(rowcount = "rowcount");
188     if (rowcount > 1)
189       return(MR_WILDCARD);
190     if (rowcount == 0)
191       return(MR_NO_MATCH);
192     if (!flags)
193         return(MR_SUCCESS);
194
195     /* parse client structure */
196     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
197         return(status);
198
199     /* check for client in access control list */
200     status = find_member(acl_type, acl_id, client_type, client_id, 0);
201     if (!status)
202         return(MR_PERM);
203
204     return(MR_SUCCESS);
205 ##}
206
207
208 /* access_member - allow user to access member of type "USER" and name matches
209  * username, or to access member of type "LIST" and list is one that user is
210  * on the acl of, or the list is visible.
211  */
212
213 access_member(q, argv, cl)
214     struct query *q;
215     char *argv[];
216     client *cl;
217 {
218     if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
219       return(access_visible_list(q, &argv[1], cl));
220
221     if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
222         if (cl->users_id == *(int *)argv[1])
223           return(MR_SUCCESS);
224     }
225
226     return(MR_PERM);
227 }
228
229
230 /* access_qgli - special access routine for Qualified_get_lists.  Allows
231  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
232  */
233
234 access_qgli(q, argv, cl)
235     struct query *q;
236     char *argv[];
237     client *cl;
238 {
239     if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
240       return(MR_SUCCESS);
241     return(MR_PERM);
242 }
243
244
245 /* access_service - allow access if user is on ACL of service.  Don't
246  * allow access if a wildcard is used.
247  */
248
249 access_service(q, argv, cl)
250     struct query *q;
251     char *argv[];
252     client *cl;
253 ##{
254 ##  int acl_id, rowcount;
255 ##  char *name, acl_type[9];
256     int client_id, status;
257     char *client_type;
258
259     name = argv[0];
260 ##  repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
261 ##      where servers.#name = uppercase(@name)
262 ##  inquire_equel(rowcount = "rowcount")
263     if (rowcount > 1)
264       return(MR_PERM);
265
266     /* parse client structure */
267     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
268         return(status);
269
270     /* check for client in access control list */
271     status = find_member(acl_type, acl_id, client_type, client_id, 0);
272     if (!status) return(MR_PERM);
273
274     return(MR_SUCCESS);
275 ##}
276
277
278
279 /* access_filesys - verify that client is owner or on owners list of filesystem
280  *      named by argv[0]
281  */
282
283 access_filesys(q, argv, cl)
284     struct query *q;
285     char *argv[];
286     client *cl;
287 ##{
288 ##  int rowcount, users_id, list_id;
289 ##  char *name;
290     int status, client_id;
291     char *client_type;
292
293     name = argv[0];
294 ##  repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
295 ##      where filesys.label = @name
296 ##  inquire_equel(rowcount = "rowcount")
297
298     if (rowcount != 1)
299       return(MR_PERM);
300     if (users_id == cl->users_id)
301       return(MR_SUCCESS);
302     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
303       return(status);
304     status = find_member("LIST", list_id, client_type, client_id, 0);
305     if (status)
306       return(MR_SUCCESS);
307     else
308       return(MR_PERM);
309 ##}
310
311     
312 \f
313 /* Setup Routines */
314
315 /* Setup routine for add_user
316  *
317  * Inputs: argv[0] - login
318  *         argv[1] - uid
319  *
320  * Description:
321  *
322  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
323  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
324  */
325
326 setup_ausr(q, argv, cl)
327     struct query *q;
328     register char *argv[];
329     client *cl;
330 ##{
331 ##  int nuid, rowcount;
332 ##  char *mit_id;
333
334 #ifdef notdef
335     /* this is currently disabled because we need an index on ID's
336      * before it can run in finite time.
337      */
338     mit_id = argv[U_MITID];
339 ##  retrieve (rowcount = any(u.#mit_id where u.#mit_id = mit_id))
340     if (ingres_errno) return(mr_errcode);
341     if (rowcount) return(MR_EXISTS);
342 #endif notdef
343
344     if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
345         if (set_next_object_id("uid", "users"))
346           return(MR_INGRES_ERR);
347 ##      repeat retrieve (nuid = values.value) where values.name = "uid"
348 ##      inquire_equel(rowcount = "rowcount")
349         if (rowcount != 1)
350           return(MR_INTERNAL);
351         sprintf(argv[1], "%d", nuid);
352     }
353
354     if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
355         sprintf(argv[0], "#%s", argv[1]);
356     }
357
358     return(MR_SUCCESS);
359 ##}
360
361
362 /* setup_dusr - verify that the user is no longer being referenced 
363  * and may safely be deleted.
364  */
365
366 int setup_dusr(q, argv)
367     struct query *q;
368     char **argv;
369 ##{
370 ##  int flag, id;
371
372     id = *(int *)argv[0];
373
374     /* For now, only allow users to be deleted if their status is 0 */
375 ##  repeat retrieve (flag = u.status) where u.users_id = @id
376     if (flag != 0 && flag != 4)
377       return(MR_IN_USE);
378
379 ##  repeat delete quota where quota.entity_id = @id and quota.type = "USER"
380 ##  repeat delete krbmap where krbmap.users_id = @id
381 ##  repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
382 ##                       and imembers.member_type = "USER"))
383     if (flag)
384         return(MR_IN_USE);
385 ##  repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
386     if (flag)
387         return(MR_IN_USE);
388 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
389 ##                      list.acl_type = "USER"))
390     if (flag)
391         return(MR_IN_USE);
392 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
393 ##                      servers.acl_type = "USER"))
394     if (flag)
395         return(MR_IN_USE);
396 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
397 ##                      hostaccess.acl_type = "USER"))
398     if (flag)
399         return(MR_IN_USE);
400     if (ingres_errno)
401         return(mr_errcode);
402     return(MR_SUCCESS);
403 ##}
404
405
406 /* setup_spop: verify that there is already a valid POP machine_id in the
407  * pop_id field.  Also take care of keeping track of the post office usage.
408  */
409 int setup_spop(q, argv)
410 struct query *q;
411 char **argv;
412 ##{
413 ##  int id, mid, flag;
414 ##  char type[9];
415
416     id = *(int *)argv[0];
417 ##  repeat retrieve (type = u.potype, mid = u.pop_id,
418 ##                   flag = any(machine.name where machine.mach_id = u.pop_id 
419 ##                                   and u.pop_id != 0 and u.users_id = @id))
420 ##      where u.users_id = @id
421     if (!flag)
422       return(MR_MACHINE);
423     if (strcmp(strtrim(type), "POP"))
424       set_pop_usage(mid, 1);
425     return(MR_SUCCESS);
426 ##}
427
428
429 /* setup_dpob:  Take care of keeping track of the post office usage.
430  */
431 int setup_dpob(q, argv)
432 struct query *q;
433 char **argv;
434 ##{
435 ##  int id, user;
436 ##  char type[9];
437
438     user = *(int *)argv[0];
439 ##  repeat retrieve (type = u.potype, id = u.pop_id)
440 ##              where u.users_id = @user
441     if (ingres_errno) return(mr_errcode);
442
443     if (!strcmp(strtrim(type), "POP"))
444       set_pop_usage(id, -1);
445     return(MR_SUCCESS);
446 ##}
447
448
449 /* setup_dmac - verify that the machine is no longer being referenced 
450  * and may safely be deleted.
451  */
452
453 int setup_dmac(q, argv)
454     struct query *q;
455     char **argv;
456 ##{
457 ##  int flag, id;
458
459     id = *(int *)argv[0];
460 ##  repeat retrieve (flag = any(users.login where users.potype = "POP" 
461 ##                                                and users.pop_id=@id))
462     if (flag)
463         return(MR_IN_USE);
464 ##  repeat retrieve (flag = any(serverhosts.mach_id
465 ##                               where serverhosts.mach_id=@id))
466     if (flag)
467         return(MR_IN_USE);
468 ##  repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
469     if (flag)
470         return(MR_IN_USE);
471 ##  repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
472     if (flag)
473         return(MR_IN_USE);
474 ##  repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
475     if (flag)
476         return(MR_IN_USE);
477 ##  repeat retrieve (flag = any(printcap.quotaserver where printcap.quotaserver=@id))
478     if (flag)
479         return(MR_IN_USE);
480 ##  repeat retrieve (flag = any(palladium.mach_id where palladium.mach_id=@id))
481     if (flag)
482         return(MR_IN_USE);
483
484 ##  repeat delete mcmap where mcmap.mach_id = @id
485     if (ingres_errno) return(mr_errcode);
486     return(MR_SUCCESS);
487 ##}
488
489
490 /* setup_dclu - verify that the cluster is no longer being referenced 
491  * and may safely be deleted.
492  */
493
494 int setup_dclu(q, argv)
495     struct query *q;
496     char **argv;
497 ##{
498 ##  int flag, id;
499
500     id = *(int *)argv[0];
501 ##  repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
502     if (flag)
503         return(MR_IN_USE);
504 ##  repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
505     if (flag)
506         return(MR_IN_USE);
507     if (ingres_errno)
508         return(mr_errcode);
509     return(MR_SUCCESS);
510 ##}
511
512
513 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
514  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
515  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
516  * a -1 there.  Remember that this is also used for ulis, with the indexes
517  * at 6 & 7.
518  */
519
520 int setup_alis(q, argv)
521 struct query *q;
522 char **argv;
523 ##{
524 ##  int ngid;
525     char *malloc();
526     int idx;
527
528     if (!strcmp(q->shortname, "alis"))
529       idx = 6;
530     else if (!strcmp(q->shortname, "ulis"))
531       idx = 7;
532
533     if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
534         if (atoi(argv[idx - 1])) {
535             if (set_next_object_id("gid", "list"))
536               return(MR_INGRES_ERR);
537 ##          repeat retrieve (ngid = values.value) where values.name = "gid"
538             if (ingres_errno) return(mr_errcode);
539             sprintf(argv[idx], "%d", ngid);
540         } else {
541             strcpy(argv[idx], "-1");
542         }
543     }
544
545     return(MR_SUCCESS);
546 ##}
547
548
549 /* setup_dlist - verify that the list is no longer being referenced 
550  * and may safely be deleted.
551  */
552
553 int setup_dlis(q, argv)
554     struct query *q;
555     char **argv;
556 ##{
557 ##  int flag, id;
558
559     id = *(int *)argv[0];
560 ##  repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
561 ##                       and imembers.member_type = "LIST"))
562     if (flag)
563         return(MR_IN_USE);
564 ##  repeat retrieve (flag = any(imembers.member_id where imembers.list_id=@id))
565     if (flag)
566         return(MR_IN_USE);
567 ##  repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
568     if (flag)
569         return(MR_IN_USE);
570 ##  repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
571     if (flag)
572         return(MR_IN_USE);
573 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
574 ##                      list.acl_type = "LIST" and list.list_id != @id))
575     if (flag)
576         return(MR_IN_USE);
577 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
578 ##                      servers.acl_type = "LIST"))
579     if (flag)
580         return(MR_IN_USE);
581 ##  repeat retrieve (flag = any(quota.entity_id where quota.entity_id=@id and
582 ##                      quota.type = "GROUP"))
583     if (flag)
584         return(MR_IN_USE);
585 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
586 ##                      hostaccess.acl_type = "LIST"))
587     if (flag)
588         return(MR_IN_USE);
589 ##  repeat retrieve (flag = any(zephyr.class
590 ##              where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
591 ##                    zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
592 ##                    zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
593 ##                    zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
594     if (flag)
595         return(MR_IN_USE);
596     if (ingres_errno)
597         return(mr_errcode);
598     return(MR_SUCCESS);
599 ##}
600
601
602 /* setup_dsin - verify that the service is no longer being referenced 
603  * and may safely be deleted.
604  */
605
606 int setup_dsin(q, argv)
607     struct query *q;
608     char **argv;
609 ##{
610 ##  int flag;
611 ##  char *name;
612
613     name = argv[0];
614 ##  repeat retrieve (flag = any(serverhosts.service 
615 ##                              where serverhosts.service=uppercase(@name)))
616     if (flag)
617         return(MR_IN_USE);
618 ##  repeat retrieve (flag = servers.inprogress) where servers.#name = @name
619     if (flag)
620         return(MR_IN_USE);
621     if (ingres_errno)
622         return(mr_errcode);
623     return(MR_SUCCESS);
624 ##}
625
626
627 /* setup_dshi - verify that the service-host is no longer being referenced 
628  * and may safely be deleted.
629  */
630
631 int setup_dshi(q, argv)
632     struct query *q;
633     char **argv;
634 ##{
635 ##  int flag, id;
636 ##  char *name;
637
638     name = argv[0];
639     id = *(int *)argv[1];
640 ##  repeat retrieve (flag=serverhosts.inprogress) 
641 ##      where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
642     if (flag)
643         return(MR_IN_USE);
644     if (ingres_errno)
645         return(mr_errcode);
646     return(MR_SUCCESS);
647 ##}
648
649
650 /**
651  ** setup_add_filesys - verify existance of referenced file systems
652  **
653  ** Inputs:     Add
654  **   argv[1] - type
655  **   argv[2] - mach_id
656  **   argv[3] - name
657  **   argv[5] - access
658  **
659  ** Description:
660  **   - for type = RVD:
661  **        * allow anything
662  **   - for type = NFS:
663  **        * extract directory prefix from name
664  **        * verify mach_id/dir in nfsphys
665  **        * verify access in {r, w, R, W}
666  **
667  **  Side effect: sets variable var_phys_id to the ID of the physical
668  **     filesystem (nfsphys_id for NFS, 0 for RVD)
669  **
670  ** Errors:
671  **   MR_NFS - specified directory not exported
672  **   MR_FILESYS_ACCESS - invalid filesys access
673  **
674  **/
675
676 ##static int var_phys_id;
677
678 setup_afil(q, argv)
679     struct query *q;
680     char *argv[];
681 ##{
682     char *type, *name;
683     int mach_id;
684 ##  int ok;
685 ##  char ftype[32], *access;
686
687     type = argv[1];
688     mach_id = *(int *)argv[2];
689     name = argv[3];
690     access = argv[5];
691     var_phys_id = 0;
692
693     sprintf(ftype, "fs_access_%s", type);
694 ##  retrieve (ok = any(alias.trans where alias.name = ftype and
695 ##                           alias.type = "TYPE" and alias.trans = access))
696     if (ingres_errno) return(mr_errcode);
697     if (ok == 0) return(MR_FILESYS_ACCESS);
698
699     if (!strcmp(type, "NFS"))
700         return (check_nfs(mach_id, name, access));
701     else
702         return(MR_SUCCESS);
703 ##}
704
705
706 /* Verify the arguments, depending on the FStype.  Also, if this is an
707  * NFS filesystem, then update any quotas for that filesystem to reflect
708  * the new phys_id.
709  */
710
711 setup_ufil(q, argv, cl)
712     struct query *q;
713     char *argv[];
714     client *cl;
715 ##{
716     int mach_id, status;
717     char *type, *name;  
718 ##  int fid, total, who;
719 ##  char *entity, ftype[32], *access;
720
721     type = argv[2];
722     mach_id = *(int *)argv[3];
723     name = argv[4];
724     access = argv[6];
725     var_phys_id = 0;
726     fid = *(int *)argv[0];
727     who = cl->client_id;
728     entity = cl->entity;
729
730     sprintf(ftype, "fs_access_%s", type);
731 ##  retrieve (total = any(alias.trans where alias.name = ftype and
732 ##                           alias.type = "TYPE" and alias.trans = access))
733     if (ingres_errno) return(mr_errcode);
734     if (total == 0) return(MR_FILESYS_ACCESS);
735
736     if (!strcmp(type, "NFS")) {
737         status = check_nfs(mach_id, name, access);
738 ##      replace quota (phys_id = var_phys_id) where quota.filsys_id = fid
739         if (ingres_errno) return(mr_errcode);
740         return(status);
741     } else if (!strcmp(type, "AFS")) {
742         total = 0;
743 ##      retrieve (total = sum(quota.quota where quota.filsys_id = fid
744 ##                            and quota.phys_id != 0))
745         if (ingres_errno) return(mr_errcode);
746         if (total != 0) {
747 ##          append quota (quota = total, filsys_id = fid,
748 ##                           phys_id = 0, entity_id = 0, type = "ANY",
749 ##                           modtime = "now", modby = who, modwith = entity)
750             if (ingres_errno) return(mr_errcode);
751         }
752     } else {
753 ##      replace quota (phys_id = 0) where quota.filsys_id = fid
754         if (ingres_errno) return(mr_errcode);
755     }
756     return(MR_SUCCESS);
757 ##}
758
759
760 /* Find the NFS physical partition that the named directory is on.
761  * This is done by comparing the dir against the mount point of the
762  * partition.  To make sure we get the correct match when there is 
763  * more than one, we sort the query in reverse order by dir name.
764  */
765
766 ##check_nfs(mach_id, name, access)
767 ##  int mach_id;
768     char *name;
769     char *access;
770 ##{
771 ##  char dir[81];
772     char caccess;
773     register int status;
774     register char *cp1;
775     register char *cp2;
776
777     status = MR_NFS;
778 ##  range of np is nfsphys
779 ##  repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
780 ##      where np.#mach_id = @mach_id sort by #dir:d {
781          cp1 = name;
782          cp2 = dir;
783          while (*cp2) {
784              if (*cp1++ != *cp2) break;
785              cp2++;
786          }
787          if (*cp2 == 0) {
788              status = MR_SUCCESS;
789 ##           endretrieve
790          }
791 ##  }
792     if (ingres_errno)
793         return(mr_errcode);
794     return(status);
795 ##}
796
797
798 /* setup_dfil: free any quota records and fsgroup info associated with
799  * a filesystem when it is deleted.  Also adjust the allocation numbers.
800  */
801
802 setup_dfil(q, argv, cl)
803     struct query  *q;
804     char **argv;
805     client *cl;
806 ##{
807 ##  int id;
808
809     id = *(int *)argv[0];
810 ##  range of q is quota
811 ##  range of n is nfsphys
812 ##  repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
813 ##      where n.nfsphys_id = filesys.phys_id and filesys.filsys_id = @id
814
815 ##  repeat delete q where q.filsys_id = @id
816 ##  repeat delete fsgroup where fsgroup.filsys_id = @id
817 ##  repeat delete fsgroup where fsgroup.group_id = @id
818     if (ingres_errno) return(mr_errcode);
819     return(MR_SUCCESS);
820 ##}
821
822
823 /* setup_dnfp: check to see that the nfs physical partition does not have
824  * any filesystems assigned to it before allowing it to be deleted.
825  */
826
827 setup_dnfp(q, argv, cl)
828     struct query  *q;
829     char **argv;
830     client *cl;
831 ##{
832 ##  int id, exists;
833
834     id = *(int *)argv[0];
835 ##  repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
836     if (exists)
837       return(MR_IN_USE);
838     if (ingres_errno)
839       return(mr_errcode);
840     return(MR_SUCCESS);
841 ##}
842
843
844 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
845  *   argv[0] = filsys_id
846  *   argv[1] = type if "update_quota" or "delete_quota"
847  *   argv[2 or 1] = users_id or list_id
848  */
849
850 setup_dqot(q, argv, cl)
851     struct query  *q;
852     char **argv;
853     client *cl;
854 ##{
855 ##  int quota, fs, id;
856 ##  char *qtype;
857
858     fs = *(int *)argv[0];
859     if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
860         qtype = argv[1];
861         id = *(int *)argv[2];
862     } else {
863         qtype = "USER";
864         id = *(int *)argv[1];
865     }
866
867 ##  range of q is #quota
868 ##  repeat retrieve (quota = q.#quota) where q.type = @qtype and
869 ##      q.entity_id = @id and q.filsys_id = @fs
870 ##  repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
871 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
872     if (ingres_errno) return(mr_errcode);
873     return(MR_SUCCESS);
874 ##}
875
876
877 /* setup_sshi: don't exclusive lock the machine table during
878  * set_server_host_internal.
879  */
880
881 setup_sshi(q, argv, cl)
882     struct query  *q;
883     char **argv;
884     client *cl;
885 ##{
886 ##  set lockmode session where readlock = system
887 ##}
888
889
890 /* setup add_kerberos_user_mapping: add the string to the string 
891  * table if necessary.
892  */
893
894 setup_akum(q, argv, cl)
895 struct query *q;
896 char **argv;
897 client *cl;
898 ##{
899 ##  int id, rowcount;
900 ##  char *name;
901
902     name = argv[1];
903     if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
904         if (q->type != APPEND) return(MR_STRING);
905 ##      range of v is values
906 ##      retrieve (id = v.value) where v.#name = "strings_id"
907         id++;
908 ##      replace v (value = id) where v.#name = "strings_id"
909 ##      append to strings (string_id = id, string = name)
910         cache_entry(name, "STRING", id);
911     }
912     if (ingres_errno) return(mr_errcode);
913     *(int *)argv[1] = id;
914     return(MR_SUCCESS);
915 ##}
916
917
918 \f
919 /* FOLLOWUP ROUTINES */
920
921 /* generic set_modtime routine.  This takes the table name from the query,
922  * and will update the modtime, modby, and modwho fields in the entry in
923  * the table whose name field matches argv[0].
924  */
925
926 set_modtime(q, argv, cl)
927     struct query *q;
928     char *argv[];
929     client *cl;
930 ##{
931 ##  char *name, *entity, *table;
932 ##  int who;
933
934     entity = cl->entity;
935     who = cl->client_id;
936     table = q->rtable;
937     name = argv[0];
938
939 ##  replace table (modtime = "now", modby = who, modwith = entity)
940 ##       where table.#name = name
941     return(MR_SUCCESS);
942 ##}
943
944 /* generic set_modtime_by_id routine.  This takes the table name from
945  * the query, and the id name from the validate record,
946  * and will update the modtime, modby, and modwho fields in the entry in
947  * the table whose id matches argv[0].
948  */
949
950 set_modtime_by_id(q, argv, cl)
951     struct query *q;
952     char **argv;
953     client *cl;
954 ##{
955 ##  char *entity, *table, *id_name;
956 ##  int who, id;
957
958     entity = cl->entity;
959     who = cl->client_id;
960     table = q->rtable;
961     id_name = q->validate->object_id;
962
963     id = *(int *)argv[0];
964 ##  replace table (modtime = "now", modby = who, modwith = entity)
965 ##       where table.id_name = id
966     return(MR_SUCCESS);
967 ##}
968
969
970 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
971  */
972
973 set_finger_modtime(q, argv, cl)
974     struct query *q;
975     char *argv[];
976     client *cl;
977 ##{
978 ##  int users_id, who;
979 ##  char *entity;
980
981     entity = cl->entity;
982     who = cl->client_id;
983     users_id = *(int *)argv[0];
984
985 ##  repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
986 ##       where u.#users_id = @users_id
987     return(MR_SUCCESS);
988 ##}
989
990
991 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
992  */
993
994 set_pobox_modtime(q, argv, cl)
995     struct query *q;
996     char **argv;
997     client *cl;
998 ##{
999 ##  int users_id, who;
1000 ##  char *entity;
1001
1002     entity = cl->entity;
1003     who = cl->client_id;
1004     users_id = *(int *)argv[0];
1005
1006 ##  repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
1007 ##       where users.#users_id = @users_id
1008     return(MR_SUCCESS);
1009 ##}
1010
1011
1012 /* Like set_modtime, but uppercases the name first.
1013  */
1014
1015 set_uppercase_modtime(q, argv, cl)
1016     struct query *q;
1017     char **argv;
1018     client *cl;
1019 ##{
1020 ##  char *name, *entity, *table;
1021 ##  int who;
1022
1023     entity = cl->entity;
1024     who = cl->client_id;
1025     table = q->rtable;
1026     name = argv[0];
1027
1028 ##  replace table (modtime = "now", modby = who, modwith = entity)
1029 ##       where table.#name = uppercase(name)
1030     return(MR_SUCCESS);
1031 ##}
1032
1033
1034 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
1035  * is necessary for add_machine_to_cluster becuase the table that query
1036  * operates on is "mcm", not "machine".
1037  */
1038
1039 set_mach_modtime_by_id(q, argv, cl)
1040     struct query *q;
1041     char **argv;
1042     client *cl;
1043 ##{
1044 ##  char *entity;
1045 ##  int who, id;
1046
1047     entity = cl->entity;
1048     who = cl->client_id;
1049
1050     id = *(int *)argv[0];
1051 ##  repeat replace machine (modtime = "now", modby = @who, modwith = @entity)
1052 ##       where machine.mach_id = @id
1053     return(MR_SUCCESS);
1054 ##}
1055
1056
1057 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
1058  * is necessary for add_cluster_data and delete_cluster_data becuase the
1059  * table that query operates on is "svc", not "cluster".
1060  */
1061
1062 set_cluster_modtime_by_id(q, argv, cl)
1063     struct query *q;
1064     char **argv;
1065     client *cl;
1066 ##{
1067 ##  char *entity;
1068 ##  int who, id;
1069
1070     entity = cl->entity;
1071     who = cl->client_id;
1072
1073     id = *(int *)argv[0];
1074 ##  repeat replace cluster (modtime = "now", modby = @who, modwith = @entity)
1075 ##       where cluster.clu_id = @id
1076     return(MR_SUCCESS);
1077 ##}
1078
1079
1080 /* sets the modtime on the serverhost where the service name is in argv[0]
1081  * and the mach_id is in argv[1].
1082  */
1083
1084 set_serverhost_modtime(q, argv, cl)
1085     struct query *q;
1086     char **argv;
1087     client *cl;
1088 ##{
1089 ##  char *entity, *serv;
1090 ##  int who, id;
1091
1092     entity = cl->entity;
1093     who = cl->client_id;
1094
1095     serv = argv[0];
1096     id = *(int *)argv[1];
1097 ##  repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
1098 ##       where sh.service = uppercase(@serv) and sh.mach_id = @id
1099     return(MR_SUCCESS);
1100 ##}
1101
1102
1103 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1104  * directory name is in argv[1].
1105  */
1106
1107 set_nfsphys_modtime(q, argv, cl)
1108     struct query *q;
1109     char **argv;
1110     client *cl;
1111 ##{
1112 ##  char *entity, *dir;
1113 ##  int who, id;
1114
1115     entity = cl->entity;
1116     who = cl->client_id;
1117
1118     id = *(int *)argv[0];
1119     dir = argv[1];
1120 ##  repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1121 ##       where np.#dir = @dir and np.mach_id = @id
1122     return(MR_SUCCESS);
1123 ##}
1124
1125
1126 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1127  * label.
1128  */
1129
1130 set_filesys_modtime(q, argv, cl)
1131     struct query *q;
1132     char *argv[];
1133     client *cl;
1134 ##{
1135 ##  char *label, *entity;
1136 ##  int who;
1137
1138     entity = cl->entity;
1139     who = cl->client_id;
1140
1141     label = argv[0];
1142     if (!strcmp(q->shortname, "ufil"))
1143       label = argv[1];
1144
1145 ##  repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1146 ##                     #phys_id = @var_phys_id)  where fs.#label = @label
1147     return(MR_SUCCESS);
1148 ##}
1149
1150
1151 /* sets the modtime on a zephyr class, where argv[0] contains the class
1152  * name.
1153  */
1154
1155 set_zephyr_modtime(q, argv, cl)
1156     struct query *q;
1157     char *argv[];
1158     client *cl;
1159 ##{
1160 ##  char *class, *entity;
1161 ##  int who;
1162
1163     entity = cl->entity;
1164     who = cl->client_id;
1165
1166     class = argv[0];
1167
1168 ##  repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1169 ##                     where z.#class = @class
1170     return(MR_SUCCESS);
1171 ##}
1172
1173
1174 /* fixes the modby field.  This will be the second to last thing in the
1175  * argv, the argv length is determined from the query structure.  It is
1176  * passed as a pointer to an integer.  This will either turn it into a
1177  * username, or # + the users_id.
1178  */
1179 followup_fix_modby(q, sq, v, action, actarg, cl)
1180     struct query *q;
1181     register struct save_queue *sq;
1182     struct validate *v;
1183     register int (*action)();
1184     register int actarg;
1185     client *cl;
1186 {
1187     register int i, j;
1188     char **argv, *malloc();
1189     int id, status;
1190
1191     i = q->vcnt - 2;
1192     while (sq_get_data(sq, &argv)) {
1193         id = atoi(argv[i]);
1194         if (id > 0)
1195           status = id_to_name(id, "USER", &argv[i]);
1196         else
1197           status = id_to_name(-id, "STRING", &argv[i]);
1198         if (status && status != MR_NO_MATCH)
1199           return(status);
1200         (*action)(q->vcnt, argv, actarg);
1201         for (j = 0; j < q->vcnt; j++)
1202           free(argv[j]);
1203         free(argv);
1204     }
1205     sq_destroy(sq);
1206     return(MR_SUCCESS);
1207 }
1208
1209
1210 /**
1211  ** followup_ausr - add finger and pobox entries, set_user_modtime
1212  **
1213  ** Inputs:
1214  **     argv[0] - login (add_user)
1215  **     argv[3] - last name
1216  **     argv[4] - first name
1217  **     argv[5] - middle name
1218  **
1219  **/
1220
1221 followup_ausr(q, argv, cl)
1222     struct query *q;
1223     char *argv[];
1224     client *cl;
1225 ##{
1226 ##  int who;
1227 ##  char *login, *entity;
1228 ##  char fullname[129];
1229
1230     login = argv[0];
1231     who = cl->client_id;
1232     entity = cl->entity;
1233
1234     /* build fullname */
1235     if (strlen(argv[4]) && strlen(argv[5]))
1236         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1237     else if (strlen(argv[4]))
1238         sprintf(fullname, "%s %s", argv[4], argv[3]);
1239     else
1240         sprintf(fullname, "%s", argv[3]);
1241
1242     /* create finger entry, pobox & set modtime on user */
1243 ##  repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1244 ##           #fullname=@fullname, mit_affil = u.mit_year,
1245 ##           fmodtime="now", fmodby=@who, fmodwith=@entity,
1246 ##           potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1247 ##      where u.#login = @login
1248
1249     return(MR_SUCCESS);
1250 ##}
1251
1252
1253 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1254  * type in argv[1].  Then completes the upcall to the user.
1255  *
1256  * argv[2] is of the form "123:234" where the first integer is the machine
1257  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1258  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1259  * are skipped.
1260  */
1261
1262 followup_gpob(q, sq, v, action, actarg, cl)
1263     register struct query *q;
1264     register struct save_queue *sq;
1265     register struct validate *v;
1266     register int (*action)();
1267     int actarg;
1268     client *cl;
1269 {
1270     char **argv, *index();
1271     char *ptype, *p;
1272     int mid, sid, status;
1273
1274     /* for each row */
1275     while (sq_get_data(sq, &argv)) {
1276         mr_trim_args(2, argv);
1277         ptype = argv[1];
1278         p = index(argv[2], ':');
1279         *p++ = 0;
1280         mid = atoi(argv[2]);
1281         sid = atoi(p);
1282
1283         if (!strcmp(ptype, "POP")) {
1284             status = id_to_name(mid, "MACHINE", &argv[2]);
1285             if (status == MR_NO_MATCH)
1286               return(MR_MACHINE);
1287         } else if (!strcmp(ptype, "SMTP")) {
1288             status = id_to_name(sid, "STRING", &argv[2]);
1289             if (status == MR_NO_MATCH)
1290               return(MR_STRING);
1291         } else /* ptype == "NONE" */ {
1292             goto skip;
1293         }
1294         if (status) return(status);
1295
1296         if (!strcmp(q->shortname, "gpob")) {
1297             sid = atoi(argv[4]);
1298             if (sid > 0)
1299               status = id_to_name(sid, "USER", &argv[4]);
1300             else
1301               status = id_to_name(-sid, "STRING", &argv[4]);
1302         }
1303         if (status && status != MR_NO_MATCH) return(status);
1304
1305         (*action)(q->vcnt, argv, actarg);
1306     skip:
1307         /* free saved data */
1308         free(argv[0]);
1309         free(argv[1]);
1310         free(argv[4]);
1311         free(argv);
1312     }
1313
1314     sq_destroy(sq);
1315     return (MR_SUCCESS);
1316 }
1317
1318
1319 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1320  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1321  * proper name based on the type, and repace that string in the argv.
1322  * Also fixes the modby field by called followup_fix_modby.
1323  */
1324
1325 followup_glin(q, sq, v, action, actarg, cl)
1326     register struct query *q;
1327     register struct save_queue *sq;
1328     register struct validate *v;
1329     register int (*action)();
1330     int actarg;
1331     client *cl;
1332 {
1333     char **argv, *malloc(), *realloc(), *type;
1334     int id, i, idx, status;
1335
1336     idx = 8;
1337     if (!strcmp(q->shortname, "gsin"))
1338       idx = 12;
1339
1340     while (sq_get_data(sq, &argv)) {
1341         mr_trim_args(q->vcnt, argv);
1342
1343         id = atoi(argv[i = q->vcnt - 2]);
1344         if (id > 0)
1345           status = id_to_name(id, "USER", &argv[i]);
1346         else
1347           status = id_to_name(-id, "STRING", &argv[i]);
1348         if (status && status != MR_NO_MATCH)
1349           return(status);
1350
1351         id = atoi(argv[idx]);
1352         type = argv[idx - 1];
1353
1354         if (!strcmp(type, "LIST")) {
1355             status = id_to_name(id, "LIST", &argv[idx]);
1356         } else if (!strcmp(type, "USER")) {
1357             status = id_to_name(id, "USER", &argv[idx]);
1358         } else if (!strcmp(type, "KERBEROS")) {
1359             status = id_to_name(id, "STRING", &argv[idx]);
1360         } else if (!strcmp(type, "NONE")) {
1361             status = 0;
1362             free(argv[idx]);
1363             argv[idx] = strsave("NONE");
1364         } else {
1365             status = 0;
1366             free(argv[idx]);
1367             argv[idx] = strsave("???");
1368         }
1369         if (status && status != MR_NO_MATCH)
1370           return(status);
1371
1372         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1373             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1374             strcpy(argv[6], UNIQUE_GID);
1375         }
1376
1377         /* send the data */
1378         (*action)(q->vcnt, argv, actarg);
1379
1380         /* free saved data */
1381         for (i = 0; i < q->vcnt; i++) 
1382             free(argv[i]);
1383         free(argv);
1384     }
1385
1386     sq_destroy(sq);
1387     return (MR_SUCCESS);
1388 }
1389
1390
1391 /* followup_gqot: Fix the entity name, directory name & modby fields
1392  *   argv[0] = filsys_id
1393  *   argv[1] = type
1394  *   argv[2] = entity_id
1395  *   argv[3] = ascii(quota)
1396  */
1397
1398 followup_gqot(q, sq, v, action, actarg, cl)
1399     struct query *q;
1400     register struct save_queue *sq;
1401     struct validate *v;
1402     register int (*action)();
1403     register int actarg;
1404     client *cl;
1405 ##{
1406     register int j;
1407     char **argv, *malloc();
1408 ##  int id, rowcount;
1409 ##  char *name, *label;
1410     int status, idx;
1411
1412     if (!strcmp(q->name, "get_quota") ||
1413         !strcmp(q->name, "get_quota_by_filesys"))
1414       idx = 4;
1415     else
1416       idx = 3;
1417     while (sq_get_data(sq, &argv)) {
1418         if (idx == 4) {
1419             switch (argv[1][0]) {
1420             case 'U':
1421                 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1422                 break;
1423             case 'G':
1424             case 'L':
1425                 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1426                 break;
1427             case 'A':
1428                 free(argv[2]);
1429                 argv[2] = strsave("system:anyuser");
1430                 break;
1431             default:
1432                 id = atoi(argv[2]);
1433                 argv[2] = malloc(8);
1434                 sprintf(argv[2], "%d", id);
1435             }
1436         }
1437         id = atoi(argv[idx]);
1438         free(argv[idx]);
1439         argv[idx] = malloc(256);
1440         name = argv[idx];
1441         if (id == 0) {
1442             label = argv[0];
1443 ##          repeat retrieve (name = filesys.#name) where filesys.#label = @label
1444         } else {
1445 ##          repeat retrieve (name = nfsphys.dir) where nfsphys.nfsphys_id = @id
1446         }
1447 ##      inquire_equel(rowcount = "rowcount")
1448         if (rowcount != 1) {
1449             sprintf(argv[idx], "#%d", id);
1450         }
1451
1452         id = atoi(argv[idx+3]);
1453         if (id > 0)
1454           status = id_to_name(id, "USER", &argv[idx+3]);
1455         else
1456           status = id_to_name(-id, "STRING", &argv[idx+3]);
1457         if (status && status != MR_NO_MATCH)
1458           return(status);
1459         (*action)(q->vcnt, argv, actarg);
1460         for (j = 0; j < q->vcnt; j++)
1461           free(argv[j]);
1462         free(argv);
1463     }
1464     sq_destroy(sq);
1465     return(MR_SUCCESS);
1466 ##}
1467
1468
1469 /* followup_aqot: Add allocation to nfsphys after creating quota.
1470  *   argv[0] = filsys_id
1471  *   argv[1] = type if "add_quota" or "update_quota"
1472  *   argv[2 or 1] = id
1473  *   argv[3 or 2] = ascii(quota)
1474  */
1475
1476 followup_aqot(q, argv, cl)
1477     struct query  *q;
1478     char **argv;
1479     client *cl;
1480 ##{
1481 ##  int quota, id, fs, who;
1482 ##  char *entity, *qtype;
1483
1484     fs = *(int *)argv[0];
1485     if (!strcmp(q->name, "add_quota") || !strcmp(q->name, "update_quota")) {
1486         qtype = argv[1];
1487         id = *(int *)argv[2];
1488         quota = atoi(argv[3]);
1489     } else {
1490         qtype = "USER";
1491         id = *(int *)argv[1];
1492         quota = atoi(argv[2]);
1493     }
1494     who = cl->client_id;
1495     entity = cl->entity;
1496
1497 ##  repeat replace q (modtime = "now", modby = @who, modwith = @entity)
1498 ##      where q.filsys_id = @fs and q.type = @qtype and q.entity_id = @id
1499 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1500 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1501     if (ingres_errno) return(mr_errcode);
1502     return(MR_SUCCESS);
1503 ##}
1504
1505
1506 followup_gpce(q, sq, v, action, actarg, cl)
1507     struct query *q;
1508     register struct save_queue *sq;
1509     struct validate *v;
1510     register int (*action)();
1511     register int actarg;
1512     client *cl;
1513 {
1514     register int i, j;
1515     char **argv, *malloc();
1516     int id, status;
1517
1518     i = q->vcnt - 2;
1519     while (sq_get_data(sq, &argv)) {
1520         id = atoi(argv[PCAP_QSERVER]);
1521         status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
1522         if (status) return (status);
1523         id = atoi(argv[i]);
1524         if (id > 0)
1525           status = id_to_name(id, "USER", &argv[i]);
1526         else
1527           status = id_to_name(-id, "STRING", &argv[i]);
1528         if (status && status != MR_NO_MATCH)
1529           return(status);
1530         (*action)(q->vcnt, argv, actarg);
1531         for (j = 0; j < q->vcnt; j++)
1532           free(argv[j]);
1533         free(argv);
1534     }
1535     sq_destroy(sq);
1536     return(MR_SUCCESS);
1537 }
1538
1539
1540 /* followup_gzcl:
1541  */
1542
1543 followup_gzcl(q, sq, v, action, actarg, cl)
1544     register struct query *q;
1545     register struct save_queue *sq;
1546     register struct validate *v;
1547     register int (*action)();
1548     int actarg;
1549     client *cl;
1550 {
1551     int id, i, status;
1552     char **argv;
1553
1554     while (sq_get_data(sq, &argv)) {
1555         mr_trim_args(q->vcnt, argv);
1556
1557         id = atoi(argv[i = q->vcnt - 2]);
1558         if (id > 0)
1559           status = id_to_name(id, "USER", &argv[i]);
1560         else
1561           status = id_to_name(-id, "STRING", &argv[i]);
1562         if (status && status != MR_NO_MATCH)
1563           return(status);
1564
1565         for (i = 1; i < 8; i+=2) {
1566             id = atoi(argv[i+1]);
1567             if (!strcmp(argv[i], "LIST")) {
1568                 status = id_to_name(id, "LIST", &argv[i+1]);
1569             } else if (!strcmp(argv[i], "USER")) {
1570                 status = id_to_name(id, "USER", &argv[i+1]);
1571             } else if (!strcmp(argv[i], "KERBEROS")) {
1572                 status = id_to_name(id, "STRING", &argv[i+1]);
1573             } else if (!strcmp(argv[i], "NONE")) {
1574                 status = 0;
1575                 free(argv[i+1]);
1576                 argv[i+1] = strsave("NONE");
1577             } else {
1578                 status = 0;
1579                 free(argv[i+1]);
1580                 argv[i+1] = strsave("???");
1581             }
1582             if (status && status != MR_NO_MATCH)
1583               return(status);
1584         }
1585
1586         /* send the data */
1587         (*action)(q->vcnt, argv, actarg);
1588
1589         /* free saved data */
1590         for (i = 0; i < q->vcnt; i++) 
1591             free(argv[i]);
1592         free(argv);
1593     }
1594     sq_destroy(sq);
1595     return(MR_SUCCESS);
1596 }
1597
1598
1599 /* followup_gsha:
1600  */
1601
1602 followup_gsha(q, sq, v, action, actarg, cl)
1603     register struct query *q;
1604     register struct save_queue *sq;
1605     register struct validate *v;
1606     register int (*action)();
1607     int actarg;
1608     client *cl;
1609 {
1610     char **argv;
1611     int i, id, status;
1612
1613     while (sq_get_data(sq, &argv)) {
1614         mr_trim_args(q->vcnt, argv);
1615
1616         id = atoi(argv[4]);
1617         if (id > 0)
1618           status = id_to_name(id, "USER", &argv[4]);
1619         else
1620           status = id_to_name(-id, "STRING", &argv[4]);
1621         if (status && status != MR_NO_MATCH)
1622           return(status);
1623
1624         id = atoi(argv[2]);
1625         if (!strcmp(argv[1], "LIST")) {
1626             status = id_to_name(id, "LIST", &argv[2]);
1627         } else if (!strcmp(argv[1], "USER")) {
1628             status = id_to_name(id, "USER", &argv[2]);
1629         } else if (!strcmp(argv[1], "KERBEROS")) {
1630             status = id_to_name(id, "STRING", &argv[2]);
1631         } else if (!strcmp(argv[1], "NONE")) {
1632             status = 0;
1633             free(argv[2]);
1634             argv[2] = strsave("NONE");
1635         } else {
1636             status = 0;
1637             free(argv[2]);
1638             argv[2] = strsave("???");
1639         }
1640         if (status && status != MR_NO_MATCH)
1641           return(status);
1642
1643         /* send the data */
1644         (*action)(q->vcnt, argv, actarg);
1645
1646         /* free saved data */
1647         for (i = 0; i < q->vcnt; i++) 
1648             free(argv[i]);
1649         free(argv);
1650     }
1651     sq_destroy(sq);
1652     return(MR_SUCCESS);
1653 }
1654
1655
1656 \f
1657 /* Special query routines */
1658
1659 /* set_pobox - this does all of the real work.
1660  *       argv = user_id, type, box
1661  * if type is POP, then box should be a machine, and its ID should be put in
1662  * pop_id.  If type is SMTP, then box should be a string and its ID should
1663  * be put in box_id.  If type is NONE, then box doesn't matter.
1664  */
1665
1666 int set_pobox(q, argv, cl)
1667     struct query *q;
1668     char **argv;
1669     client *cl;
1670 ##{
1671 ##  int user, id, rowcount;
1672 ##  char *box, potype[9];
1673     int status;
1674
1675     box = argv[2];
1676     user = *(int *)argv[0];
1677
1678 ##  repeat retrieve (id = users.pop_id, potype = users.#potype)
1679 ##              where users.users_id = @user
1680     if (ingres_errno) return(mr_errcode);
1681     if (!strcmp(strtrim(potype), "POP"))
1682       set_pop_usage(id, -1);
1683
1684     if (!strcmp(argv[1], "POP")) {
1685         status = name_to_id(box, "MACHINE", &id);
1686         if (status == MR_NO_MATCH)
1687           return(MR_MACHINE);
1688         else if (status)
1689           return(status);
1690 ##      repeat replace users (#potype = "POP", pop_id = @id)
1691 ##              where users.users_id = @user
1692         set_pop_usage(id, 1);
1693     } else if (!strcmp(argv[1], "SMTP")) {
1694         if (index(box, '/') || index(box, '|'))
1695           return(MR_BAD_CHAR);
1696         status = name_to_id(box, "STRING", &id);
1697         if (status == MR_NO_MATCH) {
1698 ##          repeat retrieve (id = values.value) where values.name = "strings_id"
1699             id++;
1700 ##          repeat replace values (value = @id) where values.name = "strings_id"
1701 ##          append to strings (string_id = id, string = box)
1702         } else if (status)
1703           return(status);
1704 ##      repeat replace users (#potype = "SMTP", box_id = @id) 
1705 ##             where users.users_id = @user
1706     } else /* argv[1] == "NONE" */ {
1707 ##      repeat replace users (#potype = "NONE") where users.users_id = @user
1708     }
1709
1710     set_pobox_modtime(q, argv, cl);
1711 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1712 ##      where tblstats.#table = "users"
1713     if (ingres_errno) return(mr_errcode);
1714     return(MR_SUCCESS);
1715 ##}
1716
1717
1718 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
1719  * each list.  This is tricky:  first build a queue of all requested
1720  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
1721  */
1722
1723 get_list_info(q, aargv, cl, action, actarg)
1724     register struct query *q;
1725     char **aargv;
1726     client *cl;
1727     register int (*action)();
1728     int actarg;
1729 ##{
1730     char *argv[13], *malloc(), *realloc();
1731 ##  char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1732 ##  char maillist[5], group[5], gid[6], acl_name[256], desc[256], modtime[27];
1733 ##  char modby[256], modwith[9];
1734 ##  int id, rowcount, acl_id, hid, modby_id;
1735     int returned, status;
1736     struct save_queue *sq, *sq_create();
1737
1738     returned = rowcount = 0;
1739     name = aargv[0];
1740
1741     sq = sq_create();
1742 ##  range of l is list
1743 ##  repeat retrieve (id = l.list_id) where l.#name = @name {
1744         sq_save_data(sq, id);
1745         rowcount++;
1746 ##  }
1747     if (ingres_errno) return(mr_errcode);
1748     if (rowcount == 0)
1749       return(MR_NO_MATCH);
1750
1751     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1752     argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1753     argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
1754
1755     while (sq_get_data(sq, &id)) {
1756         if (id == 0)
1757           continue;
1758         argv[6] = gid;
1759 ##      repeat retrieve (listname = l.#name, active = text(l.#active), 
1760 ##              public = text(l.#public), hidden = text(l.#hidden),
1761 ##              hid = l.#hidden, maillist = text(l.#maillist),
1762 ##              group = text(l.#group), gid = text(l.#gid),
1763 ##              acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1764 ##              desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1765 ##              modwith =l.#modwith)
1766 ##          where l.list_id = @id
1767         if (ingres_errno) return(mr_errcode);
1768
1769         if (atoi(gid) == -1)
1770             argv[6] = UNIQUE_GID;
1771
1772         argv[8] = malloc(0);
1773         if (!strcmp(acl_type, "LIST")) {
1774             status = id_to_name(acl_id, "LIST", &argv[8]);
1775         } else if (!strcmp(acl_type, "USER")) {
1776             status = id_to_name(acl_id, "USER", &argv[8]);
1777         } else if (!strcmp(acl_type, "KERBEROS")) {
1778             status = id_to_name(acl_id, "STRING", &argv[8]);
1779         } else if (!strcmp(acl_type, "NONE")) {
1780             status = 0;
1781             free(argv[8]);
1782             argv[8] = strsave("NONE");
1783         } else {
1784             status = 0;
1785             free(argv[8]);
1786             argv[8] = strsave("???");
1787         }
1788         if (status && status != MR_NO_MATCH) return(status);
1789
1790         argv[11] = malloc(0);
1791         if (modby_id > 0)
1792           status = id_to_name(modby_id, "USER", &argv[11]);
1793         else
1794           status = id_to_name(-modby_id, "STRING", &argv[11]);
1795         if (status && status != MR_NO_MATCH) return(status);
1796
1797         mr_trim_args(q->vcnt, argv);
1798         returned++;
1799         (*action)(q->vcnt, argv, actarg);
1800         free(argv[8]);
1801         free(argv[11]);
1802     }
1803
1804     sq_destroy(sq);
1805     if (ingres_errno) return(mr_errcode);
1806     return (MR_SUCCESS);
1807 ##}
1808
1809
1810 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
1811  * how many different ancestors a member is allowed to have.
1812  */
1813
1814 #define MAXLISTDEPTH    1024
1815
1816 int add_member_to_list(q, argv, cl)
1817     struct query *q;
1818     char **argv;
1819     client *cl;
1820 ##{
1821 ##  int id, lid, mid, exists, error, who, ref;
1822 ##  char *mtype, dtype[9], *entity;
1823     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
1824     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
1825     int status;
1826     char *dtypes[MAXLISTDEPTH];
1827     char *iargv[3], *buf;
1828
1829 ##  range of m is imembers
1830     lid = *(int *)argv[0];
1831     mtype = argv[1];
1832     mid = *(int *)argv[2];
1833     /* if the member is already a direct member of the list, punt */
1834 ##  repeat retrieve (exists = any(m.list_id where m.list_id=@lid and 
1835 ##                         m.member_id = @mid and m.member_type = @mtype
1836 ##                         and m.direct = 1))
1837     if (exists)
1838       return(MR_EXISTS);
1839     if (!strcasecmp(mtype, "STRING")) {
1840         buf = malloc(0);
1841         status = id_to_name(mid, "STRING", &buf);
1842         if (status) return(status);
1843         if (index(buf, '/') || index(buf, '|')) {
1844             free(buf);
1845             return(MR_BAD_CHAR);
1846         }
1847         free(buf);
1848     }
1849
1850     ancestors[0] = lid;
1851     aref[0] = 1;
1852     acount = 1;
1853 ##  repeat retrieve (id = m.list_id, ref = m.ref_count)
1854 ##      where m.member_id = @lid and m.member_type = "LIST" {
1855         aref[acount] = ref;
1856         ancestors[acount++] = id;
1857         if (acount >= MAXLISTDEPTH) {
1858 ##          endretrieve
1859         }
1860 ##  }
1861     if (ingres_errno) return(mr_errcode);
1862     if (acount >= MAXLISTDEPTH) {
1863         return(MR_INTERNAL);
1864     }
1865     descendants[0] = mid;
1866     dtypes[0] = mtype;
1867     dref[0] = 1;
1868     dcount = 1;
1869     error = 0;
1870     if (!strcmp(mtype, "LIST")) {
1871 ##      repeat retrieve (id = m.member_id, dtype = m.member_type,
1872 ##                       ref = m.ref_count)
1873 ##        where m.list_id = @mid {
1874             switch (dtype[0]) {
1875             case 'L':
1876                 dtypes[dcount] = "LIST";
1877                 break;
1878             case 'U':
1879                 dtypes[dcount] = "USER";
1880                 break;
1881             case 'S':
1882                 dtypes[dcount] = "STRING";
1883                 break;
1884             case 'K':
1885                 dtypes[dcount] = "KERBEROS";
1886                 break;
1887             default:
1888                 error++;
1889 ##              endretrieve
1890             }
1891             dref[dcount] = ref;
1892             descendants[dcount++] = id;
1893             if (dcount >= MAXLISTDEPTH) {
1894                 error++;
1895 ##              endretrieve
1896             }
1897 ##      }
1898         if (ingres_errno) return(mr_errcode);
1899         if (error)
1900           return(MR_INTERNAL);
1901     }
1902     for (a = 0; a < acount; a++) {
1903         lid = ancestors[a];
1904         for (d = 0; d < dcount; d++) {
1905             mid = descendants[d];
1906             mtype = dtypes[d];
1907             if (mid == lid && !strcmp(mtype, "LIST")) {
1908                 return(MR_LISTLOOP);
1909             }
1910 ##          repeat retrieve (exists = any(m.ref_count where m.list_id = @lid
1911 ##                                       and m.member_id = @mid
1912 ##                                       and m.member_type = @mtype))
1913             ref = aref[a] * dref[d];
1914             if (exists) {
1915                 if (a == 0 && d == 0)
1916 ##                replace m (ref_count = m.ref_count+ref, direct = 1)
1917 ##                           where m.list_id = lid and m.member_id = mid and
1918 ##                           m.member_type = mtype
1919                 else
1920 ##                replace m (ref_count = m.ref_count+ref)
1921 ##                           where m.list_id = lid and m.member_id = mid and
1922 ##                           m.member_type = mtype
1923             } else {
1924                 incremental_clear_before();
1925                 if (a == 0 && d == 0)
1926 ##                append imembers (list_id=lid, member_id = mid, direct = 1,
1927 ##                                 member_type=mtype, ref_count = 1)
1928                 else
1929 ##                append imembers (list_id=lid, member_id = mid,
1930 ##                                 member_type=mtype, ref_count = ref)
1931                 iargv[0] = (char *)lid;
1932                 iargv[1] = mtype;
1933                 iargv[2] = (char *)mid;
1934                 incremental_after("members", 0, iargv);
1935             }
1936         }
1937     }
1938     lid = *(int *)argv[0];
1939     entity = cl->entity;
1940     who = cl->client_id;
1941 ##  repeat replace list (modtime = "now", modby = @who, modwith = @entity)
1942 ##       where list.#list_id = @lid
1943     if (ingres_errno) return(mr_errcode);
1944     return(MR_SUCCESS);
1945 ##}
1946
1947
1948 /* Delete_member_from_list: do list flattening as we go!
1949  */
1950
1951 int delete_member_from_list(q, argv, cl)
1952     struct query *q;
1953     char **argv;
1954     client *cl;
1955 ##{
1956 ##  int id, lid, mid, cnt, exists, error, who, ref;
1957 ##  char *mtype, dtype[9], *entity;
1958     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
1959     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
1960     char *dtypes[MAXLISTDEPTH];
1961     char *iargv[3];
1962
1963 ##  range of m is imembers
1964     lid = *(int *)argv[0];
1965     mtype = argv[1];
1966     mid = *(int *)argv[2];
1967     /* if the member is not a direct member of the list, punt */
1968 ##  repeat retrieve (exists = any(m.list_id where m.list_id=@lid and 
1969 ##                         m.member_id = @mid and m.member_type = @mtype
1970 ##                         and m.direct = 1))
1971     if (ingres_errno) return(mr_errcode);
1972     if (!exists)
1973       return(MR_NO_MATCH);
1974     ancestors[0] = lid;
1975     aref[0] = 1;
1976     acount = 1;
1977 ##  repeat retrieve (id = m.list_id, ref = m.ref_count)
1978 ##      where m.member_id = @lid and m.member_type = "LIST" {
1979         aref[acount] = ref;
1980         ancestors[acount++] = id;
1981         if (acount >= MAXLISTDEPTH)
1982 ##        endretrieve
1983 ##  }
1984           if (ingres_errno) return(mr_errcode);
1985     if (acount >= MAXLISTDEPTH)
1986       return(MR_INTERNAL);
1987     descendants[0] = mid;
1988     dtypes[0] = mtype;
1989     dref[0] = 1;
1990     dcount = 1;
1991     error = 0;
1992     if (!strcmp(mtype, "LIST")) {
1993 ##      repeat retrieve (id = m.member_id, dtype = m.member_type,
1994 ##                       ref = m.ref_count)
1995 ##        where m.list_id = @mid {
1996             switch (dtype[0]) {
1997             case 'L':
1998                 dtypes[dcount] = "LIST";
1999                 break;
2000             case 'U':
2001                 dtypes[dcount] = "USER";
2002                 break;
2003             case 'S':
2004                 dtypes[dcount] = "STRING";
2005                 break;
2006             case 'K':
2007                 dtypes[dcount] = "KERBEROS";
2008                 break;
2009             default:
2010                 error++;
2011 ##              endretrieve
2012             }
2013             dref[dcount] = ref;
2014             descendants[dcount++] = id;
2015             if (dcount >= MAXLISTDEPTH)
2016 ##            endretrieve
2017 ##      }
2018               if (ingres_errno) return(mr_errcode);
2019         if (error)
2020           return(MR_INTERNAL);
2021     }
2022     for (a = 0; a < acount; a++) {
2023         lid = ancestors[a];
2024         for (d = 0; d < dcount; d++) {
2025             mid = descendants[d];
2026             mtype = dtypes[d];
2027             if (mid == lid && !strcmp(mtype, "LIST")) {
2028                 return(MR_LISTLOOP);
2029             }
2030 ##          repeat retrieve (cnt = m.ref_count)
2031 ##              where m.list_id = @lid and m.member_id = @mid
2032 ##                and m.member_type = @mtype
2033             ref = aref[a] * dref[d];
2034             if (cnt <= ref) {
2035                 iargv[0] = (char *)lid;
2036                 iargv[1] = mtype;
2037                 iargv[2] = (char *)mid;
2038                 incremental_before("members", 0, iargv);
2039 ##              delete m where m.list_id = lid and m.member_id = mid and
2040 ##                  m.member_type = mtype
2041                 incremental_clear_after();
2042             } else if (a == 0 && d == 0) {
2043 ##              replace m (ref_count = m.ref_count-ref, direct = 0)
2044 ##                  where m.list_id = lid and m.member_id = mid and
2045 ##                  m.member_type = mtype
2046             } else {
2047 ##              replace m (ref_count = m.ref_count-ref)
2048 ##                  where m.list_id = lid and m.member_id = mid and
2049 ##                  m.member_type = mtype
2050             }
2051         }
2052     }
2053     lid = *(int *)argv[0];
2054     entity = cl->entity;
2055     who = cl->client_id;
2056 ##  repeat replace list (modtime = "now", modby = @who, modwith = @entity)
2057 ##       where list.#list_id = @lid
2058     if (ingres_errno) return(mr_errcode);
2059     return(MR_SUCCESS);
2060 ##}
2061
2062
2063 /* get_ace_use - given a type and a name, return a type and a name.
2064  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2065  * and argv[1] will contain the ID of the entity in question.  The R*
2066  * types mean to recursively look at every containing list, not just
2067  * when the object in question is a direct member.  On return, the
2068  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2069  */
2070
2071 int get_ace_use(q, argv, cl, action, actarg)
2072     struct query *q;
2073     char *argv[];
2074     client *cl;
2075     int (*action)();
2076     int actarg;
2077 ##{
2078     int found = 0;
2079 ##  char *atype;
2080 ##  int aid, listid, id;
2081     struct save_queue *sq, *sq_create();
2082
2083 ##  range of m is imembers
2084     atype = argv[0];
2085     aid = *(int *)argv[1];
2086     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2087         !strcmp(atype, "KERBEROS")) {
2088         return(get_ace_internal(atype, aid, action, actarg));
2089     }
2090
2091     sq = sq_create();
2092     if (!strcmp(atype, "RLIST")) {
2093         sq_save_data(sq, aid);
2094         /* get all the list_id's of containing lists */
2095 ##      repeat retrieve (listid = m.list_id)
2096 ##              where m.member_type = "LIST" and m.member_id = @id {
2097             sq_save_unique_data(sq, listid);
2098 ##      }
2099         /* now process each one */
2100         while (sq_get_data(sq, &id)) {
2101             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2102               found++;
2103         }
2104     }
2105
2106     if (!strcmp(atype, "RUSER")) {
2107 ##      repeat retrieve (listid = m.list_id)
2108 ##              where m.member_type = "USER" and m.member_id = @aid {
2109             sq_save_data(sq, listid);
2110 ##      }
2111         /* now process each one */
2112         while (sq_get_data(sq, &id)) {
2113             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2114               found++;
2115         }
2116         if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2117           found++;
2118     }
2119
2120     if (!strcmp(atype, "RKERBERO")) {
2121 ##      repeat retrieve (listid = m.list_id)
2122 ##              where m.member_type = "KERBEROS" and m.member_id = @aid {
2123             sq_save_data(sq, listid);
2124 ##      }
2125         /* now process each one */
2126         while (sq_get_data(sq, &id)) {
2127             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2128               found++;
2129         }
2130         if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2131           found++;
2132     }
2133
2134     sq_destroy(sq);     
2135     if (ingres_errno) return(mr_errcode);
2136     if (!found) return(MR_NO_MATCH);
2137     return(MR_SUCCESS);
2138 ##}
2139
2140
2141 /* This looks up a single list or user for ace use.  atype must be "USER"
2142  * or "LIST", and aid is the ID of the corresponding object.  This is used
2143  * by get_ace_use above.
2144  */
2145
2146 ##get_ace_internal(atype, aid, action, actarg)
2147 ##  char *atype;
2148 ##  int aid;
2149     int (*action)();
2150     int actarg;
2151 ##{
2152     char *rargv[2];
2153     int found = 0;
2154 ##  char name[33];
2155
2156     rargv[1] = name;
2157     if (!strcmp(atype, "LIST")) {
2158         rargv[0] = "FILESYS";
2159 ##      repeat retrieve (name = filesys.label) 
2160 ##              where filesys.owners = @aid {
2161             (*action)(2, rargv, actarg);
2162             found++;
2163 ##      }
2164
2165         rargv[0] = "QUERY";
2166 ##      repeat retrieve (name = capacls.capability)
2167 ##              where capacls.list_id = @aid {
2168             (*action)(2, rargv, actarg);
2169             found++;
2170 ##      }
2171     } else if (!strcmp(atype, "USER")) {
2172         rargv[0] = "FILESYS";
2173 ##      repeat retrieve (name = filesys.label) 
2174 ##              where filesys.owner = @aid {
2175             (*action)(2, rargv, actarg);
2176             found++;
2177 ##      }
2178     }
2179
2180     rargv[0] = "LIST";
2181 ##  repeat retrieve (name = list.#name) 
2182 ##              where list.acl_type = @atype and list.acl_id = @aid {
2183          (*action)(2, rargv, actarg);
2184          found++;
2185 ##  }
2186
2187     rargv[0] = "SERVICE";
2188 ##  repeat retrieve (name = servers.#name) 
2189 ##              where servers.acl_type = @atype and servers.acl_id = @aid {
2190          (*action)(2, rargv, actarg);
2191          found++;
2192 ##  }
2193
2194     rargv[0] = "HOSTACCESS";
2195 ##  repeat retrieve (name = machine.#name)
2196 ##              where machine.mach_id = hostaccess.mach_id and 
2197 ##                   hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
2198         (*action)(2, rargv, actarg);
2199         found++;
2200 ##  }
2201     rargv[0] = "ZEPHYR";
2202 ##  repeat retrieve (name = zephyr.class) 
2203 ##              where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
2204 ##                    zephyr.sub_type = @atype and zephyr.sub_id = @aid or
2205 ##                    zephyr.iws_type = @atype and zephyr.iws_id = @aid or
2206 ##                    zephyr.iui_type = @atype and zephyr.iui_id = @aid {
2207          (*action)(2, rargv, actarg);
2208          found++;
2209 ##  }
2210
2211     if (!found) return(MR_NO_MATCH);
2212     return(MR_SUCCESS);
2213 ##}
2214
2215
2216 /* get_lists_of_member - given a type and a name, return the name and flags
2217  * of all of the lists of the given member.  The member_type is one of
2218  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2219  * and argv[1] will contain the ID of the entity in question.  The R*
2220  * types mean to recursively look at every containing list, not just
2221  * when the object in question is a direct member.
2222  */
2223
2224 int get_lists_of_member(q, argv, cl, action, actarg)
2225     struct query *q;
2226     char *argv[];
2227     client *cl;
2228     int (*action)();
2229     int actarg;
2230 ##{
2231     int found = 0, direct = 1;
2232     char *rargv[6];
2233 ##  char *atype;
2234 ##  int aid, listid, id;
2235 ##  char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
2236
2237     atype = argv[0];
2238     aid = *(int *)argv[1];
2239     if (!strcmp(atype, "RLIST")) {
2240         atype = "LIST";
2241         direct = 0;
2242     }
2243     if (!strcmp(atype, "RUSER")) {
2244         atype = "USER";
2245         direct = 0;
2246     }
2247     if (!strcmp(atype, "RSTRING")) {
2248         atype = "STRING";
2249         direct = 0;
2250     }
2251     if (!strcmp(atype, "RKERBEROS")) {
2252         atype = "KERBEROS";
2253         direct = 0;
2254     }
2255
2256     rargv[0] = name;
2257     rargv[1] = active;
2258     rargv[2] = public;
2259     rargv[3] = hidden;
2260     rargv[4] = maillist;
2261     rargv[5] = group;
2262 ##  range of m is imembers
2263     if (direct) {
2264 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2265 ##                   public = text(list.#public), hidden = text(list.#hidden),
2266 ##                   maillist = text(list.#maillist), group = text(list.#group))
2267 ##              where list.list_id = m.list_id and m.direct = 1 and
2268 ##                    m.member_type = @atype and m.member_id = @aid {
2269          (*action)(6, rargv, actarg);
2270          found++;
2271 ##    }
2272     } else {
2273 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2274 ##                   public = text(list.#public), hidden = text(list.#hidden),
2275 ##                   maillist = text(list.#maillist), group = text(list.#group))
2276 ##              where list.list_id = m.list_id and
2277 ##                    m.member_type = @atype and m.member_id = @aid {
2278          (*action)(6, rargv, actarg);
2279          found++;
2280 ##    }
2281     }
2282
2283     if (ingres_errno) return(mr_errcode);
2284     if (!found) return(MR_NO_MATCH);
2285     return(MR_SUCCESS);
2286 ##}
2287
2288
2289 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2290  * the five flags associated with each list.  It will return the name of
2291  * each list that meets the quailifications.  It does this by building a
2292  * where clause based on the arguments, then doing a retrieve.
2293  */
2294
2295 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2296
2297 int qualified_get_lists(q, argv, cl, action, actarg)
2298     struct query *q;
2299     char *argv[];
2300     client *cl;
2301     int (*action)();
2302     int actarg;
2303 {
2304     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2305                          "l", "name", lflags));
2306 }
2307
2308
2309 /** get_members_of_list - optimized query for retrieval of list members
2310  **
2311  ** Inputs:
2312  **   argv[0] - list_id
2313  **
2314  ** Description:
2315  **   - retrieve USER members, then LIST members, then STRING members
2316  **/
2317
2318 get_members_of_list(q, argv, cl, action, actarg)
2319     struct query *q;
2320     char *argv[];
2321     client *cl;
2322     int (*action)();
2323     int actarg;
2324 ##{
2325 ##  int list_id, member_id;
2326 ##  char member_name[129], member_type[9];
2327     char *targv[2];
2328     int members;
2329     struct save_queue *sq;
2330
2331     list_id = *(int *)argv[0];
2332     members = 0;
2333     sq = sq_create();
2334
2335 ##  repeat retrieve (member_type = imembers.#member_type,
2336 ##                   member_id = imembers.#member_id)
2337 ##      where imembers.#list_id = @list_id and imembers.direct = 1 {
2338       if (members++ > 49)
2339 ##      endretrieve
2340       sq_save_data(sq, (member_type[0] << 24) | (member_id & 0xffffff));
2341 ##  }
2342     if (members <= 49) {
2343         targv[1] = malloc(0);
2344         while (sq_remove_data(sq, &member_id)) {
2345             switch (member_id >> 24) {
2346             case 'U':
2347                 targv[0] = "USER";
2348                 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
2349                 (*action)(2, targv, actarg);
2350                 break;
2351             case 'L':
2352                 targv[0] = "LIST";
2353                 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
2354                 (*action)(2, targv, actarg);
2355                 break;
2356             case 'S':
2357                 targv[0] = "STRING";
2358                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2359                 (*action)(2, targv, actarg);
2360                 break;
2361             case 'K':
2362                 targv[0] = "KERBEROS";
2363                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2364                 (*action)(2, targv, actarg);
2365                 break;
2366             default:
2367                 sq_destroy(sq);
2368                 return(MR_INTERNAL);
2369             }
2370         }
2371         free(targv[1]);
2372         sq_destroy(sq);
2373         return(MR_SUCCESS);
2374     }
2375     sq_destroy(sq);
2376
2377     targv[1] = member_name;
2378     targv[0] = "USER";
2379 ##  range of m is imembers
2380 ##  repeat retrieve (member_name = users.login)
2381 ##             where m.#list_id = @list_id and m.#member_type = "USER"
2382 ##                   and m.#member_id = users.users_id and m.direct = 1
2383 ##             sort by #member_name
2384 ##  {
2385          (*action)(2, targv, actarg);
2386 ##  }
2387     if (ingres_errno) return(mr_errcode);
2388
2389     targv[0] = "LIST";
2390 ##  repeat retrieve (member_name = list.name)
2391 ##             where m.#list_id = @list_id and m.#member_type = "LIST"
2392 ##                   and m.#member_id = list.#list_id and m.direct = 1
2393 ##             sort by #member_name
2394 ##  {
2395          (*action)(2, targv, actarg);
2396 ##  }
2397     if (ingres_errno) return(mr_errcode);
2398
2399     targv[0] = "STRING";
2400 ##  repeat retrieve (member_name = strings.string)
2401 ##             where m.#list_id = @list_id and m.#member_type = "STRING"
2402 ##                   and m.#member_id = strings.string_id and m.direct = 1
2403 ##             sort by #member_name
2404 ##  {
2405          (*action)(2, targv, actarg);
2406 ##  }
2407     if (ingres_errno) return(mr_errcode);
2408
2409     targv[0] = "KERBEROS";
2410 ##  repeat retrieve (member_name = strings.string)
2411 ##             where m.#list_id = @list_id and m.#member_type = "KERBEROS"
2412 ##                   and m.#member_id = strings.string_id and m.direct = 1
2413 ##             sort by #member_name
2414 ##  {
2415          (*action)(2, targv, actarg);
2416 ##  }
2417     if (ingres_errno) return(mr_errcode);
2418
2419     return(MR_SUCCESS);
2420 ##}
2421
2422
2423 /* count_members_of_list: this is a simple query, but it cannot be done
2424  * through the dispatch table.
2425  */
2426
2427 int count_members_of_list(q, argv, cl, action, actarg)
2428     struct query *q;
2429     char *argv[];
2430     client *cl;
2431     int (*action)();
2432     int actarg;
2433 ##{
2434 ##  int  list, ct = 0;
2435     char *rargv[1], countbuf[5];
2436
2437     list = *(int *)argv[0];
2438     rargv[0] = countbuf;
2439 ##  repeat retrieve (ct = count(imembers.list_id
2440 ##                              where imembers.list_id = @list and
2441 ##                                    imembers.direct = 1))
2442     if (ingres_errno) return(mr_errcode);
2443     sprintf(countbuf, "%d", ct);
2444     (*action)(1, rargv, actarg);
2445     return(MR_SUCCESS);
2446 ##}
2447
2448
2449 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2450  * the three flags associated with each service.  It will return the name of
2451  * each service that meets the quailifications.  It does this by building a
2452  * where clause based on the arguments, then doing a retrieve.
2453  */
2454
2455 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2456
2457 int qualified_get_server(q, argv, cl, action, actarg)
2458     struct query *q;
2459     char *argv[];
2460     client *cl;
2461     int (*action)();
2462     int actarg;
2463 {
2464     return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2465                          "s", "name", sflags));
2466 }
2467
2468
2469 /* generic qualified get routine, used by qualified_get_lists,
2470  * qualified_get_server, and qualified_get_serverhost.
2471  *   Args:
2472  *      start - a simple where clause, must not be empty
2473  *      range - the name of the range variable
2474  *      field - the field to return
2475  *      flags - an array of strings, names of the flag variables
2476  */
2477
2478 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2479     struct query *q;
2480     char *argv[];
2481     int (*action)();
2482     int actarg;
2483     char *start;
2484     char *range;
2485     char *field;
2486     char *flags[];
2487 ##{
2488 ##  char name[33], qual[256], *rvar, *rtbl, *rfield;
2489     char *rargv[1], buf[32];
2490 ##  int rowcount, i;
2491
2492     strcpy(qual, start);
2493     for (i = 0; i < q->argc; i++) {
2494         if (!strcmp(argv[i], "TRUE")) {
2495             sprintf(buf, " and %s.%s != 0", range, flags[i]);
2496             (void) strcat(qual, buf);
2497         } else if (!strcmp(argv[i], "FALSE")) {
2498             sprintf(buf, " and %s.%s = 0", range, flags[i]);
2499             (void) strcat(qual, buf);
2500         }
2501     }
2502       
2503     rargv[0] = name;
2504     rvar = range;
2505     rtbl = q->rtable;
2506     rfield = field;
2507 ##  range of rvar is rtbl
2508 ##  retrieve (name = rvar.rfield) where qual {
2509         (*action)(1, rargv, actarg);
2510 ##  }
2511     if (ingres_errno) return(mr_errcode);
2512 ##  inquire_equel(rowcount = "rowcount")
2513     if (rowcount == 0)
2514       return(MR_NO_MATCH);
2515     return(MR_SUCCESS);
2516 ##}
2517
2518
2519 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2520  * the five flags associated with each serverhost.  It will return the name of
2521  * each service and host that meets the quailifications.  It does this by 
2522  * building a where clause based on the arguments, then doing a retrieve.
2523  */
2524
2525 static char *shflags[6] = { "service", "enable", "override", "success",
2526                             "inprogress", "hosterror" };
2527
2528 int qualified_get_serverhost(q, argv, cl, action, actarg)
2529     struct query *q;
2530     char *argv[];
2531     client *cl;
2532     int (*action)();
2533     int actarg;
2534 ##{
2535 ##  char sname[33], mname[33], qual[256];
2536     char *rargv[2], buf[32];
2537 ##  int rowcount, i;
2538
2539     sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2540             argv[0]);
2541     for (i = 1; i < q->argc; i++) {
2542         if (!strcmp(argv[i], "TRUE")) {
2543             sprintf(buf, " and sh.%s != 0", shflags[i]);
2544             strcat(qual, buf);
2545         } else if (!strcmp(argv[i], "FALSE")) {
2546             sprintf(buf, " and sh.%s = 0", shflags[i]);
2547             strcat(qual, buf);
2548         }
2549     }
2550       
2551     rargv[0] = sname;
2552     rargv[1] = mname;
2553 ##  range of sh is serverhosts
2554 ##  retrieve (sname = sh.service, mname = machine.name) where qual {
2555         (*action)(2, rargv, actarg);
2556 ##  }
2557     if (ingres_errno) return(mr_errcode);
2558 ##  inquire_equel(rowcount = "rowcount")
2559     if (rowcount == 0)
2560       return(MR_NO_MATCH);
2561     return(MR_SUCCESS);
2562 ##}
2563
2564
2565 /* register_user - change user's login name and allocate a pobox, group,
2566  * filesystem, and quota for them.  The user's status must start out as 0,
2567  * and is left as 2.  Arguments are: user's UID, new login name, and user's
2568  * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY, 
2569  * MR_FS_STAFF, MR_FS_MISC).
2570  */
2571
2572 register_user(q, argv, cl)
2573     struct query *q;
2574     char **argv;
2575     client *cl;
2576 ##{
2577 ##  char *login, dir[65], *entity, *directory, machname[33];
2578 ##  int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2579 ##  int size, alloc, pid, m_id;
2580     char buffer[256], *aargv[3];
2581     int maxsize;
2582
2583     entity = cl->entity;
2584     who = cl->client_id;
2585
2586     uid = atoi(argv[0]);
2587     login = argv[1];
2588     utype = atoi(argv[2]);
2589
2590 ##  range of u is users
2591 ##  range of l is list
2592 ##  range of sh is serverhosts
2593 ##  range of n is nfsphys
2594 ##  range of m is machine
2595
2596     /* find user */
2597 ##  repeat retrieve (users_id = u.#users_id)
2598 ##      where u.#uid = @uid and (u.status = 0 or u.status = 5 or u.status = 6)
2599 ##  inquire_equel(rowcount = "rowcount");
2600     if (rowcount == 0)
2601       return(MR_NO_MATCH);
2602     if (rowcount > 1)
2603       return(MR_NOT_UNIQUE);
2604
2605     /* check new login name */
2606 ##  repeat retrieve (flag = any(u.#login where u.#login = @login and
2607 ##                              u.#users_id != users_id))
2608     if (ingres_errno) return(mr_errcode);
2609     if (flag) return(MR_IN_USE);
2610 ##  repeat retrieve (flag = any(l.#name where l.#name = @login))
2611     if (ingres_errno) return(mr_errcode);
2612     if (flag) return(MR_IN_USE);
2613 ##  repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2614     if (ingres_errno) return(mr_errcode);
2615     if (flag) return(MR_IN_USE);
2616     com_err(whoami, 0, "new login name OK");
2617
2618     /* choose place for pobox, put in mid */
2619 ##  repeat retrieve (mid = sh.mach_id, machname = m.name)
2620 ##    where sh.service = "POP" and m.mach_id = sh.mach_id and
2621 ##      sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2622     if (ingres_errno) return(mr_errcode);
2623 ##  inquire_equel(rowcount = "rowcount");
2624     if (rowcount == 0)
2625       return(MR_NO_POBOX);
2626
2627     /* change login name, set pobox */
2628     sprintf(buffer, "u.users_id = %d", users_id);
2629     incremental_before("users", buffer, 0);
2630 ##  repeat replace u (#login = @login, status = 2, modtime = "now",
2631 ##                    modby = @who, modwith = @entity, potype="POP",
2632 ##                    pop_id = @mid, pmodtime="now", pmodby=@who,
2633 ##                    pmodwith=@entity)
2634 ##      where u.#users_id = @users_id
2635 ##  inquire_equel(rowcount = "rowcount");
2636     if (ingres_errno) return(mr_errcode);
2637     if (rowcount != 1)
2638       return(MR_INTERNAL);
2639     set_pop_usage(mid, 1);
2640     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2641             strtrim(machname));
2642     incremental_after("users", buffer, 0);
2643
2644     /* create group list */
2645     if (set_next_object_id("gid", "list"))
2646       return(MR_NO_ID);
2647     if (set_next_object_id("list_id", "list"))
2648       return(MR_NO_ID);
2649 ##  repeat retrieve (list_id = values.value) where values.name = "list_id"
2650     if (ingres_errno) return(mr_errcode);
2651 ##  inquire_equel(rowcount = "rowcount");
2652     if (rowcount != 1)
2653       return(MR_INTERNAL);
2654     incremental_clear_before();
2655 ##  repeat append list (name = @login, #list_id = @list_id, active = 1,
2656 ##                      public = 0, hidden = 0, maillist = 0, group = 1,
2657 ##                      #gid = values.value, desc = "User Group",
2658 ##                      acl_type = "USER", acl_id = @users_id, modtime = "now",
2659 ##                      modby = @who, modwith = @entity)
2660 ##      where values.name = "gid"
2661     if (ingres_errno) return(mr_errcode);
2662 ##  inquire_equel(rowcount = "rowcount");
2663     if (rowcount != 1)
2664       return(MR_INTERNAL);
2665     sprintf(buffer, "l.list_id = %d", list_id);
2666     incremental_after("list", buffer, 0);
2667     aargv[0] = (char *) list_id;
2668     aargv[1] = "USER";
2669     aargv[2] = (char *) users_id;
2670     incremental_clear_before();
2671 ##  repeat append imembers (#list_id = @list_id, member_type = "USER",
2672 ##                         member_id = @users_id, ref_count = 1, direct = 1)
2673     if (ingres_errno) return(mr_errcode);
2674 ##  inquire_equel(rowcount = "rowcount");
2675     if (rowcount != 1)
2676       return(MR_INTERNAL);
2677     incremental_after("members", 0, aargv);
2678     com_err(whoami, 0, "group list created");
2679
2680     /* decide where to put filesystem */
2681     maxsize = 0;
2682     directory = NULL;
2683 ##  repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2684 ##                   flag = n.status, size = n.#size, alloc = n.allocated) {
2685         if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2686             maxsize = size - alloc;
2687             if (directory)
2688               free(directory);
2689             directory = strsave(dir);
2690             pid = nid;
2691             m_id = mid;
2692         }
2693 ##  }
2694     if (ingres_errno) return(mr_errcode);
2695     if (maxsize == 0)
2696       return(MR_NO_FILESYS);
2697
2698     /* create filesystem */
2699     if (set_next_object_id("filsys_id", "filesys"))
2700       return(MR_NO_ID);
2701     incremental_clear_before(); 
2702 ##  repeat append filesys (filsys_id = values.value, phys_id = @pid,
2703 ##                         label = @login, type = "NFS", mach_id = @m_id,
2704 ##                         name = @directory + "/" + @login,
2705 ##                         mount = "/mit/" + @login,
2706 ##                         access = "w", comments = "User Locker",
2707 ##                         owner = @users_id, owners = @list_id, createflg = 1,
2708 ##                         lockertype = "HOMEDIR", modtime = "now",
2709 ##                         modby = @who, modwith = @entity)
2710 ##      where values.name = "filsys_id"
2711     if (ingres_errno) return(mr_errcode);
2712 ##  inquire_equel(rowcount = "rowcount");
2713     if (rowcount != 1)
2714       return(MR_INTERNAL);
2715     incremental_after("filesys", 
2716           "fs.filsys_id = values.value and values.name = \"filsys_id\"",
2717                       0);
2718     com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2719             directory, login);
2720
2721     /* set quota */
2722 ##  repeat retrieve (quota = values.value) where values.name = "def_quota"
2723     if (ingres_errno) return(mr_errcode);
2724 ##  inquire_equel(rowcount = "rowcount");
2725     if (rowcount != 1)
2726       return(MR_NO_QUOTA);
2727     incremental_clear_before();
2728 ##  repeat append #quota (entity_id = @users_id, filsys_id = values.value,
2729 ##                        type = "USER",
2730 ##                        #quota = @quota, phys_id = @pid, modtime = "now",
2731 ##                        modby = @who, modwith = @entity)
2732 ##      where values.name = "filsys_id"
2733     if (ingres_errno) return(mr_errcode);
2734 ##  inquire_equel(rowcount = "rowcount");
2735     if (rowcount != 1)
2736       return(MR_INTERNAL);
2737 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2738 ##      where nfsphys.nfsphys_id = filesys.#phys_id and
2739 ##            filesys.filsys_id = values.value and values.name = "filsys_id"
2740     if (ingres_errno) return(mr_errcode);
2741 ##  inquire_equel(rowcount = "rowcount");
2742     if (rowcount != 1)
2743       return(MR_INTERNAL);
2744     aargv[0] = login;
2745     aargv[1] = "USER";
2746     aargv[2] = login;
2747     sprintf(buffer, "q.entity_id = %d and q.filsys_id = values.value and q.type = \"USER\" and values.name = \"filsys_id\"", users_id);
2748     incremental_after("quota", buffer, aargv);
2749     com_err(whoami, 0, "quota of %d assigned", quota);
2750     if (ingres_errno) return(mr_errcode);
2751
2752     cache_entry(login, "USER", users_id);
2753
2754 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2755 ##      where tblstats.table = "users"
2756 ##  repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2757 ##      where tblstats.table = "list" or tblstats.table = "filesys" or
2758 ##            tblstats.table = "quota"
2759     if (ingres_errno) return(mr_errcode);
2760     return(MR_SUCCESS);
2761 ##}
2762
2763
2764
2765 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2766  **
2767  ** Inputs:
2768  **   id of machine
2769  **   delta (will be +/- 1)
2770  **
2771  ** Description:
2772  **   - incr/decr value field in serverhosts table for pop/mach_id
2773  **
2774  **/
2775
2776 static int set_pop_usage(id, count)
2777 int id;
2778 int count;
2779 ##{
2780 ##  int mach_id = id;
2781 ##  int n = count;
2782
2783 ##  repeat replace serverhosts (value1 = serverhosts.value1 + @n)
2784 ##         where serverhosts.service = "POP" and serverhosts.#mach_id = @mach_id
2785
2786     if (ingres_errno) return(mr_errcode);
2787     return(MR_SUCCESS);
2788 ##}
2789
2790
2791 \f
2792 /* Validation Routines */
2793
2794 validate_row(q, argv, v)
2795     register struct query *q;
2796     char *argv[];
2797     register struct validate *v;
2798 ##{
2799 ##  char *rvar;
2800 ##  char *table;
2801 ##  char *name;
2802 ##  char qual[128];
2803 ##  int rowcount;
2804
2805     /* build where clause */
2806     build_qual(v->qual, v->argc, argv, qual);
2807
2808     /* setup ingres variables */
2809     rvar = q->rvar;
2810     table = q->rtable;
2811     name = v->field;
2812
2813     if (log_flags & LOG_VALID)
2814         /* tell the logfile what we're doing */
2815         com_err(whoami, 0, "validating row: %s", qual);
2816     
2817     /* look for the record */
2818 ##  range of rvar is table
2819 ##  retrieve (rowcount = count(rvar.name where qual))
2820     if (ingres_errno) return(mr_errcode);
2821     if (rowcount == 0) return(MR_NO_MATCH);
2822     if (rowcount > 1) return(MR_NOT_UNIQUE);
2823     return(MR_EXISTS);
2824 ##}
2825
2826 validate_fields(q, argv, vo, n)
2827     struct query *q;
2828     register char *argv[];
2829     register struct valobj *vo;
2830     register int n;
2831 {
2832     register int status;
2833
2834     while (--n >= 0) {
2835         switch (vo->type) {
2836         case V_NAME:
2837             if (log_flags & LOG_VALID)
2838                 com_err(whoami, 0, "validating %s in %s: %s", 
2839                     vo->namefield, vo->table, argv[vo->index]);
2840             status = validate_name(argv, vo);
2841             break;
2842
2843         case V_ID:
2844             if (log_flags & LOG_VALID)
2845                 com_err(whoami, 0, "validating %s in %s: %s", 
2846                     vo->idfield, vo->table, argv[vo->index]);
2847             status = validate_id(argv, vo);
2848             break;
2849
2850         case V_DATE:
2851             if (log_flags & LOG_VALID)
2852                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2853             status = validate_date(argv, vo);
2854             break;
2855
2856         case V_TYPE:
2857             if (log_flags & LOG_VALID)
2858                 com_err(whoami, 0, "validating %s type: %s",
2859                     vo->table, argv[vo->index]);
2860             status = validate_type(argv, vo);
2861             break;
2862
2863         case V_TYPEDATA:
2864             if (log_flags & LOG_VALID)
2865                 com_err(whoami, 0, "validating typed data (%s): %s",
2866                     argv[vo->index - 1], argv[vo->index]);
2867             status = validate_typedata(q, argv, vo);
2868             break;
2869
2870         case V_RENAME:
2871             if (log_flags & LOG_VALID)
2872                 com_err(whoami, 0, "validating rename %s in %s",
2873                         argv[vo->index], vo->table);
2874             status = validate_rename(argv, vo);
2875             break;
2876
2877         case V_CHAR:
2878             if (log_flags & LOG_VALID)
2879               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2880             status = validate_chars(argv[vo->index]);
2881             break;
2882
2883         case V_SORT:
2884             status = MR_EXISTS;
2885             break;
2886
2887         case V_LOCK:
2888             status = lock_table(vo);
2889             break;
2890         }
2891
2892         if (status != MR_EXISTS) return(status);
2893         vo++;
2894     }
2895
2896     if (ingres_errno) return(mr_errcode);
2897     return(MR_SUCCESS);
2898 }
2899
2900
2901 /* validate_chars: verify that there are no illegal characters in
2902  * the string.  Legal characters are printing chars other than 
2903  * ", *, ?, \, [ and ].
2904  */
2905 static int illegalchars[] = {
2906     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2907     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2908     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2909     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2910     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2911     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2912     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2913     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2914     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2915     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2916     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2917     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2918     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2919     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2920     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2921     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2922 };
2923
2924 validate_chars(s)
2925 register char *s;
2926 {
2927     while (*s)
2928       if (illegalchars[*s++])
2929         return(MR_BAD_CHAR);
2930     return(MR_EXISTS);
2931 }
2932
2933
2934 validate_id(argv, vo)
2935     char *argv[];
2936     register struct valobj *vo;
2937 ##{
2938 ##  char *name;
2939 ##  char *table;
2940 ##  char *namefield;
2941 ##  char *idfield;
2942 ##  int id, rowcount;
2943     int status;
2944     register char *c;
2945
2946
2947     name = argv[vo->index];
2948     table = vo->table;
2949     namefield = vo->namefield;
2950     idfield = vo->idfield;
2951
2952     if ((!strcmp(table, "users") && !strcmp(namefield, "login")) ||
2953         !strcmp(table, "machine") ||
2954         !strcmp(table, "filesys") ||
2955         !strcmp(table, "list") ||
2956         !strcmp(table, "cluster") ||
2957         !strcmp(table, "string")) {
2958         if (!strcmp(table, "machine"))
2959           for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2960         status = name_to_id(name, table, &id);
2961         if (status == 0) {
2962             *(int *)argv[vo->index] = id;
2963             return(MR_EXISTS);
2964         } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
2965           return(vo->error);
2966         else
2967           return(status);
2968     }
2969
2970     if (!strcmp(namefield, "uid")) {
2971 ##    retrieve (id = table.idfield) where table.namefield = int4(name)
2972       if (ingres_errno) return(mr_errcode);
2973 ##    inquire_equel (rowcount = "rowcount")
2974     } else {
2975 ##    retrieve (id = table.idfield) where table.namefield = name
2976       if (ingres_errno) return(mr_errcode);
2977 ##    inquire_equel (rowcount = "rowcount")
2978     }
2979     if (rowcount != 1) return(vo->error);
2980     *(int *)argv[vo->index] = id;
2981     return(MR_EXISTS);
2982 ##}
2983
2984 validate_name(argv, vo)
2985     char *argv[];
2986     register struct valobj *vo;
2987 ##{
2988 ##  char *name;
2989 ##  char *table;
2990 ##  char *namefield;
2991 ##  int rowcount;
2992     register char *c;
2993
2994     name = argv[vo->index];
2995     table = vo->table;
2996     namefield = vo->namefield;
2997     if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2998         for (c = name; *c; c++)
2999           if (islower(*c))
3000             *c = toupper(*c);
3001     }
3002 ##  retrieve (rowcount = countu(table.namefield 
3003 ##            where table.namefield = name))
3004     if (ingres_errno) return(mr_errcode);
3005     return ((rowcount == 1) ? MR_EXISTS : vo->error);
3006 ##}
3007
3008 validate_date(argv, vo)
3009     char *argv[];
3010     struct valobj *vo;
3011 ##{
3012 ##  char *idate;
3013 ##  double dd;
3014 ##  int errorno;
3015
3016     idate = argv[vo->index];
3017
3018 ##  retrieve (dd = interval("years", date(idate) - date("today")))
3019 ##  inquire_equel (errorno = "errorno")
3020     if (errorno != 0 || dd > 5.0) return(MR_DATE);
3021     return(MR_EXISTS);
3022 ##}
3023
3024
3025 validate_rename(argv, vo)
3026 char *argv[];
3027 struct valobj *vo;
3028 ##{
3029 ##  char *name, *table, *namefield, *idfield;
3030 ##  int id;
3031     int status;
3032     register char *c;
3033
3034     c = name = argv[vo->index];
3035     while (*c)
3036       if (illegalchars[*c++])
3037         return(MR_BAD_CHAR);
3038     table = vo->table;
3039     /* minor kludge to upcasify machine names */
3040     if (!strcmp(table, "machine"))
3041         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3042     namefield = vo->namefield;
3043     idfield = vo->idfield;
3044     id = -1;
3045     if (idfield == 0) {
3046         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3047           return(MR_EXISTS);
3048 ##      retrieve (id = any(table.namefield where table.namefield = name))
3049         if (ingres_errno) return(mr_errcode);
3050         if (id)
3051           return(vo->error);
3052         else
3053           return(MR_EXISTS);
3054     }
3055     status = name_to_id(name, table, &id);
3056     if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3057       return(MR_EXISTS);
3058     else
3059       return(vo->error);
3060 ##}
3061
3062
3063 validate_type(argv, vo)
3064     char *argv[];
3065     register struct valobj *vo;
3066 ##{
3067 ##  char *typename;
3068 ##  char *value;
3069 ##  int exists;
3070     register char *c;
3071
3072     typename = vo->table;
3073     c = value = argv[vo->index];
3074     while (*c)
3075       if (illegalchars[*c++])
3076         return(MR_BAD_CHAR);
3077
3078     /* uppercase type fields */
3079     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
3080
3081 ##  repeat retrieve (exists = any(alias.trans where alias.name = @typename and
3082 ##                                alias.type = "TYPE" and alias.trans = @value))
3083     if (ingres_errno) return(mr_errcode);
3084     return (exists ? MR_EXISTS : vo->error);
3085 ##}
3086
3087 /* validate member or type-specific data field */
3088
3089 validate_typedata(q, argv, vo)
3090     register struct query *q;
3091     register char *argv[];
3092     register struct valobj *vo;
3093 ##{
3094 ##  char *name;
3095 ##  char *field_type;
3096 ##  char data_type[129];
3097 ##  int id, rowcount;
3098     int status;
3099     char *index();
3100     register char *c;
3101
3102     /* get named object */
3103     name = argv[vo->index];
3104
3105     /* get field type string (known to be at index-1) */
3106     field_type = argv[vo->index-1];
3107
3108     /* get corresponding data type associated with field type name */
3109 ##  repeat retrieve (data_type = alias.trans) 
3110 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
3111     if (ingres_errno) return(mr_errcode);
3112 ##  inquire_equel (rowcount = "rowcount")
3113     if (rowcount != 1) return(MR_TYPE);
3114
3115     /* now retrieve the record id corresponding to the named object */
3116     if (index(data_type, ' '))
3117         *index(data_type, ' ') = 0;
3118     if (!strcmp(data_type, "user")) {
3119         /* USER */
3120         status = name_to_id(name, data_type, &id);
3121         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3122           return(MR_USER);
3123         if (status) return(status);
3124     } else if (!strcmp(data_type, "list")) {
3125         /* LIST */
3126         status = name_to_id(name, data_type, &id);
3127         if (status && status == MR_NOT_UNIQUE)
3128           return(MR_LIST);
3129         if (status == MR_NO_MATCH) {
3130             /* if idfield is non-zero, then if argv[0] matches the string
3131              * that we're trying to resolve, we should get the value of
3132              * values.[idfield] for the id.
3133              */
3134             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3135                 set_next_object_id(q->validate->object_id, q->rtable);
3136                 name = vo->idfield;
3137 ##              repeat retrieve (id = values.value) where values.#name = @name
3138 ##              inquire_equel(rowcount = "rowcount")
3139                 if (rowcount != 1) return(MR_LIST);
3140             } else
3141               return(MR_LIST);
3142         } else if (status) return(status);
3143     } else if (!strcmp(data_type, "machine")) {
3144         /* MACHINE */
3145         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3146         status = name_to_id(name, data_type, &id);
3147         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3148           return(MR_MACHINE);
3149         if (status) return(status);
3150     } else if (!strcmp(data_type, "string")) {
3151         /* STRING */
3152         status = name_to_id(name, data_type, &id);
3153         if (status && status == MR_NOT_UNIQUE)
3154           return(MR_STRING);
3155         if (status == MR_NO_MATCH) {
3156             if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3157 ##          retrieve (id = values.value) where values.#name = "strings_id"
3158             id++;
3159 ##          replace values (value = id) where values.#name = "strings_id"
3160 ##          append to strings (string_id = id, string = name)
3161         } else if (status) return(status);
3162     } else if (!strcmp(data_type, "none")) {
3163         id = 0;
3164     } else {
3165         return(MR_TYPE);
3166     }
3167
3168     /* now set value in argv */
3169     *(int *)argv[vo->index] = id;
3170     
3171     return (MR_EXISTS);
3172 ##}
3173
3174
3175 /* Lock the table named by the validation object */
3176
3177 lock_table(vo)
3178 struct valobj *vo;
3179 ##{
3180 ##  char *table, *idfield;
3181 ##  int rowcount;
3182
3183     table = vo->table;
3184     idfield = vo->idfield;
3185 ##  replace table (modtime = "now") where table.idfield = 0
3186     if (ingres_errno) return(mr_errcode);
3187 ##  inquire_equel (rowcount = "rowcount")
3188     if (rowcount != 1)
3189       return(vo->error);
3190     else
3191       return(MR_EXISTS);
3192 ##}
3193
3194
3195 /* Check the database at startup time.  For now this just resets the
3196  * inprogress flags that the DCM uses.
3197  */
3198
3199 sanity_check_database()
3200 ##{
3201 ##}
This page took 0.618103 seconds and 5 git commands to generate.