file reorg, pathnames.h, paths.h
[unix-history] / usr / src / old / dbx / library.c
CommitLineData
2a24676e
DF
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 */
536150a4 6
2a24676e 7#ifndef lint
9606e7b9 8static char sccsid[] = "@(#)library.c 5.2 (Berkeley) %G%";
2a24676e 9#endif not lint
0022c355 10
9606e7b9 11static char rcsid[] = "$Header: library.c,v 1.2 87/03/25 20:50:14 donn Exp $";
2fd0f574 12
536150a4
ML
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
2fd0f574
SL
29typedef int integer;
30typedef enum { FALSE, TRUE } boolean;
536150a4
ML
31typedef char *String;
32typedef FILE *File;
33typedef String Filename;
34
35#undef FILE
36
536150a4
ML
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
9606e7b9
DS
67typedef int IntFunc();
68
69IntFunc *onsyserr();
536150a4
ML
70
71typedef struct {
9606e7b9
DS
72 IntFunc *func;
73} ErrInfo;
536150a4 74
9606e7b9
DS
75#define ERR_IGNORE ((IntFunc *) 0)
76#define ERR_CATCH ((IntFunc *) 1)
536150a4
ML
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
2fd0f574 90#define MAXNARGS 1000 /* unchecked upper limit on max num of arguments */
536150a4
ML
91#define BADEXEC 127 /* exec fails */
92
93#define ischild(pid) ((pid) == 0)
94
95/* VARARGS3 */
96public int call(name, in, out, args)
97String name;
98File in;
99File out;
100String 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 */
116public int back(name, in, out, args)
117String name;
118File in;
119File out;
120String 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
135public int callv(name, in, out, argv)
136String name;
137File in;
138File out;
139String *argv;
140{
141 int pid, status;
142
143 pid = backv(name, in, out, argv);
144 pwait(pid, &status);
145 return status;
146}
147
148public int backv(name, in, out, argv)
149String name;
150File in;
151File out;
152String *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
171private fswap(oldfd, newfd)
172int oldfd;
173int 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
188public shell(s)
189String 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.
ec4f7c5c
ML
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.
536150a4
ML
215 */
216
217typedef struct pidlist {
218 int pid;
219 int status;
220 struct pidlist *next;
221} Pidlist;
222
ec4f7c5c
ML
223private Pidlist *pidlist, *ptrclist, *pfind();
224
225public ptraced(pid)
226int pid;
227{
228 Pidlist *p;
229
230 p = alloc(1, Pidlist);
231 p->pid = pid;
232 p->next = ptrclist;
233 ptrclist = p;
234}
235
236public unptraced(pid)
237int 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
2fd0f574 257private boolean isptraced(pid)
ec4f7c5c
ML
258int pid;
259{
260 register Pidlist *p;
261
262 p = ptrclist;
263 while (p != nil(Pidlist *) and p->pid != pid) {
264 p = p->next;
265 }
2fd0f574 266 return (boolean) (p != nil(Pidlist *));
ec4f7c5c 267}
536150a4
ML
268
269public pwait(pid, statusp)
270int pid, *statusp;
271{
b3738d36
ML
272 Pidlist *p;
273 int pnum, status;
536150a4 274
b3738d36
ML
275 p = pfind(pid);
276 if (p != nil(Pidlist *)) {
277 *statusp = p->status;
278 dispose(p);
b3738d36 279 } else {
ec4f7c5c
ML
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 }
b3738d36 301 }
536150a4
ML
302}
303
304/*
305 * Look for the given process id on the pidlist.
306 *
307 * Unlink it from list if found.
308 */
309
310private Pidlist *pfind(pid)
311int 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
340extern int sys_nerr;
341extern 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
350extern int errno;
351extern _mycerror();
352
353/*
2fd0f574 354 * Initialize error information, setting defaults for handling errors.
536150a4
ML
355 */
356
9606e7b9 357private ErrInfo *errinfo;
2fd0f574
SL
358
359private initErrInfo ()
360{
361 integer i;
362
9606e7b9 363 errinfo = alloc(sys_nerr, ErrInfo);
2fd0f574
SL
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}
536150a4
ML
375
376public syserr()
377{
9606e7b9 378 register ErrInfo *e;
536150a4 379
2fd0f574
SL
380 if (errno < 0 or errno > sys_nerr) {
381 fatal("errno %d", errno);
382 } else {
9606e7b9 383 if (errinfo == nil(ErrInfo *)) {
2fd0f574
SL
384 initErrInfo();
385 }
386 e = &(errinfo[errno]);
387 if (e->func == ERR_CATCH) {
536150a4 388 fatal(sys_errlist[errno]);
2fd0f574
SL
389 } else if (e->func != ERR_IGNORE) {
390 (*e->func)();
536150a4 391 }
536150a4
ML
392 }
393}
394
395/*
2fd0f574
SL
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).
536150a4
ML
399 */
400
401public catcherrs()
402{
403 _mycerror();
2fd0f574 404 initErrInfo();
536150a4
ML
405}
406
0022c355
ML
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
412public nocatcherrs()
413{
414 integer i;
415
416 for (i = 0; i < sys_nerr; i++) {
417 errinfo[i].func = ERR_IGNORE;
418 }
419}
420
536150a4 421/*
9606e7b9 422 * Change the action on receipt of an error, returning the previous action.
536150a4
ML
423 */
424
9606e7b9 425public IntFunc *onsyserr(n, f)
536150a4 426int n;
9606e7b9 427IntFunc *f;
536150a4 428{
9606e7b9
DS
429 IntFunc *oldf;
430
431 if (errinfo == nil(ErrInfo *)) {
2fd0f574
SL
432 initErrInfo();
433 }
9606e7b9 434 oldf = errinfo[n].func;
536150a4 435 errinfo[n].func = f;
9606e7b9 436 return oldf;
536150a4
ML
437}
438
439/*
440 * Print the message associated with the given signal.
441 * Like a "perror" for signals.
442 */
443
9606e7b9 444#ifdef SIGWINCH
536150a4 445public int sys_nsig = NSIG;
9606e7b9
DS
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 */
452public 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};
480public int sys_nsig = sizeof sys_siglist / sizeof sys_siglist[0];
481#endif
536150a4 482
2fd0f574 483public psignal(s, n)
536150a4 484String s;
2fd0f574 485integer n;
536150a4 486{
2fd0f574
SL
487 String msg;
488 integer len;
fe99b76d 489 extern String sys_siglist[];
536150a4 490
2fd0f574
SL
491 if (n >= 0 and n < sys_nsig) {
492 msg = sys_siglist[n];
493 } else {
494 msg = "Unknown signal";
536150a4 495 }
2fd0f574
SL
496 len = strlen(s);
497 if (len > 0) {
498 write(2, s, len);
536150a4
ML
499 write(2, ": ", 2);
500 }
2fd0f574 501 write(2, msg, strlen(msg));
536150a4
ML
502 write(2, "\n", 1);
503}
504
505/*
506 * Standard error handling routines.
507 */
508
509private short nerrs;
510private short nwarnings;
511
512/*
513 * Main driver of error message reporting.
514 */
515
516/* VARARGS2 */
517private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
518String errname;
2fd0f574 519boolean shouldquit;
536150a4
ML
520String 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);
9606e7b9 537 fflush(stderr);
536150a4
ML
538 if (shouldquit) {
539 quit(1);
540 }
541}
542
543/*
544 * For when printf isn't sufficient for printing the error message ...
545 */
546
547public 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
558public enderrmsg()
559{
560 putc('\n', stderr);
9606e7b9 561 fflush(stderr);
536150a4
ML
562 erecover();
563}
564
565/*
566 * The messages are listed in increasing order of seriousness.
567 *
568 * First are warnings.
569 */
570
571/* VARARGS1 */
572public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
573String 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 */
588public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
589String 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 */
603public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
604String 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 */
614public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
615String s;
616{
617 errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
618}
619
620short numerrors()
621{
622 short r;
623
624 r = nerrs;
625 nerrs = 0;
626 return r;
627}
628
629short 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 *
643public erecover()
644{
645}
646 *
647 */
648
649/*
650 * Default way to quit from a program is just to exit.
651 *
652public quit(r)
653int 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
665public int cmp(s1, s2, n)
666register char *s1, *s2;
667register 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
694public mov(src, dest, n)
695register char *src, *dest;
696register 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}
9606e7b9
DS
710
711#ifdef IRIS /* or in general for 4.2 - System V C library interface */
712
713public bcopy (fromaddr, toaddr, n)
714char *fromaddr, *toaddr;
715int n;
716{
717 blt(toaddr, fromaddr, n);
718}
719
720public bzero (addr, n)
721char *addr;
722int 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
735public char *index (s, c)
736char *s, c;
737{
738 return strchr(s, c);
739}
740
741public char *rindex (s, c)
742char *s, c;
743{
744 return strrchr(s, c);
745}
746
747#endif