|
|
1.1 root 1:
2: # include <stdio.h>
3: # include <ingres.h>
4: # include <aux.h>
5: # include <version.h>
6: # include <access.h>
7: # include <symbol.h>
8: # include <opsys.h>
9: # include <pv.h>
10: # include <sccs.h>
11: # include <sys/dir.h>
12:
13: SCCSID(@(#)creatdb.c 8.6 1/31/86)
14:
15: /*
16: ** CREATDB -- create database (or modify database status)
17: **
18: ** This program creates a new database. It takes the name of
19: ** the new database (syntax defined below) and a series of
20: ** flags (also defined below).
21: **
22: ** In order to perform this command, you must be enabled by
23: ** having the U_CREATDB bit set in the user status word
24: ** of the users file.
25: **
26: ** The -m flag specifies that the directory for the database
27: ** already exists. It stands for "mounted-file-system",
28: ** because this is presumably when you might use this feature.
29: ** The directory must be empty.
30: **
31: ** The -e flag specifies that the database already exists.
32: ** It must be in all ways a valid database. This mode allows
33: ** you to turn flags on and off, as controlled by the other
34: ** flags.
35: **
36: ** Usage:
37: ** creatdb [flags] databasename
38: **
39: ** Positional Parameters:
40: ** databasename -- the name of the database to create.
41: ** It must conform to all the usual rules
42: ** about names. Notice that this is more
43: ** restrictive than UNIX usually is: names
44: ** must begin with an alpha, and must be
45: ** composed of alphanumerics. It may be
46: ** at most 14 characters long. Underscore
47: ** counts as an alphabetic.
48: **
49: ** Flags:
50: ** -m
51: ** This is a mounted filesystem. Actually,
52: ** this just means that the directory in which
53: ** the database is to reside already exists.
54: ** It must be empty.
55: ** -e
56: ** This database exists. When the -e flag is
57: ** specified, the database is brought up to date,
58: ** rather than created. Things which may be
59: ** changed with the -e flag is anything that
60: ** affects the database status or the relation
61: ** status bits.
62: ** -uXX
63: ** Run as user XX (usercode or login name). This
64: ** flag may only be used by the INGRES superuser.
65: ** Normally, the database administrator for the
66: ** new database is the user who performs the
67: ** command, but the -u flag allows INGRES to
68: ** give the database to someone else. Thus, it
69: ** is possible for someone to be a DBA without
70: ** having the U_CREATDB bit set.
71: ** -Fpathname
72: ** Use the named file as the database template.
73: ** This is, of course, for debugging use only.
74: ** +-c
75: ** Turn concurrency control on/off. The default
76: ** for a new database depends on the dbtmplt file,
77: ** but as of this writing it defaults on.
78: ** +-q
79: ** Turn query modification on/off.
80: ** +-l
81: ** Turn protection violation logging on/off.
82: **
83: ** Files:
84: ** .../files/dbtmplt<VERSION>
85: ** This file drives the entire program. The
86: ** syntax of this file is defined below in
87: ** readdbtemp(). Briefly, it tells the database
88: ** status, the relations in an 'empty' database,
89: ** and the status and format of those relations.
90: ** .../data/base
91: ** This directory is the directory in which all
92: ** databases eventually reside. Each database is
93: ** a subdirectory of this directory.
94: **
95: ** Return Codes:
96: ** zero -- success
97: ** else -- failure.
98: **
99: ** Defined Constants:
100: ** MAXRELNS
101: ** This defines the maximum number of relations
102: ** which may be declared in the dbtmplt file.
103: ** MAXDBTEMP
104: ** The maximum size of the dbtmplt file. This
105: ** determines the maximum number of characters
106: ** which may be in the file.
107: **
108: ** Compilation Flags:
109: ** xB_UNIX -- if defined, says that we have a "Berkeley
110: ** UNIX" system, with no group id's. If
111: ** undefined, specifies either a version seven
112: ** UNIX (with 16-bit group id's) or version six
113: ** UNIX (with 8-bit group id's); either way,
114: ** "setgid(getgid())" will work.
115: **
116: ** Trace Flags:
117: ** -Tn, as below:
118: **
119: ** 1 -- makereln()
120: ** 2 -- create()
121: ** 10 -- makeadmin()
122: ** 12 -- makefile()
123: ** 20 -- makedb()
124: **
125: ** Compilation Instructions:
126: ** % setup creatdb
127: **
128: ** - which translates to -
129: **
130: ** % cc -n -O creatdb.c error.c ../../lib/dbulib \
131: ** ../../lib/access ../../lib/utility
132: ** % chmod 4711 a.out
133: */
134:
135:
136:
137:
138: # define MAXRELNS 20
139: # define MAXDBTEMP 2000
140:
141: /* relation & attribute reln descriptors used in access methods */
142: extern DESC Reldes;
143: extern DESC Attdes;
144:
145: extern int Status; /* user status, set by initucode */
146: DESC Btreesec; /* desc for btree sec. structure */
147: char *Fileset;
148: int Btree_fd; /* btree file */
149: int Dbstat; /* database status */
150: int Dbson, Dbsoff; /* same: bits turned on, bits turned off */
151: typedef struct reldes
152: {
153: int bitson;
154: int bitsoff;
155: PARM parmv[PV_MAXPC];
156: } RELDES;
157: RELDES Rellist[MAXRELNS];
158: char Delim;
159: extern char *Dbpath;
160: short tTdbu[100];
161:
162:
163:
164: main(argc, argv)
165: int argc;
166: char *argv[];
167: {
168: register int i;
169: int admin;
170: char adminbuf[100];
171: extern struct admin Admin;
172: extern int errno;
173: auto int code;
174: struct relation relk;
175: char *database;
176: char **av;
177: register char *p;
178: char *user_ovrd;
179: int faterr;
180: register int *flagv;
181: char *dbtmpfile;
182: extern char *Parmvect[];
183: extern char *Flagvect[];
184: int exists;
185: int *flaglkup();
186: char *ztack();
187: extern char *rindex();
188: # ifdef rewinddir
189: DIR *dir_ptr; /* pointer to '.' */
190: struct direct *dir; /* directory entry */
191: # else rewinddir
192: struct dir direct;
193: # endif rewinddir
194:
195: argv[argc] = NULL;
196:
197: # ifdef xSTR1
198: tTrace(argv, 'T', tTdbu, 100);
199: # endif
200:
201: /*
202: ** Do a lot of magic initialization.
203: **
204: ** 'exists' get set to -1 if the database does not exist
205: ** at all, 1 if it exists, and 0 if it does not
206: ** exist but there is an indirect pointer to it.
207: */
208:
209: exists = 0;
210: i = initucode(argc, argv, TRUE, NULL, -1);
211: switch (i)
212: {
213: case 0:
214: case 5:
215: exists = 1;
216: break;
217:
218: case 6:
219: exists = 0;
220:
221: case 1:
222: break;
223:
224: case 2:
225: printf("You are not authorized to create this database\n");
226: exit(-1);
227:
228: case 3:
229: printf("You are not a valid INGRES user\n");
230: exit(-1);
231:
232: case 4:
233: printf("No database name specified\n");
234: usage:
235: printf("Usage: creatdb [-uname] [-e] [-m] [+-c] [+-q] dbname\n");
236: exit(-1);
237:
238: default:
239: syserr("initucode %d", i);
240: }
241:
242: faterr = 0;
243: dbtmpfile = 0;
244: for (av = Flagvect; (p = *av) != NULL; av++)
245: {
246: if (p[0] != '-' && p[0] != '+')
247: syserr("flag %s", p);
248: switch (p[1])
249: {
250: case 'F': /* dbtmplt file */
251: if (p[2] == 0)
252: goto badflag;
253: dbtmpfile = &p[2];
254: break;
255:
256: case 'T': /* trace flag */
257: break;
258:
259: default:
260: if (flagv = flaglkup(p[1], p[0]))
261: {
262: if (p[0] == '+')
263: *flagv = 1;
264: else
265: *flagv = -1;
266: continue;
267: }
268: badflag:
269: printf("bad flag %s\n", p);
270: faterr++;
271: continue;
272:
273: }
274: if (p[0] == '+')
275: goto badflag;
276: }
277:
278: /* check for legality of database name */
279: database = Parmvect[0];
280: if (Parmvect[1] != NULL)
281: {
282: printf("Too many parameters to creatdb");
283: goto usage;
284: }
285: if (!check(database))
286: {
287: printf("Illegal database name %s\n", database);
288: exit(-1);
289: }
290:
291: if ((Status & U_CREATDB) == 0)
292: {
293: printf("You are not allowed this command\n");
294: exit(-1);
295: }
296:
297: /* end of input checking */
298: if (faterr != 0)
299: exit(2);
300:
301: /* now see if it should have been there */
302: if (flagval('m') || flagval('e'))
303: {
304: if (exists <= 0)
305: {
306: printf("Database %s does not exist\n", database);
307: exit(-1);
308: }
309:
310: # ifdef xSTR3
311: if (tTf(1, 14))
312: printf("Dbpath = '%s'\n", Dbpath);
313: # endif
314: if (chdir(Dbpath) < 0)
315: syserr("chdir %s", Dbpath);
316:
317: if (!flagval('e'))
318: {
319: # ifdef rewinddir
320:
321: /* make certain that it is empty */
322: if ( (dir_ptr = opendir(".")) == NULL )
323: syserr(0,"Can't open '.'");
324: for ( dir = readdir(dir_ptr) ; dir != NULL ; dir = readdir(dir_ptr) )
325: {
326: if ( strcmp(".",dir->d_name) && strcmp("..",dir->d_name) )
327: syserr(0, "%s is not empty", database);
328: }
329: closedir(dir_ptr);
330:
331: # else rewinddir
332: /* make certain that it is empty */
333: freopen(".", "r", stdin);
334: /* Skip "." and ".." entries */
335: fread(&direct, sizeof (struct dir), 1, stdin);
336: fread(&direct, sizeof (struct dir), 1, stdin);
337: while ( fread(&direct, sizeof (struct dir), 1, stdin) != EOF)
338: {
339: if ( direct.d_ino != 0)
340: syserr(0, "%s is not empty", database);
341: }
342: # endif rewinddir
343: }
344: else
345: {
346: /* check for correct owner */
347: acc_init();
348: if (!bequal(Usercode, Admin.adhdr.adowner, UCODE_SZ))
349: syserr(0, "You are not the DBA for this database");
350: }
351: }
352: else
353: {
354: if (exists > 0)
355: {
356: printf("Database %s already exists\n", database);
357: exit(-1);
358: }
359:
360: /* create it */
361: i = fork();
362: if (i < 0)
363: syserr("fork err");
364: if (i == 0)
365: {
366: /* split off directory */
367: *(p = rindex(Dbpath, '/')) = '\0';
368: chdir(Dbpath);
369: if (setuid(getuid()))
370: syserr("setuid");
371: # ifndef xB_UNIX
372: if (setgid(getgid()))
373: syserr("setgid");
374: # endif
375: # ifdef xV7_UNIX
376: umask(00);
377: # endif
378: *p++ = '/';
379: execl("/bin/mkdir", "/bin/mkdir", p, 0);
380: execl("/usr/bin/mkdir", "/usr/bin/mkdir", p, 0);
381: syserr("exec /bin/mkdir");
382: }
383: while (wait(&code) != -1)
384: continue;
385:
386: /* move into data/base directory */
387: if (chdir(Dbpath) < 0)
388: syserr("chdir %s: probably bad default mode in mkdir",
389: Dbpath);
390:
391: /* change the mode of the database */
392: i = fork();
393: if (i < 0)
394: syserr("fork 2");
395: if (i == 0)
396: {
397: setuid(getuid());
398: if (chmod(".", 0777))
399: syserr("chmod");
400: exit(0);
401: }
402:
403: while (wait(&code) != -1)
404: continue;
405: if ((code & I1MASK) != 0)
406: exit(code);
407: }
408:
409: /* reset 'errno', set from possibly bad chdir */
410: errno = 0;
411:
412: /* determine name of dbtmplt file and open */
413: if (dbtmpfile == NULL)
414: {
415: /* create dbtmplt file name */
416: dbtmpfile = ztack(ztack(Pathname, "/files/dbtmplt"), VERSION);
417: }
418: if (freopen(dbtmpfile, "r", stdin) == NULL)
419: syserr("dbtmplt open %s", dbtmpfile);
420:
421: readdbtemp();
422:
423: /* check for type -- update database status versus create */
424: if (flagval('e'))
425: changedb();
426: else
427: makedb();
428:
429: /* close the cache descriptors */
430: # ifdef xSTR3
431: if (tTf(50, 0))
432: {
433: printf("Attdes.reltid = ");
434: dumptid(&Attdes.reltid);
435: printf("Reldes.reltid = ");
436: dumptid(&Reldes.reltid);
437: }
438: # endif
439: if (i = closer(&Attdes))
440: syserr("creatdb: closer(att) %d", i);
441: if (i = closer(&Reldes))
442: syserr("creatdb: closer(rel) %d", i);
443:
444: /* bring tupcount in 'admin' file to date */
445: Admin.adreld.reldum.reltups = Reldes.reldum.reltups;
446: Admin.adattd.reldum.reltups = Attdes.reldum.reltups;
447:
448: /* set other fields as appropriate */
449: Admin.adreld.relfp = Admin.adattd.relfp = -1;
450: Admin.adreld.relopn = Admin.adattd.relopn = 0;
451: Admin.adhdr.adlength = sizeof Admin.adhdr;
452: Admin.adhdr.adreldsz = Admin.adhdr.adattdsz = sizeof Admin.adreld;
453: Admin.adhdr.adversion = DBVERCODE;
454:
455: if ((admin = creat("admin", FILEMODE)) < 0)
456: syserr("main: creat admin");
457: if (write(admin, &Admin, sizeof Admin) != sizeof Admin)
458: syserr("main: write Admin");
459: close(admin);
460:
461: execl((ztack(Pathname, "/bin/sysmod")), "sysmod", database, 0);
462: /* exit successfully */
463: exit(0);
464: }
465: /*
466: ** Rubout processing.
467: */
468:
469: rubproc()
470: {
471: exit(-2);
472: }
473: /*
474: ** READDBTEMP -- read the dbtmplt file and build internal form
475: **
476: ** This routine reads the dbtmplt file (presumably openned as
477: ** the standard input) and initializes the Dbstat (global database
478: ** status word) and Rellist variables.
479: **
480: ** Rellist is an array of argument vectors, exactly as passed to
481: ** 'create'.
482: **
483: ** The syntax of the dbtmplt file is as follows:
484: **
485: ** The first line is a single status word (syntax defined below)
486: ** which is the database status.
487: **
488: ** The rest of the file is sets of lines separated by blank lines.
489: ** Each set of lines define one relation. Two blank lines in a
490: ** row or an end-of-file define the end of the file. Each set
491: ** of lines is broken down:
492: **
493: ** The first line is in the following format:
494: ** relname:status
495: ** which defines the relation name and the relation status for
496: ** this relation (syntax defined in 'getstat' below). Status
497: ** may be omitted, in which case a default status is assumed.
498: **
499: ** Second through n'th lines of each set define the attributes.
500: ** They are of the form:
501: ** attname format
502: ** separated by a single tab. 'Format' is the same as on a
503: ** 'create' statement in QUEL.
504: **
505: ** Notice that we force the S_CATALOG bit to be on in any
506: ** case. This is because the changedb() routine will fail
507: ** if the -e flag is ever used on this database if any
508: ** relation appears to be a user relation.
509: **
510: ** Parameters:
511: ** none
512: **
513: ** Returns:
514: ** none
515: **
516: ** Side Effects:
517: ** Dbstat gets the database status.
518: ** Rellist is created with a list of the relations,
519: ** (as parameter vectors -01:2st as passed to
520: ** create). The entry after the last entry
521: ** has its pv[0] == NULL.
522: **
523: ** Called By:
524: ** main
525: **
526: ** Trace Flags:
527: ** none
528: */
529:
530: readdbtemp()
531: {
532: static char buf[MAXDBTEMP];
533: register RELDES *r;
534: register PARM *q;
535: register int i;
536: int j;
537: char *p;
538: int defrstat;
539: auto int bitson, bitsoff;
540:
541: /* read database status */
542: defrstat = S_CATALOG | S_NOUPDT | S_CONCUR | S_PROTALL;
543: bitson = bitsoff = 0;
544: Dbstat = getstat(A_DBCONCUR, &Dbson, &Dbsoff);
545: if (Delim == ':')
546: defrstat = getstat(defrstat, &bitson, &bitsoff);
547: if (Delim != '\n')
548: syserr("readdbtemp: bad Dbstat %c", Delim);
549:
550: /* compute default relation status */
551:
552: /* start reading relation info */
553: p = buf;
554: for (r = Rellist; ; r++)
555: {
556: r->bitson = bitson;
557: r->bitsoff = bitsoff;
558:
559: q = r->parmv;
560:
561: /* get relation name */
562: q[1].pv_type = PV_STR;
563: q[1].pv_val.pv_str = p;
564: p += getname(p) + 1;
565:
566: /* test for end of dbtmplt file */
567: if (q[1].pv_val.pv_str[0] == 0)
568: break;
569:
570: /* get relation status */
571: i = getstat(defrstat, &r->bitson, &r->bitsoff);
572: i |= S_CATALOG; /* guarantee system catalog */
573: q->pv_type = PV_STR;
574: q++->pv_val.pv_str = p;
575: *p++ = ((i >> 15) & 1) + '0';
576: for (j = 12; j >= 0; j -= 3)
577: *p++ = ((i >> j) & 07) + '0';
578: *p++ = 0;
579: q++;
580: if (Delim != '\n')
581: syserr("readdbtemp: bad rel %c", Delim);
582:
583: /* read attribute names and formats */
584: for (;;)
585: {
586: /* get attribute name */
587: q->pv_type = PV_STR;
588: q++->pv_val.pv_str = p;
589: p += getname(p) + 1;
590: if (q[-1].pv_val.pv_str[0] == 0)
591: break;
592: if (Delim != '\t')
593: syserr("readdbtemp: bad att %s, d='%c'",
594: q[-1].pv_val.pv_str, Delim);
595:
596: /* get attribute type */
597: q->pv_type = PV_STR;
598: q++->pv_val.pv_str = p;
599: p += getname(p) + 1;
600: if (Delim != '\n')
601: syserr("readdbtemp: bad type %c", Delim);
602: }
603:
604: /* insert end of argv signal */
605: (--q)->pv_type = PV_EOF;
606:
607: /* ad-hoc overflow test */
608: if (p >= &buf[MAXDBTEMP])
609: syserr("readdbtemp: overflow");
610: }
611: /* mark the end of list */
612: q[1].pv_type = PV_EOF;
613: }
614: /*
615: ** GETSTAT -- Get status word
616: **
617: ** A status word is read from the standard input (presumably
618: ** 'dbtmplt'). The string read is interpreted as an octal
619: ** number. The syntax is:
620: ** N{+c+N[~N]}
621: ** where N is a number, + is a plus or a minus sign, and c is
622: ** a flag. '+c+N1[~N2]' groups are interpreted as follows:
623: ** If flag 'c' is set (assuming the preceeding character is a +,
624: ** clear if it is a -), then set (clear) bits N1. If tilde N2
625: ** is present, then if flag 'c' is unset (called as '-c' ('+c'))
626: ** clear (set) bits N2; if ~N2 is not present, clear (set)
627: ** bits N1.
628: **
629: ** For example, an entry might be (but probably isn't):
630: ** 1-c-1+q+6~2
631: ** having the following meaning:
632: **
633: ** 1. Default to the 1 bit set.
634: **
635: ** 2. If the -c flag is specified, clear the '1' bit. If the
636: ** +c flag is specified, set the '1' bit. If it is unspecified,
637: ** leave the '1' bit alone.
638: **
639: ** 3. If the +q flag is specified, set the '2' bit and the '4'
640: ** bit. If the -q flag is specified, clear the '2' bit (but leave
641: ** the '4' bit alone). If the +-q flag is unspecified, leave
642: ** those bits alone.
643: **
644: ** Thus, a database with this entry is initially created with
645: ** the 1 bit on. The '4' bit is a history, which says if the
646: ** 'q' flag has ever been set, while the '2' bit tells if it is
647: ** currently set.
648: **
649: ** Parameters:
650: ** def -- the default to return if there is no number
651: ** there at all.
652: ** bitson -- a pointer to a word to contain all the
653: ** bits to be turned on -- used for the -e flag.
654: ** bitsoff -- same, for bits turned off.
655: **
656: ** Returns:
657: ** The value of the status word.
658: ** There are no error returns.
659: **
660: ** Side Effects:
661: ** File activity.
662: **
663: ** Called By:
664: ** readdbtemp
665: **
666: ** Trace Flags:
667: ** none
668: */
669:
670: getstat(def, bitson, bitsoff)
671: int def;
672: int *bitson;
673: int *bitsoff;
674: {
675: register int c;
676: register int stat;
677: register int i;
678: int setbits;
679: int clrbits;
680: char ctlch;
681:
682: /* reset bits being turned on and off */
683: *bitson = *bitsoff = 0;
684:
685: /* check to see if a base status wolushs defined */
686: if (Delim == '\n' || (Delim = c = getchar()) < '0' || c > '7')
687: {
688: /* no, use default */
689: stat = def;
690: }
691: else
692: {
693: /* read base status field */
694: ungetc(c, stdin);
695: stat = roctal();
696: }
697:
698: /* scan '+c+N' entries */
699: for (;;)
700: {
701: /* check for a flag present */
702: c = Delim;
703: if (c == '\n' || c == ':')
704: return (stat);
705: if (c != '+' && c != '-')
706: {
707: badfmt:
708: syserr("getstat: bad fmt %c", c);
709: }
710:
711: /* we have some flag -- get it's value */
712: i = flagval(getchar());
713:
714: /* save sign char on flag */
715: ctlch = c;
716:
717: /* get sign on associated number and the number */
718: c = getchar();
719: if (c != '+' && c != '-')
720: goto badfmt;
721: setbits = roctal();
722:
723: /* test whether action on -X same as on +X */
724: if (Delim == '~')
725: {
726: /* they have different bits (see above) */
727: clrbits = roctal();
728: }
729: else
730: {
731: /* on 'creatdb -e -X', use opposite bits of +X */
732: clrbits = setbits;
733: }
734:
735: /* test for any effect at all */
736: if (i == 0)
737: continue;
738:
739: /* test whether we should process the '+N' */
740: if ((ctlch == '-') ? (i < 0) : (i > 0))
741: i = setbits;
742: else
743: {
744: i = clrbits;
745:
746: /* switch sense of bit action */
747: if (c == '+')
748: c = '-';
749: else
750: c = '+';
751: }
752:
753: if (c == '+')
754: {
755: stat |= i;
756: *bitson |= i;
757: }
758: else
759: {
760: stat &= ~i;
761: *bitsoff |= i;
762: }
763: }
764: }
765: /*
766: ** ROCTAL -- Read an octal number from standard input.
767: **
768: ** This routine just reads a single octal number from the standard
769: ** input and returns its value. It will only read up to a non-
770: ** octal digit. It will also skip initial and trailing blanks.
771: ** 'Delim' is set to the next character in the input stream.
772: **
773: ** Parameters:
774: ** none
775: **
776: ** Returns:
777: ** value of octal number in the input stream.
778: **
779: ** Side Effects:
780: ** 'Delim' is set to the delimiter which terminated the
781: ** number.
782: ** File activity on stdin.
783: **
784: ** Called By:
785: ** getstat()
786: **
787: ** Trace Flags:
788: ** none
789: */
790:
791: roctal()
792: {
793: register int c;
794: register int val;
795:
796: val = 0;
797:
798: /* skip initial blanks */
799: while ((c = getchar()) == ' ')
800: continue;
801:
802: /* get numeric value */
803: while (c >= '0' && c <= '7')
804: {
805: val = (val << 3) | (c - '0');
806: c = getchar();
807: }
808:
809: /* skip trailing blanks */
810: while (c == ' ')
811: c = getchar();
812:
813: /* set Delim and return numeric value */
814: Delim = c;
815: return (val);
816: }
817: /*
818: ** GETNAME -- get name from standard input
819: **
820: ** This function reads a name from the standard input. A
821: ** name is defined as a string of letters and digits.
822: **
823: ** The character which caused the scan to terminate is stored
824: ** into 'Delim'.
825: **
826: ** Parameters:
827: ** ptr -- a pointer to the buffer in which to dump the
828: ** name.
829: **
830: ** Returns:
831: ** The length of the string.
832: **
833: ** Side Effects:
834: ** File activity on standard input.
835: **
836: ** Called By:
837: ** readdbtemp
838: **
839: ** Trace Flags:
840: ** none
841: */
842:
843: getname(ptr)
844: char *ptr;
845: {
846: register int len;
847: register int c;
848: register char *p;
849:
850: len = 0;
851:
852: for (p = ptr; (c = getchar()) != EOF; len++)
853: {
854: /* check for end of name */
855: if ((c < 'a' || c > 'z') &&
856: (c < '0' || c > '9'))
857: break;
858:
859: /* store character into buffer */
860: *p++ = c;
861: }
862:
863: /* null-terminate the string */
864: *p = '\0';
865:
866: /* store the delimiting character and return length of string */
867: Delim = c;
868: return (len);
869: }
870: /*
871: ** MAKEDB -- make a database from scratch
872: **
873: ** This is the code to make a database if the -e flag is off.
874: **
875: ** The first step is to make a copy of the admin file
876: ** in the internal 'Admin' struct. This is the code which
877: ** subsequently gets used by openr and opencatalog. Notice
878: ** that the admin file is not written out; this happens after
879: ** makedb returns.
880: **
881: ** Next, the physical files are created with one initial (empty)
882: ** page. This has to happen before the 'create' call so
883: ** that it will be possible to flush 'relation' and 'attribute'
884: ** relation pages during the creates of the 'relation' and
885: ** 'attribute' relations. Other relations don't need this,
886: ** but it is more convenient to be symmetric.
887: **
888: ** The next step is to create the relations. Of course, all
889: ** this really is is inserting stuff into the system catalogs.
890: **
891: ** When we are all done we open the relation relation for the
892: ** admin cache (which of course should exist now). Thus,
893: ** the closer's in main (which must be around to update the
894: ** tuple count) will work right.
895: **
896: ** Parameters:
897: ** none
898: **
899: ** Returns:
900: ** none
901: **
902: ** Side Effects:
903: ** A database is created!!
904: ** Several files will be created in the current directory,
905: ** one for each relation mentioned in the
906: ** 'dbtmplt' file.
907: ** The 'Admin' struct will be filled in.
908: **
909: ** Called By:
910: ** main
911: **
912: ** Trace Flags:
913: ** 20
914: */
915:
916: makedb()
917: {
918: DESC d;
919: register RELDES *r;
920:
921: # ifdef xSTR3
922: if (tTf(51, 0))
923: printf(">>makedb, Usercode = %s (%u)\n", Usercode, Usercode);
924: # endif
925:
926: /* create the physical files */
927: for (r = Rellist; r->parmv[1].pv_type != PV_EOF; r++)
928: {
929: makefile(r);
930: }
931:
932: /* initialize the admin file internal cache */
933: bmove(Usercode, Admin.adhdr.adowner, UCODE_SZ);
934: Admin.adhdr.adflags = Dbstat;
935: makeadmin(&Admin.adreld, Rellist[0].parmv);
936: makeadmin(&Admin.adattd, Rellist[1].parmv);
937:
938: /* done with admin initialization */
939:
940: /* initialize relations */
941: for (r = Rellist; r->parmv[1].pv_type != PV_EOF; r++)
942: {
943: makereln(r);
944: }
945: }
946: /*
947: ** MAKEADMIN -- manually initialize descriptor for admin file
948: **
949: ** The relation descriptor pointed to by 'pv' is turned into
950: ** a descriptor, returned in 'd'. Presumably, this descriptor
951: ** is later written out to the admin file.
952: **
953: ** Notice that the 'reltid' field is filled in sequentially.
954: ** This means that the relations put into the admin file
955: ** must be created in the same order that they are 'made'
956: ** (by this routine), that the format of tid's must not
957: ** change, and that there can not be over one page worth of
958: ** relations in the admin file. Our current system currently
959: ** handles this easily.
960: **
961: ** Parameters:
962: ** d -- the descriptor to get the result.
963: ** pv -- a parm vector in 'create' format, which drives
964: ** this routine.
965: **
966: ** Returns:
967: ** none
968: **
969: ** Side Effects:
970: ** none
971: **
972: ** Called By:
973: ** main
974: **
975: ** Trace Flags:
976: ** 10
977: */
978:
979:
980:
981: makeadmin(d, pv)
982: DESC *d;
983: PARM pv[];
984: {
985: register DESC *des;
986: register PARM *p;
987: register int i;
988: auto int len;
989: static int lineno;
990: char fname[MAXNAME + 3];
991:
992: des = d;
993: p = pv;
994:
995: # ifdef xSTR2
996: if (tTf(10, -1))
997: {
998: printf("creating %s in admin\n", p[1].pv_val.pv_str);
999: }
1000: # endif
1001: i = oatoi(p++->pv_val.pv_str);
1002: ingresname(p++->pv_val.pv_str, Usercode, fname);
1003: bmove(fname, des->reldum.relid, MAXNAME + 2);
1004: des->reldum.relstat = i;
1005: des->reldum.relatts = 0;
1006: des->reldum.relwid = 0;
1007: des->reldum.relspec = M_HEAP;
1008: des->reltid.ltid = 0;
1009: des->reltid.s_tupid.line_id = lineno++;
1010: des->relfp = open(fname, O_RDWR);
1011: if (des->relfp < 0)
1012: syserr("makeadmin: open %s", fname);
1013: des->relopn = (des->relfp + 1) * -5;
1014:
1015: /* initialize domain info */
1016: for (; p++->pv_type != PV_EOF; p++)
1017: {
1018: register char c;
1019:
1020: c = p[0].pv_val.pv_str[0];
1021: if (c != 'i' && c != 'c' && c != 'f')
1022: syserr("dbtmplt: type err on %s", p[0].pv_val.pv_str);
1023: des->relfrmt[++(des->reldum.relatts)] = c;
1024: len = atoi(&p[0].pv_val.pv_str[1]);
1025: des->relfrml[des->reldum.relatts] = len;
1026: des->reloff[des->reldum.relatts] = des->reldum.relwid;
1027: des->reldum.relwid += len;
1028: }
1029: }
1030: /*
1031: ** MAKEFILE -- make an 'empty' file for a relation
1032: **
1033: ** This routine creates a file with a single (empty) page
1034: ** on it -- it is part of the 'create' code, essentially.
1035: **
1036: ** Parameters:
1037: ** rr -- a pointer to the 'reldes' structure for this
1038: ** relation (file).
1039: **
1040: ** Returns:
1041: ** none
1042: **
1043: ** Side Effects:
1044: ** A file with one page is created.
1045: **
1046: ** Called By:
1047: ** makedb
1048: ** changedb
1049: **
1050: ** Trace Flags:
1051: ** 12
1052: */
1053:
1054: makefile(r)
1055: register RELDES *r;
1056: {
1057: DESC d;
1058: register int i;
1059:
1060: ingresname(r->parmv[1].pv_val.pv_str, Usercode, d.reldum.relid);
1061: # ifdef xSTR1
1062: if (tTf(12, 0))
1063: printf("creat %s\n", d.reldum.relid);
1064: # endif
1065: if ((d.relfp = creat(d.reldum.relid, FILEMODE)) < 0)
1066: syserr("creat %s", d.reldum.relid);
1067: if ((i = formatpg(&d, (long) 1)) != 0)
1068: syserr("makefile: formatpg %d", i);
1069: close(d.relfp);
1070: }
1071: /*
1072: ** MAKERELN -- make a relation
1073: **
1074: ** This is the second half of the create, started by 'makefile'.
1075: **
1076: ** This routine just sets up argument vectors and calls create,
1077: ** which does the real work.
1078: **
1079: ** Parameters:
1080: ** rr -- a pointer to the Rellist entry for the relation
1081: ** to be created.
1082: **
1083: ** Returns:
1084: ** none
1085: **
1086: ** Side Effects:
1087: ** Information will be inserted into the 'relation' and
1088: ** 'attribute' relations.
1089: **
1090: ** Called By:
1091: ** makedb
1092: ** changedb
1093: **
1094: ** Trace Flags:
1095: ** 1
1096: */
1097:
1098: makereln(r)
1099: register RELDES *r;
1100: {
1101: register int pc;
1102: register PARM *pv;
1103: int i;
1104:
1105: pc = 0;
1106: for (pv = r->parmv; pv->pv_type != PV_EOF; pv++)
1107: pc++;
1108: pv = r->parmv;
1109: i = create(pc, pv);
1110: if (i != 0)
1111: syserr("create %d", i);
1112: }
1113: /*
1114: ** CHECK -- check database name syntax
1115: **
1116: ** The name of a database is checked for validity. A valid
1117: ** database name is not more than 14 characters long, begins
1118: ** with an alphabetic character, and contains only alpha-
1119: ** numerics. Underscore is considered numeric.
1120: **
1121: ** Parameters:
1122: ** p -- the string to check.
1123: **
1124: ** Returns:
1125: ** TRUE -- ok.
1126: ** FALSE -- failure.
1127: **
1128: ** Side Effects:
1129: ** none
1130: **
1131: ** Called By:
1132: ** main
1133: **
1134: ** Trace Flags:
1135: ** none
1136: */
1137:
1138: check(p)
1139: char *p;
1140: {
1141: register char c;
1142:
1143: /* check string length */
1144: if (length(p) > 14)
1145: return (FALSE);
1146:
1147: /* check the first character of the string for alphabetic */
1148: c = *p++;
1149: if (c < 'a' || c > 'z')
1150: return (FALSE);
1151:
1152: /* check the rest for alphanumeric */
1153: while ((c = *p++) != 0)
1154: {
1155: if (c == '_')
1156: continue;
1157: if (c >= '0' && c <= '9')
1158: continue;
1159: if (c >= 'a' && c <= 'z')
1160: continue;
1161: return (FALSE);
1162: }
1163: return (TRUE);
1164: }
1165: /*
1166: ** FLAGLKUP -- look up user flag
1167: **
1168: ** This routine helps support a variety of user flags. The
1169: ** routine takes a given user flag and looks it up (via a
1170: ** very crude linear search) in the 'Flags' vector, and
1171: ** returns a pointer to the value.
1172: **
1173: ** The 'flag' struct defines the flags. The 'flagname' field
1174: ** is the character which is the flag id, for example, 'c'
1175: ** in the flag '-c'. The 'flagtype' field defines how the
1176: ** flag may appear; if negative, only '-c' may appear, if
1177: ** positive, only '+c' may appear; if zero, either form may
1178: ** appear. Finally, the 'flagval' field is the value of the
1179: ** flag -- it may default any way the user wishes.
1180: **
1181: ** Parameters:
1182: ** flagname -- the name (as defined above) of the
1183: ** flag to be looked up.
1184: ** plusminus -- a character, '+' means the '+x' form
1185: ** was issued, '-' means the '-x' form was
1186: ** issued, something else means *don't care*.
1187: ** If an illegal form was issued (that is,
1188: ** that does not match the 'flagtype' field
1189: ** in the structure), the "not found" return
1190: ** is taken.
1191: **
1192: ** Returns:
1193: ** NULL -- flag not found, or was incorrect type,
1194: ** as when the '+x' form is specified in the
1195: ** parameters, but the 'Flags' struct says
1196: ** that only a '-x' form may appear.
1197: ** else -- pointer to the 'flagval' field of the correct
1198: ** field in the 'Flags' vector.
1199: **
1200: ** Side Effects:
1201: ** none
1202: **
1203: ** Called By:
1204: ** main
1205: ** flagval
1206: **
1207: ** Trace Flags:
1208: ** none
1209: */
1210:
1211: struct flag
1212: {
1213: char flagname; /* the name of the flag */
1214: char flagtype; /* -1: -x form; +1: +x form; 0: both */
1215: int flagval; /* user-defined value of the flag */
1216: };
1217:
1218: struct flag Flags[] =
1219: {
1220: 'q', 0, 0,
1221: 'l', 0, 0,
1222: 'c', 0, 0,
1223: 'e', -1, 0,
1224: 'm', -1, 0,
1225: 0
1226: };
1227:
1228: int *
1229: flaglkup(flagname, plusminus)
1230: char flagname;
1231: char plusminus;
1232: {
1233: register char f;
1234: register struct flag *p;
1235: register char pm;
1236:
1237: f = flagname;
1238: pm = plusminus;
1239:
1240: /* look up flag in vector */
1241: for (p = Flags; p->flagname != f; p++)
1242: {
1243: if (p->flagname == 0)
1244: return (NULL);
1245: }
1246:
1247: /* found in list -- check type */
1248: if ((pm == '+' && p->flagtype < 0) ||
1249: (pm == '-' && p->flagtype > 0))
1250: return (NULL);
1251:
1252: /* type is OK -- return pointer to value */
1253: return (&p->flagval);
1254: }
1255: /*
1256: ** FLAGVAL -- return value of a flag
1257: **
1258: ** Similar to 'flaglkup', except that the value is returned
1259: ** instead of the address, and no error return can occur.
1260: **
1261: ** Parameters:
1262: ** f -- the flag to look up (see flaglkup).
1263: **
1264: ** Returns:
1265: ** The value of flag 'f'.
1266: **
1267: ** Side Effects:
1268: ** none
1269: **
1270: ** Called By:
1271: ** readdbtemp()
1272: ** main()
1273: **
1274: ** Trace Flags:
1275: ** none
1276: */
1277:
1278: flagval(f)
1279: register char f;
1280: {
1281: register char *p;
1282: int *flaglkup();
1283:
1284: /* get value of flag */
1285: p = (char *)flaglkup(f, 0);
1286:
1287: /* test for error return, syserr if so */
1288: if (p == NULL)
1289: syserr("flagval: flag %c", f);
1290:
1291: /* return value */
1292: return (*p);
1293: }
1294: /*
1295: ** CHANGEDB -- change status bits for database/relations
1296: **
1297: ** In this function we change the status bits for use with the
1298: ** -e flag.
1299: **
1300: ** This module always uses the differential status
1301: ** change information, so that existing bits are not touched.
1302: **
1303: ** We check to see that invalid updates, such as turning off
1304: ** query modification when it is already on, can not occur.
1305: ** This is because of potential syserr's when the system is
1306: ** later run, e.g., because of views without instantiations.
1307: **
1308: ** In the second step, the database status is updated. This is
1309: ** done strictly in-core, and will be updated in the database
1310: ** after we return.
1311: **
1312: ** The list of valid relations are then scanned. For each
1313: ** relation listed, a series of steps occurs:
1314: **
1315: ** (1) The relation is checked for existance. If it does not
1316: ** exist, it is created, and we return to the beginning of the
1317: ** loop. Notice that we don't have to change modes in this
1318: ** case, since it already has been done.
1319: **
1320: ** (2) If the relation does exist, we check to see that it
1321: ** is a system catalog. If it is not, we have an error, since
1322: ** this is a user relation which just happenned to have the
1323: ** same name. We inform the user and give up.
1324: **
1325: ** (3) If the relation exists, is a system catalog, and all
1326: ** that, then we check the changes we need to make in the
1327: ** bits. If no change need be made, we continue the loop;
1328: ** otherwise, we change the bits and replace the tuple in
1329: ** the relation relation.
1330: **
1331: ** (4) If the relation being updated was the "relation" or
1332: ** "attribute" relation, we change the Admin struct accordingly.
1333: **
1334: ** Notice that the result of all this is that all relations
1335: ** which might ever be used exist and have the correct status.
1336: **
1337: ** Notice that it is fatal for either the attribute or relation
1338: ** relations to not exist, since the file is created at the
1339: ** same time that relation descriptors are filled in. This
1340: ** should not be a problem, since this is only called on an
1341: ** existing database.
1342: **
1343: ** As a final note, we open the attribute relation cache not
1344: ** because we use it, but because we want to do a closer
1345: ** in main() to insure that the tupcount is updated in all
1346: ** cases.
1347: **
1348: ** Parameters:
1349: ** none
1350: **
1351: ** Returns:
1352: ** none
1353: **
1354: ** Side Effects:
1355: ** The database is brought up to date, as described
1356: ** above.
1357: ** Tuples may be added or changed in system catalogs.
1358: ** Files may be created.
1359: **
1360: ** Called By:
1361: ** main
1362: **
1363: ** Trace Flags:
1364: ** 40
1365: */
1366:
1367: changedb()
1368: {
1369: register RELDES *r;
1370: struct relation relk, relt;
1371: TID tid;
1372: register int i;
1373:
1374: # ifdef xSTR1
1375: if (tTf(40, 0))
1376: printf(">>> changedb: Dbson=%o, Dbsoff=%o\n", Dbson, Dbsoff);
1377: # endif
1378:
1379: /* check to see we aren't doing anything illegal */
1380: if (flagval('q') < 0)
1381: {
1382: syserr(0, "I'm sorry, it is not possible to turn query modification off");
1383: }
1384:
1385: /* update the database status field */
1386: Admin.adhdr.adflags = (Admin.adhdr.adflags | Dbson) & ~Dbsoff;
1387:
1388: /* open the system catalog caches */
1389: opencatalog("relation", OR_WRITE);
1390: opencatalog("attribute", OR_READ);
1391:
1392: /* scan the relation list:- Rellist */
1393: for (r = Rellist; r->parmv[1].pv_type != PV_EOF; r++)
1394: {
1395: /* see if this relation exists */
1396: clearkeys(&Reldes);
1397: setkey(&Reldes, &relk, r->parmv[1].pv_val.pv_str, RELID);
1398: i = getequal(&Reldes, &relk, &relt, &tid);
1399:
1400: if (i < 0)
1401: syserr("changedb: getequal");
1402:
1403: if (i > 0)
1404: {
1405: /* doesn't exist, create it */
1406: printf("Creating relation %s\n", r->parmv[1].pv_val.pv_str);
1407: makefile(r);
1408: makereln(r);
1409: }
1410: else
1411: {
1412: /* exists -- check to make sure it is the right one */
1413: if ((relt.relstat & S_CATALOG) == 0)
1414: {
1415: /* exists as a user reln -- tough luck buster */
1416: printf("Relation %s already exists -- I cannot bring this database\n", r->parmv[1].pv_val.pv_str);
1417: printf(" up to date. Sorry.\n");
1418: exit(3);
1419: }
1420:
1421: /* it exists and is the right one -- update status */
1422: if (r->bitson == 0 && r->bitsoff == 0)
1423: continue;
1424:
1425: /* actual work need be done */
1426: relt.relstat = (relt.relstat | r->bitson) & ~r->bitsoff;
1427:
1428: /* replace tuple in relation relation */
1429: i = replace(&Reldes, &tid, &relt, FALSE);
1430: if (i != 0)
1431: syserr("changedb: replace %d", i);
1432:
1433: /* update Admin struct if "relation" or "attribute" */
1434: if (sequal(r->parmv[1].pv_val.pv_str, "relation"))
1435: Admin.adreld.reldum.relstat = relt.relstat;
1436: else if (sequal(r->parmv[1].pv_val.pv_str, "attribute"))
1437: Admin.adattd.reldum.relstat = relt.relstat;
1438: }
1439: }
1440: }
1441: /*
1442: ** READADMIN -- read the admin file into the 'Admin' cache
1443: **
1444: ** This routine opens and reads the 'Admin' cache from the
1445: ** 'admin' file in the current directory.
1446: **
1447: ** This version of the routine is modified for creatdb --
1448: ** the '-e' flag is checked, and nothing is performed
1449: ** unless it is set.
1450: **
1451: ** If not set, the 'relation' and 'attribute' relations
1452: ** are opened, and the descriptors for them in the Admin
1453: ** struct are filled in with their file descriptors.
1454: **
1455: ** Parameters:
1456: ** none
1457: **
1458: ** Returns:
1459: ** none
1460: **
1461: ** Side Effects:
1462: ** The 'Admin' struct is filled in.
1463: ** The 'relation...xx' and 'attribute...xx' files are
1464: ** opened.
1465: **
1466: ** Called By:
1467: ** acc_init (accbuf.c)
1468: ** changedb
1469: **
1470: ** Trace Flags:
1471: ** none
1472: */
1473:
1474: readadmin()
1475: {
1476: register int i;
1477: char relname[MAXNAME + 4];
1478:
1479: /* read the stuff from the admin file */
1480: if (flagval('e'))
1481: {
1482: i = open("admin", O_RDONLY);
1483: if (i < 0)
1484: syserr("readadmin: open admin %d", i);
1485: checkadmin(i);
1486: close(i);
1487:
1488: /* open the physical files for 'relation' and 'attribute' */
1489: ingresname("relation", Admin.adhdr.adowner, relname);
1490: if ((Admin.adreld.relfp = open(relname, O_RDWR)) < 0)
1491: syserr("readadmin: open `%.14s'", relname);
1492: ingresname("attribute", Admin.adhdr.adowner, relname);
1493: if ((Admin.adattd.relfp = open(relname, O_RDWR)) < 0)
1494: syserr("readadmin: open `%.14s'", relname);
1495: Admin.adreld.relopn = (Admin.adreld.relfp + 1) * -5;
1496: Admin.adattd.relopn = (Admin.adattd.relfp + 1) * 5;
1497: }
1498:
1499: return (0);
1500: }
1501:
1502:
1503:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.