add vdioctl
[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
DF
7#ifndef lint
8static char sccsid[] = "@(#)library.c 5.1 (Berkeley) %G%";
9#endif not lint
0022c355
ML
10
11static char rcsid[] = "$Header: library.c,v 1.5 84/12/26 10:39:52 linton 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
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
2fd0f574 88#define MAXNARGS 1000 /* unchecked upper limit on max num of arguments */
536150a4
ML
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
2fd0f574 255private boolean isptraced(pid)
ec4f7c5c
ML
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 }
2fd0f574 264 return (boolean) (p != nil(Pidlist *));
ec4f7c5c 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/*
2fd0f574 352 * Initialize error information, setting defaults for handling errors.
536150a4
ML
353 */
354
2fd0f574
SL
355private ERRINFO *errinfo;
356
357private initErrInfo ()
358{
359 integer i;
360
361 errinfo = alloc(sys_nerr, ERRINFO);
362 for (i = 0; i < sys_nerr; i++) {
363 errinfo[i].func = ERR_CATCH;
364 }
365 errinfo[0].func = ERR_IGNORE;
366 errinfo[EPERM].func = ERR_IGNORE;
367 errinfo[ENOENT].func = ERR_IGNORE;
368 errinfo[ESRCH].func = ERR_IGNORE;
369 errinfo[EBADF].func = ERR_IGNORE;
370 errinfo[ENOTTY].func = ERR_IGNORE;
371 errinfo[EOPNOTSUPP].func = ERR_IGNORE;
372}
536150a4
ML
373
374public syserr()
375{
376 ERRINFO *e;
377
2fd0f574
SL
378 if (errno < 0 or errno > sys_nerr) {
379 fatal("errno %d", errno);
380 } else {
381 if (errinfo == nil(ERRINFO *)) {
382 initErrInfo();
383 }
384 e = &(errinfo[errno]);
385 if (e->func == ERR_CATCH) {
536150a4 386 fatal(sys_errlist[errno]);
2fd0f574
SL
387 } else if (e->func != ERR_IGNORE) {
388 (*e->func)();
536150a4 389 }
536150a4
ML
390 }
391}
392
393/*
2fd0f574
SL
394 * Catcherrs' purpose is to initialize the errinfo table, get this module
395 * loaded, and make sure my cerror is loaded (only applicable when this is
396 * in a library).
536150a4
ML
397 */
398
399public catcherrs()
400{
401 _mycerror();
2fd0f574 402 initErrInfo();
536150a4
ML
403}
404
0022c355
ML
405/*
406 * Turn off the error catching mechanism completely by having all errors
407 * ignored. This is most useful between a fork and an exec.
408 */
409
410public nocatcherrs()
411{
412 integer i;
413
414 for (i = 0; i < sys_nerr; i++) {
415 errinfo[i].func = ERR_IGNORE;
416 }
417}
418
536150a4
ML
419/*
420 * Change the action on receipt of an error.
421 */
422
423public onsyserr(n, f)
424int n;
425INTFUNC *f;
426{
2fd0f574
SL
427 if (errinfo == nil(ERRINFO *)) {
428 initErrInfo();
429 }
536150a4
ML
430 errinfo[n].func = f;
431}
432
433/*
434 * Print the message associated with the given signal.
435 * Like a "perror" for signals.
436 */
437
438public int sys_nsig = NSIG;
536150a4 439
2fd0f574 440public psignal(s, n)
536150a4 441String s;
2fd0f574 442integer n;
536150a4 443{
2fd0f574
SL
444 String msg;
445 integer len;
fe99b76d 446 extern String sys_siglist[];
536150a4 447
2fd0f574
SL
448 if (n >= 0 and n < sys_nsig) {
449 msg = sys_siglist[n];
450 } else {
451 msg = "Unknown signal";
536150a4 452 }
2fd0f574
SL
453 len = strlen(s);
454 if (len > 0) {
455 write(2, s, len);
536150a4
ML
456 write(2, ": ", 2);
457 }
2fd0f574 458 write(2, msg, strlen(msg));
536150a4
ML
459 write(2, "\n", 1);
460}
461
462/*
463 * Standard error handling routines.
464 */
465
466private short nerrs;
467private short nwarnings;
468
469/*
470 * Main driver of error message reporting.
471 */
472
473/* VARARGS2 */
474private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m)
475String errname;
2fd0f574 476boolean shouldquit;
536150a4
ML
477String s;
478{
479 fflush(stdout);
480 if (shouldquit and cmdname != nil(String)) {
481 fprintf(stderr, "%s: ", cmdname);
482 }
483 if (errfilename != nil(Filename)) {
484 fprintf(stderr, "%s: ", errfilename);
485 }
486 if (errlineno > 0) {
487 fprintf(stderr, "%d: ", errlineno);
488 }
489 if (errname != nil(String)) {
490 fprintf(stderr, "%s: ", errname);
491 }
492 fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
493 putc('\n', stderr);
494 if (shouldquit) {
495 quit(1);
496 }
497}
498
499/*
500 * For when printf isn't sufficient for printing the error message ...
501 */
502
503public beginerrmsg()
504{
505 fflush(stdout);
506 if (errfilename != nil(String)) {
507 fprintf(stderr, "%s: ", errfilename);
508 }
509 if (errlineno > 0) {
510 fprintf(stderr, "%d: ", errlineno);
511 }
512}
513
514public enderrmsg()
515{
516 putc('\n', stderr);
517 erecover();
518}
519
520/*
521 * The messages are listed in increasing order of seriousness.
522 *
523 * First are warnings.
524 */
525
526/* VARARGS1 */
527public warning(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
528String s;
529{
530 nwarnings++;
531 errmsg("warning", FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
532}
533
534/*
535 * Errors are a little worse, they mean something is wrong,
536 * but not so bad that processing can't continue.
537 *
538 * The routine "erecover" is called to recover from the error,
539 * a default routine is provided that does nothing.
540 */
541
542/* VARARGS1 */
543public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
544String s;
545{
546 extern erecover();
547
548 nerrs++;
549 errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
550 erecover();
551}
552
553/*
554 * Non-recoverable user error.
555 */
556
557/* VARARGS1 */
558public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
559String s;
560{
561 errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
562}
563
564/*
565 * Panics indicate an internal program error.
566 */
567
568/* VARARGS1 */
569public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
570String s;
571{
572 errmsg("internal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m);
573}
574
575short numerrors()
576{
577 short r;
578
579 r = nerrs;
580 nerrs = 0;
581 return r;
582}
583
584short numwarnings()
585{
586 short r;
587
588 r = nwarnings;
589 nwarnings = 0;
590 return r;
591}
592
593/*
594 * Recover from an error.
595 *
596 * This is the default routine which we aren't using since we have our own.
597 *
598public erecover()
599{
600}
601 *
602 */
603
604/*
605 * Default way to quit from a program is just to exit.
606 *
607public quit(r)
608int r;
609{
610 exit(r);
611}
612 *
613 */
614
615/*
616 * Compare n-byte areas pointed to by s1 and s2
617 * if n is 0 then compare up until one has a null byte.
618 */
619
620public int cmp(s1, s2, n)
621register char *s1, *s2;
622register unsigned int n;
623{
624 if (s1 == nil(char *) || s2 == nil(char *)) {
625 panic("cmp: nil pointer");
626 }
627 if (n == 0) {
628 while (*s1 == *s2++) {
629 if (*s1++ == '\0') {
630 return(0);
631 }
632 }
633 return(*s1 - *(s2-1));
634 } else {
635 for (; n != 0; n--) {
636 if (*s1++ != *s2++) {
637 return(*(s1-1) - *(s2-1));
638 }
639 }
640 return(0);
641 }
642}
643
644/*
645 * Move n bytes from src to dest.
646 * If n is 0 move until a null is found.
647 */
648
649public mov(src, dest, n)
650register char *src, *dest;
651register unsigned int n;
652{
653 if (src == nil(char *))
654 panic("mov: nil source");
655 if (dest == nil(char *))
656 panic("mov: nil destination");
657 if (n != 0) {
658 for (; n != 0; n--) {
659 *dest++ = *src++;
660 }
661 } else {
662 while ((*dest++ = *src++) != '\0');
663 }
664}