6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qsupport_qc = "$Header$";
16 #include <mit-copyright.h>
18 #include "sms_server.h"
22 extern char *whoami, *strsave();
23 extern int ingres_errno, sms_errcode;
26 /* Specialized Access Routines */
28 /* access_user - verify that client name equals specified login name
30 * - since field validation routines are called first, a users_id is
31 * now in argv[0] instead of the login name.
34 access_user(q, argv, cl)
39 if (cl->users_id != *(int *)argv[0])
47 /* access_login - verify that client name equals specified login name
49 * argv[0...n] contain search info. q->
52 access_login(q, argv, cl)
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)
72 /* access_list - check access for most list operations
74 * Inputs: argv[0] - list_id
76 * argv[2] - member ID (only for queries "amtl" and "dmfl")
77 * argv[7] - group IID (only for query "ulis")
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
85 access_list(q, argv, cl)
90 ## int list_id, acl_id, flags, rowcount, gid;
93 int client_id, status;
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")
101 return(SMS_INTERNAL);
103 /* parse client structure */
104 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
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]))))
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);
127 /* access_visible_list - allow access to list only if it is not hidden,
128 * or if the client is on the ACL
130 * Inputs: argv[0] - list_id
131 * cl - client identifier
134 access_visible_list(q, argv, cl)
139 ## int list_id, acl_id, flags, rowcount;
142 int client_id, status;
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")
149 return(SMS_INTERNAL);
154 /* parse client structure */
155 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
158 /* check for client in access control list */
159 status = find_member(acl_type, acl_id, client_type, client_id, 0);
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
170 * Inputs: argv[0] - list name
171 * cl - client identifier
174 access_vis_list_by_name(q, argv, cl)
179 ## int acl_id, flags, rowcount;
180 ## char acl_type[9], *listname;
182 int client_id, status;
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");
189 return(SMS_WILDCARD);
191 return(SMS_NO_MATCH);
195 /* parse client structure */
196 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
199 /* check for client in access control list */
200 status = find_member(acl_type, acl_id, client_type, client_id, 0);
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.
213 access_member(q, argv, cl)
218 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
219 return(access_visible_list(q, &argv[1], cl));
221 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
222 if (cl->users_id == *(int *)argv[1])
230 /* access_qgli - special access routine for Qualified_get_lists. Allows
231 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
234 access_qgli(q, argv, cl)
239 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
245 /* access_service - allow access if user is on ACL of service. Don't
246 * allow access if a wildcard is used.
249 access_service(q, argv, cl)
254 ## int acl_id, rowcount;
255 ## char *name, acl_type[9];
256 int client_id, status;
260 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
261 ## where servers.#name = uppercase(@name)
262 ## inquire_equel(rowcount = "rowcount")
266 /* parse client structure */
267 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
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);
279 /* access_filesys - verify that client is owner or on owners list of filesystem
283 access_filesys(q, argv, cl)
288 ## int rowcount, users_id, list_id;
290 int status, client_id;
294 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
295 ## where filesys.label = @name
296 ## inquire_equel(rowcount = "rowcount")
300 if (users_id == cl->users_id)
302 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
304 status = find_member("LIST", list_id, client_type, client_id, 0);
315 /* Setup routine for add_user
317 * Inputs: argv[0] - login
322 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
323 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
326 setup_ausr(q, argv, cl)
328 register char *argv[];
331 ## int nuid, rowcount;
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")
339 return(SMS_INTERNAL);
340 sprintf(argv[1], "%d", nuid);
343 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
344 sprintf(argv[0], "#%s", argv[1]);
351 /* setup_dusr - verify that the user is no longer being referenced
352 * and may safely be deleted.
355 int setup_dusr(q, argv)
361 id = *(int *)argv[0];
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)
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"))
374 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
377 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
378 ## list.acl_type = "USER"))
381 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
382 ## servers.acl_type = "USER"))
385 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
386 ## hostaccess.acl_type = "USER"))
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.
398 int setup_spop(q, argv)
402 ## int id, mid, flag;
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
412 if (strcmp(strtrim(type), "POP"))
413 set_pop_usage(mid, 1);
418 /* setup_dpob: Take care of keeping track of the post office usage.
420 int setup_dpob(q, argv)
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);
432 if (!strcmp(strtrim(type), "POP"))
433 set_pop_usage(id, -1);
438 /* setup_dmac - verify that the machine is no longer being referenced
439 * and may safely be deleted.
442 int setup_dmac(q, argv)
448 id = *(int *)argv[0];
449 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
450 ## and users.pop_id=@id))
453 ## repeat retrieve (flag = any(serverhosts.mach_id
454 ## where serverhosts.mach_id=@id))
457 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
460 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
463 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
466 ## repeat retrieve (flag = any(palladium.mach_id where palladium.mach_id=@id))
470 ## repeat delete mcmap where mcmap.mach_id = @id
471 if (ingres_errno) return(sms_errcode);
476 /* setup_dclu - verify that the cluster is no longer being referenced
477 * and may safely be deleted.
480 int setup_dclu(q, argv)
486 id = *(int *)argv[0];
487 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
490 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
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
506 int setup_alis(q, argv)
514 if (!strcmp(q->shortname, "alis"))
516 else if (!strcmp(q->shortname, "ulis"))
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);
527 strcpy(argv[idx], "-1");
535 /* setup_dlist - verify that the list is no longer being referenced
536 * and may safely be deleted.
539 int setup_dlis(q, argv)
545 id = *(int *)argv[0];
546 ## repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
547 ## and imembers.member_type = "LIST"))
550 ## repeat retrieve (flag = any(imembers.member_id where imembers.list_id=@id))
553 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
556 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
559 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
560 ## list.acl_type = "LIST" and list.list_id != @id))
563 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
564 ## servers.acl_type = "LIST"))
567 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
568 ## hostaccess.acl_type = "LIST"))
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))
584 /* setup_dsin - verify that the service is no longer being referenced
585 * and may safely be deleted.
588 int setup_dsin(q, argv)
596 ## repeat retrieve (flag = any(serverhosts.service
597 ## where serverhosts.service=uppercase(@name)))
600 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
609 /* setup_dshi - verify that the service-host is no longer being referenced
610 * and may safely be deleted.
613 int setup_dshi(q, argv)
621 id = *(int *)argv[1];
622 ## repeat retrieve (flag=serverhosts.inprogress)
623 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
633 ** setup_add_filesys - verify existance of referenced file systems
645 ** * extract directory prefix from name
646 ** * verify mach_id/dir in nfsphys
647 ** * verify access in {r, w, R, W}
649 ** Side effect: sets variable var_phys_id to the ID of the physical
650 ** filesystem (nfsphys_id for NFS, 0 for RVD)
653 ** SMS_NFS - specified directory not exported
654 ** SMS_FILESYS_ACCESS - invalid filesys access
658 ##static int var_phys_id;
670 mach_id = *(int *)argv[2];
675 if (!strcmp(type, "NFS"))
676 return (check_nfs(mach_id, name, access));
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
692 char *type, *name, *access;
696 mach_id = *(int *)argv[3];
700 fid = *(int *)argv[0];
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);
707 } else if (!strcmp(type, "AFS")) {
709 ## retrieve (total = sum(nfsquota.quota where nfsquota.filsys_id = fid))
710 if (ingres_errno) return(sms_errcode);
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);
719 ## replace nfsquota (phys_id = 0) where nfsquota.filsys_id = fid
720 if (ingres_errno) return(sms_errcode);
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.
732 ##check_nfs(mach_id, name, access)
743 caccess = (isupper(*access)) ? tolower(*access) : *access;
744 if (caccess != 'r' && caccess != 'w' && caccess != 'n')
745 return(SMS_FILESYS_ACCESS);
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 {
754 if (*cp1++ != *cp2) break;
758 status = SMS_SUCCESS;
768 /* setup_dfil: free any quota records and fsgroup info associated with
769 * a filesystem when it is deleted. Also adjust the allocation numbers.
772 setup_dfil(q, argv, cl)
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
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);
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.
797 setup_dnfp(q, argv, cl)
804 id = *(int *)argv[0];
805 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
814 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
815 * argv[0] = filsys_id
819 setup_dnfq(q, argv, cl)
824 ## int quota, fs, user;
826 fs = *(int *)argv[0];
827 user = *(int *)argv[1];
829 ## range of q is nfsquota
830 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
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);
839 /* setup_sshi: don't exclusive lock the machine table during
840 * set_server_host_internal.
843 setup_sshi(q, argv, cl)
848 ## set lockmode session where readlock = system
852 /* setup add_kerberos_user_mapping: add the string to the string
853 * table if necessary.
856 setup_akum(q, argv, cl)
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"
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);
874 if (ingres_errno) return(sms_errcode);
875 *(int *)argv[1] = id;
881 /* FOLLOWUP ROUTINES */
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].
888 set_modtime(q, argv, cl)
893 ## char *name, *entity, *table;
901 ## replace table (modtime = "now", modby = who, modwith = entity)
902 ## where table.#name = name
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].
912 set_modtime_by_id(q, argv, cl)
917 ## char *entity, *table, *id_name;
923 id_name = q->validate->object_id;
925 id = *(int *)argv[0];
926 ## replace table (modtime = "now", modby = who, modwith = entity)
927 ## where table.id_name = id
932 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
935 set_finger_modtime(q, argv, cl)
940 ## int users_id, who;
945 users_id = *(int *)argv[0];
947 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
948 ## where u.#users_id = @users_id
953 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
956 set_pobox_modtime(q, argv, cl)
961 ## int users_id, who;
966 users_id = *(int *)argv[0];
968 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
969 ## where users.#users_id = @users_id
974 /* Like set_modtime, but uppercases the name first.
977 set_uppercase_modtime(q, argv, cl)
982 ## char *name, *entity, *table;
990 ## replace table (modtime = "now", modby = who, modwith = entity)
991 ## where table.#name = uppercase(name)
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".
1001 set_mach_modtime_by_id(q, argv, cl)
1009 entity = cl->entity;
1010 who = cl->client_id;
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);
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".
1024 set_cluster_modtime_by_id(q, argv, cl)
1032 entity = cl->entity;
1033 who = cl->client_id;
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);
1042 /* sets the modtime on the serverhost where the service name is in argv[0]
1043 * and the mach_id is in argv[1].
1046 set_serverhost_modtime(q, argv, cl)
1051 ## char *entity, *serv;
1054 entity = cl->entity;
1055 who = cl->client_id;
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);
1065 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1066 * directory name is in argv[1].
1069 set_nfsphys_modtime(q, argv, cl)
1074 ## char *entity, *dir;
1077 entity = cl->entity;
1078 who = cl->client_id;
1080 id = *(int *)argv[0];
1082 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1083 ## where np.#dir = @dir and np.mach_id = @id
1084 return(SMS_SUCCESS);
1088 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1092 set_filesys_modtime(q, argv, cl)
1097 ## char *label, *entity;
1100 entity = cl->entity;
1101 who = cl->client_id;
1104 if (!strcmp(q->shortname, "ufil"))
1107 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1108 ## #phys_id = @var_phys_id) where fs.#label = @label
1109 return(SMS_SUCCESS);
1113 /* sets the modtime on a zephyr class, where argv[0] contains the class
1117 set_zephyr_modtime(q, argv, cl)
1122 ## char *class, *entity;
1125 entity = cl->entity;
1126 who = cl->client_id;
1130 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1131 ## where z.#class = @class
1132 return(SMS_SUCCESS);
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.
1141 followup_fix_modby(q, sq, v, action, actarg, cl)
1143 register struct save_queue *sq;
1145 register int (*action)();
1146 register int actarg;
1150 char **argv, *malloc();
1154 while (sq_get_data(sq, &argv)) {
1157 status = id_to_name(id, "USER", &argv[i]);
1159 status = id_to_name(-id, "STRING", &argv[i]);
1160 if (status && status != SMS_NO_MATCH)
1162 (*action)(q->vcnt, argv, actarg);
1163 for (j = 0; j < q->vcnt; j++)
1168 return(SMS_SUCCESS);
1173 ** followup_ausr - add finger and pobox entries, set_user_modtime
1176 ** argv[0] - login (add_user)
1177 ** argv[3] - last name
1178 ** argv[4] - first name
1179 ** argv[5] - middle name
1183 followup_ausr(q, argv, cl)
1189 ## char *login, *entity;
1190 ## char fullname[129];
1193 who = cl->client_id;
1194 entity = cl->entity;
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]);
1202 sprintf(fullname, "%s", argv[3]);
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
1211 return(SMS_SUCCESS);
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.
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
1224 followup_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)();
1232 char **argv, *index();
1234 int mid, sid, status;
1237 while (sq_get_data(sq, &argv)) {
1238 sms_trim_args(2, argv);
1240 p = index(argv[2], ':');
1242 mid = atoi(argv[2]);
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)
1253 } else /* ptype == "NONE" */ {
1256 if (status) return(status);
1258 if (!strcmp(q->shortname, "gpob")) {
1259 sid = atoi(argv[4]);
1261 status = id_to_name(sid, "USER", &argv[4]);
1263 status = id_to_name(-sid, "STRING", &argv[4]);
1265 if (status && status != SMS_NO_MATCH) return(status);
1267 (*action)(q->vcnt, argv, actarg);
1269 /* free saved data */
1277 return (SMS_SUCCESS);
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.
1287 followup_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)();
1295 char **argv, *malloc(), *realloc(), *type;
1296 int id, i, idx, status;
1299 if (!strcmp(q->shortname, "gsin"))
1302 while (sq_get_data(sq, &argv)) {
1303 sms_trim_args(q->vcnt, argv);
1305 id = atoi(argv[i = q->vcnt - 2]);
1307 status = id_to_name(id, "USER", &argv[i]);
1309 status = id_to_name(-id, "STRING", &argv[i]);
1310 if (status && status != SMS_NO_MATCH)
1313 id = atoi(argv[idx]);
1314 type = argv[idx - 1];
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")) {
1325 argv[idx] = strsave("NONE");
1329 argv[idx] = strsave("???");
1331 if (status && status != SMS_NO_MATCH)
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);
1340 (*action)(q->vcnt, argv, actarg);
1342 /* free saved data */
1343 for (i = 0; i < q->vcnt; i++)
1349 return (SMS_SUCCESS);
1353 /* followup_gnfq: Fix the directory name & modby fields
1354 * argv[0] = filsys_id
1355 * argv[2] = ascii(quota)
1358 followup_gnfq(q, sq, v, action, actarg, cl)
1360 register struct save_queue *sq;
1362 register int (*action)();
1363 register int actarg;
1367 char **argv, *malloc();
1368 ## int id, rowcount;
1369 ## char *name, *label;
1372 while (sq_get_data(sq, &argv)) {
1375 argv[3] = malloc(256);
1379 ## repeat retrieve (name = filesys.#name) where filesys.#label = @label
1381 ## repeat retrieve (name = nfsphys.dir) where nfsphys.nfsphys_id = @id
1383 ## inquire_equel(rowcount = "rowcount")
1384 if (rowcount != 1) {
1385 sprintf(argv[3], "#%d", id);
1390 status = id_to_name(id, "USER", &argv[6]);
1392 status = id_to_name(-id, "STRING", &argv[6]);
1393 if (status && status != SMS_NO_MATCH)
1395 (*action)(q->vcnt, argv, actarg);
1396 for (j = 0; j < q->vcnt; j++)
1401 return(SMS_SUCCESS);
1405 /* followup_anfq: Add allocation to nfsphys after creating quota.
1406 * argv[0] = filsys_id
1407 * argv[2] = ascii(quota)
1410 followup_anfq(q, argv, cl)
1415 ## int quota, user, fs, who;
1418 fs = *(int *)argv[0];
1419 user = *(int *)argv[1];
1420 quota = atoi(argv[2]);
1421 who = cl->client_id;
1422 entity = cl->entity;
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);
1436 followup_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)();
1447 while (sq_get_data(sq, &argv)) {
1448 sms_trim_args(q->vcnt, argv);
1450 id = atoi(argv[i = q->vcnt - 2]);
1452 status = id_to_name(id, "USER", &argv[i]);
1454 status = id_to_name(-id, "STRING", &argv[i]);
1455 if (status && status != SMS_NO_MATCH)
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")) {
1469 argv[i+1] = strsave("NONE");
1473 argv[i+1] = strsave("???");
1475 if (status && status != SMS_NO_MATCH)
1480 (*action)(q->vcnt, argv, actarg);
1482 /* free saved data */
1483 for (i = 0; i < q->vcnt; i++)
1488 return(SMS_SUCCESS);
1495 followup_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)();
1506 while (sq_get_data(sq, &argv)) {
1507 sms_trim_args(q->vcnt, argv);
1511 status = id_to_name(id, "USER", &argv[4]);
1513 status = id_to_name(-id, "STRING", &argv[4]);
1514 if (status && status != SMS_NO_MATCH)
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")) {
1527 argv[2] = strsave("NONE");
1531 argv[2] = strsave("???");
1533 if (status && status != SMS_NO_MATCH)
1537 (*action)(q->vcnt, argv, actarg);
1539 /* free saved data */
1540 for (i = 0; i < q->vcnt; i++)
1545 return(SMS_SUCCESS);
1550 /* Special query routines */
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.
1559 int set_pobox(q, argv, cl)
1564 ## int user, id, rowcount;
1565 ## char *box, potype[9];
1569 user = *(int *)argv[0];
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);
1577 if (!strcmp(argv[1], "POP")) {
1578 status = name_to_id(box, "MACHINE", &id);
1579 if (status == SMS_NO_MATCH)
1580 return(SMS_MACHINE);
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"
1593 ## repeat replace values (value = @id) where values.name = "strings_id"
1594 ## append to strings (string_id = id, string = box)
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
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);
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.
1616 get_list_info(q, aargv, cl, action, actarg)
1617 register struct query *q;
1620 register int (*action)();
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();
1631 returned = rowcount = 0;
1635 ## range of l is list
1636 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1637 sq_save_data(sq, id);
1640 if (ingres_errno) return(sms_errcode);
1642 return(SMS_NO_MATCH);
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;
1648 while (sq_get_data(sq, &id)) {
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);
1662 if (atoi(gid) == -1)
1663 argv[6] = UNIQUE_GID;
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")) {
1675 argv[8] = strsave("NONE");
1679 argv[8] = strsave("???");
1681 if (status && status != SMS_NO_MATCH) return(status);
1683 argv[11] = malloc(0);
1685 status = id_to_name(modby_id, "USER", &argv[11]);
1687 status = id_to_name(-modby_id, "STRING", &argv[11]);
1688 if (status && status != SMS_NO_MATCH) return(status);
1690 sms_trim_args(q->vcnt, argv);
1692 (*action)(q->vcnt, argv, actarg);
1698 if (ingres_errno) return(sms_errcode);
1699 return (SMS_SUCCESS);
1703 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
1704 * how many different ancestors a member is allowed to have.
1707 #define MAXLISTDEPTH 100
1709 int add_member_to_list(q, argv, cl)
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;
1719 char *dtypes[MAXLISTDEPTH];
1720 char *iargv[3], *buf;
1722 ## range of m is imembers
1723 lid = *(int *)argv[0];
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))
1732 if (!strcasecmp(mtype, "STRING")) {
1734 status = id_to_name(mid, "STRING", &buf);
1735 if (status) return(status);
1736 if (index(buf, '/') || index(buf, '|')) {
1738 return(SMS_BAD_CHAR);
1746 ## repeat retrieve (id = m.list_id, ref = m.ref_count)
1747 ## where m.member_id = @lid and m.member_type = "LIST" {
1749 ancestors[acount++] = id;
1750 if (acount >= MAXLISTDEPTH) {
1754 if (ingres_errno) return(sms_errcode);
1755 if (acount >= MAXLISTDEPTH) {
1756 return(SMS_INTERNAL);
1758 descendants[0] = mid;
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 {
1769 dtypes[dcount] = "LIST";
1772 dtypes[dcount] = "USER";
1775 dtypes[dcount] = "STRING";
1778 dtypes[dcount] = "KERBEROS";
1785 descendants[dcount++] = id;
1786 if (dcount >= MAXLISTDEPTH) {
1791 if (ingres_errno) return(sms_errcode);
1793 return(SMS_INTERNAL);
1795 for (a = 0; a < acount; a++) {
1797 for (d = 0; d < dcount; d++) {
1798 mid = descendants[d];
1800 if (mid == lid && !strcmp(mtype, "LIST")) {
1801 return(SMS_LISTLOOP);
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];
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
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
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)
1822 ## append imembers (list_id=lid, member_id = mid,
1823 ## member_type=mtype, ref_count = ref)
1824 iargv[0] = (char *)lid;
1826 iargv[2] = (char *)mid;
1827 incremental_after("members", 0, iargv);
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);
1841 /* Delete_member_from_list: do list flattening as we go!
1844 int delete_member_from_list(q, argv, cl)
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];
1856 ## range of m is imembers
1857 lid = *(int *)argv[0];
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);
1866 return(SMS_NO_MATCH);
1870 ## repeat retrieve (id = m.list_id, ref = m.ref_count)
1871 ## where m.member_id = @lid and m.member_type = "LIST" {
1873 ancestors[acount++] = id;
1874 if (acount >= MAXLISTDEPTH)
1877 if (ingres_errno) return(sms_errcode);
1878 if (acount >= MAXLISTDEPTH)
1879 return(SMS_INTERNAL);
1880 descendants[0] = mid;
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 {
1891 dtypes[dcount] = "LIST";
1894 dtypes[dcount] = "USER";
1897 dtypes[dcount] = "STRING";
1900 dtypes[dcount] = "KERBEROS";
1907 descendants[dcount++] = id;
1908 if (dcount >= MAXLISTDEPTH)
1911 if (ingres_errno) return(sms_errcode);
1913 return(SMS_INTERNAL);
1915 for (a = 0; a < acount; a++) {
1917 for (d = 0; d < dcount; d++) {
1918 mid = descendants[d];
1920 if (mid == lid && !strcmp(mtype, "LIST")) {
1921 return(SMS_LISTLOOP);
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];
1928 iargv[0] = (char *)lid;
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
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
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);
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.
1964 int get_ace_use(q, argv, cl, action, actarg)
1973 ## int aid, listid, id;
1974 struct save_queue *sq, *sq_create();
1976 ## range of m is imembers
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));
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);
1992 /* now process each one */
1993 while (sq_get_data(sq, &id)) {
1994 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
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);
2004 /* now process each one */
2005 while (sq_get_data(sq, &id)) {
2006 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2009 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
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);
2018 /* now process each one */
2019 while (sq_get_data(sq, &id)) {
2020 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2023 if (get_ace_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
2028 if (ingres_errno) return(sms_errcode);
2029 if (!found) return(SMS_NO_MATCH);
2030 return(SMS_SUCCESS);
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.
2039 ##get_ace_internal(atype, aid, action, actarg)
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);
2059 ## repeat retrieve (name = capacls.capability)
2060 ## where capacls.list_id = @aid {
2061 (*action)(2, rargv, actarg);
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);
2074 ## repeat retrieve (name = list.#name)
2075 ## where list.acl_type = @atype and list.acl_id = @aid {
2076 (*action)(2, rargv, actarg);
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);
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);
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);
2104 if (!found) return(SMS_NO_MATCH);
2105 return(SMS_SUCCESS);
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.
2117 int get_lists_of_member(q, argv, cl, action, actarg)
2124 int found = 0, direct = 1;
2127 ## int aid, listid, id;
2128 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
2131 aid = *(int *)argv[1];
2132 if (!strcmp(atype, "RLIST")) {
2136 if (!strcmp(atype, "RUSER")) {
2140 if (!strcmp(atype, "RSTRING")) {
2144 if (!strcmp(atype, "RKERBEROS")) {
2153 rargv[4] = maillist;
2155 ## range of m is imembers
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);
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);
2176 if (ingres_errno) return(sms_errcode);
2177 if (!found) return(SMS_NO_MATCH);
2178 return(SMS_SUCCESS);
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.
2188 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2190 int qualified_get_lists(q, argv, cl, action, actarg)
2197 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2198 "l", "name", lflags));
2202 /** get_members_of_list - optimized query for retrieval of list members
2205 ** argv[0] - list_id
2208 ** - retrieve USER members, then LIST members, then STRING members
2211 get_members_of_list(q, argv, cl, action, actarg)
2219 ## char member_name[129];
2222 list_id = *(int *)argv[0];
2224 targv[1] = member_name;
2226 ## range of m is imembers
2227 ## repeat retrieve (member_name = users.login)
2228 ## where m.#list_id = @list_id and m.member_type = "USER"
2229 ## and m.member_id = users.users_id and m.direct = 1
2230 ## sort by #member_name
2232 (*action)(2, targv, actarg);
2234 if (ingres_errno) return(sms_errcode);
2237 ## repeat retrieve (member_name = list.name)
2238 ## where m.#list_id = @list_id and m.member_type = "LIST"
2239 ## and m.member_id = list.#list_id and m.direct = 1
2240 ## sort by #member_name
2242 (*action)(2, targv, actarg);
2244 if (ingres_errno) return(sms_errcode);
2246 targv[0] = "STRING";
2247 ## repeat retrieve (member_name = strings.string)
2248 ## where m.#list_id = @list_id and m.member_type = "STRING"
2249 ## and m.member_id = strings.string_id and m.direct = 1
2250 ## sort by #member_name
2252 (*action)(2, targv, actarg);
2254 if (ingres_errno) return(sms_errcode);
2256 targv[0] = "KERBEROS";
2257 ## repeat retrieve (member_name = strings.string)
2258 ## where m.#list_id = @list_id and m.member_type = "KERBEROS"
2259 ## and m.member_id = strings.string_id and m.direct = 1
2260 ## sort by #member_name
2262 (*action)(2, targv, actarg);
2264 if (ingres_errno) return(sms_errcode);
2266 return(SMS_SUCCESS);
2270 /* count_members_of_list: this is a simple query, but it cannot be done
2271 * through the dispatch table.
2274 int count_members_of_list(q, argv, cl, action, actarg)
2281 ## int list, ct = 0;
2282 char *rargv[1], countbuf[5];
2284 list = *(int *)argv[0];
2285 rargv[0] = countbuf;
2286 ## repeat retrieve (ct = count(imembers.list_id
2287 ## where imembers.list_id = @list and
2288 ## imembers.direct = 1))
2289 if (ingres_errno) return(sms_errcode);
2290 sprintf(countbuf, "%d", ct);
2291 (*action)(1, rargv, actarg);
2292 return(SMS_SUCCESS);
2296 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2297 * the three flags associated with each service. It will return the name of
2298 * each service that meets the quailifications. It does this by building a
2299 * where clause based on the arguments, then doing a retrieve.
2302 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2304 int qualified_get_server(q, argv, cl, action, actarg)
2311 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2312 "s", "name", sflags));
2316 /* generic qualified get routine, used by qualified_get_lists,
2317 * qualified_get_server, and qualified_get_serverhost.
2319 * start - a simple where clause, must not be empty
2320 * range - the name of the range variable
2321 * field - the field to return
2322 * flags - an array of strings, names of the flag variables
2325 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2335 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2336 char *rargv[1], buf[32];
2339 strcpy(qual, start);
2340 for (i = 0; i < q->argc; i++) {
2341 if (!strcmp(argv[i], "TRUE")) {
2342 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2343 (void) strcat(qual, buf);
2344 } else if (!strcmp(argv[i], "FALSE")) {
2345 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2346 (void) strcat(qual, buf);
2354 ## range of rvar is rtbl
2355 ## retrieve (name = rvar.rfield) where qual {
2356 (*action)(1, rargv, actarg);
2358 if (ingres_errno) return(sms_errcode);
2359 ## inquire_equel(rowcount = "rowcount")
2361 return(SMS_NO_MATCH);
2362 return(SMS_SUCCESS);
2366 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2367 * the five flags associated with each serverhost. It will return the name of
2368 * each service and host that meets the quailifications. It does this by
2369 * building a where clause based on the arguments, then doing a retrieve.
2372 static char *shflags[6] = { "service", "enable", "override", "success",
2373 "inprogress", "hosterror" };
2375 int qualified_get_serverhost(q, argv, cl, action, actarg)
2382 ## char sname[33], mname[33], qual[256];
2383 char *rargv[2], buf[32];
2386 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2388 for (i = 1; i < q->argc; i++) {
2389 if (!strcmp(argv[i], "TRUE")) {
2390 sprintf(buf, " and sh.%s != 0", shflags[i]);
2392 } else if (!strcmp(argv[i], "FALSE")) {
2393 sprintf(buf, " and sh.%s = 0", shflags[i]);
2400 ## range of sh is serverhosts
2401 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2402 (*action)(2, rargv, actarg);
2404 if (ingres_errno) return(sms_errcode);
2405 ## inquire_equel(rowcount = "rowcount")
2407 return(SMS_NO_MATCH);
2408 return(SMS_SUCCESS);
2412 /* register_user - change user's login name and allocate a pobox, group,
2413 * filesystem, and quota for them. The user's status must start out as 0,
2414 * and is left as 2. Arguments are: user's UID, new login name, and user's
2415 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2416 * SMS_FS_STAFF, SMS_FS_MISC).
2419 register_user(q, argv, cl)
2424 ## char *login, dir[65], *entity, *directory, machname[33];
2425 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2426 ## int size, alloc, pid, m_id;
2427 char buffer[256], *aargv[3];
2430 entity = cl->entity;
2431 who = cl->client_id;
2433 uid = atoi(argv[0]);
2435 utype = atoi(argv[2]);
2437 ## range of u is users
2438 ## range of l is list
2439 ## range of sh is serverhosts
2440 ## range of n is nfsphys
2441 ## range of m is machine
2444 ## repeat retrieve (users_id = u.#users_id)
2445 ## where u.#uid = @uid and (u.status = 0 or u.status = 5)
2446 ## inquire_equel(rowcount = "rowcount");
2448 return(SMS_NO_MATCH);
2450 return(SMS_NOT_UNIQUE);
2452 /* check new login name */
2453 ## repeat retrieve (flag = any(u.#login where u.#login = @login and
2454 ## u.#users_id != users_id))
2455 if (ingres_errno) return(sms_errcode);
2456 if (flag) return(SMS_IN_USE);
2457 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2458 if (ingres_errno) return(sms_errcode);
2459 if (flag) return(SMS_IN_USE);
2460 ## repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2461 if (ingres_errno) return(sms_errcode);
2462 if (flag) return(SMS_IN_USE);
2463 com_err(whoami, 0, "new login name OK");
2465 /* choose place for pobox, put in mid */
2466 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2467 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2468 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2469 if (ingres_errno) return(sms_errcode);
2470 ## inquire_equel(rowcount = "rowcount");
2472 return(SMS_NO_POBOX);
2474 /* change login name, set pobox */
2475 sprintf(buffer, "u.users_id = %d", users_id);
2476 incremental_before("users", buffer, 0);
2477 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2478 ## modby = @who, modwith = @entity, potype="POP",
2479 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2480 ## pmodwith=@entity)
2481 ## where u.#users_id = @users_id
2482 ## inquire_equel(rowcount = "rowcount");
2483 if (ingres_errno) return(sms_errcode);
2485 return(SMS_INTERNAL);
2486 set_pop_usage(mid, 1);
2487 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2489 incremental_after("users", buffer, 0);
2491 /* create group list */
2492 if (set_next_object_id("gid", "list"))
2494 if (set_next_object_id("list_id", "list"))
2496 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2497 if (ingres_errno) return(sms_errcode);
2498 ## inquire_equel(rowcount = "rowcount");
2500 return(SMS_INTERNAL);
2501 incremental_clear_before();
2502 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2503 ## public = 0, hidden = 0, maillist = 0, group = 1,
2504 ## #gid = values.value, desc = "User Group",
2505 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2506 ## modby = @who, modwith = @entity)
2507 ## where values.name = "gid"
2508 if (ingres_errno) return(sms_errcode);
2509 ## inquire_equel(rowcount = "rowcount");
2511 return(SMS_INTERNAL);
2512 sprintf(buffer, "l.list_id = %d", list_id);
2513 incremental_after("list", buffer, 0);
2514 aargv[0] = (char *) list_id;
2516 aargv[2] = (char *) users_id;
2517 incremental_clear_before();
2518 ## repeat append imembers (#list_id = @list_id, member_type = "USER",
2519 ## member_id = @users_id, ref_count = 1, direct = 1)
2520 if (ingres_errno) return(sms_errcode);
2521 ## inquire_equel(rowcount = "rowcount");
2523 return(SMS_INTERNAL);
2524 incremental_after("members", 0, aargv);
2525 com_err(whoami, 0, "group list created");
2527 /* decide where to put filesystem */
2530 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2531 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2532 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2533 maxsize = size - alloc;
2536 directory = strsave(dir);
2541 if (ingres_errno) return(sms_errcode);
2543 return(SMS_NO_FILESYS);
2545 /* create filesystem */
2546 if (set_next_object_id("filsys_id", "filesys"))
2548 incremental_clear_before();
2549 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2550 ## label = @login, type = "NFS", mach_id = @m_id,
2551 ## name = @directory + "/" + @login,
2552 ## mount = "/mit/" + @login,
2553 ## access = "w", comments = "User Locker",
2554 ## owner = @users_id, owners = @list_id, createflg = 1,
2555 ## lockertype = "HOMEDIR", modtime = "now",
2556 ## modby = @who, modwith = @entity)
2557 ## where values.name = "filsys_id"
2558 if (ingres_errno) return(sms_errcode);
2559 ## inquire_equel(rowcount = "rowcount");
2561 return(SMS_INTERNAL);
2562 incremental_after("filesys",
2563 "fs.filsys_id = values.value and values.name = \"filsys_id\"",
2565 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2569 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2570 if (ingres_errno) return(sms_errcode);
2571 ## inquire_equel(rowcount = "rowcount");
2573 return(SMS_NO_QUOTA);
2574 incremental_clear_before();
2575 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2576 ## #quota = @quota, phys_id = @pid, modtime = "now",
2577 ## modby = @who, modwith = @entity)
2578 ## where values.name = "filsys_id"
2579 if (ingres_errno) return(sms_errcode);
2580 ## inquire_equel(rowcount = "rowcount");
2582 return(SMS_INTERNAL);
2583 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2584 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2585 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2586 if (ingres_errno) return(sms_errcode);
2587 ## inquire_equel(rowcount = "rowcount");
2589 return(SMS_INTERNAL);
2592 sprintf(buffer, "nq.users_id = %d and nq.filsys_id = values.value and values.name = \"filsys_id\"", users_id);
2593 incremental_after("nfsquota", buffer, aargv);
2594 com_err(whoami, 0, "quota of %d assigned", quota);
2595 if (ingres_errno) return(sms_errcode);
2597 cache_entry(login, "USER", users_id);
2599 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2600 ## where tblstats.table = "users"
2601 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2602 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2603 ## tblstats.table = "nfsquota"
2604 if (ingres_errno) return(sms_errcode);
2605 return(SMS_SUCCESS);
2610 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2614 ** delta (will be +/- 1)
2617 ** - incr/decr value field in serverhosts table for pop/mach_id
2621 static int set_pop_usage(id, count)
2625 ## int mach_id = id;
2628 ## repeat replace serverhosts (value1 = serverhosts.value1 + @n)
2629 ## where serverhosts.service = "POP" and serverhosts.#mach_id = @mach_id
2631 if (ingres_errno) return(sms_errcode);
2632 return(SMS_SUCCESS);
2637 /* Validation Routines */
2639 validate_row(q, argv, v)
2640 register struct query *q;
2642 register struct validate *v;
2650 /* build where clause */
2651 build_qual(v->qual, v->argc, argv, qual);
2653 /* setup ingres variables */
2658 if (log_flags & LOG_VALID)
2659 /* tell the logfile what we're doing */
2660 com_err(whoami, 0, "validating row: %s", qual);
2662 /* look for the record */
2663 ## range of rvar is table
2664 ## retrieve (rowcount = count(rvar.name where qual))
2665 if (ingres_errno) return(sms_errcode);
2666 if (rowcount == 0) return(SMS_NO_MATCH);
2667 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2671 validate_fields(q, argv, vo, n)
2673 register char *argv[];
2674 register struct valobj *vo;
2677 register int status;
2682 if (log_flags & LOG_VALID)
2683 com_err(whoami, 0, "validating %s in %s: %s",
2684 vo->namefield, vo->table, argv[vo->index]);
2685 status = validate_name(argv, vo);
2689 if (log_flags & LOG_VALID)
2690 com_err(whoami, 0, "validating %s in %s: %s",
2691 vo->idfield, vo->table, argv[vo->index]);
2692 status = validate_id(argv, vo);
2696 if (log_flags & LOG_VALID)
2697 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2698 status = validate_date(argv, vo);
2702 if (log_flags & LOG_VALID)
2703 com_err(whoami, 0, "validating %s type: %s",
2704 vo->table, argv[vo->index]);
2705 status = validate_type(argv, vo);
2709 if (log_flags & LOG_VALID)
2710 com_err(whoami, 0, "validating typed data (%s): %s",
2711 argv[vo->index - 1], argv[vo->index]);
2712 status = validate_typedata(q, argv, vo);
2716 if (log_flags & LOG_VALID)
2717 com_err(whoami, 0, "validating rename %s in %s",
2718 argv[vo->index], vo->table);
2719 status = validate_rename(argv, vo);
2723 if (log_flags & LOG_VALID)
2724 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2725 status = validate_chars(argv[vo->index]);
2729 status = SMS_EXISTS;
2733 status = lock_table(vo);
2737 if (status != SMS_EXISTS) return(status);
2741 if (ingres_errno) return(sms_errcode);
2742 return(SMS_SUCCESS);
2746 /* validate_chars: verify that there are no illegal characters in
2747 * the string. Legal characters are printing chars other than
2748 * ", *, ?, \, [ and ].
2750 static int illegalchars[] = {
2751 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2752 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2753 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2754 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2755 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2756 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2757 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2758 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2759 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2760 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2761 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2762 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2763 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2764 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2765 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2766 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2773 if (illegalchars[*s++])
2774 return(SMS_BAD_CHAR);
2779 validate_id(argv, vo)
2781 register struct valobj *vo;
2787 ## int id, rowcount;
2792 name = argv[vo->index];
2794 namefield = vo->namefield;
2795 idfield = vo->idfield;
2797 if ((!strcmp(table, "users") && !strcmp(namefield, "login")) ||
2798 !strcmp(table, "machine") ||
2799 !strcmp(table, "filesys") ||
2800 !strcmp(table, "list") ||
2801 !strcmp(table, "cluster") ||
2802 !strcmp(table, "string")) {
2803 if (!strcmp(table, "machine"))
2804 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2805 status = name_to_id(name, table, &id);
2807 *(int *)argv[vo->index] = id;
2809 } else if (status == SMS_NO_MATCH || status == SMS_NOT_UNIQUE)
2815 if (!strcmp(namefield, "uid")) {
2816 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2817 if (ingres_errno) return(sms_errcode);
2818 ## inquire_equel (rowcount = "rowcount")
2820 ## retrieve (id = table.idfield) where table.namefield = name
2821 if (ingres_errno) return(sms_errcode);
2822 ## inquire_equel (rowcount = "rowcount")
2824 if (rowcount != 1) return(vo->error);
2825 *(int *)argv[vo->index] = id;
2829 validate_name(argv, vo)
2831 register struct valobj *vo;
2839 name = argv[vo->index];
2841 namefield = vo->namefield;
2842 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2843 for (c = name; *c; c++)
2847 ## retrieve (rowcount = countu(table.namefield
2848 ## where table.namefield = name))
2849 if (ingres_errno) return(sms_errcode);
2850 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2853 validate_date(argv, vo)
2861 idate = argv[vo->index];
2863 ## retrieve (dd = interval("years", date(idate) - date("today")))
2864 ## inquire_equel (errorno = "errorno")
2865 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2870 validate_rename(argv, vo)
2874 ## char *name, *table, *namefield, *idfield;
2879 c = name = argv[vo->index];
2881 if (illegalchars[*c++])
2882 return(SMS_BAD_CHAR);
2884 /* minor kludge to upcasify machine names */
2885 if (!strcmp(table, "machine"))
2886 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2887 namefield = vo->namefield;
2888 idfield = vo->idfield;
2891 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2893 ## retrieve (id = any(table.namefield where table.namefield = name))
2894 if (ingres_errno) return(sms_errcode);
2900 status = name_to_id(name, table, &id);
2901 if (status == SMS_NO_MATCH || id == *(int *)argv[vo->index - 1])
2908 validate_type(argv, vo)
2910 register struct valobj *vo;
2917 typename = vo->table;
2918 c = value = argv[vo->index];
2920 if (illegalchars[*c++])
2921 return(SMS_BAD_CHAR);
2923 /* uppercase type fields */
2924 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2926 ## repeat retrieve (exists = any(alias.trans where alias.name = @typename and
2927 ## alias.type = "TYPE" and alias.trans = @value))
2928 if (ingres_errno) return(sms_errcode);
2929 return (exists ? SMS_EXISTS : vo->error);
2932 /* validate member or type-specific data field */
2934 validate_typedata(q, argv, vo)
2935 register struct query *q;
2936 register char *argv[];
2937 register struct valobj *vo;
2940 ## char *field_type;
2941 ## char data_type[129];
2942 ## int id, rowcount;
2947 /* get named object */
2948 name = argv[vo->index];
2950 /* get field type string (known to be at index-1) */
2951 field_type = argv[vo->index-1];
2953 /* get corresponding data type associated with field type name */
2954 ## repeat retrieve (data_type = alias.trans)
2955 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2956 if (ingres_errno) return(sms_errcode);
2957 ## inquire_equel (rowcount = "rowcount")
2958 if (rowcount != 1) return(SMS_TYPE);
2960 /* now retrieve the record id corresponding to the named object */
2961 if (index(data_type, ' '))
2962 *index(data_type, ' ') = 0;
2963 if (!strcmp(data_type, "user")) {
2965 status = name_to_id(name, data_type, &id);
2966 if (status && (status == SMS_NO_MATCH || status == SMS_NOT_UNIQUE))
2968 if (status) return(status);
2969 } else if (!strcmp(data_type, "list")) {
2971 status = name_to_id(name, data_type, &id);
2972 if (status && status == SMS_NOT_UNIQUE)
2974 if (status == SMS_NO_MATCH) {
2975 /* if idfield is non-zero, then if argv[0] matches the string
2976 * that we're trying to resolve, we should get the value of
2977 * values.[idfield] for the id.
2979 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2980 set_next_object_id(q->validate->object_id, q->rtable);
2982 ## repeat retrieve (id = values.value) where values.#name = @name
2983 ## inquire_equel(rowcount = "rowcount")
2984 if (rowcount != 1) return(SMS_LIST);
2987 } else if (status) return(status);
2988 } else if (!strcmp(data_type, "machine")) {
2990 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2991 status = name_to_id(name, data_type, &id);
2992 if (status && (status == SMS_NO_MATCH || status == SMS_NOT_UNIQUE))
2993 return(SMS_MACHINE);
2994 if (status) return(status);
2995 } else if (!strcmp(data_type, "string")) {
2997 status = name_to_id(name, data_type, &id);
2998 if (status && status == SMS_NOT_UNIQUE)
3000 if (status == SMS_NO_MATCH) {
3001 if (q->type != APPEND && q->type != UPDATE) return(SMS_STRING);
3002 ## retrieve (id = values.value) where values.#name = "strings_id"
3004 ## replace values (value = id) where values.#name = "strings_id"
3005 ## append to strings (string_id = id, string = name)
3006 } else if (status) return(status);
3007 } else if (!strcmp(data_type, "none")) {
3013 /* now set value in argv */
3014 *(int *)argv[vo->index] = id;
3016 return (SMS_EXISTS);
3020 /* Lock the table named by the validation object */
3025 ## char *table, *idfield;
3029 idfield = vo->idfield;
3030 ## replace table (modtime = "now") where table.idfield = 0
3031 if (ingres_errno) return(sms_errcode);
3032 ## inquire_equel (rowcount = "rowcount")
3040 /* Check the database at startup time. For now this just resets the
3041 * inprogress flags that the DCM uses.
3044 sanity_check_database()