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