5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
11 #include "mr_server.h"
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
22 EXEC SQL INCLUDE sqlca;
27 extern int dbms_errno, mr_errcode;
29 EXEC SQL BEGIN DECLARE SECTION;
30 extern char stmt_buf[];
31 EXEC SQL END DECLARE SECTION;
33 EXEC SQL WHENEVER SQLERROR DO dbmserr();
35 int hostname_check(char *name);
36 int hostinfo_check(char *name, int num);
37 int prefetch_value(struct query *q, char **argv, client *cl);
38 int check_nfs(int mach_idx, char *name, char *access);
42 /* Setup routine for add_user
44 * Inputs: argv[0] - login
49 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
50 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
53 int setup_ausr(struct query *q, char *argv[], client *cl)
56 EXEC SQL BEGIN DECLARE SECTION;
58 EXEC SQL END DECLARE SECTION;
60 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
65 if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
66 strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
67 return MR_ARG_TOO_LONG;
69 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
71 if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
73 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
74 if (sqlca.sqlerrd[2] != 1)
76 sprintf(argv[row], "%d", nuid);
79 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
80 sprintf(argv[0], "#%s", argv[row]);
82 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
89 /* setup_dusr - verify that the user is no longer being referenced
90 * and may safely be deleted.
93 int setup_dusr(struct query *q, char *argv[], client *cl)
95 EXEC SQL BEGIN DECLARE SECTION;
97 EXEC SQL END DECLARE SECTION;
101 /* For now, only allow users to be deleted if their status is 0 */
102 EXEC SQL SELECT status INTO :flag FROM users WHERE users_id = :id;
103 if (flag != 0 && flag != 4)
106 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
107 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
108 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
109 WHERE member_id = :id AND member_type = 'USER';
112 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
116 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
117 WHERE acl_id = :id AND acl_type = 'USER';
120 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
121 WHERE acl_id = :id AND acl_type = 'USER';
124 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
125 WHERE acl_id = :id AND acl_type = 'USER';
134 /* setup_dpob: Take care of keeping track of the post office usage.
136 int setup_dpob(struct query *q, char *argv[], client *cl)
138 EXEC SQL BEGIN DECLARE SECTION;
140 char type[USERS_POTYPE_SIZE];
141 EXEC SQL END DECLARE SECTION;
143 user = *(int *)argv[0];
144 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
145 WHERE users_id = :user;
149 if (!strcmp(strtrim(type), "POP"))
150 set_pop_usage(id, -1);
155 /* setup_dmac - verify that the machine is no longer being referenced
156 * and may safely be deleted.
159 int setup_dmac(struct query *q, char *argv[], client *cl)
161 EXEC SQL BEGIN DECLARE SECTION;
163 EXEC SQL END DECLARE SECTION;
165 id = *(int *)argv[0];
167 EXEC SQL SELECT status INTO :flag FROM machine
171 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
172 WHERE potype = 'POP' AND pop_id = :id;
175 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
179 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
183 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
187 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
191 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
195 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
199 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
203 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
208 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
215 /* setup_dsnt - verify that the subnet is no longer being referenced
216 * and may safely be deleted.
219 int setup_dsnt(struct query *q, char *argv[], client *cl)
221 EXEC SQL BEGIN DECLARE SECTION;
223 EXEC SQL END DECLARE SECTION;
225 id = *(int *)argv[0];
226 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
234 /* setup_dclu - verify that the cluster is no longer being referenced
235 * and may safely be deleted.
238 int setup_dclu(struct query *q, char *argv[], client *cl)
240 EXEC SQL BEGIN DECLARE SECTION;
242 EXEC SQL END DECLARE SECTION;
244 id = *(int *)argv[0];
245 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
249 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
259 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
260 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
261 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
262 * a -1 there. Remember that this is also used for ulis, with the indexes
263 * at 6 & 7. Also check that the list name does not contain uppercase
264 * characters, control characters, @, or :.
267 static int badlistchars[] = {
268 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
269 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
270 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
272 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
273 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
275 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
276 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
277 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
278 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
279 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
280 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
281 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
282 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
283 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
286 int setup_alis(struct query *q, char *argv[], client *cl)
288 EXEC SQL BEGIN DECLARE SECTION;
291 EXEC SQL END DECLARE SECTION;
295 if (!strcmp(q->shortname, "alis"))
297 else if (!strcmp(q->shortname, "ulis"))
303 EXEC SQL BEGIN DECLARE SECTION;
304 int lid = *(int *)argv[0];
305 EXEC SQL END DECLARE SECTION;
307 if (acl_access_check(lid, cl))
311 for (p = (unsigned char *) name; *p; p++)
313 if (badlistchars[*p])
317 /* Check that it doesn't conflict with a pre-existing weirdly-cased
319 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
320 WHERE LOWER(name) = :name AND name != :name;
324 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
326 if (atoi(argv[5 + idx]))
328 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
330 EXEC SQL SELECT value INTO :ngid FROM numvalues
334 sprintf(argv[6 + idx], "%d", ngid);
337 strcpy(argv[6 + idx], "-1");
340 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
347 /* setup_dlis - verify that the list is no longer being referenced
348 * and may safely be deleted.
351 int setup_dlis(struct query *q, char *argv[], client *cl)
354 EXEC SQL BEGIN DECLARE SECTION;
356 EXEC SQL END DECLARE SECTION;
358 id = *(int *)argv[0];
360 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
361 WHERE member_id = :id AND member_type = 'LIST';
365 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
366 WHERE member_id = :id AND member_type = 'LIST';
370 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
375 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
379 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
383 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
384 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
388 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
389 WHERE acl_id = :id AND acl_type = 'LIST';
393 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
394 WHERE entity_id = :id AND type = 'GROUP';
398 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
399 WHERE acl_id = :id AND acl_type = 'LIST';
403 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
404 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
405 OR z.sub_type = 'LIST' AND z.sub_id = :id
406 OR z.iws_type = 'LIST' AND z.iws_id = :id
407 OR z.iui_type = 'LIST' AND z.iui_id = :id;
411 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
412 WHERE lpc_acl = :id OR ac = :id;
416 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
417 WHERE owner_type = 'LIST' AND owner_id = :id
426 /* setup_dsin - verify that the service is no longer being referenced
427 * and may safely be deleted.
430 int setup_dsin(struct query *q, char *argv[], client *cl)
432 EXEC SQL BEGIN DECLARE SECTION;
435 EXEC SQL END DECLARE SECTION;
438 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
439 WHERE service = UPPER(:svrname);
443 EXEC SQL SELECT inprogress INTO :ec FROM servers
444 WHERE name = UPPER(:svrname);
454 /* setup_dshi - verify that the service-host is no longer being referenced
455 * and may safely be deleted.
458 int setup_dshi(struct query *q, char *argv[], client *cl)
460 EXEC SQL BEGIN DECLARE SECTION;
463 EXEC SQL END DECLARE SECTION;
466 id = *(int *)argv[1];
468 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
469 WHERE service = UPPER(:svrname) AND mach_id = :id;
480 ** setup_add_filesys - verify existance of referenced file systems
486 ** argv[5] - rwaccess
491 ** - for type = NFS/IMAP:
492 ** * extract directory prefix from name
493 ** * verify mach_id/dir in nfsphys
494 ** * verify rwaccess in {r, w, R, W}
496 ** Side effect: sets variable _var_phys_id to the ID of the physical
497 ** filesystem (nfsphys_id for NFS, 0 for RVD)
500 ** MR_NFS - specified directory not exported
501 ** MR_FILESYS_ACCESS - invalid filesys access
505 EXEC SQL BEGIN DECLARE SECTION;
507 EXEC SQL END DECLARE SECTION;
509 int setup_afil(struct query *q, char *argv[], client *cl)
513 EXEC SQL BEGIN DECLARE SECTION;
515 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
516 EXEC SQL END DECLARE SECTION;
519 mach_id = *(int *)argv[2];
524 sprintf(ftype, "fs_access_%s", type);
525 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
526 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
530 return MR_FILESYS_ACCESS;
532 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
535 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
536 return check_nfs(mach_id, name, rwaccess);
542 /* Verify the arguments, depending on the FStype. Also, if this is an
543 * NFS filesystem, then update any quotas for that filesystem to reflect
547 int setup_ufil(struct query *q, char *argv[], client *cl)
551 EXEC SQL BEGIN DECLARE SECTION;
552 int fid, total, who, ok;
553 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
554 short int total_null;
555 EXEC SQL END DECLARE SECTION;
559 mach_id = *(int *)argv[3];
562 fid = *(int *)argv[0];
566 sprintf(ftype, "fs_access_%s", type);
567 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
568 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
572 return MR_FILESYS_ACCESS;
574 EXEC SQL SELECT type INTO :ftype FROM filesys
575 WHERE filsys_id = :fid;
579 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
581 status = check_nfs(mach_id, name, access);
582 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
583 WHERE filsys_id = :fid;
588 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
589 && strcmp(strtrim(ftype), "ERR"))
592 EXEC SQL DELETE FROM quota
593 WHERE type = 'ANY' AND filsys_id = :fid;
594 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
595 WHERE filsys_id = :fid AND phys_id != 0;
598 if (!total_null && (total != 0))
600 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
601 type, modtime, modby, modwith)
602 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
609 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
617 /* Find the NFS physical partition that the named directory is on.
618 * This is done by comparing the dir against the mount point of the
619 * partition. To make sure we get the correct match when there is
620 * more than one, we sort the query in reverse order by dir name.
623 int check_nfs(int mach_id, char *name, char *access)
625 EXEC SQL BEGIN DECLARE SECTION;
626 char dir[NFSPHYS_DIR_SIZE];
628 EXEC SQL END DECLARE SECTION;
634 EXEC SQL DECLARE csr101 CURSOR FOR
635 SELECT nfsphys_id, dir FROM nfsphys
640 EXEC SQL OPEN csr101;
645 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
662 EXEC SQL CLOSE csr101;
669 /* setup_dfil: free any quota records and fsgroup info associated with
670 * a filesystem when it is deleted. Also adjust the allocation numbers.
673 int setup_dfil(struct query *q, char **argv, client *cl)
675 EXEC SQL BEGIN DECLARE SECTION;
676 int id, total, phys_id;
678 EXEC SQL END DECLARE SECTION;
680 id = *(int *)argv[0];
681 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
682 WHERE filsys_id = :id;
687 /** What if there are multiple phys_id's per f/s? (bad data) **/
688 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
689 WHERE filsys_id = :id;
690 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
691 WHERE nfsphys_id = :phys_id;
694 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
695 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
696 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
703 /* setup_dnfp: check to see that the nfs physical partition does not have
704 * any filesystems assigned to it before allowing it to be deleted.
707 int setup_dnfp(struct query *q, char **argv, client *cl)
709 EXEC SQL BEGIN DECLARE SECTION;
712 EXEC SQL END DECLARE SECTION;
714 id = *(int *)argv[0];
716 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
717 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
718 AND np.mach_id = :id AND np.dir = :dir;
727 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
728 * argv[0] = filsys_id
729 * argv[1] = type if "update_quota" or "delete_quota"
730 * argv[2 or 1] = users_id or list_id
733 int setup_dqot(struct query *q, char **argv, client *cl)
735 EXEC SQL BEGIN DECLARE SECTION;
736 int quota, fs, id, physid;
738 EXEC SQL END DECLARE SECTION;
740 fs = *(int *)argv[0];
741 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
744 id = *(int *)argv[2];
749 id = *(int *)argv[1];
752 EXEC SQL SELECT quota INTO :quota FROM quota
753 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
754 EXEC SQL SELECT phys_id INTO :physid FROM filesys
755 WHERE filsys_id = :fs;
756 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
757 WHERE nfsphys_id = :physid;
766 * This routine fetches an appropriate value from the numvalues table.
767 * It is a little hack to get around the fact that SQL doesn't let you
768 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
770 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
771 * from within a setup_...() routine with the appropriate arguments.
773 * Correct functioning of this routine may depend on the assumption
774 * that this query is an APPEND.
777 int prefetch_value(struct query *q, char **argv, client *cl)
779 EXEC SQL BEGIN DECLARE SECTION;
780 char *name = q->validate->object_id;
782 EXEC SQL END DECLARE SECTION;
783 int status, limit, argc;
785 /* set next object id, limiting it if necessary */
786 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
787 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
790 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
793 /* fetch object id */
794 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
797 if (sqlca.sqlerrd[2] != 1)
800 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
801 sprintf(argv[argc], "%d", value);
806 /* prefetch_filesys():
807 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
808 * Appends the filsys_id and the phys_id to the argv so they can be
809 * referenced in an INSERT into a table other than filesys. Also
810 * see comments at prefetch_value().
812 * Assumes the existence of a row where filsys_id = argv[0], since a
813 * filesys label has already been resolved to a filsys_id.
815 int prefetch_filesys(struct query *q, char **argv, client *cl)
817 EXEC SQL BEGIN DECLARE SECTION;
819 EXEC SQL END DECLARE SECTION;
822 fid = *(int *)argv[0];
823 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
827 argc = q->argc + q->vcnt;
828 sprintf(argv[argc++], "%d", phid);
829 sprintf(argv[argc], "%d", fid);
838 int setup_ahst(struct query *q, char **argv, client *cl)
840 EXEC SQL BEGIN DECLARE SECTION;
841 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
842 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
843 int value, id, ssaddr, smask, shigh, slow, cnt;
844 unsigned int saddr, mask, high, low;
845 EXEC SQL END DECLARE SECTION;
849 id = *(int *)argv[0];
851 if (!strcmp(q->shortname, "uhst"))
854 EXEC SQL SELECT name, vendor, model, os
855 INTO :oldname, :vendor, :model, :os
856 FROM machine WHERE mach_id = :id;
861 /* Sanity check name, vendor, model, and os. */
862 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
863 !hostname_check(argv[row]))
865 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
866 !hostinfo_check(argv[row + 1], 0))
868 if ((row == 0 || strcasecmp(argv[3], model)) &&
869 !hostinfo_check(argv[row + 2], 1))
871 if ((row == 0 || strcasecmp(argv[4], os)) &&
872 !hostinfo_check(argv[row + 3], 0))
875 /* check for duplicate name */
877 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
878 WHERE name = UPPER(:name);
885 if (!strcmp(argv[9 + row], "unassigned"))
887 else if (!strcmp(argv[9 + row], "unique"))
889 if (*(int *)argv[8 + row] == 0)
896 value = ntohl(inet_addr(argv[9 + row]));
905 * an address or unique was specified.
907 id = *(int *)argv[8 + row];
908 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
909 :shigh, :slow FROM subnet WHERE snet_id = :id;
912 saddr = (unsigned) ssaddr;
913 mask = (unsigned) smask;
914 high = (unsigned) shigh;
915 low = (unsigned) slow;
919 * someone specified an IP address for the host record
921 if ((value & mask) != saddr || value < low || value > high)
924 * run the address argument through inet_addr(). This
925 * has the effect that any out of bounds host addrs will
926 * be converted to a valid host addr. We do this now
927 * so that the uniqueness check works. We should also
928 * link in an inet_addr() that returns an error for
931 addr.s_addr = inet_addr(argv[9 + row]);
932 name = inet_ntoa(addr);
933 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
934 WHERE address = :name;
940 * make IP address is unique. If this a modify request
941 * (row == 1), then we expect one record to exist.
943 if (row == 0 || (row == 1 && cnt > 1))
945 if (row == 1 && cnt == 1)
947 EXEC SQL SELECT mach_id INTO :id FROM machine
948 WHERE address = :name;
949 if (id != *(int *)argv[0])
957 * a "unique" address was specified. Walk through the
958 * range specified in the network record, return
959 * error if no room left.
961 for (id = low; id <= high; id++)
963 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
965 addr.s_addr = htonl(id);
966 name = inet_ntoa(addr);
967 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
968 WHERE address = :name;
980 * we have an address in value. Convert it to a string and store it.
982 addr.s_addr = htonl(value);
983 strcpy(argv[9 + row], inet_ntoa(addr));
986 strcpy(argv[9 + row], "unassigned");
988 /* status checking */
989 value = atoi(argv[7 + row]);
990 if (row == 0 && !(value == 1 || value == 0))
994 id = *(int *)argv[0];
995 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1000 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1001 WHERE mach_id = :id;
1006 * If this is an update_host query, we're done.
1012 * For an add_host query, allocate and fill in a new machine id,
1013 * and then insert the creator id.
1015 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1018 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1026 int setup_ahal(struct query *q, char **argv, client *cl)
1028 EXEC SQL BEGIN DECLARE SECTION;
1031 EXEC SQL END DECLARE SECTION;
1035 if (!hostname_check(argv[0]))
1038 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1039 name = UPPER(:name);
1048 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1051 int setup_uhha(struct query *q, char **argv, client *cl)
1053 EXEC SQL BEGIN DECLARE SECTION;
1054 char *hwaddr = argv[1];
1056 EXEC SQL END DECLARE SECTION;
1059 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1061 for (p = hwaddr; *p; p++)
1068 if (p != hwaddr + 12)
1071 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1072 FROM machine WHERE hwaddr = :hwaddr;
1074 return MR_NOT_UNIQUE;
1080 /* setup_aprn(): Make sure name/duplexname don't conflict with
1081 * anything. If [ANY] was specified for the spooling host, pick the
1082 * least loaded print server that serves this kind of printer.
1084 int setup_aprn(struct query *q, char **argv, client *cl)
1088 EXEC SQL BEGIN DECLARE SECTION;
1089 int mid, usage, count;
1090 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1091 EXEC SQL END DECLARE SECTION;
1093 /* Check for aprn or uprn. */
1094 if (q->type == APPEND)
1099 name = argv[PRN_NAME + row];
1100 duplexname = argv[PRN_DUPLEXNAME + row];
1107 if (q->type == APPEND)
1109 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1110 WHERE name = :name OR duplexname = :name;
1114 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1115 WHERE ( name = :name OR duplexname = :name )
1116 AND name != :oldname;
1121 return MR_NOT_UNIQUE;
1126 if (q->type == APPEND)
1128 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1129 WHERE name = :duplexname OR duplexname = :duplexname;
1133 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1134 WHERE ( name = :duplexname OR duplexname = :duplexname )
1135 AND name != :oldname;
1141 return MR_NOT_UNIQUE;
1144 if (!strcmp(name, duplexname))
1145 return MR_NOT_UNIQUE;
1147 mid = *(int *)argv[PRN_RM + row];
1150 EXEC SQL DECLARE csr_rm CURSOR FOR
1151 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1153 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1155 AND ps.printer_types = s.string_id;
1158 EXEC SQL OPEN csr_rm;
1164 EXEC SQL FETCH csr_rm INTO :mid, :types;
1168 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1170 if (!strcasecmp(argv[PRN_TYPE + row], p))
1172 EXEC SQL SELECT COUNT(name) INTO :usage
1173 FROM printers WHERE rm = :mid;
1175 if (best < 0 || usage < best)
1178 *(int *)argv[PRN_RM + row] = mid;
1184 EXEC SQL CLOSE csr_rm;
1193 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1194 WHERE mach_id = :mid;
1202 int setup_dpsv(struct query *q, char **argv, client *cl)
1205 EXEC SQL BEGIN DECLARE SECTION;
1207 EXEC SQL END DECLARE SECTION;
1209 id = *(int *)argv[0];
1211 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1220 * validate the rfc1035/rfc1123-ness of a hostname
1223 int hostname_check(char *name)
1228 /* Sanity check name: must contain only letters, numerals, and
1229 * hyphen, and not start or end with a hyphen. Also make sure no
1230 * label (the thing the .s seperate) is longer than 63 characters,
1234 for (p = name, count = 0; *p; p++)
1237 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1238 (*p == '-' && p[1] == '.'))
1249 if (*(p - 1) == '-')
1254 int hostinfo_check(char *info, int num)
1261 /* Sanity check host hostinfo: must start with a letter (or number
1262 * if num is true), contain only letters, numerals, and hyphen, and
1263 * not end with a hyphen.
1266 if (!isalpha(*info) && (!num || !isdigit(*info)))
1268 for (p = info; *p; p++)
1270 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1271 (*p == '-' && p[1] == '.'))
1274 if (!isalnum(*(p - 1)))