19666Slinton /* Copyright (c) 1982 Regents of the University of California */ 29666Slinton 3*18538Sralph static char sccsid[] = "@(#)library.c 1.7 (Berkeley) 03/28/85"; 416611Ssam 518221Slinton static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $"; 618221Slinton 79666Slinton /* 89666Slinton * General purpose routines. 99666Slinton */ 109666Slinton 119666Slinton #include <stdio.h> 129666Slinton #include <errno.h> 139666Slinton #include <signal.h> 149666Slinton 159666Slinton #define public 169666Slinton #define private static 179666Slinton #define and && 189666Slinton #define or || 199666Slinton #define not ! 209666Slinton #define ord(enumcon) ((int) enumcon) 219666Slinton #define nil(type) ((type) 0) 229666Slinton 2316611Ssam typedef int integer; 2416611Ssam typedef enum { FALSE, TRUE } boolean; 259666Slinton typedef char *String; 269666Slinton typedef FILE *File; 279666Slinton typedef String Filename; 289666Slinton 299666Slinton #undef FILE 309666Slinton 319666Slinton String cmdname; /* name of command for error messages */ 329666Slinton Filename errfilename; /* current file associated with error */ 339666Slinton short errlineno; /* line number associated with error */ 349666Slinton 359666Slinton /* 369666Slinton * Definitions for doing memory allocation. 379666Slinton */ 389666Slinton 399666Slinton extern char *malloc(); 409666Slinton 419666Slinton #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type))) 429666Slinton #define dispose(p) { free((char *) p); p = 0; } 439666Slinton 449666Slinton /* 459666Slinton * Macros for doing freads + fwrites. 469666Slinton */ 479666Slinton 489666Slinton #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp) 499666Slinton #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp) 509666Slinton 519666Slinton /* 529666Slinton * String definitions. 539666Slinton */ 549666Slinton 559666Slinton extern String strcpy(), index(), rindex(); 569666Slinton extern int strlen(); 579666Slinton 589666Slinton #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s) 599666Slinton #define streq(s1, s2) (strcmp(s1, s2) == 0) 609666Slinton 619666Slinton typedef int INTFUNC(); 629666Slinton 639666Slinton typedef struct { 649666Slinton INTFUNC *func; 659666Slinton } ERRINFO; 669666Slinton 679666Slinton #define ERR_IGNORE ((INTFUNC *) 0) 689666Slinton #define ERR_CATCH ((INTFUNC *) 1) 699666Slinton 709666Slinton /* 719666Slinton * Call a program. 729666Slinton * 739666Slinton * Four entries: 749666Slinton * 759666Slinton * call, callv - call a program and wait for it, returning status 769666Slinton * back, backv - call a program and don't wait, returning process id 779666Slinton * 789666Slinton * The command's standard input and output are passed as FILE's. 799666Slinton */ 809666Slinton 819666Slinton 8216611Ssam #define MAXNARGS 1000 /* unchecked upper limit on max num of arguments */ 839666Slinton #define BADEXEC 127 /* exec fails */ 849666Slinton 859666Slinton #define ischild(pid) ((pid) == 0) 869666Slinton 879666Slinton /* VARARGS3 */ 889666Slinton public int call(name, in, out, args) 899666Slinton String name; 909666Slinton File in; 919666Slinton File out; 929666Slinton String args; 939666Slinton { 949666Slinton String *ap, *argp; 959666Slinton String argv[MAXNARGS]; 969666Slinton 979666Slinton argp = &argv[0]; 989666Slinton *argp++ = name; 999666Slinton ap = &args; 1009666Slinton while (*ap != nil(String)) { 1019666Slinton *argp++ = *ap++; 1029666Slinton } 1039666Slinton *argp = nil(String); 1049666Slinton return callv(name, in, out, argv); 1059666Slinton } 1069666Slinton 1079666Slinton /* VARARGS3 */ 1089666Slinton public int back(name, in, out, args) 1099666Slinton String name; 1109666Slinton File in; 1119666Slinton File out; 1129666Slinton String args; 1139666Slinton { 1149666Slinton String *ap, *argp; 1159666Slinton String argv[MAXNARGS]; 1169666Slinton 1179666Slinton argp = &argv[0]; 1189666Slinton *argp++ = name; 1199666Slinton ap = &args; 1209666Slinton while (*ap != nil(String)) { 1219666Slinton *argp++ = *ap++; 1229666Slinton } 1239666Slinton *argp = nil(String); 1249666Slinton return backv(name, in, out, argv); 1259666Slinton } 1269666Slinton 1279666Slinton public int callv(name, in, out, argv) 1289666Slinton String name; 1299666Slinton File in; 1309666Slinton File out; 1319666Slinton String *argv; 1329666Slinton { 1339666Slinton int pid, status; 1349666Slinton 1359666Slinton pid = backv(name, in, out, argv); 1369666Slinton pwait(pid, &status); 1379666Slinton return status; 1389666Slinton } 1399666Slinton 1409666Slinton public int backv(name, in, out, argv) 1419666Slinton String name; 1429666Slinton File in; 1439666Slinton File out; 1449666Slinton String *argv; 1459666Slinton { 1469666Slinton int pid; 1479666Slinton 1489666Slinton fflush(stdout); 1499666Slinton if (ischild(pid = fork())) { 1509666Slinton fswap(0, fileno(in)); 1519666Slinton fswap(1, fileno(out)); 1529666Slinton onsyserr(EACCES, ERR_IGNORE); 1539666Slinton execvp(name, argv); 1549666Slinton _exit(BADEXEC); 1559666Slinton } 1569666Slinton return pid; 1579666Slinton } 1589666Slinton 1599666Slinton /* 1609666Slinton * Swap file numbers so as to redirect standard input and output. 1619666Slinton */ 1629666Slinton 1639666Slinton private fswap(oldfd, newfd) 1649666Slinton int oldfd; 1659666Slinton int newfd; 1669666Slinton { 1679666Slinton if (oldfd != newfd) { 1689666Slinton close(oldfd); 1699666Slinton dup(newfd); 1709666Slinton close(newfd); 1719666Slinton } 1729666Slinton } 1739666Slinton 1749666Slinton /* 1759666Slinton * Invoke a shell on a command line. 1769666Slinton */ 1779666Slinton 1789666Slinton #define DEF_SHELL "csh" 1799666Slinton 1809666Slinton public shell(s) 1819666Slinton String s; 1829666Slinton { 1839666Slinton extern String getenv(); 1849666Slinton String sh; 1859666Slinton 1869666Slinton if ((sh = getenv("SHELL")) == nil(String)) { 1879666Slinton sh = DEF_SHELL; 1889666Slinton } 1899666Slinton if (s != nil(String) and *s != '\0') { 1909666Slinton call(sh, stdin, stdout, "-c", s, 0); 1919666Slinton } else { 1929666Slinton call(sh, stdin, stdout, 0); 1939666Slinton } 1949666Slinton } 1959666Slinton 1969666Slinton /* 1979666Slinton * Wait for a process the right way. We wait for a particular 1989666Slinton * process and if any others come along in between, we remember them 1999666Slinton * in case they are eventually waited for. 2009666Slinton * 2019666Slinton * This routine is not very efficient when the number of processes 2029666Slinton * to be remembered is large. 20314394Slinton * 20414394Slinton * To deal with a kernel idiosyncrasy, we keep a list on the side 20514394Slinton * of "traced" processes, and do not notice them when waiting for 20614394Slinton * another process. 2079666Slinton */ 2089666Slinton 2099666Slinton typedef struct pidlist { 2109666Slinton int pid; 2119666Slinton int status; 2129666Slinton struct pidlist *next; 2139666Slinton } Pidlist; 2149666Slinton 21514394Slinton private Pidlist *pidlist, *ptrclist, *pfind(); 2169666Slinton 21714394Slinton public ptraced(pid) 21814394Slinton int pid; 21914394Slinton { 22014394Slinton Pidlist *p; 22114394Slinton 22214394Slinton p = alloc(1, Pidlist); 22314394Slinton p->pid = pid; 22414394Slinton p->next = ptrclist; 22514394Slinton ptrclist = p; 22614394Slinton } 22714394Slinton 22814394Slinton public unptraced(pid) 22914394Slinton int pid; 23014394Slinton { 23114394Slinton register Pidlist *p, *prev; 23214394Slinton 23314394Slinton prev = nil(Pidlist *); 23414394Slinton p = ptrclist; 23514394Slinton while (p != nil(Pidlist *) and p->pid != pid) { 23614394Slinton prev = p; 23714394Slinton p = p->next; 23814394Slinton } 23914394Slinton if (p != nil(Pidlist *)) { 24014394Slinton if (prev == nil(Pidlist *)) { 24114394Slinton ptrclist = p->next; 24214394Slinton } else { 24314394Slinton prev->next = p->next; 24414394Slinton } 24514394Slinton dispose(p); 24614394Slinton } 24714394Slinton } 24814394Slinton 24916611Ssam private boolean isptraced(pid) 25014394Slinton int pid; 25114394Slinton { 25214394Slinton register Pidlist *p; 25314394Slinton 25414394Slinton p = ptrclist; 25514394Slinton while (p != nil(Pidlist *) and p->pid != pid) { 25614394Slinton p = p->next; 25714394Slinton } 25816611Ssam return (boolean) (p != nil(Pidlist *)); 25914394Slinton } 26014394Slinton 2619666Slinton public pwait(pid, statusp) 2629666Slinton int pid, *statusp; 2639666Slinton { 26414393Slinton Pidlist *p; 26514393Slinton int pnum, status; 2669666Slinton 26714393Slinton p = pfind(pid); 26814393Slinton if (p != nil(Pidlist *)) { 26914393Slinton *statusp = p->status; 27014393Slinton dispose(p); 27114394Slinton } else { 27214394Slinton pnum = wait(&status); 27314394Slinton while (pnum != pid and pnum >= 0) { 27414394Slinton if (not isptraced(pnum)) { 27514394Slinton p = alloc(1, Pidlist); 27614394Slinton p->pid = pnum; 27714394Slinton p->status = status; 27814394Slinton p->next = pidlist; 27914394Slinton pidlist = p; 28014394Slinton } 28114394Slinton pnum = wait(&status); 2829666Slinton } 28314394Slinton if (pnum < 0) { 28414394Slinton p = pfind(pid); 28514394Slinton if (p == nil(Pidlist *)) { 28614394Slinton panic("pwait: pid %d not found", pid); 28714394Slinton } 28814394Slinton *statusp = p->status; 28914394Slinton dispose(p); 29014394Slinton } else { 29114394Slinton *statusp = status; 29214394Slinton } 29314393Slinton } 2949666Slinton } 2959666Slinton 2969666Slinton /* 2979666Slinton * Look for the given process id on the pidlist. 2989666Slinton * 2999666Slinton * Unlink it from list if found. 3009666Slinton */ 3019666Slinton 3029666Slinton private Pidlist *pfind(pid) 3039666Slinton int pid; 3049666Slinton { 3059666Slinton register Pidlist *p, *prev; 3069666Slinton 3079666Slinton prev = nil(Pidlist *); 3089666Slinton for (p = pidlist; p != nil(Pidlist *); p = p->next) { 3099666Slinton if (p->pid == pid) { 3109666Slinton break; 3119666Slinton } 3129666Slinton prev = p; 3139666Slinton } 3149666Slinton if (p != nil(Pidlist *)) { 3159666Slinton if (prev == nil(Pidlist *)) { 3169666Slinton pidlist = p->next; 3179666Slinton } else { 3189666Slinton prev->next = p->next; 3199666Slinton } 3209666Slinton } 3219666Slinton return p; 3229666Slinton } 3239666Slinton 3249666Slinton /* 3259666Slinton * System call error handler. 3269666Slinton * 3279666Slinton * The syserr routine is called when a system call is about to 3289666Slinton * set the c-bit to report an error. Certain errors are caught 3299666Slinton * and cause the process to print a message and immediately exit. 3309666Slinton */ 3319666Slinton 3329666Slinton extern int sys_nerr; 3339666Slinton extern char *sys_errlist[]; 3349666Slinton 3359666Slinton /* 3369666Slinton * Before calling syserr, the integer errno is set to contain the 3379666Slinton * number of the error. The routine "_mycerror" is a dummy which 3389666Slinton * is used to force the loader to get my version of cerror rather 3399666Slinton * than the usual one. 3409666Slinton */ 3419666Slinton 3429666Slinton extern int errno; 3439666Slinton extern _mycerror(); 3449666Slinton 3459666Slinton /* 34616611Ssam * Initialize error information, setting defaults for handling errors. 3479666Slinton */ 3489666Slinton 34916611Ssam private ERRINFO *errinfo; 3509666Slinton 35116611Ssam private initErrInfo () 35216611Ssam { 35316611Ssam integer i; 35416611Ssam 35516611Ssam errinfo = alloc(sys_nerr, ERRINFO); 35616611Ssam for (i = 0; i < sys_nerr; i++) { 35716611Ssam errinfo[i].func = ERR_CATCH; 35816611Ssam } 35916611Ssam errinfo[0].func = ERR_IGNORE; 36016611Ssam errinfo[EPERM].func = ERR_IGNORE; 36116611Ssam errinfo[ENOENT].func = ERR_IGNORE; 36216611Ssam errinfo[ESRCH].func = ERR_IGNORE; 36316611Ssam errinfo[EBADF].func = ERR_IGNORE; 36416611Ssam errinfo[ENOTTY].func = ERR_IGNORE; 36516611Ssam errinfo[EOPNOTSUPP].func = ERR_IGNORE; 36616611Ssam } 36716611Ssam 3689666Slinton public syserr() 3699666Slinton { 3709666Slinton ERRINFO *e; 3719666Slinton 37216611Ssam if (errno < 0 or errno > sys_nerr) { 37316611Ssam fatal("errno %d", errno); 37416611Ssam } else { 37516611Ssam if (errinfo == nil(ERRINFO *)) { 37616611Ssam initErrInfo(); 37716611Ssam } 37816611Ssam e = &(errinfo[errno]); 37916611Ssam if (e->func == ERR_CATCH) { 3809666Slinton fatal(sys_errlist[errno]); 38116611Ssam } else if (e->func != ERR_IGNORE) { 38216611Ssam (*e->func)(); 3839666Slinton } 3849666Slinton } 3859666Slinton } 3869666Slinton 3879666Slinton /* 38816611Ssam * Catcherrs' purpose is to initialize the errinfo table, get this module 38916611Ssam * loaded, and make sure my cerror is loaded (only applicable when this is 39016611Ssam * in a library). 3919666Slinton */ 3929666Slinton 3939666Slinton public catcherrs() 3949666Slinton { 3959666Slinton _mycerror(); 39616611Ssam initErrInfo(); 3979666Slinton } 3989666Slinton 3999666Slinton /* 40018221Slinton * Turn off the error catching mechanism completely by having all errors 40118221Slinton * ignored. This is most useful between a fork and an exec. 40218221Slinton */ 40318221Slinton 40418221Slinton public nocatcherrs() 40518221Slinton { 40618221Slinton integer i; 40718221Slinton 40818221Slinton for (i = 0; i < sys_nerr; i++) { 40918221Slinton errinfo[i].func = ERR_IGNORE; 41018221Slinton } 41118221Slinton } 41218221Slinton 41318221Slinton /* 4149666Slinton * Change the action on receipt of an error. 4159666Slinton */ 4169666Slinton 4179666Slinton public onsyserr(n, f) 4189666Slinton int n; 4199666Slinton INTFUNC *f; 4209666Slinton { 42116611Ssam if (errinfo == nil(ERRINFO *)) { 42216611Ssam initErrInfo(); 42316611Ssam } 4249666Slinton errinfo[n].func = f; 4259666Slinton } 4269666Slinton 4279666Slinton /* 4289666Slinton * Print the message associated with the given signal. 4299666Slinton * Like a "perror" for signals. 4309666Slinton */ 4319666Slinton 4329666Slinton public int sys_nsig = NSIG; 4339666Slinton 43416611Ssam public psignal(s, n) 4359666Slinton String s; 43616611Ssam integer n; 4379666Slinton { 43816611Ssam String msg; 43916611Ssam integer len; 440*18538Sralph extern String sys_siglist[]; 4419666Slinton 44216611Ssam if (n >= 0 and n < sys_nsig) { 44316611Ssam msg = sys_siglist[n]; 44416611Ssam } else { 44516611Ssam msg = "Unknown signal"; 4469666Slinton } 44716611Ssam len = strlen(s); 44816611Ssam if (len > 0) { 44916611Ssam write(2, s, len); 4509666Slinton write(2, ": ", 2); 4519666Slinton } 45216611Ssam write(2, msg, strlen(msg)); 4539666Slinton write(2, "\n", 1); 4549666Slinton } 4559666Slinton 4569666Slinton /* 4579666Slinton * Standard error handling routines. 4589666Slinton */ 4599666Slinton 4609666Slinton private short nerrs; 4619666Slinton private short nwarnings; 4629666Slinton 4639666Slinton /* 4649666Slinton * Main driver of error message reporting. 4659666Slinton */ 4669666Slinton 4679666Slinton /* VARARGS2 */ 4689666Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 4699666Slinton String errname; 47016611Ssam boolean shouldquit; 4719666Slinton String s; 4729666Slinton { 4739666Slinton fflush(stdout); 4749666Slinton if (shouldquit and cmdname != nil(String)) { 4759666Slinton fprintf(stderr, "%s: ", cmdname); 4769666Slinton } 4779666Slinton if (errfilename != nil(Filename)) { 4789666Slinton fprintf(stderr, "%s: ", errfilename); 4799666Slinton } 4809666Slinton if (errlineno > 0) { 4819666Slinton fprintf(stderr, "%d: ", errlineno); 4829666Slinton } 4839666Slinton if (errname != nil(String)) { 4849666Slinton fprintf(stderr, "%s: ", errname); 4859666Slinton } 4869666Slinton fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 4879666Slinton putc('\n', stderr); 4889666Slinton if (shouldquit) { 4899666Slinton quit(1); 4909666Slinton } 4919666Slinton } 4929666Slinton 4939666Slinton /* 4949666Slinton * For when printf isn't sufficient for printing the error message ... 4959666Slinton */ 4969666Slinton 4979666Slinton public beginerrmsg() 4989666Slinton { 4999666Slinton fflush(stdout); 5009666Slinton if (errfilename != nil(String)) { 5019666Slinton fprintf(stderr, "%s: ", errfilename); 5029666Slinton } 5039666Slinton if (errlineno > 0) { 5049666Slinton fprintf(stderr, "%d: ", errlineno); 5059666Slinton } 5069666Slinton } 5079666Slinton 5089666Slinton public enderrmsg() 5099666Slinton { 5109666Slinton putc('\n', stderr); 5119666Slinton erecover(); 5129666Slinton } 5139666Slinton 5149666Slinton /* 5159666Slinton * The messages are listed in increasing order of seriousness. 5169666Slinton * 5179666Slinton * First are warnings. 5189666Slinton */ 5199666Slinton 5209666Slinton /* VARARGS1 */ 5219666Slinton public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5229666Slinton String s; 5239666Slinton { 5249666Slinton nwarnings++; 5259666Slinton errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5269666Slinton } 5279666Slinton 5289666Slinton /* 5299666Slinton * Errors are a little worse, they mean something is wrong, 5309666Slinton * but not so bad that processing can't continue. 5319666Slinton * 5329666Slinton * The routine "erecover" is called to recover from the error, 5339666Slinton * a default routine is provided that does nothing. 5349666Slinton */ 5359666Slinton 5369666Slinton /* VARARGS1 */ 5379666Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5389666Slinton String s; 5399666Slinton { 5409666Slinton extern erecover(); 5419666Slinton 5429666Slinton nerrs++; 5439666Slinton errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5449666Slinton erecover(); 5459666Slinton } 5469666Slinton 5479666Slinton /* 5489666Slinton * Non-recoverable user error. 5499666Slinton */ 5509666Slinton 5519666Slinton /* VARARGS1 */ 5529666Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5539666Slinton String s; 5549666Slinton { 5559666Slinton errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5569666Slinton } 5579666Slinton 5589666Slinton /* 5599666Slinton * Panics indicate an internal program error. 5609666Slinton */ 5619666Slinton 5629666Slinton /* VARARGS1 */ 5639666Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 5649666Slinton String s; 5659666Slinton { 5669666Slinton errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 5679666Slinton } 5689666Slinton 5699666Slinton short numerrors() 5709666Slinton { 5719666Slinton short r; 5729666Slinton 5739666Slinton r = nerrs; 5749666Slinton nerrs = 0; 5759666Slinton return r; 5769666Slinton } 5779666Slinton 5789666Slinton short numwarnings() 5799666Slinton { 5809666Slinton short r; 5819666Slinton 5829666Slinton r = nwarnings; 5839666Slinton nwarnings = 0; 5849666Slinton return r; 5859666Slinton } 5869666Slinton 5879666Slinton /* 5889666Slinton * Recover from an error. 5899666Slinton * 5909666Slinton * This is the default routine which we aren't using since we have our own. 5919666Slinton * 5929666Slinton public erecover() 5939666Slinton { 5949666Slinton } 5959666Slinton * 5969666Slinton */ 5979666Slinton 5989666Slinton /* 5999666Slinton * Default way to quit from a program is just to exit. 6009666Slinton * 6019666Slinton public quit(r) 6029666Slinton int r; 6039666Slinton { 6049666Slinton exit(r); 6059666Slinton } 6069666Slinton * 6079666Slinton */ 6089666Slinton 6099666Slinton /* 6109666Slinton * Compare n-byte areas pointed to by s1 and s2 6119666Slinton * if n is 0 then compare up until one has a null byte. 6129666Slinton */ 6139666Slinton 6149666Slinton public int cmp(s1, s2, n) 6159666Slinton register char *s1, *s2; 6169666Slinton register unsigned int n; 6179666Slinton { 6189666Slinton if (s1 == nil(char *) || s2 == nil(char *)) { 6199666Slinton panic("cmp: nil pointer"); 6209666Slinton } 6219666Slinton if (n == 0) { 6229666Slinton while (*s1 == *s2++) { 6239666Slinton if (*s1++ == '\0') { 6249666Slinton return(0); 6259666Slinton } 6269666Slinton } 6279666Slinton return(*s1 - *(s2-1)); 6289666Slinton } else { 6299666Slinton for (; n != 0; n--) { 6309666Slinton if (*s1++ != *s2++) { 6319666Slinton return(*(s1-1) - *(s2-1)); 6329666Slinton } 6339666Slinton } 6349666Slinton return(0); 6359666Slinton } 6369666Slinton } 6379666Slinton 6389666Slinton /* 6399666Slinton * Move n bytes from src to dest. 6409666Slinton * If n is 0 move until a null is found. 6419666Slinton */ 6429666Slinton 6439666Slinton public mov(src, dest, n) 6449666Slinton register char *src, *dest; 6459666Slinton register unsigned int n; 6469666Slinton { 6479666Slinton if (src == nil(char *)) 6489666Slinton panic("mov: nil source"); 6499666Slinton if (dest == nil(char *)) 6509666Slinton panic("mov: nil destination"); 6519666Slinton if (n != 0) { 6529666Slinton for (; n != 0; n--) { 6539666Slinton *dest++ = *src++; 6549666Slinton } 6559666Slinton } else { 6569666Slinton while ((*dest++ = *src++) != '\0'); 6579666Slinton } 6589666Slinton } 659