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