|
|
1.1 root 1: /*
2: * Copyright (c) 1982 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)library.c 5.2 (Berkeley) 4/7/87";
9: #endif not lint
10:
11: /*
12: * General purpose routines.
13: */
14:
15: #include <stdio.h>
16: #include <errno.h>
17: #include "defs.h"
18:
19: #define public
20: #define private static
21: #define and &&
22: #define nil(type) ((type) 0)
23:
24: typedef char *String;
25: typedef FILE *File;
26: typedef String Filename;
27: typedef char Boolean;
28:
29: #undef FILE
30:
31: String cmdname; /* name of command for error messages */
32: Filename errfilename; /* current file associated with error */
33: short errlineno; /* line number associated with error */
34:
35: typedef int INTFUNC();
36:
37: typedef struct {
38: INTFUNC *func;
39: } ERRINFO;
40:
41: #define ERR_IGNORE ((INTFUNC *) 0)
42: #define ERR_CATCH ((INTFUNC *) 1)
43:
44: public INTFUNC *onsyserr();
45:
46: /*
47: * Call a program.
48: *
49: * Three entries:
50: *
51: * call, callv - call a program and wait for it, returning status
52: * backv - call a program and don't wait, returning process id
53: *
54: * The command's standard input and output are passed as FILE's.
55: */
56:
57:
58: #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */
59: #define BADEXEC 127 /* exec fails */
60:
61: #define ischild(pid) ((pid) == 0)
62:
63: /* VARARGS3 */
64: public int call(name, in, out, args)
65: String name;
66: File in;
67: File out;
68: String args;
69: {
70: String *ap, *argp;
71: String argv[MAXNARGS];
72:
73: argp = &argv[0];
74: *argp++ = name;
75: ap = &args;
76: while (*ap != nil(String)) {
77: *argp++ = *ap++;
78: }
79: *argp = nil(String);
80: return callv(name, in, out, argv);
81: }
82:
83: public int callv(name, in, out, argv)
84: String name;
85: File in;
86: File out;
87: String *argv;
88: {
89: int pid, status;
90:
91: pid = backv(name, in, out, argv);
92: pwait(pid, &status);
93: return status;
94: }
95:
96: public int backv(name, in, out, argv)
97: String name;
98: File in;
99: File out;
100: String *argv;
101: {
102: int pid;
103:
104: fflush(stdout);
105: if (ischild(pid = fork())) {
106: fswap(0, fileno(in));
107: fswap(1, fileno(out));
108: (void) onsyserr(EACCES, ERR_IGNORE);
109: execvp(name, argv);
110: _exit(BADEXEC);
111: }
112: return pid;
113: }
114:
115: /*
116: * Swap file numbers so as to redirect standard input and output.
117: */
118:
119: private fswap(oldfd, newfd)
120: int oldfd;
121: int newfd;
122: {
123: if (oldfd != newfd) {
124: close(oldfd);
125: dup(newfd);
126: close(newfd);
127: }
128: }
129:
130: /*
131: * Invoke a shell on a command line.
132: */
133:
134: #define DEF_SHELL "csh"
135:
136: public shell(s)
137: String s;
138: {
139: extern String getenv();
140: String sh;
141:
142: if ((sh = getenv("SHELL")) == nil(String)) {
143: sh = DEF_SHELL;
144: }
145: call(sh, stdin, stdout, "-c", s, 0);
146: }
147:
148: /*
149: * Wait for a process the right way. We wait for a particular
150: * process and if any others come along in between, we remember them
151: * in case they are eventually waited for.
152: *
153: * This routine is not very efficient when the number of processes
154: * to be remembered is large.
155: */
156:
157: typedef struct pidlist {
158: int pid;
159: int status;
160: struct pidlist *next;
161: } Pidlist;
162:
163: private Pidlist *pidlist, *pfind();
164:
165: public pwait(pid, statusp)
166: int pid, *statusp;
167: {
168: Pidlist *p;
169: int pnum, status;
170:
171: p = pfind(pid);
172: if (p != nil(Pidlist *)) {
173: *statusp = p->status;
174: dispose(p);
175: return;
176: }
177: while ((pnum = wait(&status)) != pid && pnum >= 0) {
178: p = alloc(1, Pidlist);
179: p->pid = pnum;
180: p->status = status;
181: p->next = pidlist;
182: pidlist = p;
183: }
184: if (pnum < 0) {
185: p = pfind(pid);
186: if (p == nil(Pidlist *)) {
187: panic("pwait: pid %d not found", pid);
188: }
189: *statusp = p->status;
190: dispose(p);
191: } else {
192: *statusp = status;
193: }
194: #ifdef tahoe
195: chkret(p, status);
196: #endif
197: }
198:
199: /*
200: * Look for the given process id on the pidlist.
201: *
202: * Unlink it from list if found.
203: */
204:
205: private Pidlist *pfind(pid)
206: int pid;
207: {
208: register Pidlist *p, *prev;
209:
210: prev = nil(Pidlist *);
211: for (p = pidlist; p != nil(Pidlist *); p = p->next) {
212: if (p->pid == pid) {
213: break;
214: }
215: prev = p;
216: }
217: if (p != nil(Pidlist *)) {
218: if (prev == nil(Pidlist *)) {
219: pidlist = p->next;
220: } else {
221: prev->next = p->next;
222: }
223: }
224: return p;
225: }
226:
227: /*
228: * System call error handler.
229: *
230: * The syserr routine is called when a system call is about to
231: * set the c-bit to report an error. Certain errors are caught
232: * and cause the process to print a message and immediately exit.
233: */
234:
235: extern int sys_nerr;
236: extern char *sys_errlist[];
237:
238: /*
239: * Before calling syserr, the integer errno is set to contain the
240: * number of the error.
241: */
242:
243: extern int errno;
244:
245: /*
246: * default error handling
247: */
248:
249: private ERRINFO errinfo[] ={
250: /* no error */ ERR_IGNORE,
251: /* EPERM */ ERR_IGNORE,
252: /* ENOENT */ ERR_IGNORE,
253: /* ESRCH */ ERR_IGNORE,
254: /* EINTR */ ERR_CATCH,
255: /* EIO */ ERR_CATCH,
256: /* ENXIO */ ERR_CATCH,
257: /* E2BIG */ ERR_CATCH,
258: /* ENOEXEC */ ERR_CATCH,
259: /* EBADF */ ERR_IGNORE,
260: /* ECHILD */ ERR_CATCH,
261: /* EAGAIN */ ERR_CATCH,
262: /* ENOMEM */ ERR_CATCH,
263: /* EACCES */ ERR_CATCH,
264: /* EFAULT */ ERR_CATCH,
265: /* ENOTBLK */ ERR_CATCH,
266: /* EBUSY */ ERR_CATCH,
267: /* EEXIST */ ERR_CATCH,
268: /* EXDEV */ ERR_CATCH,
269: /* ENODEV */ ERR_CATCH,
270: /* ENOTDIR */ ERR_CATCH,
271: /* EISDIR */ ERR_CATCH,
272: /* EINVAL */ ERR_CATCH,
273: /* ENFILE */ ERR_CATCH,
274: /* EMFILE */ ERR_CATCH,
275: /* ENOTTY */ ERR_IGNORE,
276: /* ETXTBSY */ ERR_CATCH,
277: /* EFBIG */ ERR_CATCH,
278: /* ENOSPC */ ERR_CATCH,
279: /* ESPIPE */ ERR_CATCH,
280: /* EROFS */ ERR_CATCH,
281: /* EMLINK */ ERR_CATCH,
282: /* EPIPE */ ERR_CATCH,
283: /* EDOM */ ERR_CATCH,
284: /* ERANGE */ ERR_CATCH,
285: /* EQUOT */ ERR_CATCH,
286: };
287:
288: public syserr()
289: {
290: ERRINFO *e;
291:
292: e = &errinfo[errno];
293: if (e->func == ERR_CATCH) {
294: if (errno < sys_nerr) {
295: panic(sys_errlist[errno]);
296: } else {
297: panic("errno %d", errno);
298: }
299: } else if (e->func != ERR_IGNORE) {
300: (*e->func)();
301: }
302: }
303:
304: /*
305: * Change the action on receipt of an error.
306: */
307:
308: public INTFUNC *onsyserr(n, f)
309: int n;
310: INTFUNC *f;
311: {
312: INTFUNC *g = errinfo[n].func;
313:
314: errinfo[n].func = f;
315: return(g);
316: }
317:
318: /*
319: * Main driver of error message reporting.
320: */
321:
322: /* VARARGS2 */
323: private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
324: String errname;
325: Boolean shouldquit;
326: String s;
327: {
328: fflush(stdout);
329: if (shouldquit and cmdname != nil(String)) {
330: fprintf(stderr, "%s: ", cmdname);
331: }
332: if (errfilename != nil(Filename)) {
333: fprintf(stderr, "%s: ", errfilename);
334: }
335: if (errlineno > 0) {
336: fprintf(stderr, "%d: ", errlineno);
337: }
338: if (errname != nil(String)) {
339: fprintf(stderr, "%s: ", errname);
340: }
341: fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
342: putc('\n', stderr);
343: if (shouldquit) {
344: quit(1);
345: }
346: }
347:
348: /*
349: * Errors are a little worse, they mean something is wrong,
350: * but not so bad that processing can't continue.
351: *
352: * The routine "erecover" is called to recover from the error,
353: * a default routine is provided that does nothing.
354: */
355:
356: /* VARARGS1 */
357: public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
358: String s;
359: {
360: extern erecover();
361:
362: errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
363: erecover();
364: }
365:
366: /*
367: * Non-recoverable user error.
368: */
369:
370: /* VARARGS1 */
371: public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
372: String s;
373: {
374: errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
375: }
376:
377: /*
378: * Panics indicate an internal program error.
379: */
380:
381: /* VARARGS1 */
382: public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
383: String s;
384: {
385: errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
386: }
387:
388: /*
389: * Compare n-byte areas pointed to by s1 and s2
390: * if n is 0 then compare up until one has a null byte.
391: */
392:
393: public int cmp(s1, s2, n)
394: register char *s1, *s2;
395: register unsigned int n;
396: {
397: if (s1 == nil(char *) || s2 == nil(char *)) {
398: panic("cmp: nil pointer");
399: }
400: if (n == 0) {
401: while (*s1 == *s2++) {
402: if (*s1++ == '\0') {
403: return(0);
404: }
405: }
406: return(*s1 - *(s2-1));
407: } else {
408: for (; n != 0; n--) {
409: if (*s1++ != *s2++) {
410: return(*(s1-1) - *(s2-1));
411: }
412: }
413: return(0);
414: }
415: }
416:
417: /*
418: * Move n bytes from src to dest.
419: * If n is 0 move until a null is found.
420: */
421:
422: public mov(src, dest, n)
423: register char *src, *dest;
424: register int n;
425: {
426: if (src == nil(char *)) {
427: panic("mov: nil source");
428: }
429: if (dest == nil(char *)) {
430: panic("mov: nil destination");
431: }
432: if (n > 0) {
433: for (; n != 0; n--) {
434: *dest++ = *src++;
435: }
436: } else {
437: while ((*dest++ = *src++) != '\0');
438: }
439: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.