|
|
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.2 (Berkeley) 1/12/88"; ! 9: #endif not lint ! 10: ! 11: static char rcsid[] = "$Header: library.c,v 1.2 87/03/25 20:50:14 donn 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: IntFunc *onsyserr(); ! 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 1000 /* 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: * Initialize error information, setting defaults for handling errors. ! 355: */ ! 356: ! 357: private ErrInfo *errinfo; ! 358: ! 359: private initErrInfo () ! 360: { ! 361: integer i; ! 362: ! 363: errinfo = alloc(sys_nerr, ErrInfo); ! 364: for (i = 0; i < sys_nerr; i++) { ! 365: errinfo[i].func = ERR_CATCH; ! 366: } ! 367: errinfo[0].func = ERR_IGNORE; ! 368: errinfo[EPERM].func = ERR_IGNORE; ! 369: errinfo[ENOENT].func = ERR_IGNORE; ! 370: errinfo[ESRCH].func = ERR_IGNORE; ! 371: errinfo[EBADF].func = ERR_IGNORE; ! 372: errinfo[ENOTTY].func = ERR_IGNORE; ! 373: errinfo[EOPNOTSUPP].func = ERR_IGNORE; ! 374: } ! 375: ! 376: public syserr() ! 377: { ! 378: register ErrInfo *e; ! 379: ! 380: if (errno < 0 or errno > sys_nerr) { ! 381: fatal("errno %d", errno); ! 382: } else { ! 383: if (errinfo == nil(ErrInfo *)) { ! 384: initErrInfo(); ! 385: } ! 386: e = &(errinfo[errno]); ! 387: if (e->func == ERR_CATCH) { ! 388: fatal(sys_errlist[errno]); ! 389: } else if (e->func != ERR_IGNORE) { ! 390: (*e->func)(); ! 391: } ! 392: } ! 393: } ! 394: ! 395: /* ! 396: * Catcherrs' purpose is to initialize the errinfo table, get this module ! 397: * loaded, and make sure my cerror is loaded (only applicable when this is ! 398: * in a library). ! 399: */ ! 400: ! 401: public catcherrs() ! 402: { ! 403: _mycerror(); ! 404: initErrInfo(); ! 405: } ! 406: ! 407: /* ! 408: * Turn off the error catching mechanism completely by having all errors ! 409: * ignored. This is most useful between a fork and an exec. ! 410: */ ! 411: ! 412: public nocatcherrs() ! 413: { ! 414: integer i; ! 415: ! 416: for (i = 0; i < sys_nerr; i++) { ! 417: errinfo[i].func = ERR_IGNORE; ! 418: } ! 419: } ! 420: ! 421: /* ! 422: * Change the action on receipt of an error, returning the previous action. ! 423: */ ! 424: ! 425: public IntFunc *onsyserr(n, f) ! 426: int n; ! 427: IntFunc *f; ! 428: { ! 429: IntFunc *oldf; ! 430: ! 431: if (errinfo == nil(ErrInfo *)) { ! 432: initErrInfo(); ! 433: } ! 434: oldf = errinfo[n].func; ! 435: errinfo[n].func = f; ! 436: return oldf; ! 437: } ! 438: ! 439: /* ! 440: * Print the message associated with the given signal. ! 441: * Like a "perror" for signals. ! 442: */ ! 443: ! 444: #ifdef SIGWINCH ! 445: public int sys_nsig = NSIG; ! 446: #else not 4.3 BSD ! 447: /* ! 448: * This table is correct for 4.2-like systems but will ! 449: * be inadequate for System V (which is the sort of ! 450: * Unix that needs it!). ! 451: */ ! 452: public String sys_siglist[] = { ! 453: "no signal", ! 454: "hangup", ! 455: "interrupt", ! 456: "quit", ! 457: "illegal instruction", ! 458: "trace trap", ! 459: "IOT instruction", ! 460: "EMT instruction", ! 461: "floating point exception", ! 462: "kill", ! 463: "bus error", ! 464: "segmentation violation", ! 465: "bad argument to system call", ! 466: "broken pipe", ! 467: "alarm clock", ! 468: "soft kill", ! 469: "urgent I/O condition", ! 470: "stop signal not from tty", ! 471: "stop signal from tty", ! 472: "continue", ! 473: "child termination", ! 474: "stop (tty input)", ! 475: "stop (tty output)", ! 476: "possible input/output", ! 477: "exceeded CPU time limit", ! 478: "exceeded file size limit" ! 479: }; ! 480: public int sys_nsig = sizeof sys_siglist / sizeof sys_siglist[0]; ! 481: #endif ! 482: ! 483: public psignal(s, n) ! 484: String s; ! 485: integer n; ! 486: { ! 487: String msg; ! 488: integer len; ! 489: extern String sys_siglist[]; ! 490: ! 491: if (n >= 0 and n < sys_nsig) { ! 492: msg = sys_siglist[n]; ! 493: } else { ! 494: msg = "Unknown signal"; ! 495: } ! 496: len = strlen(s); ! 497: if (len > 0) { ! 498: write(2, s, len); ! 499: write(2, ": ", 2); ! 500: } ! 501: write(2, msg, strlen(msg)); ! 502: write(2, "\n", 1); ! 503: } ! 504: ! 505: /* ! 506: * Standard error handling routines. ! 507: */ ! 508: ! 509: private short nerrs; ! 510: private short nwarnings; ! 511: ! 512: /* ! 513: * Main driver of error message reporting. ! 514: */ ! 515: ! 516: /* VARARGS2 */ ! 517: private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 518: String errname; ! 519: boolean shouldquit; ! 520: String s; ! 521: { ! 522: fflush(stdout); ! 523: if (shouldquit and cmdname != nil(String)) { ! 524: fprintf(stderr, "%s: ", cmdname); ! 525: } ! 526: if (errfilename != nil(Filename)) { ! 527: fprintf(stderr, "%s: ", errfilename); ! 528: } ! 529: if (errlineno > 0) { ! 530: fprintf(stderr, "%d: ", errlineno); ! 531: } ! 532: if (errname != nil(String)) { ! 533: fprintf(stderr, "%s: ", errname); ! 534: } ! 535: fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 536: putc('\n', stderr); ! 537: fflush(stderr); ! 538: if (shouldquit) { ! 539: quit(1); ! 540: } ! 541: } ! 542: ! 543: /* ! 544: * For when printf isn't sufficient for printing the error message ... ! 545: */ ! 546: ! 547: public beginerrmsg() ! 548: { ! 549: fflush(stdout); ! 550: if (errfilename != nil(String)) { ! 551: fprintf(stderr, "%s: ", errfilename); ! 552: } ! 553: if (errlineno > 0) { ! 554: fprintf(stderr, "%d: ", errlineno); ! 555: } ! 556: } ! 557: ! 558: public enderrmsg() ! 559: { ! 560: putc('\n', stderr); ! 561: fflush(stderr); ! 562: erecover(); ! 563: } ! 564: ! 565: /* ! 566: * The messages are listed in increasing order of seriousness. ! 567: * ! 568: * First are warnings. ! 569: */ ! 570: ! 571: /* VARARGS1 */ ! 572: public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 573: String s; ! 574: { ! 575: nwarnings++; ! 576: errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 577: } ! 578: ! 579: /* ! 580: * Errors are a little worse, they mean something is wrong, ! 581: * but not so bad that processing can't continue. ! 582: * ! 583: * The routine "erecover" is called to recover from the error, ! 584: * a default routine is provided that does nothing. ! 585: */ ! 586: ! 587: /* VARARGS1 */ ! 588: public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 589: String s; ! 590: { ! 591: extern erecover(); ! 592: ! 593: nerrs++; ! 594: errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 595: erecover(); ! 596: } ! 597: ! 598: /* ! 599: * Non-recoverable user error. ! 600: */ ! 601: ! 602: /* VARARGS1 */ ! 603: public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 604: String s; ! 605: { ! 606: errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 607: } ! 608: ! 609: /* ! 610: * Panics indicate an internal program error. ! 611: */ ! 612: ! 613: /* VARARGS1 */ ! 614: public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) ! 615: String s; ! 616: { ! 617: errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); ! 618: } ! 619: ! 620: short numerrors() ! 621: { ! 622: short r; ! 623: ! 624: r = nerrs; ! 625: nerrs = 0; ! 626: return r; ! 627: } ! 628: ! 629: short numwarnings() ! 630: { ! 631: short r; ! 632: ! 633: r = nwarnings; ! 634: nwarnings = 0; ! 635: return r; ! 636: } ! 637: ! 638: /* ! 639: * Recover from an error. ! 640: * ! 641: * This is the default routine which we aren't using since we have our own. ! 642: * ! 643: public erecover() ! 644: { ! 645: } ! 646: * ! 647: */ ! 648: ! 649: /* ! 650: * Default way to quit from a program is just to exit. ! 651: * ! 652: public quit(r) ! 653: int r; ! 654: { ! 655: exit(r); ! 656: } ! 657: * ! 658: */ ! 659: ! 660: /* ! 661: * Compare n-byte areas pointed to by s1 and s2 ! 662: * if n is 0 then compare up until one has a null byte. ! 663: */ ! 664: ! 665: public int cmp(s1, s2, n) ! 666: register char *s1, *s2; ! 667: register unsigned int n; ! 668: { ! 669: if (s1 == nil(char *) || s2 == nil(char *)) { ! 670: panic("cmp: nil pointer"); ! 671: } ! 672: if (n == 0) { ! 673: while (*s1 == *s2++) { ! 674: if (*s1++ == '\0') { ! 675: return(0); ! 676: } ! 677: } ! 678: return(*s1 - *(s2-1)); ! 679: } else { ! 680: for (; n != 0; n--) { ! 681: if (*s1++ != *s2++) { ! 682: return(*(s1-1) - *(s2-1)); ! 683: } ! 684: } ! 685: return(0); ! 686: } ! 687: } ! 688: ! 689: /* ! 690: * Move n bytes from src to dest. ! 691: * If n is 0 move until a null is found. ! 692: */ ! 693: ! 694: public mov(src, dest, n) ! 695: register char *src, *dest; ! 696: register unsigned int n; ! 697: { ! 698: if (src == nil(char *)) ! 699: panic("mov: nil source"); ! 700: if (dest == nil(char *)) ! 701: panic("mov: nil destination"); ! 702: if (n != 0) { ! 703: for (; n != 0; n--) { ! 704: *dest++ = *src++; ! 705: } ! 706: } else { ! 707: while ((*dest++ = *src++) != '\0'); ! 708: } ! 709: } ! 710: ! 711: #ifdef IRIS /* or in general for 4.2 - System V C library interface */ ! 712: ! 713: public bcopy (fromaddr, toaddr, n) ! 714: char *fromaddr, *toaddr; ! 715: int n; ! 716: { ! 717: blt(toaddr, fromaddr, n); ! 718: } ! 719: ! 720: public bzero (addr, n) ! 721: char *addr; ! 722: int n; ! 723: { ! 724: register char *p, *q; ! 725: ! 726: p = addr; ! 727: q = p + n; ! 728: while (p < q) { ! 729: *p++ = '\0'; ! 730: } ! 731: } ! 732: ! 733: #include <string.h> ! 734: ! 735: public char *index (s, c) ! 736: char *s, c; ! 737: { ! 738: return strchr(s, c); ! 739: } ! 740: ! 741: public char *rindex (s, c) ! 742: char *s, c; ! 743: { ! 744: return strrchr(s, c); ! 745: } ! 746: ! 747: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.