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