|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: static char sccsid[] = "@(#)library.c 5.1 (Berkeley) 5/31/85"; ! 9: #endif not lint ! 10: ! 11: static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $"; ! 12: ! 13: /* ! 14: * General purpose routines. ! 15: */ ! 16: ! 17: #include <stdio.h> ! 18: #include <errno.h> ! 19: #include <signal.h> ! 20: ! 21: #define public ! 22: #define private static ! 23: #define and && ! 24: #define or || ! 25: #define not ! ! 26: #define ord(enumcon) ((int) enumcon) ! 27: #define nil(type) ((type) 0) ! 28: ! 29: typedef int integer; ! 30: typedef enum { FALSE, TRUE } boolean; ! 31: typedef char *String; ! 32: typedef FILE *File; ! 33: typedef String Filename; ! 34: ! 35: #undef FILE ! 36: ! 37: String cmdname; /* name of command for error messages */ ! 38: Filename errfilename; /* current file associated with error */ ! 39: short errlineno; /* line number associated with error */ ! 40: ! 41: /* ! 42: * Definitions for doing memory allocation. ! 43: */ ! 44: ! 45: extern char *malloc(); ! 46: ! 47: #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type))) ! 48: #define dispose(p) { free((char *) p); p = 0; } ! 49: ! 50: /* ! 51: * Macros for doing freads + fwrites. ! 52: */ ! 53: ! 54: #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp) ! 55: #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp) ! 56: ! 57: /* ! 58: * String definitions. ! 59: */ ! 60: ! 61: extern String strcpy(), index(), rindex(); ! 62: extern int strlen(); ! 63: ! 64: #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s) ! 65: #define streq(s1, s2) (strcmp(s1, s2) == 0) ! 66: ! 67: typedef int INTFUNC(); ! 68: ! 69: typedef struct { ! 70: INTFUNC *func; ! 71: } ERRINFO; ! 72: ! 73: #define ERR_IGNORE ((INTFUNC *) 0) ! 74: #define ERR_CATCH ((INTFUNC *) 1) ! 75: ! 76: /* ! 77: * Call a program. ! 78: * ! 79: * Four entries: ! 80: * ! 81: * call, callv - call a program and wait for it, returning status ! 82: * back, backv - call a program and don't wait, returning process id ! 83: * ! 84: * The command's standard input and output are passed as FILE's. ! 85: */ ! 86: ! 87: ! 88: #define MAXNARGS 1000 /* unchecked upper limit on max num of arguments */ ! 89: #define BADEXEC 127 /* exec fails */ ! 90: ! 91: #define ischild(pid) ((pid) == 0) ! 92: ! 93: /* VARARGS3 */ ! 94: public int call(name, in, out, args) ! 95: String name; ! 96: File in; ! 97: File out; ! 98: String args; ! 99: { ! 100: String *ap, *argp; ! 101: String argv[MAXNARGS]; ! 102: ! 103: argp = &argv[0]; ! 104: *argp++ = name; ! 105: ap = &args; ! 106: while (*ap != nil(String)) { ! 107: *argp++ = *ap++; ! 108: } ! 109: *argp = nil(String); ! 110: return callv(name, in, out, argv); ! 111: } ! 112: ! 113: /* VARARGS3 */ ! 114: public int back(name, in, out, args) ! 115: String name; ! 116: File in; ! 117: File out; ! 118: String args; ! 119: { ! 120: String *ap, *argp; ! 121: String argv[MAXNARGS]; ! 122: ! 123: argp = &argv[0]; ! 124: *argp++ = name; ! 125: ap = &args; ! 126: while (*ap != nil(String)) { ! 127: *argp++ = *ap++; ! 128: } ! 129: *argp = nil(String); ! 130: return backv(name, in, out, argv); ! 131: } ! 132: ! 133: public int callv(name, in, out, argv) ! 134: String name; ! 135: File in; ! 136: File out; ! 137: String *argv; ! 138: { ! 139: int pid, status; ! 140: ! 141: pid = backv(name, in, out, argv); ! 142: pwait(pid, &status); ! 143: return status; ! 144: } ! 145: ! 146: public int backv(name, in, out, argv) ! 147: String name; ! 148: File in; ! 149: File out; ! 150: String *argv; ! 151: { ! 152: int pid; ! 153: ! 154: fflush(stdout); ! 155: if (ischild(pid = fork())) { ! 156: fswap(0, fileno(in)); ! 157: fswap(1, fileno(out)); ! 158: onsyserr(EACCES, ERR_IGNORE); ! 159: execvp(name, argv); ! 160: _exit(BADEXEC); ! 161: } ! 162: return pid; ! 163: } ! 164: ! 165: /* ! 166: * Swap file numbers so as to redirect standard input and output. ! 167: */ ! 168: ! 169: private fswap(oldfd, newfd) ! 170: int oldfd; ! 171: int newfd; ! 172: { ! 173: if (oldfd != newfd) { ! 174: close(oldfd); ! 175: dup(newfd); ! 176: close(newfd); ! 177: } ! 178: } ! 179: ! 180: /* ! 181: * Invoke a shell on a command line. ! 182: */ ! 183: ! 184: #define DEF_SHELL "csh" ! 185: ! 186: public shell(s) ! 187: String s; ! 188: { ! 189: extern String getenv(); ! 190: String sh; ! 191: ! 192: if ((sh = getenv("SHELL")) == nil(String)) { ! 193: sh = DEF_SHELL; ! 194: } ! 195: if (s != nil(String) and *s != '\0') { ! 196: call(sh, stdin, stdout, "-c", s, 0); ! 197: } else { ! 198: call(sh, stdin, stdout, 0); ! 199: } ! 200: } ! 201: ! 202: /* ! 203: * Wait for a process the right way. We wait for a particular ! 204: * process and if any others come along in between, we remember them ! 205: * in case they are eventually waited for. ! 206: * ! 207: * This routine is not very efficient when the number of processes ! 208: * to be remembered is large. ! 209: * ! 210: * To deal with a kernel idiosyncrasy, we keep a list on the side ! 211: * of "traced" processes, and do not notice them when waiting for ! 212: * another process. ! 213: */ ! 214: ! 215: typedef struct pidlist { ! 216: int pid; ! 217: int status; ! 218: struct pidlist *next; ! 219: } Pidlist; ! 220: ! 221: private Pidlist *pidlist, *ptrclist, *pfind(); ! 222: ! 223: public ptraced(pid) ! 224: int pid; ! 225: { ! 226: Pidlist *p; ! 227: ! 228: p = alloc(1, Pidlist); ! 229: p->pid = pid; ! 230: p->next = ptrclist; ! 231: ptrclist = p; ! 232: } ! 233: ! 234: public unptraced(pid) ! 235: int pid; ! 236: { ! 237: register Pidlist *p, *prev; ! 238: ! 239: prev = nil(Pidlist *); ! 240: p = ptrclist; ! 241: while (p != nil(Pidlist *) and p->pid != pid) { ! 242: prev = p; ! 243: p = p->next; ! 244: } ! 245: if (p != nil(Pidlist *)) { ! 246: if (prev == nil(Pidlist *)) { ! 247: ptrclist = p->next; ! 248: } else { ! 249: prev->next = p->next; ! 250: } ! 251: dispose(p); ! 252: } ! 253: } ! 254: ! 255: private boolean isptraced(pid) ! 256: int pid; ! 257: { ! 258: register Pidlist *p; ! 259: ! 260: p = ptrclist; ! 261: while (p != nil(Pidlist *) and p->pid != pid) { ! 262: p = p->next; ! 263: } ! 264: return (boolean) (p != nil(Pidlist *)); ! 265: } ! 266: ! 267: public pwait(pid, statusp) ! 268: int pid, *statusp; ! 269: { ! 270: Pidlist *p; ! 271: int pnum, status; ! 272: ! 273: p = pfind(pid); ! 274: if (p != nil(Pidlist *)) { ! 275: *statusp = p->status; ! 276: dispose(p); ! 277: } else { ! 278: pnum = wait(&status); ! 279: while (pnum != pid and pnum >= 0) { ! 280: if (not isptraced(pnum)) { ! 281: p = alloc(1, Pidlist); ! 282: p->pid = pnum; ! 283: p->status = status; ! 284: p->next = pidlist; ! 285: pidlist = p; ! 286: } ! 287: pnum = wait(&status); ! 288: } ! 289: if (pnum < 0) { ! 290: p = pfind(pid); ! 291: if (p == nil(Pidlist *)) { ! 292: panic("pwait: pid %d not found", pid); ! 293: } ! 294: *statusp = p->status; ! 295: dispose(p); ! 296: } else { ! 297: *statusp = status; ! 298: } ! 299: } ! 300: } ! 301: ! 302: /* ! 303: * Look for the given process id on the pidlist. ! 304: * ! 305: * Unlink it from list if found. ! 306: */ ! 307: ! 308: private Pidlist *pfind(pid) ! 309: int pid; ! 310: { ! 311: register Pidlist *p, *prev; ! 312: ! 313: prev = nil(Pidlist *); ! 314: for (p = pidlist; p != nil(Pidlist *); p = p->next) { ! 315: if (p->pid == pid) { ! 316: break; ! 317: } ! 318: prev = p; ! 319: } ! 320: if (p != nil(Pidlist *)) { ! 321: if (prev == nil(Pidlist *)) { ! 322: pidlist = p->next; ! 323: } else { ! 324: prev->next = p->next; ! 325: } ! 326: } ! 327: return p; ! 328: } ! 329: ! 330: /* ! 331: * System call error handler. ! 332: * ! 333: * The syserr routine is called when a system call is about to ! 334: * set the c-bit to report an error. Certain errors are caught ! 335: * and cause the process to print a message and immediately exit. ! 336: */ ! 337: ! 338: extern int sys_nerr; ! 339: extern char *sys_errlist[]; ! 340: ! 341: /* ! 342: * Before calling syserr, the integer errno is set to contain the ! 343: * number of the error. The routine "_mycerror" is a dummy which ! 344: * is used to force the loader to get my version of cerror rather ! 345: * than the usual one. ! 346: */ ! 347: ! 348: extern int errno; ! 349: extern _mycerror(); ! 350: ! 351: /* ! 352: * Initialize error information, setting defaults for handling errors. ! 353: */ ! 354: ! 355: private ERRINFO *errinfo; ! 356: ! 357: private initErrInfo () ! 358: { ! 359: integer i; ! 360: ! 361: errinfo = alloc(sys_nerr, ERRINFO); ! 362: for (i = 0; i < sys_nerr; i++) { ! 363: errinfo[i].func = ERR_CATCH; ! 364: } ! 365: errinfo[0].func = ERR_IGNORE; ! 366: errinfo[EPERM].func = ERR_IGNORE; ! 367: errinfo[ENOENT].func = ERR_IGNORE; ! 368: errinfo[ESRCH].func = ERR_IGNORE; ! 369: errinfo[EBADF].func = ERR_IGNORE; ! 370: errinfo[ENOTTY].func = ERR_IGNORE; ! 371: errinfo[EOPNOTSUPP].func = ERR_IGNORE; ! 372: } ! 373: ! 374: public syserr() ! 375: { ! 376: ERRINFO *e; ! 377: ! 378: if (errno < 0 or errno > sys_nerr) { ! 379: fatal("errno %d", errno); ! 380: } else { ! 381: if (errinfo == nil(ERRINFO *)) { ! 382: initErrInfo(); ! 383: } ! 384: e = &(errinfo[errno]); ! 385: if (e->func == ERR_CATCH) { ! 386: fatal(sys_errlist[errno]); ! 387: } else if (e->func != ERR_IGNORE) { ! 388: (*e->func)(); ! 389: } ! 390: } ! 391: } ! 392: ! 393: /* ! 394: * Catcherrs' purpose is to initialize the errinfo table, get this module ! 395: * loaded, and make sure my cerror is loaded (only applicable when this is ! 396: * in a library). ! 397: */ ! 398: ! 399: public catcherrs() ! 400: { ! 401: _mycerror(); ! 402: initErrInfo(); ! 403: } ! 404: ! 405: /* ! 406: * Turn off the error catching mechanism completely by having all errors ! 407: * ignored. This is most useful between a fork and an exec. ! 408: */ ! 409: ! 410: public nocatcherrs() ! 411: { ! 412: integer i; ! 413: ! 414: for (i = 0; i < sys_nerr; i++) { ! 415: errinfo[i].func = ERR_IGNORE; ! 416: } ! 417: } ! 418: ! 419: /* ! 420: * Change the action on receipt of an error. ! 421: */ ! 422: ! 423: public onsyserr(n, f) ! 424: int n; ! 425: INTFUNC *f; ! 426: { ! 427: if (errinfo == nil(ERRINFO *)) { ! 428: initErrInfo(); ! 429: } ! 430: errinfo[n].func = f; ! 431: } ! 432: ! 433: /* ! 434: * Print the message associated with the given signal. ! 435: * Like a "perror" for signals. ! 436: */ ! 437: ! 438: public int sys_nsig = NSIG; ! 439: ! 440: public psignal(s, n) ! 441: String s; ! 442: integer n; ! 443: { ! 444: String msg; ! 445: integer len; ! 446: extern String sys_siglist[]; ! 447: ! 448: if (n >= 0 and n < sys_nsig) { ! 449: msg = sys_siglist[n]; ! 450: } else { ! 451: msg = "Unknown signal"; ! 452: } ! 453: len = strlen(s); ! 454: if (len > 0) { ! 455: write(2, s, len); ! 456: write(2, ": ", 2); ! 457: } ! 458: write(2, msg, strlen(msg)); ! 459: write(2, "\n", 1); ! 460: } ! 461: ! 462: /* ! 463: * Standard error handling routines. ! 464: */ ! 465: ! 466: private short nerrs; ! 467: private short nwarnings; ! 468: ! 469: /* ! 470: * Main driver of error message reporting. ! 471: */ ! 472: ! 473: /* VARARGS2 */ ! 474: private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 475: String errname; ! 476: boolean shouldquit; ! 477: String s; ! 478: { ! 479: fflush(stdout); ! 480: if (shouldquit and cmdname != nil(String)) { ! 481: fprintf(stderr, "%s: ", cmdname); ! 482: } ! 483: if (errfilename != nil(Filename)) { ! 484: fprintf(stderr, "%s: ", errfilename); ! 485: } ! 486: if (errlineno > 0) { ! 487: fprintf(stderr, "%d: ", errlineno); ! 488: } ! 489: if (errname != nil(String)) { ! 490: fprintf(stderr, "%s: ", errname); ! 491: } ! 492: fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 493: putc('\n', stderr); ! 494: if (shouldquit) { ! 495: quit(1); ! 496: } ! 497: } ! 498: ! 499: /* ! 500: * For when printf isn't sufficient for printing the error message ... ! 501: */ ! 502: ! 503: public beginerrmsg() ! 504: { ! 505: fflush(stdout); ! 506: if (errfilename != nil(String)) { ! 507: fprintf(stderr, "%s: ", errfilename); ! 508: } ! 509: if (errlineno > 0) { ! 510: fprintf(stderr, "%d: ", errlineno); ! 511: } ! 512: } ! 513: ! 514: public enderrmsg() ! 515: { ! 516: putc('\n', stderr); ! 517: erecover(); ! 518: } ! 519: ! 520: /* ! 521: * The messages are listed in increasing order of seriousness. ! 522: * ! 523: * First are warnings. ! 524: */ ! 525: ! 526: /* VARARGS1 */ ! 527: public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 528: String s; ! 529: { ! 530: nwarnings++; ! 531: errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 532: } ! 533: ! 534: /* ! 535: * Errors are a little worse, they mean something is wrong, ! 536: * but not so bad that processing can't continue. ! 537: * ! 538: * The routine "erecover" is called to recover from the error, ! 539: * a default routine is provided that does nothing. ! 540: */ ! 541: ! 542: /* VARARGS1 */ ! 543: public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 544: String s; ! 545: { ! 546: extern erecover(); ! 547: ! 548: nerrs++; ! 549: errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 550: erecover(); ! 551: } ! 552: ! 553: /* ! 554: * Non-recoverable user error. ! 555: */ ! 556: ! 557: /* VARARGS1 */ ! 558: public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 559: String s; ! 560: { ! 561: errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 562: } ! 563: ! 564: /* ! 565: * Panics indicate an internal program error. ! 566: */ ! 567: ! 568: /* VARARGS1 */ ! 569: public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 570: String s; ! 571: { ! 572: errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 573: } ! 574: ! 575: short numerrors() ! 576: { ! 577: short r; ! 578: ! 579: r = nerrs; ! 580: nerrs = 0; ! 581: return r; ! 582: } ! 583: ! 584: short numwarnings() ! 585: { ! 586: short r; ! 587: ! 588: r = nwarnings; ! 589: nwarnings = 0; ! 590: return r; ! 591: } ! 592: ! 593: /* ! 594: * Recover from an error. ! 595: * ! 596: * This is the default routine which we aren't using since we have our own. ! 597: * ! 598: public erecover() ! 599: { ! 600: } ! 601: * ! 602: */ ! 603: ! 604: /* ! 605: * Default way to quit from a program is just to exit. ! 606: * ! 607: public quit(r) ! 608: int r; ! 609: { ! 610: exit(r); ! 611: } ! 612: * ! 613: */ ! 614: ! 615: /* ! 616: * Compare n-byte areas pointed to by s1 and s2 ! 617: * if n is 0 then compare up until one has a null byte. ! 618: */ ! 619: ! 620: public int cmp(s1, s2, n) ! 621: register char *s1, *s2; ! 622: register unsigned int n; ! 623: { ! 624: if (s1 == nil(char *) || s2 == nil(char *)) { ! 625: panic("cmp: nil pointer"); ! 626: } ! 627: if (n == 0) { ! 628: while (*s1 == *s2++) { ! 629: if (*s1++ == '\0') { ! 630: return(0); ! 631: } ! 632: } ! 633: return(*s1 - *(s2-1)); ! 634: } else { ! 635: for (; n != 0; n--) { ! 636: if (*s1++ != *s2++) { ! 637: return(*(s1-1) - *(s2-1)); ! 638: } ! 639: } ! 640: return(0); ! 641: } ! 642: } ! 643: ! 644: /* ! 645: * Move n bytes from src to dest. ! 646: * If n is 0 move until a null is found. ! 647: */ ! 648: ! 649: public mov(src, dest, n) ! 650: register char *src, *dest; ! 651: register unsigned int n; ! 652: { ! 653: if (src == nil(char *)) ! 654: panic("mov: nil source"); ! 655: if (dest == nil(char *)) ! 656: panic("mov: nil destination"); ! 657: if (n != 0) { ! 658: for (; n != 0; n--) { ! 659: *dest++ = *src++; ! 660: } ! 661: } else { ! 662: while ((*dest++ = *src++) != '\0'); ! 663: } ! 664: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.