148104Sbostic /*- 2*62131Sbostic * Copyright (c) 1982, 1993 3*62131Sbostic * The Regents of the University of California. All rights reserved. 448104Sbostic * 548104Sbostic * %sccs.include.redist.c% 622759Smckusick */ 78020Slinton 822759Smckusick #ifndef lint 9*62131Sbostic static char sccsid[] = "@(#)library.c 8.1 (Berkeley) 06/06/93"; 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 */ 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 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 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 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 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 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 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 extern char *sys_errlist[]; 2388020Slinton 2398020Slinton /* 2408020Slinton * Before calling syserr, the integer errno is set to contain the 24130842Smckusick * number of the error. 2428020Slinton */ 2438020Slinton 2448020Slinton extern int errno; 2458020Slinton 2468020Slinton /* 2478020Slinton * default error handling 2488020Slinton */ 2498020Slinton 2508020Slinton private ERRINFO errinfo[] ={ 2518020Slinton /* no error */ ERR_IGNORE, 2528020Slinton /* EPERM */ ERR_IGNORE, 2538020Slinton /* ENOENT */ ERR_IGNORE, 2548020Slinton /* ESRCH */ ERR_IGNORE, 2558020Slinton /* EINTR */ ERR_CATCH, 2568020Slinton /* EIO */ ERR_CATCH, 2578020Slinton /* ENXIO */ ERR_CATCH, 2588020Slinton /* E2BIG */ ERR_CATCH, 2598020Slinton /* ENOEXEC */ ERR_CATCH, 2608020Slinton /* EBADF */ ERR_IGNORE, 2618020Slinton /* ECHILD */ ERR_CATCH, 2628020Slinton /* EAGAIN */ ERR_CATCH, 2638020Slinton /* ENOMEM */ ERR_CATCH, 2648020Slinton /* EACCES */ ERR_CATCH, 2658020Slinton /* EFAULT */ ERR_CATCH, 2668020Slinton /* ENOTBLK */ ERR_CATCH, 2678020Slinton /* EBUSY */ ERR_CATCH, 2688020Slinton /* EEXIST */ ERR_CATCH, 2698020Slinton /* EXDEV */ ERR_CATCH, 2708020Slinton /* ENODEV */ ERR_CATCH, 2718020Slinton /* ENOTDIR */ ERR_CATCH, 2728020Slinton /* EISDIR */ ERR_CATCH, 2738020Slinton /* EINVAL */ ERR_CATCH, 2748020Slinton /* ENFILE */ ERR_CATCH, 2758020Slinton /* EMFILE */ ERR_CATCH, 2768020Slinton /* ENOTTY */ ERR_IGNORE, 2778020Slinton /* ETXTBSY */ ERR_CATCH, 2788020Slinton /* EFBIG */ ERR_CATCH, 2798020Slinton /* ENOSPC */ ERR_CATCH, 2808020Slinton /* ESPIPE */ ERR_CATCH, 2818020Slinton /* EROFS */ ERR_CATCH, 2828020Slinton /* EMLINK */ ERR_CATCH, 2838020Slinton /* EPIPE */ ERR_CATCH, 2848020Slinton /* EDOM */ ERR_CATCH, 2858020Slinton /* ERANGE */ ERR_CATCH, 2868020Slinton /* EQUOT */ ERR_CATCH, 2878020Slinton }; 2888020Slinton 2898020Slinton public syserr() 2908020Slinton { 2918020Slinton ERRINFO *e; 2928020Slinton 2938020Slinton e = &errinfo[errno]; 2948020Slinton if (e->func == ERR_CATCH) { 2958020Slinton if (errno < sys_nerr) { 2968020Slinton panic(sys_errlist[errno]); 2978020Slinton } else { 2988020Slinton panic("errno %d", errno); 2998020Slinton } 3008020Slinton } else if (e->func != ERR_IGNORE) { 3018020Slinton (*e->func)(); 3028020Slinton } 3038020Slinton } 3048020Slinton 3058020Slinton /* 3068020Slinton * Change the action on receipt of an error. 3078020Slinton */ 3088020Slinton 30930842Smckusick public INTFUNC *onsyserr(n, f) 3108020Slinton int n; 3118020Slinton INTFUNC *f; 3128020Slinton { 31330842Smckusick INTFUNC *g = errinfo[n].func; 31430842Smckusick 3158020Slinton errinfo[n].func = f; 31630842Smckusick return(g); 3178020Slinton } 3188020Slinton 3198020Slinton /* 3208020Slinton * Main driver of error message reporting. 3218020Slinton */ 3228020Slinton 3238020Slinton /* VARARGS2 */ 3248020Slinton private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 3258020Slinton String errname; 3268020Slinton Boolean shouldquit; 3278020Slinton String s; 3288020Slinton { 3298020Slinton fflush(stdout); 3308020Slinton if (shouldquit and cmdname != nil(String)) { 3318020Slinton fprintf(stderr, "%s: ", cmdname); 3328020Slinton } 3338020Slinton if (errfilename != nil(Filename)) { 3348020Slinton fprintf(stderr, "%s: ", errfilename); 3358020Slinton } 3368020Slinton if (errlineno > 0) { 3378020Slinton fprintf(stderr, "%d: ", errlineno); 3388020Slinton } 3398020Slinton if (errname != nil(String)) { 3408020Slinton fprintf(stderr, "%s: ", errname); 3418020Slinton } 3428020Slinton fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 3438020Slinton putc('\n', stderr); 3448020Slinton if (shouldquit) { 3458020Slinton quit(1); 3468020Slinton } 3478020Slinton } 3488020Slinton 3498020Slinton /* 3508020Slinton * Errors are a little worse, they mean something is wrong, 3518020Slinton * but not so bad that processing can't continue. 3528020Slinton * 3538020Slinton * The routine "erecover" is called to recover from the error, 3548020Slinton * a default routine is provided that does nothing. 3558020Slinton */ 3568020Slinton 3578020Slinton /* VARARGS1 */ 3588020Slinton public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 3598020Slinton String s; 3608020Slinton { 3618020Slinton extern erecover(); 3628020Slinton 3638020Slinton errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 3648020Slinton erecover(); 3658020Slinton } 3668020Slinton 3678020Slinton /* 3688020Slinton * Non-recoverable user error. 3698020Slinton */ 3708020Slinton 3718020Slinton /* VARARGS1 */ 3728020Slinton public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 3738020Slinton String s; 3748020Slinton { 3758020Slinton errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 3768020Slinton } 3778020Slinton 3788020Slinton /* 3798020Slinton * Panics indicate an internal program error. 3808020Slinton */ 3818020Slinton 3828020Slinton /* VARARGS1 */ 3838020Slinton public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 3848020Slinton String s; 3858020Slinton { 3868020Slinton errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 3878020Slinton } 3888020Slinton 3898020Slinton /* 3908020Slinton * Compare n-byte areas pointed to by s1 and s2 3918020Slinton * if n is 0 then compare up until one has a null byte. 3928020Slinton */ 3938020Slinton 3948020Slinton public int cmp(s1, s2, n) 3958020Slinton register char *s1, *s2; 3968020Slinton register unsigned int n; 3978020Slinton { 3988020Slinton if (s1 == nil(char *) || s2 == nil(char *)) { 3998020Slinton panic("cmp: nil pointer"); 4008020Slinton } 4018020Slinton if (n == 0) { 4028020Slinton while (*s1 == *s2++) { 4038020Slinton if (*s1++ == '\0') { 4048020Slinton return(0); 4058020Slinton } 4068020Slinton } 4078020Slinton return(*s1 - *(s2-1)); 4088020Slinton } else { 4098020Slinton for (; n != 0; n--) { 4108020Slinton if (*s1++ != *s2++) { 4118020Slinton return(*(s1-1) - *(s2-1)); 4128020Slinton } 4138020Slinton } 4148020Slinton return(0); 4158020Slinton } 4168020Slinton } 4178020Slinton 4188020Slinton /* 4198020Slinton * Move n bytes from src to dest. 4208020Slinton * If n is 0 move until a null is found. 4218020Slinton */ 4228020Slinton 4238020Slinton public mov(src, dest, n) 4248020Slinton register char *src, *dest; 42530842Smckusick register int n; 4268020Slinton { 42730842Smckusick if (src == nil(char *)) { 4288020Slinton panic("mov: nil source"); 42930842Smckusick } 43030842Smckusick if (dest == nil(char *)) { 4318020Slinton panic("mov: nil destination"); 43230842Smckusick } 4338020Slinton if (n > 0) { 4348020Slinton for (; n != 0; n--) { 4358020Slinton *dest++ = *src++; 4368020Slinton } 4378020Slinton } else { 4388020Slinton while ((*dest++ = *src++) != '\0'); 4398020Slinton } 4408020Slinton } 441