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