|
|
1.1 ! root 1: # include <stdio.h> ! 2: # include <ingres.h> ! 3: # include <aux.h> ! 4: # include <version.h> ! 5: # include <opsys.h> ! 6: # include <access.h> ! 7: # include <lock.h> ! 8: # include <signal.h> ! 9: # include <sccs.h> ! 10: ! 11: SCCSID(@(#)initucode.c 7.4 9/26/83) ! 12: ! 13: /* ! 14: ** INITUCODE -- initialize standalone process ! 15: ** ! 16: ** This function initializes a standalone process, initializing ! 17: ** a lot of global variables, scanning the argument vector for ! 18: ** some special flags (-u and +-w), seperating flags and ! 19: ** parameters, and so forth. ! 20: ** ! 21: ** Every standalone program should begin with the lines: ! 22: ** i = initucode(argc, argv, ...); ! 23: ** switch (i) ! 24: ** ... ! 25: ** ! 26: ** On a return of 2, 3, or 4, essentially none of the processing ! 27: ** is done (particularly true with return 4). Virtually nothing ! 28: ** can be done in the calling program except print a "usage" ! 29: ** message and exit. The exception to this is that 'Pathname' ! 30: ** is set, so that it can be used in the error printing. For ! 31: ** example, ingres.c cats file .../files/usage on this sort of ! 32: ** error. ! 33: ** ! 34: ** If it is preferable to not lock the database at this time, ! 35: ** the 'waitmode' parameter should be passed as -1. This still ! 36: ** causes the 'Wait_action' variable to be initialized, but the ! 37: ** database is not actually locked. It can be locked by calling: ! 38: ** db_lock(Dbpath, M_EXCL); ! 39: ** at the proper time. ! 40: ** ! 41: ** For the main effects of this routine, see the "Side Effects" ! 42: ** section below. ! 43: ** ! 44: ** Parameters: ! 45: ** argc -- argc from main. ! 46: ** argv -- argv from main. ! 47: ** dbflag -- TRUE -- take the first parameter as the ! 48: ** database name. ! 49: ** FALSE -- don't take the first parameter as ! 50: ** the database name. ! 51: ** paramlist -- a pointer to an array[4] of pointers ! 52: ** to character; set to the extra fields of ! 53: ** the users file entry for the real user ! 54: ** executing the code (not the user on the ! 55: ** -u flag). If NULL, this is ignored. ! 56: ** waitmode -- M_EXCL -- set an exclusive lock on the ! 57: ** database. ! 58: ** M_SHARE -- set a shared lock on the database. ! 59: ** -1 -- don't set a lock on the database. ! 60: ** However, other stuff (Wait_action) is ! 61: ** still set up so that the lock can be ! 62: ** placed later by calling 'db_lock'. ! 63: ** ! 64: ** Returns: ! 65: ** 0 -- everything is ok. ! 66: ** 1 -- the database does not exist. ! 67: ** 2 -- you are not authorized to access this database. ! 68: ** 3 -- you are not a valid INGRES user. ! 69: ** 4 -- no database name was specified (only if dbflag ! 70: ** == TRUE). ! 71: ** 5 -- everything is ok, but there was an indirect ! 72: ** taken. ! 73: ** 6 -- there was an indirect taken, but there was no ! 74: ** database there. ! 75: ** ! 76: ** If dbflag == FALSE, you can only get returns 0 and ! 77: ** 3. ! 78: ** ! 79: ** Side Effects: ! 80: ** A lot of variables are set, as follows: ! 81: ** ! 82: ** Dbpath -- set to the pathname of the database (only ! 83: ** if dbflag == TRUE). It is set even if the ! 84: ** database does not exist. ! 85: ** Parmvect -- set to the parameters from argv, that is, ! 86: ** anything not beginning with '+' or '-'. ! 87: ** Flagvect -- set to the flags from argv, that is, ! 88: ** everything beginning with '+' or '-'. The ! 89: ** flags '+w', '-w', and '-u' are stripped out, ! 90: ** however. ! 91: ** Wait_action -- set to the appropriate action (A_SLP ! 92: ** or A_RTN) based on the +-w flags and whether ! 93: ** we are running in background or not. ! 94: ** This is automatically used by 'db_lock()'. ! 95: ** Usercode -- set to the persons effective user code ! 96: ** (that is, after the -u processing). Only ! 97: ** the INGRES user or the DBA can use the -u ! 98: ** flag. ! 99: ** Pathname -- set to the pathname of the INGRES subtree. ! 100: ** Status -- an integer set to the user status field ! 101: ** of the users file for the real user. ! 102: ** Ing_uid -- set to the user id of the INGRES user. ! 103: ** ! 104: ** The rubout signal (signal 2) is caught, and refered ! 105: ** to the standard rubout processor (see rub.c); thus, ! 106: ** a routine called 'rubproc' must be defined in the ! 107: ** standalone code (which will just call exit, in the ! 108: ** normal case). ! 109: ** ! 110: ** The 'adminhdr' part of the 'Admin' struct is filled ! 111: ** in. This is not done with readadmin() and is not ! 112: ** equivalent to an 'admininit()', but it does make ! 113: ** the DBA and database status available. ! 114: ** ! 115: ** This routine can also exit immediately with an ! 116: ** error message. ! 117: ** ! 118: ** Defined Constants: ! 119: ** MAXPARGS -- the maximum number of parameter type ! 120: ** arguments to any standalone program. ! 121: ** MAXFARGS -- the maximum number of flag type arg- ! 122: ** uments to any standalong program (not inclu- ! 123: ** ding flags in the users file, and the +-w ! 124: ** and -u flags). ! 125: ** ! 126: ** Files: ! 127: ** /etc/passwd -- to get the pathname for user "ingres". ! 128: ** .../files/users -- to get all the per-user information, ! 129: ** and to process the -u flag. ! 130: ** ! 131: ** Compilation Flags: ! 132: ** xB_UNIX, xV6_UNIX -- see comments in aux.h ! 133: ** ! 134: ** Trace Flags: ! 135: ** none ! 136: */ ! 137: ! 138: ! 139: # define MAXFARGS 15 /* maximum flag-type arguments */ ! 140: # define MAXPARGS 20 /* maximum parameter-type args */ ! 141: ! 142: char *Usercode; /* the usercode of the effective user */ ! 143: char *Pathname; /* path of INGRES subtree */ ! 144: int Status; /* the user status of the real user */ ! 145: int Rubignored; /* set if rubouts ignored */ ! 146: /* (also in initproc for system processes) */ ! 147: int Wait_action; /* the action on the db_lock */ ! 148: char *Dbpath; /* the pathname of the database */ ! 149: char *Flagvect[MAXFARGS+1]; /* the flags from argv */ ! 150: char *Parmvect[MAXPARGS+1]; /* the parameters from argv */ ! 151: int Ing_uid; /* the user id of the INGRES user */ ! 152: ! 153: initucode(argc, argv, dbflag, paramlist, waitmode) ! 154: int argc; ! 155: char **argv; ! 156: int dbflag; ! 157: char *paramlist[4]; ! 158: int waitmode; ! 159: { ! 160: register char *p; ! 161: char *q; ! 162: char c; ! 163: FILE *iop; ! 164: static char sbuf[MAXLINE * 2]; ! 165: register char *sbufp; ! 166: char buf[MAXLINE+1]; ! 167: register int i; ! 168: int npermit; ! 169: int rtval; ! 170: char *field[UF_NFIELDS]; ! 171: int actualuid; ! 172: auto int uid; ! 173: auto int gid; ! 174: int waitflag; ! 175: char *userflag; ! 176: struct sgttyb gttydummy; ! 177: int fvi, pvi; ! 178: char **avp; ! 179: char usr_ovrd[3]; ! 180: static int reenter; ! 181: extern rubcatch(); ! 182: static short tvect[100]; ! 183: bool nobuffer; ! 184: # ifdef xV7_UNIX ! 185: extern char *getenv(); ! 186: # endif xV7_UNIX ! 187: ! 188: /* ! 189: ** Set up interrupts. ! 190: */ ! 191: ! 192: reenter = 0; ! 193: setexit(); ! 194: if (reenter++) ! 195: exit(-1); ! 196: if (signal(SIGINT, SIG_IGN) == SIG_DFL) ! 197: signal(SIGINT, rubcatch); ! 198: # ifdef xV6_UNIX ! 199: for (avp = argv; *avp != 0 && *avp != (char *) -1; avp++) ! 200: continue; ! 201: *avp = NULL; ! 202: # endif ! 203: ! 204: /* ! 205: ** Do basic initialization, such as setting trace flags. ! 206: */ ! 207: ! 208: nobuffer = tTrace(argv, 'T', tvect, 100); ! 209: if (!nobuffer) ! 210: set_so_buf(); ! 211: sbufp = sbuf; ! 212: ! 213: /* ! 214: ** Get pathname of INGRES subtree from /etc/passwd file ! 215: ** entry for USERINGRES (presumably "ingres") and save it ! 216: ** in 'Pathname'. ! 217: ** ! 218: ** This algorithm suggested by Jim Popa. ! 219: */ ! 220: ! 221: # ifdef xV7_UNIX ! 222: Pathname = getenv("INGPATH"); ! 223: if (Pathname == NULL) ! 224: { ! 225: # endif xV7_UNIX ! 226: if ((iop = fopen("/etc/passwd", "r")) == NULL) ! 227: syserr("initucode: passwd"); ! 228: ! 229: do ! 230: { ! 231: if (fgets(buf, MAXLINE, iop) == NULL) ! 232: syserr("initucode: no INGRES"); ! 233: ! 234: /* decode passwd entry */ ! 235: i = 0; ! 236: for (p = buf; *p != '\n' && *p != '\0'; p++) ! 237: { ! 238: if (*p == ':') ! 239: { ! 240: *p = 0; ! 241: i++; ! 242: field[i] = p + 1; ! 243: } ! 244: } ! 245: *p = '\0'; ! 246: ! 247: /* check for enough fields for valid entry */ ! 248: if (i < 3) ! 249: syserr("initucode: passwd fmt %s", buf); ! 250: } while (!sequal(buf, USERINGRES)); ! 251: ! 252: /* we now have the INGRES passwd file entry in 'buf' */ ! 253: fclose(iop); ! 254: ! 255: /* copy pathname entry into 'Pathname' variable */ ! 256: Pathname = sbufp; ! 257: sbufp += smove(field[i - 1], sbufp) + 1; ! 258: # ifdef PATHEXT ! 259: sbufp += smove(PATHEXT, sbufp - 1); ! 260: # endif PATHEXT ! 261: # ifdef xV7_UNIX ! 262: } ! 263: # endif xV7_UNIX ! 264: ! 265: /* create the INGRES user id */ ! 266: Ing_uid = atoi(field[2]); ! 267: # ifdef xV6_UNIX ! 268: Ing_uid &= 0377; ! 269: # endif ! 270: # ifdef xB_UNIX ! 271: gid = atoi(field[3]); ! 272: Ing_uid = (Ing_uid & 0377) | ((gid & 0377) << 8); ! 273: # endif ! 274: ! 275: /* ! 276: ** Scan the argument vector. The following flags are pulled ! 277: ** out of the vector (and argc and argv are adjusted so it ! 278: ** looks like they never existed): ! 279: ** +w, -w -- (don't) wait for the database to be free. ! 280: ** -uxxx -- run as user xxx. If first character is a ! 281: ** colon, the format must be '-u:xx' where 'xx' is the ! 282: ** internal user code. ! 283: */ ! 284: ! 285: avp = argv; ! 286: fvi = 0; ! 287: pvi = 0; ! 288: waitflag = 0; ! 289: userflag = NULL; ! 290: usr_ovrd[0] = 0; ! 291: ! 292: for (i = argc; --i > 0; ) ! 293: { ! 294: p = *++avp; ! 295: if (p[0] == '+') ! 296: { ! 297: if (p[1] == 'w') ! 298: waitflag = 1; ! 299: else ! 300: goto boring; ! 301: } ! 302: else if (p[0] == '-') ! 303: { ! 304: switch (p[1]) ! 305: { ! 306: case 'w': ! 307: waitflag = -1; ! 308: break; ! 309: ! 310: case 'u': ! 311: if (p[2] == ':') ! 312: { ! 313: if (p[3] == 0 || p[4] == 0 || p[5] != 0) ! 314: { ! 315: printf("Bad flag %s\n", p); ! 316: exit(-1); ! 317: } ! 318: smove(&p[3], usr_ovrd); ! 319: } ! 320: else ! 321: userflag = &p[2]; ! 322: break; ! 323: ! 324: default: ! 325: /* not an interesting flag */ ! 326: boring: ! 327: if (fvi >= MAXFARGS) ! 328: { ! 329: printf("Too many flags\n"); ! 330: exit(-1); ! 331: } ! 332: Flagvect[fvi++] = p; ! 333: break; ! 334: } ! 335: } ! 336: else ! 337: { ! 338: /* not a flag: save in Parmvect */ ! 339: if (pvi >= MAXPARGS) ! 340: { ! 341: printf("Too many parmameters\n"); ! 342: exit(-1); ! 343: } ! 344: Parmvect[pvi++] = p; ! 345: } ! 346: } ! 347: ! 348: if (pvi <= 0 && dbflag) ! 349: { ! 350: return (4); /* no database name specified */ ! 351: } ! 352: ! 353: /* ! 354: ** Scan the "users" file. ! 355: */ ! 356: ! 357: if ((iop = fopen(ztack(Pathname, "/files/users"), "r")) == NULL) ! 358: syserr("initucode: open error"); ! 359: ! 360: /* get uid (out of loop) for test */ ! 361: # ifdef xV6_UNIX ! 362: actualuid = getuid() & 0377; ! 363: # endif ! 364: # ifndef xV6_UNIX ! 365: actualuid = getuid(); ! 366: # endif ! 367: ! 368: /* scan users file, one line at a time */ ! 369: rtval = 3; ! 370: while ((Usercode == NULL || userflag != NULL) && fgets(buf, MAXLINE, iop) != NULL) ! 371: { ! 372: ! 373: /* decode users file entry */ ! 374: i = 0; ! 375: field[0] = buf; ! 376: for (p = buf; *p != '\n' && *p != '\0'; p++) ! 377: { ! 378: if (*p == ':') ! 379: { ! 380: *p = 0; ! 381: i++; ! 382: field[i] = p + 1; ! 383: } ! 384: } ! 385: *p = '\0'; ! 386: ! 387: /* check for correct number of fields */ ! 388: if (i != UF_NFIELDS - 1) ! 389: syserr("initucode: users fmt %s", buf); ! 390: ! 391: /* ! 392: ** Check to see if this entry is the override user. ! 393: ** If so, save his user code in usr_ovrd. ! 394: */ ! 395: ! 396: if (userflag != NULL && sequal(userflag, field[UF_NAME])) ! 397: { ! 398: smove(field[UF_UCODE], usr_ovrd); ! 399: userflag = NULL; ! 400: } ! 401: ! 402: /* don't bother with this shit if not needed */ ! 403: if (Usercode != NULL) ! 404: continue; ! 405: ! 406: /* ! 407: ** Build the user id of this entry into 'uid' ! 408: ** and see if it is this user. ! 409: */ ! 410: ! 411: uid = atoi(field[UF_UID]); ! 412: ! 413: # ifdef xB_UNIX ! 414: gid = atoi(field[UF_GID]); ! 415: uid = (uid & 0377) | ((gid & 0377) << 8); ! 416: # endif ! 417: ! 418: # ifdef xV6_UNIX ! 419: if ((uid & 0377) != actualuid) ! 420: continue; ! 421: # endif ! 422: # ifndef xV6_UNIX ! 423: if (uid != actualuid) ! 424: continue; ! 425: # endif ! 426: ! 427: /* ! 428: ** We now have the real user entry. ! 429: ** Fetch the usercode, the status bits, and other ! 430: ** fields from the users file, and save them in ! 431: ** a safe place (sbuf). ! 432: */ ! 433: ! 434: Usercode = sbufp; ! 435: sbufp += smove(field[UF_UCODE], sbufp) + 1; ! 436: Status = oatoi(field[UF_STAT]); ! 437: if (paramlist != NULL) ! 438: { ! 439: for (i = 0; i < 4; i++) ! 440: { ! 441: paramlist[i] = sbufp; ! 442: sbufp += smove(field[UF_FLAGS + i], sbufp) + 1; ! 443: } ! 444: } ! 445: ! 446: /* validate access permission */ ! 447: rtval = 0; ! 448: if (!dbflag || (Status & U_SUPER) != 0) ! 449: continue; ! 450: p = field[UF_DBLIST]; ! 451: if (*p == 0) ! 452: continue; ! 453: ! 454: /* select permission/no-permission */ ! 455: npermit = 0; ! 456: if (*p == '-') ! 457: { ! 458: p++; ! 459: npermit++; ! 460: } ! 461: ! 462: /* scan for database listed */ ! 463: if (!npermit) ! 464: rtval = 2; ! 465: for (c = *p; c != 0; p = q + 1) ! 466: { ! 467: for (q = p; *q != ',' && *q != 0; q++) ! 468: continue; ! 469: c = *q; ! 470: *q = 0; ! 471: if (sequal(Parmvect[0], p)) ! 472: { ! 473: rtval = npermit ? 2 : 0; ! 474: break; ! 475: } ! 476: } ! 477: } ! 478: fclose(iop); ! 479: ! 480: if (rtval != 0) ! 481: return (rtval); ! 482: ! 483: /* ! 484: ** Check for existance of the database. This is done by ! 485: ** first building the pathname of the database into ! 486: ** 'Dbpath', and then reading the admin file (just ! 487: ** the adhdr part). ! 488: */ ! 489: ! 490: if (dbflag) ! 491: { ! 492: Dbpath = sbufp; ! 493: switch (i = initdbpath(Parmvect[0], Dbpath, TRUE)) ! 494: { ! 495: case 0: ! 496: rtval = 0; ! 497: break; ! 498: ! 499: case 1: ! 500: rtval = 5; ! 501: break; ! 502: ! 503: case 2: ! 504: rtval = 1; ! 505: break; ! 506: ! 507: case 3: ! 508: rtval = 6; ! 509: break; ! 510: ! 511: default: ! 512: syserr("initucode: initdbpath %d", i); ! 513: } ! 514: sbufp += length(Dbpath) + 1; ! 515: ! 516: if (rtval == 0 || rtval == 5) ! 517: { ! 518: i = open(ztack(Dbpath, "/admin"), 0); ! 519: if (i < 0) ! 520: rtval += 1; ! 521: else ! 522: { ! 523: /* open and check admin file */ ! 524: checkadmin(i); ! 525: close(i); ! 526: } ! 527: } ! 528: } ! 529: ! 530: /* ! 531: ** Check to see if the name on the -u flag is valid, and ! 532: ** that this user is allowed to use it. ! 533: */ ! 534: ! 535: if (userflag != NULL) ! 536: { ! 537: printf("Invalid user name %s\n", userflag); ! 538: exit(-1); ! 539: } ! 540: if (usr_ovrd[0] != '\0') ! 541: { ! 542: if ((Status & U_SUPER) == 0) ! 543: { ! 544: if (!dbflag || !bequal(Admin.adhdr.adowner, Usercode, 2)) ! 545: { ! 546: printf("You may not use the -u flag\n"); ! 547: exit(-1); ! 548: } ! 549: } ! 550: bmove(usr_ovrd, Usercode, 2); ! 551: } ! 552: ! 553: /* ! 554: ** Process the +-w flag. ! 555: ** First, determine the locking mode. If +w, always ! 556: ** wait; if -w, never wait; if unspecified, wait if in ! 557: ** background, but print error and exit if running ! 558: ** interactive. ! 559: */ ! 560: ! 561: if (waitflag > 0 || (waitflag == 0 && gtty(0, >tydummy) < 0)) ! 562: Wait_action = A_SLP; ! 563: else ! 564: Wait_action = A_RTN; ! 565: if (dbflag && waitmode >= 0) ! 566: db_lock(waitmode); ! 567: ! 568: /* ! 569: ** Return authorization value. ! 570: */ ! 571: ! 572: return (rtval); ! 573: } ! 574: /* ! 575: ** DB_LOCK -- lock database ! 576: ** ! 577: ** Locks the database. Everyone should do this before using any ! 578: ** database. ! 579: ** ! 580: ** Parameters: ! 581: ** database -- the pathname of the database. ! 582: ** mode -- M_EXCL -- get an exclusive lock. ! 583: ** M_SHARE -- get a shared lock. ! 584: ** ! 585: ** Returns: ! 586: ** none ! 587: ** ! 588: ** Side Effects: ! 589: ** Alockdes is opened. ! 590: */ ! 591: ! 592: struct lockreq Lock; /* the database lock structure */ ! 593: ! 594: db_lock(mode) ! 595: int mode; ! 596: { ! 597: if ((Admin.adhdr.adflags & A_DBCONCUR) == 0) ! 598: return; ! 599: if (Alockdes < 0) ! 600: Alockdes = start_up_lock_driver(); ! 601: if (setdbl(Wait_action, mode) < 0) ! 602: { ! 603: printf("Database temporarily unavailable\n"); ! 604: exit(1); ! 605: } ! 606: } ! 607: /* ! 608: ** INITDBPATH -- initialize the pathname of the database ! 609: ** ! 610: ** The pathname of a specified database is created. Indirection ! 611: ** via a file is supported, so that if the pathname is a file, ! 612: ** the first line of the file is read and used as the pathname ! 613: ** of the real database. ! 614: ** ! 615: ** Parameters: ! 616: ** database -- the name of the database. If NULL, ! 617: ** the pathname of datadir is returned. ! 618: ** dbbuf -- a buffer into which the pathname should ! 619: ** be dumped. ! 620: ** follow -- if set, follow the indirect chain of ! 621: ** database pathnames. ! 622: ** ! 623: ** Returns: ! 624: ** 0 -- database exists in datadir ! 625: ** 1 -- database exists, but I followed a pointer. ! 626: ** 2 -- database doesn't exist in datadir. ! 627: ** 3 -- databae doesn't exist, but I followed a pointer. ! 628: ** ! 629: ** Side Effects: ! 630: ** none. ! 631: */ ! 632: ! 633: initdbpath(database, dbpath, follow) ! 634: char *database; ! 635: char *dbpath; ! 636: int follow; ! 637: { ! 638: struct stat ibuf; ! 639: register char *d; ! 640: register FILE *f; ! 641: register int phase; ! 642: int retval; ! 643: int uid; ! 644: extern char *index(); ! 645: ! 646: d = dbpath; ! 647: ! 648: if (database == NULL) ! 649: { ! 650: # ifndef xDBPATH ! 651: concat(Pathname, "/data/base/", d); ! 652: # else ! 653: smove(xDBPATH, d); ! 654: # endif ! 655: return (0); ! 656: } ! 657: ! 658: /* get the basic pathname */ ! 659: concat(ztack(Pathname, "/datadir/"), database, d); ! 660: ! 661: /* ! 662: ** Iterate looking for database. ! 663: ** "Phase" is what we are trying: ! 664: ** -1 -- looking in datadir ! 665: ** 0 -- looking in data/base ! 666: ** 1 -- following indirect. ! 667: */ ! 668: ! 669: retval = 2; ! 670: for (phase = -1;;) ! 671: { ! 672: /* find out what sort of filesystem node this is */ ! 673: if (stat(d, &ibuf) < 0) ! 674: { ! 675: if (phase < 0) ! 676: { ! 677: # ifdef xDBPATH ! 678: concat(xDBPATH, database, d); ! 679: # else ! 680: concat(ztack(Pathname, "/data/base/"), database, d); ! 681: # endif ! 682: phase = 0; ! 683: continue; ! 684: } ! 685: else ! 686: return (retval); ! 687: } ! 688: ! 689: /* set up the lock structure for future use */ ! 690: bmove(&ibuf, Lock.dbnode, 4); ! 691: ! 692: retval -= 2; ! 693: if ((ibuf.st_mode & S_IFMT) == S_IFDIR) ! 694: return (retval); ! 695: ! 696: /* if second time through, the database must be a directory */ ! 697: if (phase > 0) ! 698: syserr("initdbpath: not direc"); ! 699: ! 700: /* if we shouldn't follow the chain, say it exists */ ! 701: if (!follow) ! 702: return (3); ! 703: ! 704: /* it's a file -- see if we can use it */ ! 705: uid = ibuf.st_uid; ! 706: # ifdef xB_UNIX ! 707: uid = (uid & 0377) | ((ibuf.st_gid & 0377) << 8); ! 708: # endif ! 709: # ifdef xV6_UNIX ! 710: uid &= 0377; ! 711: # endif ! 712: if (uid != Ing_uid || (ibuf.st_mode & 0777) != 0600) ! 713: return (3); ! 714: ! 715: f = fopen(d, "r"); ! 716: if (f == NULL) ! 717: syserr("initdbpath: fopen"); ! 718: ! 719: /* read the pathname of the database */ ! 720: if (fgets(d, MAXLINE, f) == NULL || d[0] != '/') ! 721: syserr("initdbpath: bad indirect"); ! 722: *index(d, '\n') = '\0'; ! 723: fclose(f); ! 724: ! 725: /* prepare for next iteration */ ! 726: retval = 3; ! 727: phase = 1; ! 728: } ! 729: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.