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

Defined functions

changedb defined in line 1367; used 1 times
check defined in line 1138; used 1 times
flaglkup defined in line 1228; used 4 times
flagval defined in line 1278; used 9 times
getname defined in line 843; used 3 times
getstat defined in line 670; used 3 times
main defined in line 164; never used
makeadmin defined in line 981; used 2 times
makedb defined in line 916; used 1 times
makefile defined in line 1054; used 2 times
makereln defined in line 1098; used 2 times
readadmin defined in line 1474; never used
readdbtemp defined in line 530; used 1 times
roctal defined in line 791; used 3 times
rubproc defined in line 469; never used

Defined variables

Btree_fd defined in line 148; never used
Dbsoff defined in line 150; used 3 times
Dbson defined in line 150; used 3 times
Dbstat defined in line 149; used 2 times
Delim defined in line 158; used 15 times
Fileset defined in line 147; never used
Flags defined in line 1218; used 1 times
Rellist defined in line 157; used 6 times
tTdbu defined in line 160; used 1 times

Defined struct's

flag defined in line 1211; used 4 times
reldes defined in line 151; never used

Defined typedef's

RELDES defined in line 156; used 6 times

Defined macros

MAXDBTEMP defined in line 139; used 2 times
MAXRELNS defined in line 138; used 1 times
Last modified: 1986-04-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2754
Valid CSS Valid XHTML 1.0 Strict