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