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