1: /* 2: * @(#) ingres.c 1.1 (2.11BSD) 1996/3/22 3: */ 4: 5: #include <errno.h> 6: # include "../ingres.h" 7: # include "../aux.h" 8: # include "../access.h" 9: # include "../lock.h" 10: # include "../unix.h" 11: 12: 13: /* 14: ** INGRES -- INGRES startup 15: ** 16: ** This program starts up the entire system. 17: ** 18: ** Parameters: 19: ** 1 -- database name 20: ** 2 -- optional process table name 21: ** x -- flags of the form +x or -x may be freely inter- 22: ** sperced in the argument list. 23: ** 24: ** Return: 25: ** none if successful 26: ** 1 -- user error (no database, etc) 27: ** -1 -- system error 28: ** 29: ** Flags: 30: ** -&xxxx -- EQUEL flag: xxxx are file descriptors for the 31: ** status return pipe, the command write pipe, the 32: ** data return pipe, and the data transfer pipe 33: ** respectively. 34: ** -@xxxx -- xxxx is same as EQUEL flag, but no flags 35: ** are set. 36: ** -*?? -- Masterid flag. Gives the siteid of the master 37: ** site in a distributed ingres. (Used in dist. 38: ** ingres' initproc() function.) 39: ** -|xxxx -- Network flag. This flag is just passed to 40: ** the other processes, to be processed by the 41: ** DBU's. 42: ** -uusername -- set effective user to be username. You 43: ** must be INGRES or the DBA for the database to 44: ** use this option. 45: ** -cN -- set minimum character field output width to be 46: ** N, default 6. This is the fewest number of 47: ** characters which may be output in any "c" type 48: ** field. 49: ** -inN -- integer output width. this is the width of 50: ** an integer field. The small "n" is the size 51: ** of the internal field ("1", "2", or "4") and 52: ** N is the width of the field for that flag. 53: ** The defaults are -i16, -i26, and -i413. 54: ** -fnxN.M -- floating point output width and precision. 55: ** Small "n" is the internal width in bytes ("4" 56: ** or "8"), x is the format (f, F, g, G, e, E, 57: ** n, or N), N is the field width, and M is the 58: ** precision (number of digits after the decimal 59: ** point). The formats are: 60: ** "f" or "F": FORTRAN-style F format: digits, 61: ** decimal point, digits, no exponent. 62: ** "e" or "E": FORTRAN-style E format: digits, 63: ** decimal point, digits, letter "e" (or 64: ** "E", depending on "x" in the param- 65: ** eter), and an exponent. The scaling 66: ** factor is always one, that is, there 67: ** is always one digit before the decimal 68: ** point. 69: ** "g" or "G": F format if it will fit in the 70: ** field, otherwise E format. Space is 71: ** always left at the right of the field 72: ** for the exponent, so that decimal 73: ** points will align. 74: ** "n" or "N": like G, except that space is not 75: ** left for the decimal point in F style 76: ** format (useful if you expect everything 77: ** to fit, but you're not sure). 78: ** The default is -fn10.3. 79: ** -vx -- set vertical seperator for print operations 80: ** and retrieves to the terminal to be "x". The 81: ** default is vertical bar ("|"). 82: ** +w -- database wait state. If set ("+w"), you will 83: ** wait until the database is not busy. If clear, 84: ** you will be informed if the database is busy. 85: ** If not specified, the same operations take 86: ** place depending on whether or not you are 87: ** running in background (determined by whether 88: ** or not your input is a teletype). If in fore- 89: ** ground, you are informed; if in background, 90: ** you wait. 91: ** -M -- monitor trace flag 92: ** -P -- parser trace flag 93: ** -O -- ovqp trace flag 94: ** -Q -- qrymod trace flag 95: ** -D -- decomp trace flag 96: ** -Z -- dbu trace flag. These flags require the 020 bit 97: ** in the status field of the users file to be 98: ** set. The syntax is loose and is described 99: ** elsewhere. Briefly, "-Z" sets all flags except 100: ** the last 20, "-Z4" sets flag 4, and "-Z5/7" 101: ** sets all flags from 5 through 7. 102: ** +L -- enable/disable upper to lower case mapping in the 103: ** parser. Used for debugging. 104: ** -rmode -- retrieve into mode 105: ** -nmode -- index mode. These flags give the default 106: ** modify mode for retrieve into and index. They 107: ** default to cheapsort and isam. "Mode" can be 108: ** any mode to modify except "truncated". 109: ** +a -- enable/disable autoclear function in monitor. 110: ** Default on. 111: ** +b -- enable/disable batch update. Default on. 112: ** The 02 bit is needed to clear this flag. 113: ** +d -- enable/disable printing of the dayfile. Default 114: ** on. 115: ** +s -- enable/disable printing of almost everything from 116: ** the monitor. 117: ** +U -- enable/disable direct update of system catalogs. 118: ** Default off. The 04 bit is needed to set this 119: ** option. 120: ** 121: ** Files: 122: ** .../files/usage -- to print a "usage: ..." message. 123: ** .../data/base/<database>/admin -- to determine 124: ** existance and some info about <database>. 125: ** .../files/dayfile<VERSION> -- dayfile (printed by 126: ** monitor). 127: ** .../files/users -- file with UNIX uid -> INGRES code 128: ** mapping, plus a pile of other information about 129: ** the user. 130: ** .../files/proctab<VERSION> -- default process table 131: ** 132: ** History: 133: ** 2/26/79 (marc) -- -* flag added. 134: ** 8/9/78 (eric) -- Changed so that a variable number of 135: ** parameters may be sent to each process. These 136: ** are indicated in the process table by a list 137: ** of any number of parameters colon-separated 138: ** at the end of the line. Notice that even if 139: ** there are no parameters, the first colon must 140: ** be stated (actually, it terminates the previous 141: ** argument, rather than beginning the parameter 142: ** argument). 143: ** 7/24/78 (eric) -- File descriptor processing on -&, 144: ** -@, and -| flags changed to stop on first 145: ** descriptor which is not an upper case letter, 146: ** used (maybe someday) by -| flag. Also, fd's 147: ** changed to be stored with the 0100 bit set 148: ** internally, so that fd 0 will work. 149: ** 7/21/78 (bob) -- '-|' flag changed back. 150: ** 7/19/78 (eric) -- '-|' changed to not be processed 151: ** here. 152: ** 7/18/78 (eric) -- code added to close 0 & 2. 153: ** 7/5/78 (eric) -- '-|' network flag added. 154: ** 3/27/78 (eric) -- changed to pass EQUEL flag, add 155: ** the -@ flag, and drop the Equel variable. 156: ** Also, the Fdesc vector was added. 157: ** 1/29/78 -- changed to give more reasonable error 158: ** messages, and to include the .../files/usage 159: ** file. Also, the "directory" field in the 160: ** process table has been changed to a "status" 161: ** field, bits being assigned to exec the process 162: ** as the real user (01) and to run in the default 163: ** directory (rather than the database) (02). 164: ** [by eric] 165: ** 1/18/78 -- changed to exec processes as user INGRES, 166: ** so that someone else cannot write a dummy 167: ** driver which bypasses the protection system. 168: ** Processes must henceforth be mode 4700. [eric] 169: */ 170: 171: # define PTSIZE 2048 /* maximum size of the process table */ 172: # define PTPARAM '$' /* parameter expansion indicator */ 173: # define PTDELIM "$" /* separator string in proctab */ 174: # define MAXPARAMS 10 /* max number of params in proctab */ 175: # define MAXOPTNS 10 /* maximum number of options you can specify */ 176: # define MAXPROCS 10 /* maximum number of processes in the system */ 177: # define PVECTSIZE 6 /* number of pipes to each process */ 178: # define EQUELFLAG '&' 179: # define NETFLAG '|' /* network slave flag */ 180: # define CLOSED '?' 181: 182: char Fileset[10]; 183: char *Database; 184: extern char *Dbpath; /* defined in initucode */ 185: struct admin Admin; /* set in initucode */ 186: char Fdesc[10] = {'?','?','?','?','?','?','?','?','?','?'}; 187: struct lockreq Lock; 188: char Ptbuf[PTSIZE + 1]; 189: char *Ptptr = Ptbuf; /* ptr to freespace in Ptbuf */ 190: char *Opt[MAXOPTNS + 1]; 191: int Nopts; 192: int No_exec; /* if set, don't execute */ 193: char *User_ovrd; /* override usercode from -u flag */ 194: 195: main(argc, argv) 196: int argc; 197: char **argv; 198: { 199: register int i; 200: register int j; 201: extern char *Proc_name; 202: int fd; 203: extern int Status; 204: char *proctab; 205: register char *p; 206: char *ptr; 207: extern char *Flagvect[]; /* defined in initucode.c */ 208: extern char *Parmvect[]; /* ditto */ 209: char *uservect[4]; 210: extern char Version[]; /* version number */ 211: 212: Proc_name = "INGRES"; 213: itoa(getpid(), Fileset); 214: proctab = NULL; 215: Database = NULL; 216: 217: /* 218: ** Initialize everything, like Flagvect, Parmvect, Usercode, 219: ** etc. 220: */ 221: 222: i = initucode(argc, argv, TRUE, uservect, -1); 223: switch (i) 224: { 225: case 0: /* ok */ 226: case 5: 227: break; 228: 229: case 1: /* database does not exist */ 230: case 6: 231: printf("Database %s does not exist\n", Parmvect[0]); 232: goto usage; 233: 234: case 2: /* you are not authorized */ 235: printf("You may not access database %s\n", Database); 236: goto usage; 237: 238: case 3: /* not a valid user */ 239: printf("You are not a valid INGRES user\n"); 240: goto usage; 241: 242: case 4: /* no database name specified */ 243: printf("No database name specified\n"); 244: goto usage; 245: 246: default: 247: syserr("initucode %d", i); 248: } 249: 250: /* 251: ** Extract database name and process table name from 252: ** parameter vector. 253: */ 254: 255: Database = Parmvect[0]; 256: proctab = Parmvect[1]; 257: if (checkdbname(Database)) 258: { 259: printf("Improper database name: %s\n", Database); 260: goto usage; 261: } 262: 263: /* scan flags in users file */ 264: for (p = uservect[0]; *p != '\0'; p++) 265: { 266: /* skip initial blanks and tabs */ 267: if (*p == ' ' || *p == '\t') 268: continue; 269: ptr = p; 270: 271: /* find end of flag and null-terminate it */ 272: while (*p != '\0' && *p != ' ' && *p != '\t') 273: p++; 274: i = *p; 275: *p = '\0'; 276: 277: /* process the flag */ 278: doflag(ptr, 1); 279: if (i == '\0') 280: break; 281: } 282: 283: /* scan flags on command line */ 284: for (i = 0; (p = Flagvect[i]) != NULL; i++) 285: doflag(p, 0); 286: 287: /* check for query modification specified for this database */ 288: if ((Admin.adhdr.adflags & A_QRYMOD) == 0) 289: doflag("-q", -1); 290: 291: /* do the -u flag processing */ 292: if (User_ovrd != 0) 293: bmove(User_ovrd, Usercode, 2); 294: 295: /* close any extraneous files, being careful not to close anything we need */ 296: for (i = 'C'; i < 0100 + MAXFILES; i++) 297: { 298: for (j = 0; j < (sizeof Fdesc / sizeof *Fdesc); j++) 299: { 300: if (Fdesc[j] == i) 301: break; 302: } 303: if (j >= (sizeof Fdesc / sizeof *Fdesc)) 304: close(i & 077); 305: } 306: 307: /* determine process table */ 308: if (proctab == NULL) 309: { 310: /* use default proctab */ 311: proctab = uservect[1]; 312: if (proctab[0] == 0) 313: { 314: /* no proctab in users file */ 315: concat("=proctab", Version, Ptbuf); 316: 317: /* strip off the mod number */ 318: for (p = Ptbuf; *p != 0; p++) 319: if (*p == '/') 320: break; 321: *p = 0; 322: proctab = Ptbuf; 323: } 324: } 325: else 326: { 327: /* proctab specified; check permissions */ 328: if ((Status & (proctab[0] == '=' ? U_EPROCTAB : U_APROCTAB)) == 0) 329: { 330: printf("You may not specify this process table\n"); 331: goto usage; 332: } 333: } 334: 335: /* expand process table name */ 336: if (proctab[0] == '=') 337: { 338: smove(ztack(ztack(Pathname, "/files/"), &proctab[1]), Ptbuf); 339: proctab = Ptbuf; 340: } 341: 342: /* open and read the process table */ 343: if ((fd = open(proctab, 0)) < 0) 344: { 345: printf("Proctab %s: %s\n", proctab, strerror(errno)); 346: goto usage; 347: } 348: 349: if ((i = read(fd, Ptbuf, PTSIZE + 1)) < 0) 350: syserr("Cannot read proctab %s", proctab); 351: if (i > PTSIZE) 352: syserr("Proctab %s too big, lim %d", proctab, PTSIZE); 353: 354: close(fd); 355: Ptbuf[i] = 0; 356: 357: /* build internal form of the process table */ 358: buildint(); 359: 360: /* don't bother executing if we have found errors */ 361: if (No_exec) 362: { 363: usage: 364: /* cat .../files/usage */ 365: cat(ztack(Pathname, "/files/usage")); 366: exit(1); 367: } 368: 369: /* set locks on the database */ 370: dolocks(); 371: 372: /* satisfy process table (never returns) */ 373: satisfypt(); 374: } 375: 376: 377: 378: /* 379: ** Process rubouts (just exit) 380: */ 381: 382: rubproc() 383: { 384: exit(2); 385: } 386: /* 387: ** DOFLAG -- process flag 388: ** 389: ** Parameters: 390: ** flag -- the flag (as a string) 391: ** where -- where it is called from 392: ** -1 -- internally inserted 393: ** 0 -- on user command line 394: ** 1 -- from users file 395: ** 396: ** Return: 397: ** none 398: ** 399: ** Side effects: 400: ** All flags are inserted on the end of the 401: ** "Flaglist" vector for passing to the processes. 402: ** The "No_exec" flag is set if the flag is bad or you 403: ** are not authorized to use it. 404: ** 405: ** Requires: 406: ** Status -- to get the status bits set for this user. 407: ** syserr -- for the obvious 408: ** printf -- to print errors 409: ** atoi -- to check syntax on numerically-valued flags 410: ** 411: ** Defines: 412: ** doflag() 413: ** Flagok -- a list of legal flags and attributes (for 414: ** local use only). 415: ** Relmode -- a list of legal relation modes. 416: ** 417: ** Called by: 418: ** main 419: ** 420: ** History: 421: ** 11/6/79 (6.2/8) (eric) -- -u flag processing dropped, 422: ** since initucode does it anyhow. -E flag 423: ** removed (what is it?). F_USER code dropped. 424: ** F_DROP is still around; we may need it some- 425: ** day. Also, test of U_SUPER flag and/or DBA 426: ** status was wrong. 427: ** 7/5/78 (eric) -- NETFLAG added to list. 428: ** 3/27/78 (eric) -- EQUELFLAG added to the list. 429: ** 1/29/78 -- do_u_flag broken off by eric 430: ** 1/4/78 -- written by eric 431: */ 432: 433: struct flag 434: { 435: char flagname; /* name of the flag */ 436: char flagstat; /* status of flag (see below) */ 437: int flagsyntx; /* syntax code for this flag */ 438: int flagperm; /* status bits needed to use this flag */ 439: }; 440: 441: /* status bits for flag */ 442: # define F_PLOK 01 /* allow +x form */ 443: # define F_PLD 02 /* defaults to +x */ 444: # define F_DBA 04 /* must be the DBA to use */ 445: # define F_DROP 010 /* don't save in Flaglist */ 446: 447: /* syntax codes */ 448: # define F_ACCPT 1 /* always accept */ 449: # define F_C_SPEC 3 /* -cN spec */ 450: # define F_I_SPEC 4 /* -inN spec */ 451: # define F_F_SPEC 5 /* -fnxN.M spec */ 452: # define F_CHAR 6 /* single character */ 453: # define F_MODE 7 /* a modify mode */ 454: # define F_INTERNAL 8 /* internal flag, e.g., -q */ 455: # define F_EQUEL 9 /* EQUEL flag */ 456: 457: struct flag Flagok[] = 458: { 459: 'a', F_PLD|F_PLOK, F_ACCPT, 0, 460: 'b', F_PLD|F_PLOK, F_ACCPT, U_DRCTUPDT, 461: 'c', 0, F_C_SPEC, 0, 462: 'd', F_PLD|F_PLOK, F_ACCPT, 0, 463: 'f', 0, F_F_SPEC, 0, 464: 'i', 0, F_I_SPEC, 0, 465: 'n', 0, F_MODE, 0, 466: 'q', F_PLD|F_PLOK, F_INTERNAL, 0, 467: 'r', 0, F_MODE, 0, 468: 's', F_PLD|F_PLOK, F_ACCPT, 0, 469: 'v', 0, F_CHAR, 0, 470: 'w', F_PLOK|F_DROP, F_ACCPT, 0, 471: 'D', 0, F_ACCPT, U_TRACE, 472: /* 'E', F_PLOK|F_DBA, F_ACCPT, 0, */ 473: 'L', F_PLOK, F_ACCPT, 0, 474: 'M', 0, F_ACCPT, U_TRACE, 475: 'O', 0, F_ACCPT, U_TRACE, 476: 'P', 0, F_ACCPT, U_TRACE, 477: 'Q', 0, F_ACCPT, U_TRACE, 478: 'U', F_PLOK, F_ACCPT, U_UPSYSCAT, 479: 'Z', 0, F_ACCPT, U_TRACE, 480: EQUELFLAG, 0, F_EQUEL, 0, 481: NETFLAG, 0, F_EQUEL, 0, 482: '@', 0, F_EQUEL, 0, 483: '*', 0, F_ACCPT, 0, 484: 0, 0, 0, 0 485: }; 486: 487: /* list of valid retrieve into or index modes */ 488: char *Relmode[] = 489: { 490: "isam", 491: "cisam", 492: "hash", 493: "chash", 494: "heap", 495: "cheap", 496: "heapsort", 497: "cheapsort", 498: NULL 499: }; 500: 501: 502: doflag(flag, where) 503: char *flag; 504: int where; 505: { 506: register char *p; 507: register struct flag *f; 508: auto int intxx; 509: register char *ptr; 510: int i; 511: extern int Status; 512: 513: p = flag; 514: 515: /* check for valid flag format (begin with + or -) */ 516: if (p[0] != '+' && p[0] != '-') 517: goto badflag; 518: 519: /* check for flag in table */ 520: for (f = Flagok; f->flagname != p[1]; f++) 521: { 522: if (f->flagname == 0) 523: goto badflag; 524: } 525: 526: /* check for +x form allowed */ 527: if (p[0] == '+' && (f->flagstat & F_PLOK) == 0) 528: goto badflag; 529: 530: /* check for permission to use the flag */ 531: if ((f->flagperm != 0 && (Status & f->flagperm) == 0 && 532: (((f->flagstat & F_PLD) == 0) ? (p[0] == '+') : (p[0] == '-'))) || 533: ((f->flagstat & F_DBA) != 0 && (Status & U_SUPER) == 0 && 534: !bequal(Usercode, Admin.adhdr.adowner, 2))) 535: { 536: printf("You are not authorized to use the %s flag\n", p); 537: No_exec++; 538: } 539: 540: /* check syntax */ 541: switch (f->flagsyntx) 542: { 543: case F_ACCPT: 544: break; 545: 546: case F_C_SPEC: 547: if (atoi(&p[2], &intxx) || intxx > MAXFIELD) 548: goto badflag; 549: break; 550: 551: case F_I_SPEC: 552: if (p[2] != '1' && p[2] != '2' && p[2] != '4') 553: goto badflag; 554: if (atoi(&p[3], &intxx) || intxx > MAXFIELD) 555: goto badflag; 556: break; 557: 558: case F_F_SPEC: 559: if (p[2] != '4' && p[2] != '8') 560: goto badflag; 561: switch (p[3]) 562: { 563: case 'e': 564: case 'E': 565: case 'f': 566: case 'F': 567: case 'g': 568: case 'G': 569: case 'n': 570: case 'N': 571: break; 572: 573: default: 574: goto badflag; 575: 576: } 577: ptr = &p[4]; 578: while (*ptr != '.') 579: if (*ptr == 0) 580: goto badflag; 581: else 582: ptr++; 583: *ptr = 0; 584: if (atoi(&p[4], &intxx) || intxx > MAXFIELD) 585: goto badflag; 586: *ptr++ = '.'; 587: if (atoi(ptr, &intxx) || intxx > MAXFIELD) 588: goto badflag; 589: break; 590: 591: case F_CHAR: 592: if (p[2] == 0 || p[3] != 0) 593: goto badflag; 594: break; 595: 596: case F_MODE: 597: for (i = 0; (ptr = Relmode[i]) != NULL; i++) 598: { 599: if (sequal(&p[2], ptr)) 600: break; 601: } 602: if (ptr == NULL) 603: goto badflag; 604: break; 605: 606: case F_INTERNAL: 607: if (where >= 0) 608: goto badflag; 609: break; 610: 611: case F_EQUEL: 612: ptr = &p[2]; 613: for (i = 0; i < (sizeof Fdesc / sizeof *Fdesc); i++, ptr++) 614: { 615: if (*ptr == CLOSED) 616: continue; 617: if (*ptr == '\0' || *ptr < 0100 || *ptr >= 0100 + MAXFILES) 618: break; 619: Fdesc[i] = (*ptr & 077) | 0100; 620: } 621: break; 622: 623: default: 624: syserr("doflag: syntx %d", f->flagsyntx); 625: 626: } 627: 628: /* save flag */ 629: if (Nopts >= MAXOPTNS) 630: { 631: printf("Too many options to INGRES\n"); 632: exit(1); 633: } 634: if ((f->flagstat & F_DROP) == 0) 635: Opt[Nopts++] = p; 636: return; 637: 638: badflag: 639: printf("Bad flag format: %s\n", p); 640: No_exec++; 641: return; 642: } 643: /* 644: ** DOLOCKS -- set database lock 645: ** 646: ** A lock is set on the database. 647: */ 648: 649: dolocks() 650: { 651: db_lock(flagval('E') > 0 ? M_EXCL : M_SHARE); 652: close(Alockdes); 653: } 654: /* 655: ** BUILDINT -- build internal form of process table 656: ** 657: ** The text of the process table is scanned and converted to 658: ** internal form. Non-applicable entries are deleted in this 659: ** pass, and the EQUEL pipes are turned into real file descrip- 660: ** tors. 661: ** 662: ** Parameters: 663: ** none 664: ** 665: ** Returns: 666: ** nothing 667: ** 668: ** Requires: 669: ** scanpt -- to return next field of the process table 670: ** flagval -- to return the value of a given flag 671: ** Ptbuf -- the text of the process table 672: ** Ptptr -- pointer to freespace in Ptbuf 673: ** getptline -- to return next line of process table 674: ** 675: ** Defines: 676: ** buildint 677: ** Proctab -- the internal form of the process table 678: ** Params -- the parameter symbol table 679: ** 680: ** Called by: 681: ** main 682: ** 683: ** History: 684: ** 8/9/78 (eric) -- moved parameter expansion to 685: ** ingexec. Also, changed the pt line selection 686: ** algorithm slightly to fix possible degenerate 687: ** bug -- flags could not be '+', '-', '<', '>', 688: ** or '=' without problems. 689: ** 3/27/78 (eric) -- changed pt line selection criteria 690: ** to be more explicit in default cases; needed 691: ** to do networking with the +& flag. 692: ** 1/4/78 -- written by eric 693: */ 694: 695: struct proc 696: { 697: char *prpath; 698: char *prcond; 699: int prstat; 700: char *prstdout; /* file for standard output this proc */ 701: char prpipes[PVECTSIZE + 1]; 702: char *prparam; 703: }; 704: 705: /* bits for prstat */ 706: # define PR_REALUID 01 /* run the process as the real user */ 707: # define PR_NOCHDIR 02 /* run in the user's directory */ 708: # define PR_CLSSIN 04 /* close standard input */ 709: # define PR_CLSDOUT 010 /* close diagnostic output */ 710: 711: struct proc Proctab[MAXPROCS]; 712: 713: struct param 714: { 715: char *pname; 716: char *pvalue; 717: }; 718: 719: struct param Params[MAXPARAMS]; 720: 721: 722: buildint() 723: { 724: register struct proc *pr; 725: char *ptp; 726: register char *p; 727: register char *pipes; 728: int i; 729: int j; 730: struct param *pp; 731: char *getptline(); 732: 733: /* scan the template */ 734: pr = Proctab; 735: while ((ptp = getptline()) != 0) 736: { 737: /* check for overflow of internal Proctab */ 738: if (pr >= &Proctab[MAXPROCS]) 739: syserr("Too many processes"); 740: 741: /* collect a line into the fixed-format proctab */ 742: pr->prpath = ptp; 743: scanpt(&ptp, ':'); 744: pr->prcond = ptp; 745: scanpt(&ptp, ':'); 746: pipes = ptp; 747: scanpt(&ptp, ':'); 748: pr->prstat = oatoi(pipes); 749: pr->prstdout = ptp; 750: scanpt(&ptp, ':'); 751: pipes = ptp; 752: scanpt(&ptp, ':'); 753: if (length(pipes) != PVECTSIZE) 754: syserr("buildint: pipes(%s, %s)", pr->prpath, pipes); 755: smove(pipes, pr->prpipes); 756: for (p = pr->prpipes; p < &pr->prpipes[PVECTSIZE]; p++) 757: if (*p == 0) 758: *p = CLOSED; 759: pr->prparam = ptp; 760: 761: /* check to see if this entry is applicable */ 762: for (p = pr->prcond; *p != 0; ) 763: { 764: /* determine type of flag */ 765: switch (*p++) 766: { 767: case '=': /* flag must not be set */ 768: j = 1; 769: break; 770: 771: case '+': /* flag must be set on */ 772: case '>': 773: j = 2; 774: if (*p == '=') 775: { 776: j++; 777: p++; 778: } 779: break; 780: 781: case '-': /* flag must be set off */ 782: case '<': 783: j = 4; 784: if (*p == '=') 785: { 786: j++; 787: p++; 788: } 789: break; 790: 791: default: 792: /* skip any initial garbage */ 793: continue; 794: } 795: 796: /* get value of this flag */ 797: i = flagval(*p++); 798: 799: /* check to see if we should keep looking */ 800: switch (j) 801: { 802: case 1: 803: if (i == 0) 804: continue; 805: break; 806: 807: case 2: 808: if (i > 0) 809: continue; 810: break; 811: 812: case 3: 813: if (i >= 0) 814: continue; 815: break; 816: 817: case 4: 818: if (i < 0) 819: continue; 820: break; 821: 822: case 5: 823: if (i <= 0) 824: continue; 825: break; 826: } 827: 828: /* mark this entry as a loser and quit */ 829: p = NULL; 830: break; 831: } 832: 833: if (p == NULL) 834: { 835: /* this entry does not apply; throw it out */ 836: continue; 837: } 838: 839: /* replace EQUEL codes with actual file descriptors */ 840: for (p = pr->prpipes; *p != 0; p++) 841: { 842: if (*p < '0' || *p > '9') 843: continue; 844: 845: *p = Fdesc[*p - '0']; 846: } 847: 848: /* this entry is valid, move up to next entry */ 849: pr++; 850: } 851: pr->prpath = 0; 852: 853: /* scan for parameters */ 854: pp = Params; 855: pp->pname = "pathname"; 856: pp++->pvalue = Pathname; 857: while ((p = getptline()) != 0) 858: { 859: /* check for parameter list overflow */ 860: if (pp >= &Params[MAXPARAMS]) 861: syserr("Too many parameters"); 862: 863: pp->pname = p; 864: 865: /* get value for parameter */ 866: if ((pp->pvalue = p = getptline()) == 0) 867: { 868: /* if no lines, make it null string */ 869: pp->pvalue = ""; 870: } 871: else 872: { 873: /* get 2nd thru nth and concatenate them */ 874: do 875: { 876: ptp = &p[length(p)]; 877: p = getptline(); 878: *ptp = '\n'; 879: } while (p != 0); 880: } 881: 882: /* bump to next entry */ 883: pp++; 884: } 885: 886: /* adjust free space pointer for eventual call to expand() */ 887: Ptptr++; 888: } 889: /* 890: ** FLAGVAL -- return value of flag 891: ** 892: ** Parameter: 893: ** flag -- the name of the flag 894: ** 895: ** Return: 896: ** -1 -- flag is de-asserted (-x) 897: ** 0 -- flag is not specified 898: ** 1 -- flag is asserted (+x) 899: ** 900: ** Requires: 901: ** Opt -- to scan the flags 902: ** 903: ** Defines: 904: ** flagval 905: ** 906: ** Called by: 907: ** buildint 908: ** dolocks 909: ** 910: ** History: 911: ** 3/27/78 (eric) -- changed to handle EQUEL flag 912: ** normally. 913: ** 1/4/78 -- written by eric 914: */ 915: 916: flagval(flag) 917: char flag; 918: { 919: register char f; 920: register char **p; 921: register char *o; 922: 923: f = flag; 924: 925: /* start scanning option list */ 926: for (p = Opt; (o = *p) != 0; p++) 927: { 928: if (o[1] == f) 929: if (o[0] == '+') 930: return (1); 931: else 932: return (-1); 933: } 934: return (0); 935: } 936: /* 937: ** SCANPT -- scan through process table for a set of delimiters 938: ** 939: ** Parameters: 940: ** pp -- a pointer to a pointer to the process table 941: ** delim -- a primary delimiter. 942: ** 943: ** Returns: 944: ** The actual delimiter found 945: ** 946: ** Side effects: 947: ** Updates pp to point the the delimiter. The delimiter 948: ** is replaced with null. 949: ** 950: ** Requires: 951: ** nothing 952: ** 953: ** Defines: 954: ** scanpt 955: ** 956: ** Called by: 957: ** buildint 958: ** 959: ** History: 960: ** 1/4/78 -- written by eric 961: */ 962: 963: scanpt(pp, delim) 964: char **pp; 965: char delim; 966: { 967: register char *p; 968: register char c; 969: register char d; 970: 971: d = delim; 972: 973: for (p = *pp; ; p++) 974: { 975: c = *p; 976: 977: /* check to see if it is a delimiter */ 978: if (c == d) 979: { 980: /* we have a delim match */ 981: *p++ = 0; 982: *pp = p; 983: return (c); 984: } 985: if (c == 0) 986: { 987: syserr("proctab: d=%c, *pp=%s", d, *pp); 988: } 989: } 990: } 991: /* 992: ** GETPTLINE -- get line from process table 993: ** 994: ** Parameters: 995: ** none 996: ** 997: ** Return: 998: ** zero -- end of process table or section 999: ** else -- pointer to a line, which is a null-terminated 1000: ** string (without the newline). 1001: ** 1002: ** Side effects: 1003: ** sticks a null byte into Ptbuf at the end of the line. 1004: ** 1005: ** Note: 1006: ** sequential lines returned will be sequential in core, 1007: ** that is, they can be concatenated by just 1008: ** changing the null-terminator back to a newline. 1009: ** 1010: ** Requires: 1011: ** Ptptr -- should point to the next line of the process 1012: ** table. 1013: ** sequal -- to do a string equality test for "$" 1014: ** 1015: ** Defines: 1016: ** getptline 1017: ** 1018: ** Called by: 1019: ** buildint 1020: ** 1021: ** History: 1022: ** 1/8/77 -- written by eric 1023: */ 1024: 1025: char *getptline() 1026: { 1027: register char c; 1028: register char *line; 1029: 1030: /* mark the beginning of the line */ 1031: line = Ptptr; 1032: 1033: /* scan for a newline or a null */ 1034: while ((c = *Ptptr++) != '\n') 1035: { 1036: if (c == 0) 1037: { 1038: /* arrange to return zero next time too */ 1039: Ptptr--; 1040: return ((char *) 0); 1041: } 1042: } 1043: 1044: /* replace the newline with null */ 1045: Ptptr[-1] = 0; 1046: 1047: /* see if it is an "end-of-section" mark */ 1048: if (sequal(line, PTDELIM)) 1049: { 1050: line[0] = 0; 1051: return (0); 1052: } 1053: return (line); 1054: } 1055: /* 1056: ** EXPAND -- macro expand a string 1057: ** 1058: ** A string is expanded: $name constructs are looked up and 1059: ** expanded if found. If not, the old construct is passed 1060: ** thru. The return is the address of a new string that will 1061: ** do what you want. Calls may be recursive. The string is 1062: ** not copied unless necessary. 1063: ** 1064: ** Parameters: 1065: ** s1 -- the string to expand 1066: ** intflag -- a flag set if recursing 1067: ** 1068: ** Return: 1069: ** the address of the expanded string, not copied unless 1070: ** necessary. 1071: ** 1072: ** Side effects: 1073: ** Ptbuf is allocated (from Ptptr) for copy space. There 1074: ** must be enough space to copy, even if the copy 1075: ** is not saved. 1076: ** Ptptr is updated to point to the new free space. 1077: ** 1078: ** Requires: 1079: ** Ptbuf, Ptptr -- to get buffer space 1080: ** Params -- to scan parameter 1081: ** sequal -- to check for parameter name match 1082: ** syserr 1083: ** 1084: ** Defines: 1085: ** expand 1086: ** 1087: ** Syserrs: 1088: ** "Proctab too big to macro expand" 1089: ** ran out of space making a copy of the parame- 1090: ** ter. 1091: ** 1092: ** History: 1093: ** 1/8/78 -- written by eric 1094: */ 1095: 1096: char *expand(s1, intflag) 1097: char *s1; 1098: int intflag; 1099: { 1100: register struct param *pp; 1101: register char *s; 1102: register char c; 1103: int flag; 1104: int count; 1105: char *mark, *xmark; 1106: 1107: s = s1; 1108: xmark = Ptptr; 1109: flag = 0; /* set if made a macro expansion */ 1110: count = 0; /* set if any characters copied directly */ 1111: 1112: /* scan input string to end */ 1113: while ((c = *s++) != 0) 1114: { 1115: /* check for possible parameter expansion */ 1116: if (c != PTPARAM) 1117: { 1118: /* nope, copy through if space */ 1119: if (Ptptr >= &Ptbuf[PTSIZE]) 1120: goto ptsizeerr; 1121: *Ptptr++ = c; 1122: count++; 1123: continue; 1124: } 1125: 1126: /* possible expansion; mark this point */ 1127: mark = Ptptr; 1128: 1129: /* collect the name of the parameter */ 1130: do 1131: { 1132: if (Ptptr >= &Ptbuf[PTSIZE]) 1133: { 1134: ptsizeerr: 1135: syserr("Proctab too big to macro expand"); 1136: } 1137: *Ptptr++ = c; 1138: c = *s++; 1139: } while ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); 1140: s--; 1141: 1142: /* look up in parameter table */ 1143: *Ptptr = 0; 1144: for (pp = Params; pp->pname != 0; pp++) 1145: { 1146: if (sequal(pp->pname, mark + 1)) 1147: break; 1148: } 1149: 1150: if (pp->pname == 0) 1151: { 1152: /* search failed, take string as is */ 1153: count++; 1154: continue; 1155: } 1156: 1157: /* reprocess name delimiter unless a newline */ 1158: if (c == '\n') 1159: s++; 1160: 1161: /* found entry, copy it in instead */ 1162: /* back up over name */ 1163: Ptptr = mark; 1164: 1165: /* check to see if we can return expansion as value */ 1166: if (count == 0 && *s == 0) 1167: { 1168: /* then nothing before or after this call */ 1169: if (intflag == 0) 1170: Ptptr = xmark; 1171: return (pp->pvalue = expand(pp->pvalue, 1)); 1172: } 1173: 1174: /* expand to new buffer */ 1175: pp->pvalue = expand(pp->pvalue, 1); 1176: 1177: /* we are appending */ 1178: Ptptr--; 1179: flag++; 1180: } 1181: 1182: /* null terminate the new entry (which must be copied) */ 1183: *Ptptr++ = 0; 1184: 1185: /* see if we expanded anything */ 1186: if (flag) 1187: { 1188: /* yes, return the new stuff in buffer */ 1189: return (xmark); 1190: } 1191: 1192: /* no, then we can return the original and reclaim space */ 1193: if (intflag == 0) 1194: Ptptr = xmark; 1195: return (s1); 1196: } 1197: /* 1198: ** SATISFYPT -- satisfy the process table 1199: ** 1200: ** Well folks, now that you've read this far, this is it!!! I 1201: ** mean, this one really does it!!! It takes the internal form 1202: ** built by buildint() and creates pipes as necessary, forks, and 1203: ** execs the INGRES processes. Isn't that neat? 1204: ** 1205: ** * * * * * W A R N I N G * * * * * 1206: ** 1207: ** In some versions, the pipe() system call support function 1208: ** in libc.a clobbers r2. In versions 6 and 7 PDP-11 C compilers, 1209: ** this is the third register variable declared (in this case, 1210: ** "i"). This isn't a problem here, but take care if you change 1211: ** this routine. 1212: ** 1213: ** Parameters: 1214: ** none 1215: ** 1216: ** Returns: 1217: ** never 1218: ** 1219: ** Requires: 1220: ** Proctab -- the internal form 1221: ** ingexec -- to actually exec the process 1222: ** pipe -- to create the pipe 1223: ** syserr -- for the obvious 1224: ** fillpipe -- to extend a newly opened pipe through all 1225: ** further references to it. 1226: ** checkpipes -- to see if a given pipe will ever be 1227: ** referenced again. 1228: ** fork -- to create a new process 1229: ** 1230: ** Defines: 1231: ** satisfypt 1232: ** 1233: ** Called by: 1234: ** main 1235: ** 1236: ** History: 1237: ** 7/24/78 (eric) -- Actual file descriptors stored in 1238: ** 'prpipes' are changed to have the 0100 bit 1239: ** set internally (as well as externally), so 1240: ** fd 0 will work correctly. 1241: ** 1/4/78 -- written by eric 1242: */ 1243: 1244: satisfypt() 1245: { 1246: register struct proc *pr; 1247: int pipex[2]; 1248: register char *p; 1249: register int i; 1250: 1251: /* scan the process table */ 1252: for (pr = Proctab; pr->prpath != 0; pr++) 1253: { 1254: /* scan pipe vector, creating new pipes as needed */ 1255: for (p = pr->prpipes; *p != 0; p++) 1256: { 1257: if ((*p >= 0100 && *p < 0100 + MAXFILES) || *p == CLOSED) 1258: { 1259: /* then already open or never open */ 1260: continue; 1261: } 1262: 1263: /* not yet open: create a pipe */ 1264: if (pipe(pipex)) 1265: syserr("satisfypt: pipe %c", *p); 1266: 1267: /* propagate pipe through rest of proctab */ 1268: fillpipe(*p, pr, pipex); 1269: } 1270: 1271: /* fork if necessary */ 1272: if (pr[1].prpath == 0 || (i = fork()) == 0) 1273: { 1274: /* child!! */ 1275: ingexec(pr); 1276: } 1277: 1278: /* parent */ 1279: if (i < 0) 1280: syserr("satisfypt: fork"); 1281: 1282: /* scan pipes. close all not used in the future */ 1283: for (p = pr->prpipes; *p != 0; p++) 1284: { 1285: if (*p == CLOSED) 1286: continue; 1287: if (checkpipes(&pr[1], *p)) 1288: if (close(*p & 077)) 1289: syserr("satisfypt: close(%s, %d)", pr->prpath, *p & 077); 1290: } 1291: } 1292: syserr("satisfypt: fell out"); 1293: } 1294: /* 1295: ** FILLPIPE -- extend pipe through rest of process table 1296: ** 1297: ** The only tricky thing in here is that "rw" alternates between 1298: ** zero and one as a pipe vector is scanned, so that it will know 1299: ** whether to get the read or the write end of a pipe. 1300: ** 1301: ** Parameters: 1302: ** name -- external name of the pipe 1303: ** proc -- the point in the process table to scan from 1304: ** pipex -- the pipe 1305: ** 1306: ** Returns: 1307: ** nothing 1308: ** 1309: ** Requires: 1310: ** nothing 1311: ** 1312: ** Defines: 1313: ** fillpipe 1314: ** 1315: ** Called by: 1316: ** satisfypt 1317: ** 1318: ** History: 1319: ** 7/24/78 (eric) -- 0100 bit set on file descriptors. 1320: ** 1/4/78 -- written by eric 1321: */ 1322: 1323: fillpipe(name, proc, pipex) 1324: char name; 1325: struct proc *proc; 1326: int pipex[2]; 1327: { 1328: register struct proc *pr; 1329: register char *p; 1330: register int rw; 1331: 1332: /* scan rest of processes */ 1333: for (pr = proc; pr->prpath != 0; pr++) 1334: { 1335: /* scan the pipe vector */ 1336: rw = 1; 1337: for (p = pr->prpipes; *p != 0; p++) 1338: { 1339: rw = 1 - rw; 1340: if (*p == name) 1341: *p = pipex[rw] | 0100; 1342: } 1343: } 1344: } 1345: /* 1346: ** CHECKPIPES -- check for pipe referenced in the future 1347: ** 1348: ** Parameters: 1349: ** proc -- point in the process table to start looking 1350: ** from. 1351: ** fd -- the file descriptor to look for. 1352: ** 1353: ** Return: 1354: ** zero -- it will be referenced in the future. 1355: ** one -- it is never again referenced. 1356: ** 1357: ** Requires: 1358: ** nothing 1359: ** 1360: ** Defines: 1361: ** checkpipes 1362: ** 1363: ** Called by: 1364: ** satisfypt 1365: ** 1366: ** History: 1367: ** 7/24/78 (eric) -- 0100 bit on file descriptors handled. 1368: ** 1/4/78 -- written by eric 1369: */ 1370: 1371: checkpipes(proc, fd) 1372: struct proc *proc; 1373: int fd; 1374: { 1375: register struct proc *pr; 1376: register char *p; 1377: register int fdx; 1378: 1379: fdx = fd | 0100; 1380: 1381: for (pr = proc; pr->prpath != 0; pr++) 1382: { 1383: for (p = pr->prpipes; *p != 0; p++) 1384: if (*p == fdx) 1385: return (0); 1386: } 1387: return (1); 1388: } 1389: /* 1390: ** INGEXEC -- execute INGRES process 1391: ** 1392: ** This routine handles all the setup of the argument vector 1393: ** and then executes a process. 1394: ** 1395: ** Parameters: 1396: ** process -- a pointer to the process table entry which 1397: ** describes this process. 1398: ** 1399: ** Returns: 1400: ** never 1401: ** 1402: ** Side Effects: 1403: ** never returns, but starts up a new overlay. Notice 1404: ** that it does NOT fork. 1405: ** 1406: ** Requires: 1407: ** none 1408: ** 1409: ** Called By: 1410: ** satisfypt 1411: ** 1412: ** Trace Flags: 1413: ** none 1414: ** 1415: ** Diagnostics: 1416: ** none 1417: ** 1418: ** Syserrs: 1419: ** chdir %s -- could not change directory into the data- 1420: ** base. 1421: ** creat %s -- could not create the redirected standard 1422: ** output file. 1423: ** %s not executable -- could not execute the process. 1424: ** 1425: ** History: 1426: ** 8/9/78 (eric) -- changed "prparam" to be a colon- 1427: ** separated list of parameters (so the number 1428: ** is variable); also, moved parameter expansion 1429: ** into this routine from buildint() so that 1430: ** the colons in the dbu part of the proctab 1431: ** would not confuse things. 1432: ** 7/24/78 (eric) -- changed the technique of closing 1433: ** files 0 & 2 so that they will never be closed 1434: ** (even if requested in the status field) 1435: ** if they are mentioned in the pipe vector. 1436: ** Also, some fiddling is done to handle the 1437: ** 0100 bit on file descriptors correctly. 1438: */ 1439: 1440: ingexec(process) 1441: struct proc *process; 1442: { 1443: char *vect[30]; 1444: register char *p; 1445: register char **v; 1446: char **opt; 1447: int i; 1448: register struct proc *pr; 1449: int outfd; 1450: 1451: v = vect; 1452: pr = process; 1453: 1454: *v++ = expand(pr->prpath); 1455: *v++ = pr->prpipes; 1456: *v++ = Fileset; 1457: *v++ = Usercode; 1458: *v++ = Database; 1459: *v++ = Pathname; 1460: 1461: /* expand variable number of parameters */ 1462: for (p = pr->prparam; *p != 0; ) 1463: { 1464: for (*v = p; *p != 0; p++) 1465: { 1466: if (*p == ':') 1467: { 1468: *p++ = 0; 1469: break; 1470: } 1471: } 1472: 1473: /* expand macros in parameters */ 1474: *v++ = expand(*v); 1475: } 1476: 1477: /* insert flag parameters */ 1478: for (opt = Opt; *opt; opt++) 1479: *v++ = *opt; 1480: *v = 0; 1481: 1482: /* close extra pipes (those not in pipe vector) */ 1483: for (i = 0100; i < 0100 + MAXFILES; i++) 1484: { 1485: for (p = pr->prpipes; *p != 0; p++) 1486: { 1487: if (i == *p) 1488: break; 1489: } 1490: if (*p == 0 && i != 0100 + 1 && 1491: (i != 0100 || (pr->prstat & PR_CLSSIN) != 0) && 1492: (i != 0100 + 2 || (pr->prstat & PR_CLSDOUT) != 0)) 1493: close(i & 077); 1494: } 1495: 1496: /* change to the correct directory */ 1497: if ((pr->prstat & PR_NOCHDIR) == 0) 1498: { 1499: if (chdir(Dbpath)) 1500: syserr("ingexec: chdir %s", Dbpath); 1501: } 1502: 1503: /* change to normal userid/groupid if a non-dangerous process */ 1504: if ((pr->prstat & PR_REALUID) != 0) 1505: { 1506: setuid(getuid()); 1507: # ifndef xB_UNIX 1508: setgid(getgid()); 1509: # endif 1510: } 1511: 1512: /* change standard output if specified in proctab */ 1513: p = pr->prstdout; 1514: if (*p != 0) 1515: { 1516: /* chew up fd 0 (just in case) */ 1517: outfd = dup(1); 1518: close(1); 1519: if (creat(p, 0666) != 1) 1520: { 1521: /* restore standard output and print error */ 1522: close(1); 1523: dup(outfd); /* better go into slot 1 */ 1524: syserr("ingexec: creat %s", p); 1525: } 1526: close(outfd); 1527: } 1528: 1529: /* give it the old college (or in this case, University) try */ 1530: execv(vect[0], vect); 1531: syserr("\"%s\" not executable", vect[0]); 1532: } 1533: /* 1534: ** CHECKDBNAME -- check for valid database name 1535: ** 1536: ** Parameter: 1537: ** name -- the database name 1538: ** 1539: ** Return: 1540: ** zero -- ok 1541: ** else -- bad database name 1542: ** 1543: ** Side effects: 1544: ** none 1545: ** 1546: ** Requires: 1547: ** nothing 1548: ** 1549: ** Defines: 1550: ** checkdbname 1551: ** 1552: ** History: 1553: ** 1/9/78 -- written by eric 1554: */ 1555: 1556: checkdbname(name) 1557: char *name; 1558: { 1559: register char *n; 1560: register char c; 1561: 1562: n = name; 1563: 1564: if (length(n) > 14) 1565: return (1); 1566: while ((c = *n++) != 0) 1567: { 1568: if (c == '/') 1569: return (1); 1570: } 1571: return (0); 1572: }