148104Sbostic /*-
262131Sbostic * Copyright (c) 1982, 1993
362131Sbostic * The Regents of the University of California. All rights reserved.
448104Sbostic *
548104Sbostic * %sccs.include.redist.c%
622759Smckusick */
78020Slinton
822759Smckusick #ifndef lint
9*67254Smckusick static char sccsid[] = "@(#)library.c 8.2 (Berkeley) 05/27/94";
1048104Sbostic #endif /* not lint */
118020Slinton
128020Slinton /*
138020Slinton * General purpose routines.
148020Slinton */
158020Slinton
168020Slinton #include <stdio.h>
178020Slinton #include <errno.h>
1830842Smckusick #include "defs.h"
198020Slinton
208020Slinton #define public
218020Slinton #define private static
228020Slinton #define and &&
238020Slinton #define nil(type) ((type) 0)
248020Slinton
258020Slinton typedef char *String;
268020Slinton typedef FILE *File;
278020Slinton typedef String Filename;
2830842Smckusick typedef char Boolean;
298020Slinton
308020Slinton #undef FILE
318020Slinton
328020Slinton String cmdname; /* name of command for error messages */
338020Slinton Filename errfilename; /* current file associated with error */
348020Slinton short errlineno; /* line number associated with error */
358020Slinton
368020Slinton typedef int INTFUNC();
378020Slinton
388020Slinton typedef struct {
398020Slinton INTFUNC *func;
408020Slinton } ERRINFO;
418020Slinton
428020Slinton #define ERR_IGNORE ((INTFUNC *) 0)
438020Slinton #define ERR_CATCH ((INTFUNC *) 1)
448020Slinton
4530842Smckusick public INTFUNC *onsyserr();
4630842Smckusick
478020Slinton /*
488020Slinton * Call a program.
498020Slinton *
5030842Smckusick * Three entries:
518020Slinton *
528020Slinton * call, callv - call a program and wait for it, returning status
5330842Smckusick * backv - call a program and don't wait, returning process id
548020Slinton *
558020Slinton * The command's standard input and output are passed as FILE's.
568020Slinton */
578020Slinton
588020Slinton
598020Slinton #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */
608020Slinton #define BADEXEC 127 /* exec fails */
618020Slinton
628020Slinton #define ischild(pid) ((pid) == 0)
638020Slinton
648020Slinton /* VARARGS3 */
call(name,in,out,args)658020Slinton public int call(name, in, out, args)
668020Slinton String name;
678020Slinton File in;
688020Slinton File out;
698020Slinton String args;
708020Slinton {
718020Slinton String *ap, *argp;
728020Slinton String argv[MAXNARGS];
738020Slinton
748020Slinton argp = &argv[0];
758020Slinton *argp++ = name;
768020Slinton ap = &args;
778020Slinton while (*ap != nil(String)) {
788020Slinton *argp++ = *ap++;
798020Slinton }
808020Slinton *argp = nil(String);
818020Slinton return callv(name, in, out, argv);
828020Slinton }
838020Slinton
callv(name,in,out,argv)848020Slinton public int callv(name, in, out, argv)
858020Slinton String name;
868020Slinton File in;
878020Slinton File out;
888020Slinton String *argv;
898020Slinton {
908020Slinton int pid, status;
918020Slinton
928020Slinton pid = backv(name, in, out, argv);
938020Slinton pwait(pid, &status);
948020Slinton return status;
958020Slinton }
968020Slinton
backv(name,in,out,argv)978020Slinton public int backv(name, in, out, argv)
988020Slinton String name;
998020Slinton File in;
1008020Slinton File out;
1018020Slinton String *argv;
1028020Slinton {
1038020Slinton int pid;
1048020Slinton
1058020Slinton fflush(stdout);
1068020Slinton if (ischild(pid = fork())) {
1078020Slinton fswap(0, fileno(in));
1088020Slinton fswap(1, fileno(out));
10930842Smckusick (void) onsyserr(EACCES, ERR_IGNORE);
1108020Slinton execvp(name, argv);
1118020Slinton _exit(BADEXEC);
1128020Slinton }
1138020Slinton return pid;
1148020Slinton }
1158020Slinton
1168020Slinton /*
1178020Slinton * Swap file numbers so as to redirect standard input and output.
1188020Slinton */
1198020Slinton
fswap(oldfd,newfd)1208020Slinton private fswap(oldfd, newfd)
1218020Slinton int oldfd;
1228020Slinton int newfd;
1238020Slinton {
1248020Slinton if (oldfd != newfd) {
1258020Slinton close(oldfd);
1268020Slinton dup(newfd);
1278020Slinton close(newfd);
1288020Slinton }
1298020Slinton }
1308020Slinton
1318020Slinton /*
1328020Slinton * Invoke a shell on a command line.
1338020Slinton */
1348020Slinton
1358020Slinton #define DEF_SHELL "csh"
1368020Slinton
shell(s)1378020Slinton public shell(s)
1388020Slinton String s;
1398020Slinton {
1408020Slinton extern String getenv();
1418020Slinton String sh;
1428020Slinton
1438020Slinton if ((sh = getenv("SHELL")) == nil(String)) {
1448020Slinton sh = DEF_SHELL;
1458020Slinton }
1468020Slinton call(sh, stdin, stdout, "-c", s, 0);
1478020Slinton }
1488020Slinton
1498020Slinton /*
1508020Slinton * Wait for a process the right way. We wait for a particular
1518020Slinton * process and if any others come along in between, we remember them
1528020Slinton * in case they are eventually waited for.
1538020Slinton *
1548020Slinton * This routine is not very efficient when the number of processes
1558020Slinton * to be remembered is large.
1568020Slinton */
1578020Slinton
1588020Slinton typedef struct pidlist {
1598020Slinton int pid;
1608020Slinton int status;
1618020Slinton struct pidlist *next;
1628020Slinton } Pidlist;
1638020Slinton
1648020Slinton private Pidlist *pidlist, *pfind();
1658020Slinton
pwait(pid,statusp)1668020Slinton public pwait(pid, statusp)
1678020Slinton int pid, *statusp;
1688020Slinton {
1698020Slinton Pidlist *p;
1708020Slinton int pnum, status;
1718020Slinton
1728020Slinton p = pfind(pid);
1738020Slinton if (p != nil(Pidlist *)) {
1748020Slinton *statusp = p->status;
1758020Slinton dispose(p);
1768020Slinton return;
1778020Slinton }
1788020Slinton while ((pnum = wait(&status)) != pid && pnum >= 0) {
1798020Slinton p = alloc(1, Pidlist);
1808020Slinton p->pid = pnum;
1818020Slinton p->status = status;
1828020Slinton p->next = pidlist;
1838020Slinton pidlist = p;
1848020Slinton }
1858020Slinton if (pnum < 0) {
1868020Slinton p = pfind(pid);
1878020Slinton if (p == nil(Pidlist *)) {
1888020Slinton panic("pwait: pid %d not found", pid);
1898020Slinton }
1908020Slinton *statusp = p->status;
1918020Slinton dispose(p);
1928020Slinton } else {
19330842Smckusick *statusp = status;
1948020Slinton }
19530842Smckusick #ifdef tahoe
19630842Smckusick chkret(p, status);
19730842Smckusick #endif
1988020Slinton }
1998020Slinton
2008020Slinton /*
2018020Slinton * Look for the given process id on the pidlist.
2028020Slinton *
2038020Slinton * Unlink it from list if found.
2048020Slinton */
2058020Slinton
pfind(pid)2068020Slinton private Pidlist *pfind(pid)
2078020Slinton int pid;
2088020Slinton {
2098020Slinton register Pidlist *p, *prev;
2108020Slinton
2118020Slinton prev = nil(Pidlist *);
2128020Slinton for (p = pidlist; p != nil(Pidlist *); p = p->next) {
2138020Slinton if (p->pid == pid) {
2148020Slinton break;
2158020Slinton }
2168020Slinton prev = p;
2178020Slinton }
2188020Slinton if (p != nil(Pidlist *)) {
2198020Slinton if (prev == nil(Pidlist *)) {
22030842Smckusick pidlist = p->next;
2218020Slinton } else {
22230842Smckusick prev->next = p->next;
2238020Slinton }
2248020Slinton }
2258020Slinton return p;
2268020Slinton }
2278020Slinton
2288020Slinton /*
2298020Slinton * System call error handler.
2308020Slinton *
2318020Slinton * The syserr routine is called when a system call is about to
2328020Slinton * set the c-bit to report an error. Certain errors are caught
2338020Slinton * and cause the process to print a message and immediately exit.
2348020Slinton */
2358020Slinton
2368020Slinton extern int sys_nerr;
2378020Slinton
2388020Slinton /*
2398020Slinton * Before calling syserr, the integer errno is set to contain the
24030842Smckusick * number of the error.
2418020Slinton */
2428020Slinton
2438020Slinton extern int errno;
2448020Slinton
2458020Slinton /*
2468020Slinton * default error handling
2478020Slinton */
2488020Slinton
2498020Slinton private ERRINFO errinfo[] ={
2508020Slinton /* no error */ ERR_IGNORE,
2518020Slinton /* EPERM */ ERR_IGNORE,
2528020Slinton /* ENOENT */ ERR_IGNORE,
2538020Slinton /* ESRCH */ ERR_IGNORE,
2548020Slinton /* EINTR */ ERR_CATCH,
2558020Slinton /* EIO */ ERR_CATCH,
2568020Slinton /* ENXIO */ ERR_CATCH,
2578020Slinton /* E2BIG */ ERR_CATCH,
2588020Slinton /* ENOEXEC */ ERR_CATCH,
2598020Slinton /* EBADF */ ERR_IGNORE,
2608020Slinton /* ECHILD */ ERR_CATCH,
2618020Slinton /* EAGAIN */ ERR_CATCH,
2628020Slinton /* ENOMEM */ ERR_CATCH,
2638020Slinton /* EACCES */ ERR_CATCH,
2648020Slinton /* EFAULT */ ERR_CATCH,
2658020Slinton /* ENOTBLK */ ERR_CATCH,
2668020Slinton /* EBUSY */ ERR_CATCH,
2678020Slinton /* EEXIST */ ERR_CATCH,
2688020Slinton /* EXDEV */ ERR_CATCH,
2698020Slinton /* ENODEV */ ERR_CATCH,
2708020Slinton /* ENOTDIR */ ERR_CATCH,
2718020Slinton /* EISDIR */ ERR_CATCH,
2728020Slinton /* EINVAL */ ERR_CATCH,
2738020Slinton /* ENFILE */ ERR_CATCH,
2748020Slinton /* EMFILE */ ERR_CATCH,
2758020Slinton /* ENOTTY */ ERR_IGNORE,
2768020Slinton /* ETXTBSY */ ERR_CATCH,
2778020Slinton /* EFBIG */ ERR_CATCH,
2788020Slinton /* ENOSPC */ ERR_CATCH,
2798020Slinton /* ESPIPE */ ERR_CATCH,
2808020Slinton /* EROFS */ ERR_CATCH,
2818020Slinton /* EMLINK */ ERR_CATCH,
2828020Slinton /* EPIPE */ ERR_CATCH,
2838020Slinton /* EDOM */ ERR_CATCH,
2848020Slinton /* ERANGE */ ERR_CATCH,
2858020Slinton /* EQUOT */ ERR_CATCH,
2868020Slinton };
2878020Slinton
syserr()2888020Slinton public syserr()
2898020Slinton {
2908020Slinton ERRINFO *e;
2918020Slinton
2928020Slinton e = &errinfo[errno];
2938020Slinton if (e->func == ERR_CATCH) {
2948020Slinton if (errno < sys_nerr) {
2958020Slinton panic(sys_errlist[errno]);
2968020Slinton } else {
2978020Slinton panic("errno %d", errno);
2988020Slinton }
2998020Slinton } else if (e->func != ERR_IGNORE) {
3008020Slinton (*e->func)();
3018020Slinton }
3028020Slinton }
3038020Slinton
3048020Slinton /*
3058020Slinton * Change the action on receipt of an error.
3068020Slinton */
3078020Slinton
onsyserr(n,f)30830842Smckusick public INTFUNC *onsyserr(n, f)
3098020Slinton int n;
3108020Slinton INTFUNC *f;
3118020Slinton {
31230842Smckusick INTFUNC *g = errinfo[n].func;
31330842Smckusick
3148020Slinton errinfo[n].func = f;
31530842Smckusick return(g);
3168020Slinton }
3178020Slinton
3188020Slinton /*
3198020Slinton * Main driver of error message reporting.
3208020Slinton */
3218020Slinton
3228020Slinton /* VARARGS2 */
errmsg(errname,shouldquit,s,a,b,c,d,e,f,g,h,i,j,k,l,m)3238020Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3248020Slinton String errname;
3258020Slinton Boolean shouldquit;
3268020Slinton String s;
3278020Slinton {
3288020Slinton fflush(stdout);
3298020Slinton if (shouldquit and cmdname != nil(String)) {
3308020Slinton fprintf(stderr, "%s: ", cmdname);
3318020Slinton }
3328020Slinton if (errfilename != nil(Filename)) {
3338020Slinton fprintf(stderr, "%s: ", errfilename);
3348020Slinton }
3358020Slinton if (errlineno > 0) {
3368020Slinton fprintf(stderr, "%d: ", errlineno);
3378020Slinton }
3388020Slinton if (errname != nil(String)) {
3398020Slinton fprintf(stderr, "%s: ", errname);
3408020Slinton }
3418020Slinton fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3428020Slinton putc('\n', stderr);
3438020Slinton if (shouldquit) {
3448020Slinton quit(1);
3458020Slinton }
3468020Slinton }
3478020Slinton
3488020Slinton /*
3498020Slinton * Errors are a little worse, they mean something is wrong,
3508020Slinton * but not so bad that processing can't continue.
3518020Slinton *
3528020Slinton * The routine "erecover" is called to recover from the error,
3538020Slinton * a default routine is provided that does nothing.
3548020Slinton */
3558020Slinton
3568020Slinton /* VARARGS1 */
error(s,a,b,c,d,e,f,g,h,i,j,k,l,m)3578020Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3588020Slinton String s;
3598020Slinton {
3608020Slinton extern erecover();
3618020Slinton
3628020Slinton errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3638020Slinton erecover();
3648020Slinton }
3658020Slinton
3668020Slinton /*
3678020Slinton * Non-recoverable user error.
3688020Slinton */
3698020Slinton
3708020Slinton /* VARARGS1 */
fatal(s,a,b,c,d,e,f,g,h,i,j,k,l,m)3718020Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3728020Slinton String s;
3738020Slinton {
3748020Slinton errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3758020Slinton }
3768020Slinton
3778020Slinton /*
3788020Slinton * Panics indicate an internal program error.
3798020Slinton */
3808020Slinton
3818020Slinton /* VARARGS1 */
panic(s,a,b,c,d,e,f,g,h,i,j,k,l,m)3828020Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
3838020Slinton String s;
3848020Slinton {
3858020Slinton errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
3868020Slinton }
3878020Slinton
3888020Slinton /*
3898020Slinton * Compare n-byte areas pointed to by s1 and s2
3908020Slinton * if n is 0 then compare up until one has a null byte.
3918020Slinton */
3928020Slinton
cmp(s1,s2,n)3938020Slinton public int cmp(s1, s2, n)
3948020Slinton register char *s1, *s2;
3958020Slinton register unsigned int n;
3968020Slinton {
3978020Slinton if (s1 == nil(char *) || s2 == nil(char *)) {
3988020Slinton panic("cmp: nil pointer");
3998020Slinton }
4008020Slinton if (n == 0) {
4018020Slinton while (*s1 == *s2++) {
4028020Slinton if (*s1++ == '\0') {
4038020Slinton return(0);
4048020Slinton }
4058020Slinton }
4068020Slinton return(*s1 - *(s2-1));
4078020Slinton } else {
4088020Slinton for (; n != 0; n--) {
4098020Slinton if (*s1++ != *s2++) {
4108020Slinton return(*(s1-1) - *(s2-1));
4118020Slinton }
4128020Slinton }
4138020Slinton return(0);
4148020Slinton }
4158020Slinton }
4168020Slinton
4178020Slinton /*
4188020Slinton * Move n bytes from src to dest.
4198020Slinton * If n is 0 move until a null is found.
4208020Slinton */
4218020Slinton
mov(src,dest,n)4228020Slinton public mov(src, dest, n)
4238020Slinton register char *src, *dest;
42430842Smckusick register int n;
4258020Slinton {
42630842Smckusick if (src == nil(char *)) {
4278020Slinton panic("mov: nil source");
42830842Smckusick }
42930842Smckusick if (dest == nil(char *)) {
4308020Slinton panic("mov: nil destination");
43130842Smckusick }
4328020Slinton if (n > 0) {
4338020Slinton for (; n != 0; n--) {
4348020Slinton *dest++ = *src++;
4358020Slinton }
4368020Slinton } else {
4378020Slinton while ((*dest++ = *src++) != '\0');
4388020Slinton }
4398020Slinton }
440