123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691 |
- #ifndef lint
- static char sccsid[] = "@(#)library.c 1.4 (Berkeley) 8/13/83";
- #endif
- /* Copyright (c) 1982 Regents of the University of California */
- /*
- * General purpose routines.
- */
- #include <stdio.h>
- #include <errno.h>
- #include <signal.h>
- #define public
- #define private static
- #define and &&
- #define or ||
- #define not !
- #define ord(enumcon) ((int) enumcon)
- #define nil(type) ((type) 0)
- typedef enum { FALSE, TRUE } Boolean;
- typedef char *String;
- typedef FILE *File;
- typedef String Filename;
- #undef FILE
- /*
- * Definitions of standard C library routines that aren't in the
- * standard I/O library, but which are generally useful.
- */
- extern long atol(); /* ascii to long */
- extern double atof(); /* ascii to floating point */
- extern char *mktemp(); /* make a temporary file name */
- String cmdname; /* name of command for error messages */
- Filename errfilename; /* current file associated with error */
- short errlineno; /* line number associated with error */
- /*
- * Definitions for doing memory allocation.
- */
- extern char *malloc();
- #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type)))
- #define dispose(p) { free((char *) p); p = 0; }
- /*
- * Macros for doing freads + fwrites.
- */
- #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp)
- #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp)
- /*
- * String definitions.
- */
- extern String strcpy(), index(), rindex();
- extern int strlen();
- #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s)
- #define streq(s1, s2) (strcmp(s1, s2) == 0)
- typedef int INTFUNC();
- typedef struct {
- INTFUNC *func;
- } ERRINFO;
- #define ERR_IGNORE ((INTFUNC *) 0)
- #define ERR_CATCH ((INTFUNC *) 1)
- /*
- * Call a program.
- *
- * Four entries:
- *
- * call, callv - call a program and wait for it, returning status
- * back, backv - call a program and don't wait, returning process id
- *
- * The command's standard input and output are passed as FILE's.
- */
- #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */
- #define BADEXEC 127 /* exec fails */
- #define ischild(pid) ((pid) == 0)
- /* VARARGS3 */
- public int call(name, in, out, args)
- String name;
- File in;
- File out;
- String args;
- {
- String *ap, *argp;
- String argv[MAXNARGS];
- argp = &argv[0];
- *argp++ = name;
- ap = &args;
- while (*ap != nil(String)) {
- *argp++ = *ap++;
- }
- *argp = nil(String);
- return callv(name, in, out, argv);
- }
- /* VARARGS3 */
- public int back(name, in, out, args)
- String name;
- File in;
- File out;
- String args;
- {
- String *ap, *argp;
- String argv[MAXNARGS];
- argp = &argv[0];
- *argp++ = name;
- ap = &args;
- while (*ap != nil(String)) {
- *argp++ = *ap++;
- }
- *argp = nil(String);
- return backv(name, in, out, argv);
- }
- public int callv(name, in, out, argv)
- String name;
- File in;
- File out;
- String *argv;
- {
- int pid, status;
- pid = backv(name, in, out, argv);
- pwait(pid, &status);
- return status;
- }
- public int backv(name, in, out, argv)
- String name;
- File in;
- File out;
- String *argv;
- {
- int pid;
- fflush(stdout);
- if (ischild(pid = fork())) {
- fswap(0, fileno(in));
- fswap(1, fileno(out));
- onsyserr(EACCES, ERR_IGNORE);
- execvp(name, argv);
- _exit(BADEXEC);
- }
- return pid;
- }
- /*
- * Swap file numbers so as to redirect standard input and output.
- */
- private fswap(oldfd, newfd)
- int oldfd;
- int newfd;
- {
- if (oldfd != newfd) {
- close(oldfd);
- dup(newfd);
- close(newfd);
- }
- }
- /*
- * Invoke a shell on a command line.
- */
- #define DEF_SHELL "csh"
- public shell(s)
- String s;
- {
- extern String getenv();
- String sh;
- if ((sh = getenv("SHELL")) == nil(String)) {
- sh = DEF_SHELL;
- }
- if (s != nil(String) and *s != '\0') {
- call(sh, stdin, stdout, "-c", s, 0);
- } else {
- call(sh, stdin, stdout, 0);
- }
- }
- /*
- * Wait for a process the right way. We wait for a particular
- * process and if any others come along in between, we remember them
- * in case they are eventually waited for.
- *
- * This routine is not very efficient when the number of processes
- * to be remembered is large.
- *
- * To deal with a kernel idiosyncrasy, we keep a list on the side
- * of "traced" processes, and do not notice them when waiting for
- * another process.
- */
- typedef struct pidlist {
- int pid;
- int status;
- struct pidlist *next;
- } Pidlist;
- private Pidlist *pidlist, *ptrclist, *pfind();
- public ptraced(pid)
- int pid;
- {
- Pidlist *p;
- p = alloc(1, Pidlist);
- p->pid = pid;
- p->next = ptrclist;
- ptrclist = p;
- }
- public unptraced(pid)
- int pid;
- {
- register Pidlist *p, *prev;
- prev = nil(Pidlist *);
- p = ptrclist;
- while (p != nil(Pidlist *) and p->pid != pid) {
- prev = p;
- p = p->next;
- }
- if (p != nil(Pidlist *)) {
- if (prev == nil(Pidlist *)) {
- ptrclist = p->next;
- } else {
- prev->next = p->next;
- }
- dispose(p);
- }
- }
- private Boolean isptraced(pid)
- int pid;
- {
- register Pidlist *p;
- p = ptrclist;
- while (p != nil(Pidlist *) and p->pid != pid) {
- p = p->next;
- }
- return (Boolean) (p != nil(Pidlist *));
- }
- public pwait(pid, statusp)
- int pid, *statusp;
- {
- Pidlist *p;
- int pnum, status;
- p = pfind(pid);
- if (p != nil(Pidlist *)) {
- *statusp = p->status;
- dispose(p);
- } else {
- pnum = wait(&status);
- while (pnum != pid and pnum >= 0) {
- if (not isptraced(pnum)) {
- p = alloc(1, Pidlist);
- p->pid = pnum;
- p->status = status;
- p->next = pidlist;
- pidlist = p;
- }
- pnum = wait(&status);
- }
- if (pnum < 0) {
- p = pfind(pid);
- if (p == nil(Pidlist *)) {
- panic("pwait: pid %d not found", pid);
- }
- *statusp = p->status;
- dispose(p);
- } else {
- *statusp = status;
- }
- }
- }
- /*
- * Look for the given process id on the pidlist.
- *
- * Unlink it from list if found.
- */
- private Pidlist *pfind(pid)
- int pid;
- {
- register Pidlist *p, *prev;
- prev = nil(Pidlist *);
- for (p = pidlist; p != nil(Pidlist *); p = p->next) {
- if (p->pid == pid) {
- break;
- }
- prev = p;
- }
- if (p != nil(Pidlist *)) {
- if (prev == nil(Pidlist *)) {
- pidlist = p->next;
- } else {
- prev->next = p->next;
- }
- }
- return p;
- }
- /*
- * System call error handler.
- *
- * The syserr routine is called when a system call is about to
- * set the c-bit to report an error. Certain errors are caught
- * and cause the process to print a message and immediately exit.
- */
- extern int sys_nerr;
- extern char *sys_errlist[];
-
- /*
- * Before calling syserr, the integer errno is set to contain the
- * number of the error. The routine "_mycerror" is a dummy which
- * is used to force the loader to get my version of cerror rather
- * than the usual one.
- */
- extern int errno;
- extern _mycerror();
- /*
- * Default error handling.
- */
- private ERRINFO errinfo[] ={
- /* no error */ ERR_IGNORE,
- /* EPERM */ ERR_IGNORE,
- /* ENOENT */ ERR_IGNORE,
- /* ESRCH */ ERR_IGNORE,
- /* EINTR */ ERR_CATCH,
- /* EIO */ ERR_CATCH,
- /* ENXIO */ ERR_CATCH,
- /* E2BIG */ ERR_CATCH,
- /* ENOEXEC */ ERR_CATCH,
- /* EBADF */ ERR_IGNORE,
- /* ECHILD */ ERR_CATCH,
- /* EAGAIN */ ERR_CATCH,
- /* ENOMEM */ ERR_CATCH,
- /* EACCES */ ERR_CATCH,
- /* EFAULT */ ERR_CATCH,
- /* ENOTBLK */ ERR_CATCH,
- /* EBUSY */ ERR_CATCH,
- /* EEXIST */ ERR_CATCH,
- /* EXDEV */ ERR_CATCH,
- /* ENODEV */ ERR_CATCH,
- /* ENOTDIR */ ERR_CATCH,
- /* EISDIR */ ERR_CATCH,
- /* EINVAL */ ERR_CATCH,
- /* ENFILE */ ERR_CATCH,
- /* EMFILE */ ERR_CATCH,
- /* ENOTTY */ ERR_IGNORE,
- /* ETXTBSY */ ERR_CATCH,
- /* EFBIG */ ERR_CATCH,
- /* ENOSPC */ ERR_CATCH,
- /* ESPIPE */ ERR_CATCH,
- /* EROFS */ ERR_CATCH,
- /* EMLINK */ ERR_CATCH,
- /* EPIPE */ ERR_CATCH,
- /* EDOM */ ERR_CATCH,
- /* ERANGE */ ERR_CATCH,
- /* EQUOT */ ERR_CATCH,
- };
- public syserr()
- {
- ERRINFO *e;
- e = &errinfo[errno];
- if (e->func == ERR_CATCH) {
- if (errno < sys_nerr) {
- fatal(sys_errlist[errno]);
- } else {
- fatal("errno %d", errno);
- }
- } else if (e->func != ERR_IGNORE) {
- (*e->func)();
- }
- }
- /*
- * Catcherrs only purpose is to get this module loaded and make
- * sure my cerror is loaded (only applicable when this is in a library).
- */
- public catcherrs()
- {
- _mycerror();
- }
- /*
- * Change the action on receipt of an error.
- */
- public onsyserr(n, f)
- int n;
- INTFUNC *f;
- {
- errinfo[n].func = f;
- }
- /*
- * Print the message associated with the given signal.
- * Like a "perror" for signals.
- */
- public int sys_nsig = NSIG;
- public String sys_siglist[] = {
- "no signal",
- "hangup",
- "interrupt",
- "quit",
- "illegal instruction",
- "trace trap",
- "IOT instruction",
- "EMT instruction",
- "floating point exception",
- "kill",
- "bus error",
- "segmentation violation",
- "bad argument to system call",
- "broken pipe",
- "alarm clock",
- "soft kill",
- "urgent I/O condition",
- "stop signal not from tty",
- "stop signal from tty",
- "continue",
- "child termination",
- "stop (tty input)",
- "stop (tty output)",
- "possible input/output",
- "exceeded CPU time limit",
- "exceeded file size limit",
- nil(String)
- };
- public psig(s)
- String s;
- {
- String c;
- int n;
- c = "Unknown signal";
- if (errno < sys_nsig) {
- c = sys_errlist[errno];
- }
- n = strlen(s);
- if (n > 0) {
- write(2, s, n);
- write(2, ": ", 2);
- }
- write(2, c, strlen(c));
- write(2, "\n", 1);
- }
- /*
- * Standard error handling routines.
- */
- private short nerrs;
- private short nwarnings;
- /*
- * Main driver of error message reporting.
- */
- /* VARARGS2 */
- private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
- String errname;
- Boolean shouldquit;
- String s;
- {
- fflush(stdout);
- if (shouldquit and cmdname != nil(String)) {
- fprintf(stderr, "%s: ", cmdname);
- }
- if (errfilename != nil(Filename)) {
- fprintf(stderr, "%s: ", errfilename);
- }
- if (errlineno > 0) {
- fprintf(stderr, "%d: ", errlineno);
- }
- if (errname != nil(String)) {
- fprintf(stderr, "%s: ", errname);
- }
- fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
- putc('\n', stderr);
- if (shouldquit) {
- quit(1);
- }
- }
- /*
- * For when printf isn't sufficient for printing the error message ...
- */
- public beginerrmsg()
- {
- fflush(stdout);
- if (errfilename != nil(String)) {
- fprintf(stderr, "%s: ", errfilename);
- }
- if (errlineno > 0) {
- fprintf(stderr, "%d: ", errlineno);
- }
- }
- public enderrmsg()
- {
- putc('\n', stderr);
- erecover();
- }
- /*
- * The messages are listed in increasing order of seriousness.
- *
- * First are warnings.
- */
- /* VARARGS1 */
- public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
- String s;
- {
- nwarnings++;
- errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
- }
- /*
- * Errors are a little worse, they mean something is wrong,
- * but not so bad that processing can't continue.
- *
- * The routine "erecover" is called to recover from the error,
- * a default routine is provided that does nothing.
- */
- /* VARARGS1 */
- public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
- String s;
- {
- extern erecover();
- nerrs++;
- errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
- erecover();
- }
- /*
- * Non-recoverable user error.
- */
- /* VARARGS1 */
- public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
- String s;
- {
- errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
- }
- /*
- * Panics indicate an internal program error.
- */
- /* VARARGS1 */
- public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
- String s;
- {
- errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
- }
- short numerrors()
- {
- short r;
- r = nerrs;
- nerrs = 0;
- return r;
- }
- short numwarnings()
- {
- short r;
- r = nwarnings;
- nwarnings = 0;
- return r;
- }
- /*
- * Recover from an error.
- *
- * This is the default routine which we aren't using since we have our own.
- *
- public erecover()
- {
- }
- *
- */
- /*
- * Default way to quit from a program is just to exit.
- *
- public quit(r)
- int r;
- {
- exit(r);
- }
- *
- */
- /*
- * Compare n-byte areas pointed to by s1 and s2
- * if n is 0 then compare up until one has a null byte.
- */
- public int cmp(s1, s2, n)
- register char *s1, *s2;
- register unsigned int n;
- {
- if (s1 == nil(char *) || s2 == nil(char *)) {
- panic("cmp: nil pointer");
- }
- if (n == 0) {
- while (*s1 == *s2++) {
- if (*s1++ == '\0') {
- return(0);
- }
- }
- return(*s1 - *(s2-1));
- } else {
- for (; n != 0; n--) {
- if (*s1++ != *s2++) {
- return(*(s1-1) - *(s2-1));
- }
- }
- return(0);
- }
- }
- /*
- * Move n bytes from src to dest.
- * If n is 0 move until a null is found.
- */
- public mov(src, dest, n)
- register char *src, *dest;
- register unsigned int n;
- {
- if (src == nil(char *))
- panic("mov: nil source");
- if (dest == nil(char *))
- panic("mov: nil destination");
- if (n != 0) {
- for (; n != 0; n--) {
- *dest++ = *src++;
- }
- } else {
- while ((*dest++ = *src++) != '\0');
- }
- }
|