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

Defined functions

back defined in line 114; used 1 times
backv defined in line 146; used 2 times
call defined in line 94; used 6 times
callv defined in line 133; used 1 times
catcherrs defined in line 399; used 1 times
cmp defined in line 620; used 2 times
errmsg defined in line 474; used 4 times
fatal defined in line 558; used 15 times
fswap defined in line 169; used 2 times
initErrInfo defined in line 357; used 3 times
isptraced defined in line 255; used 1 times
mov defined in line 649; used 9 times
nocatcherrs defined in line 410; used 1 times
numerrors defined in line 575; never used
numwarnings defined in line 584; never used
onsyserr defined in line 423; used 13 times
pfind defined in line 308; used 3 times
psignal defined in line 440; never used
ptraced defined in line 223; used 1 times
pwait defined in line 267; used 6 times
shell defined in line 186; used 1 times
syserr defined in line 374; used 1 times
unptraced defined in line 234; used 1 times
warning defined in line 527; used 2 times

Defined variables

cmdname defined in line 37; used 4 times
errfilename defined in line 38; used 8 times
errlineno defined in line 39; used 11 times
nerrs defined in line 466; used 3 times
nwarnings defined in line 467; used 3 times
pidlist defined in line 221; used 4 times
ptrclist defined in line 221; used 5 times
public defined in line 620; never used
rcsid defined in line 11; never used
sccsid defined in line 8; never used
sys_nsig defined in line 438; used 1 times

Defined struct's

pidlist defined in line 215; used 2 times
  • in line 218(2)

Defined typedef's

Filename defined in line 33; used 2 times
Pidlist defined in line 219; used 21 times
String defined in line 31; used 37 times
integer defined in line 29; used 4 times

Defined macros

BADEXEC defined in line 89; used 1 times
DEF_SHELL defined in line 184; used 1 times
ERR_CATCH defined in line 74; used 2 times
ERR_IGNORE defined in line 73; used 10 times
MAXNARGS defined in line 88; used 2 times
alloc defined in line 47; used 3 times
and defined in line 23; used 6 times
dispose defined in line 48; used 3 times
get defined in line 54; never used
ischild defined in line 91; used 1 times
nil defined in line 27; used 29 times
not defined in line 25; used 1 times
or defined in line 24; used 1 times
ord defined in line 26; never used
private defined in line 22; used 9 times
public defined in line 21; used 21 times
put defined in line 55; never used
strdup defined in line 64; never used
streq defined in line 65; never used
Last modified: 1985-05-31
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2516
Valid CSS Valid XHTML 1.0 Strict