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