forgot a newline in the last change (to psym)
[unix-history] / usr / src / old / dbx / library.c
CommitLineData
536150a4
ML
1/* Copyright (c) 1982 Regents of the University of California */
2
ec4f7c5c 3static char sccsid[] = "@(#)library.c 1.3 %G%";
536150a4
ML
4
5/*
6 * General purpose routines.
7 */
8
9#include <stdio.h>
10#include <errno.h>
11#include <signal.h>
12
13#define public
14#define private static
15#define and &&
16#define or ||
17#define not !
18#define ord(enumcon) ((int) enumcon)
19#define nil(type) ((type) 0)
20
21typedef enum { FALSE, TRUE } Boolean;
22typedef char *String;
23typedef FILE *File;
24typedef String Filename;
25
26#undef FILE
27
28/*
29 * Definitions of standard C library routines that aren't in the
30 * standard I/O library, but which are generally useful.
31 */
32
33extern long atol(); /* ascii to long */
34extern double atof(); /* ascii to floating point */
35extern char *mktemp(); /* make a temporary file name */
36
37String cmdname; /* name of command for error messages */
38Filename errfilename; /* current file associated with error */
39short errlineno; /* line number associated with error */
40
41/*
42 * Definitions for doing memory allocation.
43 */
44
45extern 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
61extern String strcpy(), index(), rindex();
62extern int strlen();
63
64#define strdup(s) strcpy(malloc((unsigned) strlen(s) + 1), s)
65#define streq(s1, s2) (strcmp(s1, s2) == 0)
66
67typedef int INTFUNC();
68
69typedef 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 100 /* unchecked upper limit on max num of arguments */
89#define BADEXEC 127 /* exec fails */
90
91#define ischild(pid) ((pid) == 0)
92
93/* VARARGS3 */
94public int call(name, in, out, args)
95String name;
96File in;
97File out;
98String 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 */
114public int back(name, in, out, args)
115String name;
116File in;
117File out;
118String 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
133public int callv(name, in, out, argv)
134String name;
135File in;
136File out;
137String *argv;
138{
139 int pid, status;
140
141 pid = backv(name, in, out, argv);
142 pwait(pid, &status);
143 return status;
144}
145
146public int backv(name, in, out, argv)
147String name;
148File in;
149File out;
150String *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
169private fswap(oldfd, newfd)
170int oldfd;
171int 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
186public shell(s)
187String 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.
ec4f7c5c
ML
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.
536150a4
ML
213 */
214
215typedef struct pidlist {
216 int pid;
217 int status;
218 struct pidlist *next;
219} Pidlist;
220
ec4f7c5c
ML
221private Pidlist *pidlist, *ptrclist, *pfind();
222
223public ptraced(pid)
224int pid;
225{
226 Pidlist *p;
227
228 p = alloc(1, Pidlist);
229 p->pid = pid;
230 p->next = ptrclist;
231 ptrclist = p;
232}
233
234public unptraced(pid)
235int 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
255private Boolean isptraced(pid)
256int 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}
536150a4
ML
266
267public pwait(pid, statusp)
268int pid, *statusp;
269{
b3738d36
ML
270 Pidlist *p;
271 int pnum, status;
536150a4 272
b3738d36
ML
273 p = pfind(pid);
274 if (p != nil(Pidlist *)) {
275 *statusp = p->status;
276 dispose(p);
b3738d36 277 } else {
ec4f7c5c
ML
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 }
b3738d36 299 }
536150a4
ML
300}
301
302/*
303 * Look for the given process id on the pidlist.
304 *
305 * Unlink it from list if found.
306 */
307
308private Pidlist *pfind(pid)
309int 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
338extern int sys_nerr;
339extern 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
348extern int errno;
349extern _mycerror();
350
351/*
352 * Default error handling.
353 */
354
355private ERRINFO errinfo[] ={
356/* no error */ ERR_IGNORE,
357/* EPERM */ ERR_IGNORE,
358/* ENOENT */ ERR_IGNORE,
359/* ESRCH */ ERR_IGNORE,
360/* EINTR */ ERR_CATCH,
361/* EIO */ ERR_CATCH,
362/* ENXIO */ ERR_CATCH,
363/* E2BIG */ ERR_CATCH,
364/* ENOEXEC */ ERR_CATCH,
365/* EBADF */ ERR_IGNORE,
366/* ECHILD */ ERR_CATCH,
367/* EAGAIN */ ERR_CATCH,
368/* ENOMEM */ ERR_CATCH,
369/* EACCES */ ERR_CATCH,
370/* EFAULT */ ERR_CATCH,
371/* ENOTBLK */ ERR_CATCH,
372/* EBUSY */ ERR_CATCH,
373/* EEXIST */ ERR_CATCH,
374/* EXDEV */ ERR_CATCH,
375/* ENODEV */ ERR_CATCH,
376/* ENOTDIR */ ERR_CATCH,
377/* EISDIR */ ERR_CATCH,
378/* EINVAL */ ERR_CATCH,
379/* ENFILE */ ERR_CATCH,
380/* EMFILE */ ERR_CATCH,
381/* ENOTTY */ ERR_IGNORE,
382/* ETXTBSY */ ERR_CATCH,
383/* EFBIG */ ERR_CATCH,
384/* ENOSPC */ ERR_CATCH,
385/* ESPIPE */ ERR_CATCH,
386/* EROFS */ ERR_CATCH,
387/* EMLINK */ ERR_CATCH,
388/* EPIPE */ ERR_CATCH,
389/* EDOM */ ERR_CATCH,
390/* ERANGE */ ERR_CATCH,
391/* EQUOT */ ERR_CATCH,
392};
393
394public syserr()
395{
396 ERRINFO *e;
397
398 e = &errinfo[errno];
399 if (e->func == ERR_CATCH) {
400 if (errno < sys_nerr) {
401 fatal(sys_errlist[errno]);
402 } else {
403 fatal("errno %d", errno);
404 }
405 } else if (e->func != ERR_IGNORE) {
406 (*e->func)();
407 }
408}
409
410/*
411 * Catcherrs only purpose is to get this module loaded and make
412 * sure my cerror is loaded (only applicable when this is in a library).
413 */
414
415public catcherrs()
416{
417 _mycerror();
418}
419
420/*
421 * Change the action on receipt of an error.
422 */
423
424public onsyserr(n, f)
425int n;
426INTFUNC *f;
427{
428 errinfo[n].func = f;
429}
430
431/*
432 * Print the message associated with the given signal.
433 * Like a "perror" for signals.
434 */
435
436public int sys_nsig = NSIG;
437public String sys_siglist[] = {
438 "no signal",
439 "hangup",
440 "interrupt",
441 "quit",
442 "illegal instruction",
443 "trace trap",
444 "IOT instruction",
445 "EMT instruction",
446 "floating point exception",
447 "kill",
448 "bus error",
449 "segmentation violation",
450 "bad argument to system call",
451 "broken pipe",
452 "alarm clock",
453 "soft kill",
454 "urgent I/O condition",
455 "stop signal not from tty",
456 "stop signal from tty",
457 "continue",
458 "child termination",
459 "stop (tty input)",
460 "stop (tty output)",
461 "possible input/output",
462 "exceeded CPU time limit",
463 "exceeded file size limit",
464 nil(String)
465};
466
467public psig(s)
468String s;
469{
470 String c;
471 int n;
472
473 c = "Unknown signal";
474 if (errno < sys_nsig) {
475 c = sys_errlist[errno];
476 }
477 n = strlen(s);
478 if (n > 0) {
479 write(2, s, n);
480 write(2, ": ", 2);
481 }
482 write(2, c, strlen(c));
483 write(2, "\n", 1);
484}
485
486/*
487 * Standard error handling routines.
488 */
489
490private short nerrs;
491private short nwarnings;
492
493/*
494 * Main driver of error message reporting.
495 */
496
497/* VARARGS2 */
498private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
499String errname;
500Boolean shouldquit;
501String s;
502{
503 fflush(stdout);
504 if (shouldquit and cmdname != nil(String)) {
505 fprintf(stderr, "%s: ", cmdname);
506 }
507 if (errfilename != nil(Filename)) {
508 fprintf(stderr, "%s: ", errfilename);
509 }
510 if (errlineno > 0) {
511 fprintf(stderr, "%d: ", errlineno);
512 }
513 if (errname != nil(String)) {
514 fprintf(stderr, "%s: ", errname);
515 }
516 fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
517 putc('\n', stderr);
518 if (shouldquit) {
519 quit(1);
520 }
521}
522
523/*
524 * For when printf isn't sufficient for printing the error message ...
525 */
526
527public beginerrmsg()
528{
529 fflush(stdout);
530 if (errfilename != nil(String)) {
531 fprintf(stderr, "%s: ", errfilename);
532 }
533 if (errlineno > 0) {
534 fprintf(stderr, "%d: ", errlineno);
535 }
536}
537
538public enderrmsg()
539{
540 putc('\n', stderr);
541 erecover();
542}
543
544/*
545 * The messages are listed in increasing order of seriousness.
546 *
547 * First are warnings.
548 */
549
550/* VARARGS1 */
551public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
552String s;
553{
554 nwarnings++;
555 errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
556}
557
558/*
559 * Errors are a little worse, they mean something is wrong,
560 * but not so bad that processing can't continue.
561 *
562 * The routine "erecover" is called to recover from the error,
563 * a default routine is provided that does nothing.
564 */
565
566/* VARARGS1 */
567public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
568String s;
569{
570 extern erecover();
571
572 nerrs++;
573 errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
574 erecover();
575}
576
577/*
578 * Non-recoverable user error.
579 */
580
581/* VARARGS1 */
582public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
583String s;
584{
585 errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
586}
587
588/*
589 * Panics indicate an internal program error.
590 */
591
592/* VARARGS1 */
593public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
594String s;
595{
596 errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
597}
598
599short numerrors()
600{
601 short r;
602
603 r = nerrs;
604 nerrs = 0;
605 return r;
606}
607
608short numwarnings()
609{
610 short r;
611
612 r = nwarnings;
613 nwarnings = 0;
614 return r;
615}
616
617/*
618 * Recover from an error.
619 *
620 * This is the default routine which we aren't using since we have our own.
621 *
622public erecover()
623{
624}
625 *
626 */
627
628/*
629 * Default way to quit from a program is just to exit.
630 *
631public quit(r)
632int r;
633{
634 exit(r);
635}
636 *
637 */
638
639/*
640 * Compare n-byte areas pointed to by s1 and s2
641 * if n is 0 then compare up until one has a null byte.
642 */
643
644public int cmp(s1, s2, n)
645register char *s1, *s2;
646register unsigned int n;
647{
648 if (s1 == nil(char *) || s2 == nil(char *)) {
649 panic("cmp: nil pointer");
650 }
651 if (n == 0) {
652 while (*s1 == *s2++) {
653 if (*s1++ == '\0') {
654 return(0);
655 }
656 }
657 return(*s1 - *(s2-1));
658 } else {
659 for (; n != 0; n--) {
660 if (*s1++ != *s2++) {
661 return(*(s1-1) - *(s2-1));
662 }
663 }
664 return(0);
665 }
666}
667
668/*
669 * Move n bytes from src to dest.
670 * If n is 0 move until a null is found.
671 */
672
673public mov(src, dest, n)
674register char *src, *dest;
675register unsigned int n;
676{
677 if (src == nil(char *))
678 panic("mov: nil source");
679 if (dest == nil(char *))
680 panic("mov: nil destination");
681 if (n != 0) {
682 for (; n != 0; n--) {
683 *dest++ = *src++;
684 }
685 } else {
686 while ((*dest++ = *src++) != '\0');
687 }
688}