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: }