|
|
1.1 root 1: /*
2: * Copyright (c) 1983 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.1 (Berkeley) 5/31/85";
9: #endif not lint
10:
11: static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton Exp $";
12:
13: /*
14: * General purpose routines.
15: */
16:
17: #include <stdio.h>
18: #include <errno.h>
19: #include <signal.h>
20:
21: #define public
22: #define private static
23: #define and &&
24: #define or ||
25: #define not !
26: #define ord(enumcon) ((int) enumcon)
27: #define nil(type) ((type) 0)
28:
29: typedef int integer;
30: typedef enum { FALSE, TRUE } boolean;
31: typedef char *String;
32: typedef FILE *File;
33: typedef String Filename;
34:
35: #undef FILE
36:
37: String cmdname; /* name of command for error messages */
38: Filename errfilename; /* current file associated with error */
39: short errlineno; /* line number associated with error */
40:
41: /*
42: * Definitions for doing memory allocation.
43: */
44:
45: extern char *malloc();
46:
47: #define alloc(n, type) ((type *) malloc((unsigned) (n) * sizeof(type)))
48: #define dispose(p) { free((char *) p); p = 0; }
49:
50: /*
51: * Macros for doing freads + fwrites.
52: */
53:
54: #define get(fp, var) fread((char *) &(var), sizeof(var), 1, fp)
55: #define put(fp, var) fwrite((char *) &(var), sizeof(var), 1, fp)
56:
57: /*
58: * String definitions.
59: */
60:
61: extern String strcpy(), index(), rindex();
62: extern int strlen();
63:
64: #define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s)
65: #define streq(s1, s2) (strcmp(s1, s2) == 0)
66:
67: typedef int INTFUNC();
68:
69: typedef struct {
70: INTFUNC *func;
71: } ERRINFO;
72:
73: #define ERR_IGNORE ((INTFUNC *) 0)
74: #define ERR_CATCH ((INTFUNC *) 1)
75:
76: /*
77: * Call a program.
78: *
79: * Four entries:
80: *
81: * call, callv - call a program and wait for it, returning status
82: * back, backv - call a program and don't wait, returning process id
83: *
84: * The command's standard input and output are passed as FILE's.
85: */
86:
87:
88: #define MAXNARGS 1000 /* unchecked upper limit on max num of arguments */
89: #define BADEXEC 127 /* exec fails */
90:
91: #define ischild(pid) ((pid) == 0)
92:
93: /* VARARGS3 */
94: public int call(name, in, out, args)
95: String name;
96: File in;
97: File out;
98: String args;
99: {
100: String *ap, *argp;
101: String argv[MAXNARGS];
102:
103: argp = &argv[0];
104: *argp++ = name;
105: ap = &args;
106: while (*ap != nil(String)) {
107: *argp++ = *ap++;
108: }
109: *argp = nil(String);
110: return callv(name, in, out, argv);
111: }
112:
113: /* VARARGS3 */
114: public int back(name, in, out, args)
115: String name;
116: File in;
117: File out;
118: String args;
119: {
120: String *ap, *argp;
121: String argv[MAXNARGS];
122:
123: argp = &argv[0];
124: *argp++ = name;
125: ap = &args;
126: while (*ap != nil(String)) {
127: *argp++ = *ap++;
128: }
129: *argp = nil(String);
130: return backv(name, in, out, argv);
131: }
132:
133: public int callv(name, in, out, argv)
134: String name;
135: File in;
136: File out;
137: String *argv;
138: {
139: int pid, status;
140:
141: pid = backv(name, in, out, argv);
142: pwait(pid, &status);
143: return status;
144: }
145:
146: public int backv(name, in, out, argv)
147: String name;
148: File in;
149: File out;
150: String *argv;
151: {
152: int pid;
153:
154: fflush(stdout);
155: if (ischild(pid = fork())) {
156: fswap(0, fileno(in));
157: fswap(1, fileno(out));
158: onsyserr(EACCES, ERR_IGNORE);
159: execvp(name, argv);
160: _exit(BADEXEC);
161: }
162: return pid;
163: }
164:
165: /*
166: * Swap file numbers so as to redirect standard input and output.
167: */
168:
169: private fswap(oldfd, newfd)
170: int oldfd;
171: int newfd;
172: {
173: if (oldfd != newfd) {
174: close(oldfd);
175: dup(newfd);
176: close(newfd);
177: }
178: }
179:
180: /*
181: * Invoke a shell on a command line.
182: */
183:
184: #define DEF_SHELL "csh"
185:
186: public shell(s)
187: String s;
188: {
189: extern String getenv();
190: String sh;
191:
192: if ((sh = getenv("SHELL")) == nil(String)) {
193: sh = DEF_SHELL;
194: }
195: if (s != nil(String) and *s != '\0') {
196: call(sh, stdin, stdout, "-c", s, 0);
197: } else {
198: call(sh, stdin, stdout, 0);
199: }
200: }
201:
202: /*
203: * Wait for a process the right way. We wait for a particular
204: * process and if any others come along in between, we remember them
205: * in case they are eventually waited for.
206: *
207: * This routine is not very efficient when the number of processes
208: * to be remembered is large.
209: *
210: * To deal with a kernel idiosyncrasy, we keep a list on the side
211: * of "traced" processes, and do not notice them when waiting for
212: * another process.
213: */
214:
215: typedef struct pidlist {
216: int pid;
217: int status;
218: struct pidlist *next;
219: } Pidlist;
220:
221: private Pidlist *pidlist, *ptrclist, *pfind();
222:
223: public ptraced(pid)
224: int pid;
225: {
226: Pidlist *p;
227:
228: p = alloc(1, Pidlist);
229: p->pid = pid;
230: p->next = ptrclist;
231: ptrclist = p;
232: }
233:
234: public unptraced(pid)
235: int pid;
236: {
237: register Pidlist *p, *prev;
238:
239: prev = nil(Pidlist *);
240: p = ptrclist;
241: while (p != nil(Pidlist *) and p->pid != pid) {
242: prev = p;
243: p = p->next;
244: }
245: if (p != nil(Pidlist *)) {
246: if (prev == nil(Pidlist *)) {
247: ptrclist = p->next;
248: } else {
249: prev->next = p->next;
250: }
251: dispose(p);
252: }
253: }
254:
255: private boolean isptraced(pid)
256: int pid;
257: {
258: register Pidlist *p;
259:
260: p = ptrclist;
261: while (p != nil(Pidlist *) and p->pid != pid) {
262: p = p->next;
263: }
264: return (boolean) (p != nil(Pidlist *));
265: }
266:
267: public pwait(pid, statusp)
268: int pid, *statusp;
269: {
270: Pidlist *p;
271: int pnum, status;
272:
273: p = pfind(pid);
274: if (p != nil(Pidlist *)) {
275: *statusp = p->status;
276: dispose(p);
277: } else {
278: pnum = wait(&status);
279: while (pnum != pid and pnum >= 0) {
280: if (not isptraced(pnum)) {
281: p = alloc(1, Pidlist);
282: p->pid = pnum;
283: p->status = status;
284: p->next = pidlist;
285: pidlist = p;
286: }
287: pnum = wait(&status);
288: }
289: if (pnum < 0) {
290: p = pfind(pid);
291: if (p == nil(Pidlist *)) {
292: panic("pwait: pid %d not found", pid);
293: }
294: *statusp = p->status;
295: dispose(p);
296: } else {
297: *statusp = status;
298: }
299: }
300: }
301:
302: /*
303: * Look for the given process id on the pidlist.
304: *
305: * Unlink it from list if found.
306: */
307:
308: private Pidlist *pfind(pid)
309: int pid;
310: {
311: register Pidlist *p, *prev;
312:
313: prev = nil(Pidlist *);
314: for (p = pidlist; p != nil(Pidlist *); p = p->next) {
315: if (p->pid == pid) {
316: break;
317: }
318: prev = p;
319: }
320: if (p != nil(Pidlist *)) {
321: if (prev == nil(Pidlist *)) {
322: pidlist = p->next;
323: } else {
324: prev->next = p->next;
325: }
326: }
327: return p;
328: }
329:
330: /*
331: * System call error handler.
332: *
333: * The syserr routine is called when a system call is about to
334: * set the c-bit to report an error. Certain errors are caught
335: * and cause the process to print a message and immediately exit.
336: */
337:
338: extern int sys_nerr;
339: extern char *sys_errlist[];
340:
341: /*
342: * Before calling syserr, the integer errno is set to contain the
343: * number of the error. The routine "_mycerror" is a dummy which
344: * is used to force the loader to get my version of cerror rather
345: * than the usual one.
346: */
347:
348: extern int errno;
349: extern _mycerror();
350:
351: /*
352: * Initialize error information, setting defaults for handling errors.
353: */
354:
355: private ERRINFO *errinfo;
356:
357: private initErrInfo ()
358: {
359: integer i;
360:
361: errinfo = alloc(sys_nerr, ERRINFO);
362: for (i = 0; i < sys_nerr; i++) {
363: errinfo[i].func = ERR_CATCH;
364: }
365: errinfo[0].func = ERR_IGNORE;
366: errinfo[EPERM].func = ERR_IGNORE;
367: errinfo[ENOENT].func = ERR_IGNORE;
368: errinfo[ESRCH].func = ERR_IGNORE;
369: errinfo[EBADF].func = ERR_IGNORE;
370: errinfo[ENOTTY].func = ERR_IGNORE;
371: errinfo[EOPNOTSUPP].func = ERR_IGNORE;
372: }
373:
374: public syserr()
375: {
376: ERRINFO *e;
377:
378: if (errno < 0 or errno > sys_nerr) {
379: fatal("errno %d", errno);
380: } else {
381: if (errinfo == nil(ERRINFO *)) {
382: initErrInfo();
383: }
384: e = &(errinfo[errno]);
385: if (e->func == ERR_CATCH) {
386: fatal(sys_errlist[errno]);
387: } else if (e->func != ERR_IGNORE) {
388: (*e->func)();
389: }
390: }
391: }
392:
393: /*
394: * Catcherrs' purpose is to initialize the errinfo table, get this module
395: * loaded, and make sure my cerror is loaded (only applicable when this is
396: * in a library).
397: */
398:
399: public catcherrs()
400: {
401: _mycerror();
402: initErrInfo();
403: }
404:
405: /*
406: * Turn off the error catching mechanism completely by having all errors
407: * ignored. This is most useful between a fork and an exec.
408: */
409:
410: public nocatcherrs()
411: {
412: integer i;
413:
414: for (i = 0; i < sys_nerr; i++) {
415: errinfo[i].func = ERR_IGNORE;
416: }
417: }
418:
419: /*
420: * Change the action on receipt of an error.
421: */
422:
423: public onsyserr(n, f)
424: int n;
425: INTFUNC *f;
426: {
427: if (errinfo == nil(ERRINFO *)) {
428: initErrInfo();
429: }
430: errinfo[n].func = f;
431: }
432:
433: /*
434: * Print the message associated with the given signal.
435: * Like a "perror" for signals.
436: */
437:
438: public int sys_nsig = NSIG;
439:
440: public psignal(s, n)
441: String s;
442: integer n;
443: {
444: String msg;
445: integer len;
446: extern String sys_siglist[];
447:
448: if (n >= 0 and n < sys_nsig) {
449: msg = sys_siglist[n];
450: } else {
451: msg = "Unknown signal";
452: }
453: len = strlen(s);
454: if (len > 0) {
455: write(2, s, len);
456: write(2, ": ", 2);
457: }
458: write(2, msg, strlen(msg));
459: write(2, "\n", 1);
460: }
461:
462: /*
463: * Standard error handling routines.
464: */
465:
466: private short nerrs;
467: private short nwarnings;
468:
469: /*
470: * Main driver of error message reporting.
471: */
472:
473: /* VARARGS2 */
474: private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
475: String errname;
476: boolean shouldquit;
477: String s;
478: {
479: fflush(stdout);
480: if (shouldquit and cmdname != nil(String)) {
481: fprintf(stderr, "%s: ", cmdname);
482: }
483: if (errfilename != nil(Filename)) {
484: fprintf(stderr, "%s: ", errfilename);
485: }
486: if (errlineno > 0) {
487: fprintf(stderr, "%d: ", errlineno);
488: }
489: if (errname != nil(String)) {
490: fprintf(stderr, "%s: ", errname);
491: }
492: fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
493: putc('\n', stderr);
494: if (shouldquit) {
495: quit(1);
496: }
497: }
498:
499: /*
500: * For when printf isn't sufficient for printing the error message ...
501: */
502:
503: public beginerrmsg()
504: {
505: fflush(stdout);
506: if (errfilename != nil(String)) {
507: fprintf(stderr, "%s: ", errfilename);
508: }
509: if (errlineno > 0) {
510: fprintf(stderr, "%d: ", errlineno);
511: }
512: }
513:
514: public enderrmsg()
515: {
516: putc('\n', stderr);
517: erecover();
518: }
519:
520: /*
521: * The messages are listed in increasing order of seriousness.
522: *
523: * First are warnings.
524: */
525:
526: /* VARARGS1 */
527: public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
528: String s;
529: {
530: nwarnings++;
531: errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
532: }
533:
534: /*
535: * Errors are a little worse, they mean something is wrong,
536: * but not so bad that processing can't continue.
537: *
538: * The routine "erecover" is called to recover from the error,
539: * a default routine is provided that does nothing.
540: */
541:
542: /* VARARGS1 */
543: public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
544: String s;
545: {
546: extern erecover();
547:
548: nerrs++;
549: errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
550: erecover();
551: }
552:
553: /*
554: * Non-recoverable user error.
555: */
556:
557: /* VARARGS1 */
558: public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
559: String s;
560: {
561: errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
562: }
563:
564: /*
565: * Panics indicate an internal program error.
566: */
567:
568: /* VARARGS1 */
569: public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
570: String s;
571: {
572: errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
573: }
574:
575: short numerrors()
576: {
577: short r;
578:
579: r = nerrs;
580: nerrs = 0;
581: return r;
582: }
583:
584: short numwarnings()
585: {
586: short r;
587:
588: r = nwarnings;
589: nwarnings = 0;
590: return r;
591: }
592:
593: /*
594: * Recover from an error.
595: *
596: * This is the default routine which we aren't using since we have our own.
597: *
598: public erecover()
599: {
600: }
601: *
602: */
603:
604: /*
605: * Default way to quit from a program is just to exit.
606: *
607: public quit(r)
608: int r;
609: {
610: exit(r);
611: }
612: *
613: */
614:
615: /*
616: * Compare n-byte areas pointed to by s1 and s2
617: * if n is 0 then compare up until one has a null byte.
618: */
619:
620: public int cmp(s1, s2, n)
621: register char *s1, *s2;
622: register unsigned int n;
623: {
624: if (s1 == nil(char *) || s2 == nil(char *)) {
625: panic("cmp: nil pointer");
626: }
627: if (n == 0) {
628: while (*s1 == *s2++) {
629: if (*s1++ == '\0') {
630: return(0);
631: }
632: }
633: return(*s1 - *(s2-1));
634: } else {
635: for (; n != 0; n--) {
636: if (*s1++ != *s2++) {
637: return(*(s1-1) - *(s2-1));
638: }
639: }
640: return(0);
641: }
642: }
643:
644: /*
645: * Move n bytes from src to dest.
646: * If n is 0 move until a null is found.
647: */
648:
649: public mov(src, dest, n)
650: register char *src, *dest;
651: register unsigned int n;
652: {
653: if (src == nil(char *))
654: panic("mov: nil source");
655: if (dest == nil(char *))
656: panic("mov: nil destination");
657: if (n != 0) {
658: for (; n != 0; n--) {
659: *dest++ = *src++;
660: }
661: } else {
662: while ((*dest++ = *src++) != '\0');
663: }
664: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.