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: }