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