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