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

1.1       root        1: #ifndef lint
                      2: static char sccsid[] = "@(#)library.c  1.4 (Berkeley) 8/13/83";
                      3: #endif
                      4: 
                      5: /* Copyright (c) 1982 Regents of the University of California */
                      6: 
                      7: /*
                      8:  * General purpose routines.
                      9:  */
                     10: 
                     11: #include <stdio.h>
                     12: #include <errno.h>
                     13: #include <signal.h>
                     14: 
                     15: #define public
                     16: #define private static
                     17: #define and &&
                     18: #define or ||
                     19: #define not !
                     20: #define ord(enumcon)   ((int) enumcon)
                     21: #define nil(type)      ((type) 0)
                     22: 
                     23: typedef enum { FALSE, TRUE } Boolean;
                     24: typedef char *String;
                     25: typedef FILE *File;
                     26: typedef String Filename;
                     27: 
                     28: #undef FILE
                     29: 
                     30: /*
                     31:  * Definitions of standard C library routines that aren't in the
                     32:  * standard I/O library, but which are generally useful.
                     33:  */
                     34: 
                     35: extern long atol();            /* ascii to long */
                     36: extern double atof();          /* ascii to floating point */
                     37: extern char *mktemp();         /* make a temporary file name */
                     38: 
                     39: String cmdname;                        /* name of command for error messages */
                     40: Filename errfilename;          /* current file associated with error */
                     41: short errlineno;               /* line number associated with error */
                     42: 
                     43: /*
                     44:  * Definitions for doing memory allocation.
                     45:  */
                     46: 
                     47: extern char *malloc();
                     48: 
                     49: #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type)))
                     50: #define dispose(p)     { free((char *) p); p = 0; }
                     51: 
                     52: /*
                     53:  * Macros for doing freads + fwrites.
                     54:  */
                     55: 
                     56: #define get(fp, var)   fread((char *) &(var), sizeof(var), 1, fp)
                     57: #define put(fp, var)   fwrite((char *) &(var), sizeof(var), 1, fp)
                     58: 
                     59: /*
                     60:  * String definitions.
                     61:  */
                     62: 
                     63: extern String strcpy(), index(), rindex();
                     64: extern int strlen();
                     65: 
                     66: #define strdup(s)              strcpy(malloc((unsigned) strlen(s) + 1), s)
                     67: #define streq(s1, s2)  (strcmp(s1, s2) == 0)
                     68: 
                     69: typedef int INTFUNC();
                     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 100    /* 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:  * Default error handling.
                    355:  */
                    356: 
                    357: private ERRINFO errinfo[] ={
                    358: /* no error */ ERR_IGNORE,
                    359: /* EPERM */    ERR_IGNORE,
                    360: /* ENOENT */   ERR_IGNORE,
                    361: /* ESRCH */    ERR_IGNORE,
                    362: /* EINTR */    ERR_CATCH,
                    363: /* EIO */      ERR_CATCH,
                    364: /* ENXIO */    ERR_CATCH,
                    365: /* E2BIG */    ERR_CATCH,
                    366: /* ENOEXEC */  ERR_CATCH,
                    367: /* EBADF */    ERR_IGNORE,
                    368: /* ECHILD */   ERR_CATCH,
                    369: /* EAGAIN */   ERR_CATCH,
                    370: /* ENOMEM */   ERR_CATCH,
                    371: /* EACCES */   ERR_CATCH,
                    372: /* EFAULT */   ERR_CATCH,
                    373: /* ENOTBLK */  ERR_CATCH,
                    374: /* EBUSY */    ERR_CATCH,
                    375: /* EEXIST */   ERR_CATCH,
                    376: /* EXDEV */    ERR_CATCH,
                    377: /* ENODEV */   ERR_CATCH,
                    378: /* ENOTDIR */  ERR_CATCH,
                    379: /* EISDIR */   ERR_CATCH,
                    380: /* EINVAL */   ERR_CATCH,
                    381: /* ENFILE */   ERR_CATCH,
                    382: /* EMFILE */   ERR_CATCH,
                    383: /* ENOTTY */   ERR_IGNORE,
                    384: /* ETXTBSY */  ERR_CATCH,
                    385: /* EFBIG */    ERR_CATCH,
                    386: /* ENOSPC */   ERR_CATCH,
                    387: /* ESPIPE */   ERR_CATCH,
                    388: /* EROFS */    ERR_CATCH,
                    389: /* EMLINK */   ERR_CATCH,
                    390: /* EPIPE */    ERR_CATCH,
                    391: /* EDOM */     ERR_CATCH,
                    392: /* ERANGE */   ERR_CATCH,
                    393: /* EQUOT */    ERR_CATCH,
                    394: };
                    395: 
                    396: public syserr()
                    397: {
                    398:     ERRINFO *e;
                    399: 
                    400:     e = &errinfo[errno];
                    401:     if (e->func == ERR_CATCH) {
                    402:        if (errno < sys_nerr) {
                    403:            fatal(sys_errlist[errno]);
                    404:        } else {
                    405:            fatal("errno %d", errno);
                    406:        }
                    407:     } else if (e->func != ERR_IGNORE) {
                    408:        (*e->func)();
                    409:     }
                    410: }
                    411: 
                    412: /*
                    413:  * Catcherrs only purpose is to get this module loaded and make
                    414:  * sure my cerror is loaded (only applicable when this is in a library).
                    415:  */
                    416: 
                    417: public catcherrs()
                    418: {
                    419:     _mycerror();
                    420: }
                    421: 
                    422: /*
                    423:  * Change the action on receipt of an error.
                    424:  */
                    425: 
                    426: public onsyserr(n, f)
                    427: int n;
                    428: INTFUNC *f;
                    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: public String sys_siglist[] = {
                    440:     "no signal",
                    441:     "hangup",
                    442:     "interrupt",
                    443:     "quit",
                    444:     "illegal instruction",
                    445:     "trace trap",
                    446:     "IOT instruction",
                    447:     "EMT instruction",
                    448:     "floating point exception",
                    449:     "kill",
                    450:     "bus error",
                    451:     "segmentation violation",
                    452:     "bad argument to system call",
                    453:     "broken pipe",
                    454:     "alarm clock",
                    455:     "soft kill",
                    456:     "urgent I/O condition",
                    457:     "stop signal not from tty",
                    458:     "stop signal from tty",
                    459:     "continue",
                    460:     "child termination",
                    461:     "stop (tty input)",
                    462:     "stop (tty output)",
                    463:     "possible input/output",
                    464:     "exceeded CPU time limit",
                    465:     "exceeded file size limit",
                    466:     nil(String)
                    467: };
                    468: 
                    469: public psig(s)
                    470: String s;
                    471: {
                    472:     String c;
                    473:     int n;
                    474: 
                    475:     c = "Unknown signal";
                    476:     if (errno < sys_nsig) {
                    477:        c = sys_errlist[errno];
                    478:     }
                    479:     n = strlen(s);
                    480:     if (n > 0) {
                    481:        write(2, s, n);
                    482:        write(2, ": ", 2);
                    483:     }
                    484:     write(2, c, strlen(c));
                    485:     write(2, "\n", 1);
                    486: }
                    487: 
                    488: /*
                    489:  * Standard error handling routines.
                    490:  */
                    491: 
                    492: private short nerrs;
                    493: private short nwarnings;
                    494: 
                    495: /*
                    496:  * Main driver of error message reporting.
                    497:  */
                    498: 
                    499: /* VARARGS2 */
                    500: private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
                    501: String errname;
                    502: Boolean shouldquit;
                    503: String s;
                    504: {
                    505:     fflush(stdout);
                    506:     if (shouldquit and cmdname != nil(String)) {
                    507:        fprintf(stderr, "%s: ", cmdname);
                    508:     }
                    509:     if (errfilename != nil(Filename)) {
                    510:        fprintf(stderr, "%s: ", errfilename);
                    511:     }
                    512:     if (errlineno > 0) {
                    513:        fprintf(stderr, "%d: ", errlineno);
                    514:     }
                    515:     if (errname != nil(String)) {
                    516:        fprintf(stderr, "%s: ", errname);
                    517:     }
                    518:     fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
                    519:     putc('\n', stderr);
                    520:     if (shouldquit) {
                    521:        quit(1);
                    522:     }
                    523: }
                    524: 
                    525: /*
                    526:  * For when printf isn't sufficient for printing the error message ...
                    527:  */
                    528: 
                    529: public beginerrmsg()
                    530: {
                    531:     fflush(stdout);
                    532:     if (errfilename != nil(String)) {
                    533:        fprintf(stderr, "%s: ", errfilename);
                    534:     }
                    535:     if (errlineno > 0) {
                    536:        fprintf(stderr, "%d: ", errlineno);
                    537:     }
                    538: }
                    539: 
                    540: public enderrmsg()
                    541: {
                    542:     putc('\n', stderr);
                    543:     erecover();
                    544: }
                    545: 
                    546: /*
                    547:  * The messages are listed in increasing order of seriousness.
                    548:  *
                    549:  * First are warnings.
                    550:  */
                    551: 
                    552: /* VARARGS1 */
                    553: public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
                    554: String s;
                    555: {
                    556:     nwarnings++;
                    557:     errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
                    558: }
                    559: 
                    560: /*
                    561:  * Errors are a little worse, they mean something is wrong,
                    562:  * but not so bad that processing can't continue.
                    563:  *
                    564:  * The routine "erecover" is called to recover from the error,
                    565:  * a default routine is provided that does nothing.
                    566:  */
                    567: 
                    568: /* VARARGS1 */
                    569: public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
                    570: String s;
                    571: {
                    572:     extern erecover();
                    573: 
                    574:     nerrs++;
                    575:     errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
                    576:     erecover();
                    577: }
                    578: 
                    579: /*
                    580:  * Non-recoverable user error.
                    581:  */
                    582: 
                    583: /* VARARGS1 */
                    584: public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
                    585: String s;
                    586: {
                    587:     errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
                    588: }
                    589: 
                    590: /*
                    591:  * Panics indicate an internal program error.
                    592:  */
                    593: 
                    594: /* VARARGS1 */
                    595: public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
                    596: String s;
                    597: {
                    598:     errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
                    599: }
                    600: 
                    601: short numerrors()
                    602: {
                    603:     short r;
                    604: 
                    605:     r = nerrs;
                    606:     nerrs = 0;
                    607:     return r;
                    608: }
                    609: 
                    610: short numwarnings()
                    611: {
                    612:     short r;
                    613: 
                    614:     r = nwarnings;
                    615:     nwarnings = 0;
                    616:     return r;
                    617: }
                    618: 
                    619: /*
                    620:  * Recover from an error.
                    621:  *
                    622:  * This is the default routine which we aren't using since we have our own.
                    623:  *
                    624: public erecover()
                    625: {
                    626: }
                    627:  *
                    628:  */
                    629: 
                    630: /*
                    631:  * Default way to quit from a program is just to exit.
                    632:  *
                    633: public quit(r)
                    634: int r;
                    635: {
                    636:     exit(r);
                    637: }
                    638:  *
                    639:  */
                    640: 
                    641: /*
                    642:  * Compare n-byte areas pointed to by s1 and s2
                    643:  * if n is 0 then compare up until one has a null byte.
                    644:  */
                    645: 
                    646: public int cmp(s1, s2, n)
                    647: register char *s1, *s2;
                    648: register unsigned int n;
                    649: {
                    650:     if (s1 == nil(char *) || s2 == nil(char *)) {
                    651:        panic("cmp: nil pointer");
                    652:     }
                    653:     if (n == 0) {
                    654:        while (*s1 == *s2++) {
                    655:            if (*s1++ == '\0') {
                    656:                return(0);
                    657:            }
                    658:        }
                    659:        return(*s1 - *(s2-1));
                    660:     } else {
                    661:        for (; n != 0; n--) {
                    662:            if (*s1++ != *s2++) {
                    663:                return(*(s1-1) - *(s2-1));
                    664:            }
                    665:        }
                    666:        return(0);
                    667:     }
                    668: }
                    669: 
                    670: /*
                    671:  * Move n bytes from src to dest.
                    672:  * If n is 0 move until a null is found.
                    673:  */
                    674: 
                    675: public mov(src, dest, n)
                    676: register char *src, *dest;
                    677: register unsigned int n;
                    678: {
                    679:     if (src == nil(char *))
                    680:        panic("mov: nil source");
                    681:     if (dest == nil(char *))
                    682:        panic("mov: nil destination");
                    683:     if (n != 0) {
                    684:        for (; n != 0; n--) {
                    685:            *dest++ = *src++;
                    686:        }
                    687:     } else {
                    688:        while ((*dest++ = *src++) != '\0');
                    689:     }
                    690: }

unix.superglobalmegacorp.com

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