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