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