Annotation of 43BSD/ucb/dbx/library.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.