|
|
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.2 (Berkeley) 1/12/88";
9: #endif not lint
10:
11: static char rcsid[] = "$Header: library.c,v 1.2 87/03/25 20:50:14 donn 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: IntFunc *onsyserr();
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 1000 /* 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: * Initialize error information, setting defaults for handling errors.
355: */
356:
357: private ErrInfo *errinfo;
358:
359: private initErrInfo ()
360: {
361: integer i;
362:
363: errinfo = alloc(sys_nerr, ErrInfo);
364: for (i = 0; i < sys_nerr; i++) {
365: errinfo[i].func = ERR_CATCH;
366: }
367: errinfo[0].func = ERR_IGNORE;
368: errinfo[EPERM].func = ERR_IGNORE;
369: errinfo[ENOENT].func = ERR_IGNORE;
370: errinfo[ESRCH].func = ERR_IGNORE;
371: errinfo[EBADF].func = ERR_IGNORE;
372: errinfo[ENOTTY].func = ERR_IGNORE;
373: errinfo[EOPNOTSUPP].func = ERR_IGNORE;
374: }
375:
376: public syserr()
377: {
378: register ErrInfo *e;
379:
380: if (errno < 0 or errno > sys_nerr) {
381: fatal("errno %d", errno);
382: } else {
383: if (errinfo == nil(ErrInfo *)) {
384: initErrInfo();
385: }
386: e = &(errinfo[errno]);
387: if (e->func == ERR_CATCH) {
388: fatal(sys_errlist[errno]);
389: } else if (e->func != ERR_IGNORE) {
390: (*e->func)();
391: }
392: }
393: }
394:
395: /*
396: * Catcherrs' purpose is to initialize the errinfo table, get this module
397: * loaded, and make sure my cerror is loaded (only applicable when this is
398: * in a library).
399: */
400:
401: public catcherrs()
402: {
403: _mycerror();
404: initErrInfo();
405: }
406:
407: /*
408: * Turn off the error catching mechanism completely by having all errors
409: * ignored. This is most useful between a fork and an exec.
410: */
411:
412: public nocatcherrs()
413: {
414: integer i;
415:
416: for (i = 0; i < sys_nerr; i++) {
417: errinfo[i].func = ERR_IGNORE;
418: }
419: }
420:
421: /*
422: * Change the action on receipt of an error, returning the previous action.
423: */
424:
425: public IntFunc *onsyserr(n, f)
426: int n;
427: IntFunc *f;
428: {
429: IntFunc *oldf;
430:
431: if (errinfo == nil(ErrInfo *)) {
432: initErrInfo();
433: }
434: oldf = errinfo[n].func;
435: errinfo[n].func = f;
436: return oldf;
437: }
438:
439: /*
440: * Print the message associated with the given signal.
441: * Like a "perror" for signals.
442: */
443:
444: #ifdef SIGWINCH
445: public int sys_nsig = NSIG;
446: #else not 4.3 BSD
447: /*
448: * This table is correct for 4.2-like systems but will
449: * be inadequate for System V (which is the sort of
450: * Unix that needs it!).
451: */
452: public String sys_siglist[] = {
453: "no signal",
454: "hangup",
455: "interrupt",
456: "quit",
457: "illegal instruction",
458: "trace trap",
459: "IOT instruction",
460: "EMT instruction",
461: "floating point exception",
462: "kill",
463: "bus error",
464: "segmentation violation",
465: "bad argument to system call",
466: "broken pipe",
467: "alarm clock",
468: "soft kill",
469: "urgent I/O condition",
470: "stop signal not from tty",
471: "stop signal from tty",
472: "continue",
473: "child termination",
474: "stop (tty input)",
475: "stop (tty output)",
476: "possible input/output",
477: "exceeded CPU time limit",
478: "exceeded file size limit"
479: };
480: public int sys_nsig = sizeof sys_siglist / sizeof sys_siglist[0];
481: #endif
482:
483: public psignal(s, n)
484: String s;
485: integer n;
486: {
487: String msg;
488: integer len;
489: extern String sys_siglist[];
490:
491: if (n >= 0 and n < sys_nsig) {
492: msg = sys_siglist[n];
493: } else {
494: msg = "Unknown signal";
495: }
496: len = strlen(s);
497: if (len > 0) {
498: write(2, s, len);
499: write(2, ": ", 2);
500: }
501: write(2, msg, strlen(msg));
502: write(2, "\n", 1);
503: }
504:
505: /*
506: * Standard error handling routines.
507: */
508:
509: private short nerrs;
510: private short nwarnings;
511:
512: /*
513: * Main driver of error message reporting.
514: */
515:
516: /* VARARGS2 */
517: private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
518: String errname;
519: boolean shouldquit;
520: String s;
521: {
522: fflush(stdout);
523: if (shouldquit and cmdname != nil(String)) {
524: fprintf(stderr, "%s: ", cmdname);
525: }
526: if (errfilename != nil(Filename)) {
527: fprintf(stderr, "%s: ", errfilename);
528: }
529: if (errlineno > 0) {
530: fprintf(stderr, "%d: ", errlineno);
531: }
532: if (errname != nil(String)) {
533: fprintf(stderr, "%s: ", errname);
534: }
535: fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
536: putc('\n', stderr);
537: fflush(stderr);
538: if (shouldquit) {
539: quit(1);
540: }
541: }
542:
543: /*
544: * For when printf isn't sufficient for printing the error message ...
545: */
546:
547: public beginerrmsg()
548: {
549: fflush(stdout);
550: if (errfilename != nil(String)) {
551: fprintf(stderr, "%s: ", errfilename);
552: }
553: if (errlineno > 0) {
554: fprintf(stderr, "%d: ", errlineno);
555: }
556: }
557:
558: public enderrmsg()
559: {
560: putc('\n', stderr);
561: fflush(stderr);
562: erecover();
563: }
564:
565: /*
566: * The messages are listed in increasing order of seriousness.
567: *
568: * First are warnings.
569: */
570:
571: /* VARARGS1 */
572: public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
573: String s;
574: {
575: nwarnings++;
576: errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
577: }
578:
579: /*
580: * Errors are a little worse, they mean something is wrong,
581: * but not so bad that processing can't continue.
582: *
583: * The routine "erecover" is called to recover from the error,
584: * a default routine is provided that does nothing.
585: */
586:
587: /* VARARGS1 */
588: public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
589: String s;
590: {
591: extern erecover();
592:
593: nerrs++;
594: errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
595: erecover();
596: }
597:
598: /*
599: * Non-recoverable user error.
600: */
601:
602: /* VARARGS1 */
603: public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
604: String s;
605: {
606: errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
607: }
608:
609: /*
610: * Panics indicate an internal program error.
611: */
612:
613: /* VARARGS1 */
614: public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
615: String s;
616: {
617: errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
618: }
619:
620: short numerrors()
621: {
622: short r;
623:
624: r = nerrs;
625: nerrs = 0;
626: return r;
627: }
628:
629: short numwarnings()
630: {
631: short r;
632:
633: r = nwarnings;
634: nwarnings = 0;
635: return r;
636: }
637:
638: /*
639: * Recover from an error.
640: *
641: * This is the default routine which we aren't using since we have our own.
642: *
643: public erecover()
644: {
645: }
646: *
647: */
648:
649: /*
650: * Default way to quit from a program is just to exit.
651: *
652: public quit(r)
653: int r;
654: {
655: exit(r);
656: }
657: *
658: */
659:
660: /*
661: * Compare n-byte areas pointed to by s1 and s2
662: * if n is 0 then compare up until one has a null byte.
663: */
664:
665: public int cmp(s1, s2, n)
666: register char *s1, *s2;
667: register unsigned int n;
668: {
669: if (s1 == nil(char *) || s2 == nil(char *)) {
670: panic("cmp: nil pointer");
671: }
672: if (n == 0) {
673: while (*s1 == *s2++) {
674: if (*s1++ == '\0') {
675: return(0);
676: }
677: }
678: return(*s1 - *(s2-1));
679: } else {
680: for (; n != 0; n--) {
681: if (*s1++ != *s2++) {
682: return(*(s1-1) - *(s2-1));
683: }
684: }
685: return(0);
686: }
687: }
688:
689: /*
690: * Move n bytes from src to dest.
691: * If n is 0 move until a null is found.
692: */
693:
694: public mov(src, dest, n)
695: register char *src, *dest;
696: register unsigned int n;
697: {
698: if (src == nil(char *))
699: panic("mov: nil source");
700: if (dest == nil(char *))
701: panic("mov: nil destination");
702: if (n != 0) {
703: for (; n != 0; n--) {
704: *dest++ = *src++;
705: }
706: } else {
707: while ((*dest++ = *src++) != '\0');
708: }
709: }
710:
711: #ifdef IRIS /* or in general for 4.2 - System V C library interface */
712:
713: public bcopy (fromaddr, toaddr, n)
714: char *fromaddr, *toaddr;
715: int n;
716: {
717: blt(toaddr, fromaddr, n);
718: }
719:
720: public bzero (addr, n)
721: char *addr;
722: int n;
723: {
724: register char *p, *q;
725:
726: p = addr;
727: q = p + n;
728: while (p < q) {
729: *p++ = '\0';
730: }
731: }
732:
733: #include <string.h>
734:
735: public char *index (s, c)
736: char *s, c;
737: {
738: return strchr(s, c);
739: }
740:
741: public char *rindex (s, c)
742: char *s, c;
743: {
744: return strrchr(s, c);
745: }
746:
747: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.