122759Smckusick /* 222759Smckusick * Copyright (c) 1982 Regents of the University of California. 322759Smckusick * All rights reserved. The Berkeley software License Agreement 422759Smckusick * specifies the terms and conditions for redistribution. 522759Smckusick */ 68020Slinton 722759Smckusick #ifndef lint 8*30842Smckusick static char sccsid[] = "@(#)library.c 5.2 (Berkeley) 04/07/87"; 922759Smckusick #endif not lint 108020Slinton 118020Slinton /* 128020Slinton * General purpose routines. 138020Slinton */ 148020Slinton 158020Slinton #include <stdio.h> 168020Slinton #include <errno.h> 17*30842Smckusick #include "defs.h" 188020Slinton 198020Slinton #define public 208020Slinton #define private static 218020Slinton #define and && 228020Slinton #define nil(type) ((type) 0) 238020Slinton 248020Slinton typedef char *String; 258020Slinton typedef FILE *File; 268020Slinton typedef String Filename; 27*30842Smckusick typedef char Boolean; 288020Slinton 298020Slinton #undef FILE 308020Slinton 318020Slinton String cmdname; /* name of command for error messages */ 328020Slinton Filename errfilename; /* current file associated with error */ 338020Slinton short errlineno; /* line number associated with error */ 348020Slinton 358020Slinton typedef int INTFUNC(); 368020Slinton 378020Slinton typedef struct { 388020Slinton INTFUNC *func; 398020Slinton } ERRINFO; 408020Slinton 418020Slinton #define ERR_IGNORE ((INTFUNC *) 0) 428020Slinton #define ERR_CATCH ((INTFUNC *) 1) 438020Slinton 44*30842Smckusick public INTFUNC *onsyserr(); 45*30842Smckusick 468020Slinton /* 478020Slinton * Call a program. 488020Slinton * 49*30842Smckusick * Three entries: 508020Slinton * 518020Slinton * call, callv - call a program and wait for it, returning status 52*30842Smckusick * backv - call a program and don't wait, returning process id 538020Slinton * 548020Slinton * The command's standard input and output are passed as FILE's. 558020Slinton */ 568020Slinton 578020Slinton 588020Slinton #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */ 598020Slinton #define BADEXEC 127 /* exec fails */ 608020Slinton 618020Slinton #define ischild(pid) ((pid) == 0) 628020Slinton 638020Slinton /* VARARGS3 */ 648020Slinton public int call(name, in, out, args) 658020Slinton String name; 668020Slinton File in; 678020Slinton File out; 688020Slinton String args; 698020Slinton { 708020Slinton String *ap, *argp; 718020Slinton String argv[MAXNARGS]; 728020Slinton 738020Slinton argp = &argv[0]; 748020Slinton *argp++ = name; 758020Slinton ap = &args; 768020Slinton while (*ap != nil(String)) { 778020Slinton *argp++ = *ap++; 788020Slinton } 798020Slinton *argp = nil(String); 808020Slinton return callv(name, in, out, argv); 818020Slinton } 828020Slinton 838020Slinton public int callv(name, in, out, argv) 848020Slinton String name; 858020Slinton File in; 868020Slinton File out; 878020Slinton String *argv; 888020Slinton { 898020Slinton int pid, status; 908020Slinton 918020Slinton pid = backv(name, in, out, argv); 928020Slinton pwait(pid, &status); 938020Slinton return status; 948020Slinton } 958020Slinton 968020Slinton public int backv(name, in, out, argv) 978020Slinton String name; 988020Slinton File in; 998020Slinton File out; 1008020Slinton String *argv; 1018020Slinton { 1028020Slinton int pid; 1038020Slinton 1048020Slinton fflush(stdout); 1058020Slinton if (ischild(pid = fork())) { 1068020Slinton fswap(0, fileno(in)); 1078020Slinton fswap(1, fileno(out)); 108*30842Smckusick (void) onsyserr(EACCES, ERR_IGNORE); 1098020Slinton execvp(name, argv); 1108020Slinton _exit(BADEXEC); 1118020Slinton } 1128020Slinton return pid; 1138020Slinton } 1148020Slinton 1158020Slinton /* 1168020Slinton * Swap file numbers so as to redirect standard input and output. 1178020Slinton */ 1188020Slinton 1198020Slinton private fswap(oldfd, newfd) 1208020Slinton int oldfd; 1218020Slinton int newfd; 1228020Slinton { 1238020Slinton if (oldfd != newfd) { 1248020Slinton close(oldfd); 1258020Slinton dup(newfd); 1268020Slinton close(newfd); 1278020Slinton } 1288020Slinton } 1298020Slinton 1308020Slinton /* 1318020Slinton * Invoke a shell on a command line. 1328020Slinton */ 1338020Slinton 1348020Slinton #define DEF_SHELL "csh" 1358020Slinton 1368020Slinton public shell(s) 1378020Slinton String s; 1388020Slinton { 1398020Slinton extern String getenv(); 1408020Slinton String sh; 1418020Slinton 1428020Slinton if ((sh = getenv("SHELL")) == nil(String)) { 1438020Slinton sh = DEF_SHELL; 1448020Slinton } 1458020Slinton call(sh, stdin, stdout, "-c", s, 0); 1468020Slinton } 1478020Slinton 1488020Slinton /* 1498020Slinton * Wait for a process the right way. We wait for a particular 1508020Slinton * process and if any others come along in between, we remember them 1518020Slinton * in case they are eventually waited for. 1528020Slinton * 1538020Slinton * This routine is not very efficient when the number of processes 1548020Slinton * to be remembered is large. 1558020Slinton */ 1568020Slinton 1578020Slinton typedef struct pidlist { 1588020Slinton int pid; 1598020Slinton int status; 1608020Slinton struct pidlist *next; 1618020Slinton } Pidlist; 1628020Slinton 1638020Slinton private Pidlist *pidlist, *pfind(); 1648020Slinton 1658020Slinton public pwait(pid, statusp) 1668020Slinton int pid, *statusp; 1678020Slinton { 1688020Slinton Pidlist *p; 1698020Slinton int pnum, status; 1708020Slinton 1718020Slinton p = pfind(pid); 1728020Slinton if (p != nil(Pidlist *)) { 1738020Slinton *statusp = p->status; 1748020Slinton dispose(p); 1758020Slinton return; 1768020Slinton } 1778020Slinton while ((pnum = wait(&status)) != pid && pnum >= 0) { 1788020Slinton p = alloc(1, Pidlist); 1798020Slinton p->pid = pnum; 1808020Slinton p->status = status; 1818020Slinton p->next = pidlist; 1828020Slinton pidlist = p; 1838020Slinton } 1848020Slinton if (pnum < 0) { 1858020Slinton p = pfind(pid); 1868020Slinton if (p == nil(Pidlist *)) { 1878020Slinton panic("pwait: pid %d not found", pid); 1888020Slinton } 1898020Slinton *statusp = p->status; 1908020Slinton dispose(p); 1918020Slinton } else { 192*30842Smckusick *statusp = status; 1938020Slinton } 194*30842Smckusick #ifdef tahoe 195*30842Smckusick chkret(p, status); 196*30842Smckusick #endif 1978020Slinton } 1988020Slinton 1998020Slinton /* 2008020Slinton * Look for the given process id on the pidlist. 2018020Slinton * 2028020Slinton * Unlink it from list if found. 2038020Slinton */ 2048020Slinton 2058020Slinton private Pidlist *pfind(pid) 2068020Slinton int pid; 2078020Slinton { 2088020Slinton register Pidlist *p, *prev; 2098020Slinton 2108020Slinton prev = nil(Pidlist *); 2118020Slinton for (p = pidlist; p != nil(Pidlist *); p = p->next) { 2128020Slinton if (p->pid == pid) { 2138020Slinton break; 2148020Slinton } 2158020Slinton prev = p; 2168020Slinton } 2178020Slinton if (p != nil(Pidlist *)) { 2188020Slinton if (prev == nil(Pidlist *)) { 219*30842Smckusick pidlist = p->next; 2208020Slinton } else { 221*30842Smckusick prev->next = p->next; 2228020Slinton } 2238020Slinton } 2248020Slinton return p; 2258020Slinton } 2268020Slinton 2278020Slinton /* 2288020Slinton * System call error handler. 2298020Slinton * 2308020Slinton * The syserr routine is called when a system call is about to 2318020Slinton * set the c-bit to report an error. Certain errors are caught 2328020Slinton * and cause the process to print a message and immediately exit. 2338020Slinton */ 2348020Slinton 2358020Slinton extern int sys_nerr; 2368020Slinton extern char *sys_errlist[]; 2378020Slinton 2388020Slinton /* 2398020Slinton * Before calling syserr, the integer errno is set to contain the 240*30842Smckusick * 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 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 308*30842Smckusick public INTFUNC *onsyserr(n, f) 3098020Slinton int n; 3108020Slinton INTFUNC *f; 3118020Slinton { 312*30842Smckusick INTFUNC *g = errinfo[n].func; 313*30842Smckusick 3148020Slinton errinfo[n].func = f; 315*30842Smckusick return(g); 3168020Slinton } 3178020Slinton 3188020Slinton /* 3198020Slinton * Main driver of error message reporting. 3208020Slinton */ 3218020Slinton 3228020Slinton /* VARARGS2 */ 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 */ 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 */ 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 */ 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 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 4228020Slinton public mov(src, dest, n) 4238020Slinton register char *src, *dest; 424*30842Smckusick register int n; 4258020Slinton { 426*30842Smckusick if (src == nil(char *)) { 4278020Slinton panic("mov: nil source"); 428*30842Smckusick } 429*30842Smckusick if (dest == nil(char *)) { 4308020Slinton panic("mov: nil destination"); 431*30842Smckusick } 4328020Slinton if (n > 0) { 4338020Slinton for (; n != 0; n--) { 4348020Slinton *dest++ = *src++; 4358020Slinton } 4368020Slinton } else { 4378020Slinton while ((*dest++ = *src++) != '\0'); 4388020Slinton } 4398020Slinton } 440