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