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