1 /* 2 * Copyright (c) 1982 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) 04/07/87"; 9 #endif not lint 10 11 /* 12 * General purpose routines. 13 */ 14 15 #include <stdio.h> 16 #include <errno.h> 17 #include "defs.h" 18 19 #define public 20 #define private static 21 #define and && 22 #define nil(type) ((type) 0) 23 24 typedef char *String; 25 typedef FILE *File; 26 typedef String Filename; 27 typedef char Boolean; 28 29 #undef FILE 30 31 String cmdname; /* name of command for error messages */ 32 Filename errfilename; /* current file associated with error */ 33 short errlineno; /* line number associated with error */ 34 35 typedef int INTFUNC(); 36 37 typedef struct { 38 INTFUNC *func; 39 } ERRINFO; 40 41 #define ERR_IGNORE ((INTFUNC *) 0) 42 #define ERR_CATCH ((INTFUNC *) 1) 43 44 public INTFUNC *onsyserr(); 45 46 /* 47 * Call a program. 48 * 49 * Three entries: 50 * 51 * call, callv - call a program and wait for it, returning status 52 * backv - call a program and don't wait, returning process id 53 * 54 * The command's standard input and output are passed as FILE's. 55 */ 56 57 58 #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */ 59 #define BADEXEC 127 /* exec fails */ 60 61 #define ischild(pid) ((pid) == 0) 62 63 /* VARARGS3 */ 64 public int call(name, in, out, args) 65 String name; 66 File in; 67 File out; 68 String args; 69 { 70 String *ap, *argp; 71 String argv[MAXNARGS]; 72 73 argp = &argv[0]; 74 *argp++ = name; 75 ap = &args; 76 while (*ap != nil(String)) { 77 *argp++ = *ap++; 78 } 79 *argp = nil(String); 80 return callv(name, in, out, argv); 81 } 82 83 public int callv(name, in, out, argv) 84 String name; 85 File in; 86 File out; 87 String *argv; 88 { 89 int pid, status; 90 91 pid = backv(name, in, out, argv); 92 pwait(pid, &status); 93 return status; 94 } 95 96 public int backv(name, in, out, argv) 97 String name; 98 File in; 99 File out; 100 String *argv; 101 { 102 int pid; 103 104 fflush(stdout); 105 if (ischild(pid = fork())) { 106 fswap(0, fileno(in)); 107 fswap(1, fileno(out)); 108 (void) onsyserr(EACCES, ERR_IGNORE); 109 execvp(name, argv); 110 _exit(BADEXEC); 111 } 112 return pid; 113 } 114 115 /* 116 * Swap file numbers so as to redirect standard input and output. 117 */ 118 119 private fswap(oldfd, newfd) 120 int oldfd; 121 int newfd; 122 { 123 if (oldfd != newfd) { 124 close(oldfd); 125 dup(newfd); 126 close(newfd); 127 } 128 } 129 130 /* 131 * Invoke a shell on a command line. 132 */ 133 134 #define DEF_SHELL "csh" 135 136 public shell(s) 137 String s; 138 { 139 extern String getenv(); 140 String sh; 141 142 if ((sh = getenv("SHELL")) == nil(String)) { 143 sh = DEF_SHELL; 144 } 145 call(sh, stdin, stdout, "-c", s, 0); 146 } 147 148 /* 149 * Wait for a process the right way. We wait for a particular 150 * process and if any others come along in between, we remember them 151 * in case they are eventually waited for. 152 * 153 * This routine is not very efficient when the number of processes 154 * to be remembered is large. 155 */ 156 157 typedef struct pidlist { 158 int pid; 159 int status; 160 struct pidlist *next; 161 } Pidlist; 162 163 private Pidlist *pidlist, *pfind(); 164 165 public pwait(pid, statusp) 166 int pid, *statusp; 167 { 168 Pidlist *p; 169 int pnum, status; 170 171 p = pfind(pid); 172 if (p != nil(Pidlist *)) { 173 *statusp = p->status; 174 dispose(p); 175 return; 176 } 177 while ((pnum = wait(&status)) != pid && pnum >= 0) { 178 p = alloc(1, Pidlist); 179 p->pid = pnum; 180 p->status = status; 181 p->next = pidlist; 182 pidlist = p; 183 } 184 if (pnum < 0) { 185 p = pfind(pid); 186 if (p == nil(Pidlist *)) { 187 panic("pwait: pid %d not found", pid); 188 } 189 *statusp = p->status; 190 dispose(p); 191 } else { 192 *statusp = status; 193 } 194 #ifdef tahoe 195 chkret(p, status); 196 #endif 197 } 198 199 /* 200 * Look for the given process id on the pidlist. 201 * 202 * Unlink it from list if found. 203 */ 204 205 private Pidlist *pfind(pid) 206 int pid; 207 { 208 register Pidlist *p, *prev; 209 210 prev = nil(Pidlist *); 211 for (p = pidlist; p != nil(Pidlist *); p = p->next) { 212 if (p->pid == pid) { 213 break; 214 } 215 prev = p; 216 } 217 if (p != nil(Pidlist *)) { 218 if (prev == nil(Pidlist *)) { 219 pidlist = p->next; 220 } else { 221 prev->next = p->next; 222 } 223 } 224 return p; 225 } 226 227 /* 228 * System call error handler. 229 * 230 * The syserr routine is called when a system call is about to 231 * set the c-bit to report an error. Certain errors are caught 232 * and cause the process to print a message and immediately exit. 233 */ 234 235 extern int sys_nerr; 236 extern char *sys_errlist[]; 237 238 /* 239 * Before calling syserr, the integer errno is set to contain the 240 * number of the error. 241 */ 242 243 extern int errno; 244 245 /* 246 * default error handling 247 */ 248 249 private ERRINFO errinfo[] ={ 250 /* no error */ ERR_IGNORE, 251 /* EPERM */ ERR_IGNORE, 252 /* ENOENT */ ERR_IGNORE, 253 /* ESRCH */ ERR_IGNORE, 254 /* EINTR */ ERR_CATCH, 255 /* EIO */ ERR_CATCH, 256 /* ENXIO */ ERR_CATCH, 257 /* E2BIG */ ERR_CATCH, 258 /* ENOEXEC */ ERR_CATCH, 259 /* EBADF */ ERR_IGNORE, 260 /* ECHILD */ ERR_CATCH, 261 /* EAGAIN */ ERR_CATCH, 262 /* ENOMEM */ ERR_CATCH, 263 /* EACCES */ ERR_CATCH, 264 /* EFAULT */ ERR_CATCH, 265 /* ENOTBLK */ ERR_CATCH, 266 /* EBUSY */ ERR_CATCH, 267 /* EEXIST */ ERR_CATCH, 268 /* EXDEV */ ERR_CATCH, 269 /* ENODEV */ ERR_CATCH, 270 /* ENOTDIR */ ERR_CATCH, 271 /* EISDIR */ ERR_CATCH, 272 /* EINVAL */ ERR_CATCH, 273 /* ENFILE */ ERR_CATCH, 274 /* EMFILE */ ERR_CATCH, 275 /* ENOTTY */ ERR_IGNORE, 276 /* ETXTBSY */ ERR_CATCH, 277 /* EFBIG */ ERR_CATCH, 278 /* ENOSPC */ ERR_CATCH, 279 /* ESPIPE */ ERR_CATCH, 280 /* EROFS */ ERR_CATCH, 281 /* EMLINK */ ERR_CATCH, 282 /* EPIPE */ ERR_CATCH, 283 /* EDOM */ ERR_CATCH, 284 /* ERANGE */ ERR_CATCH, 285 /* EQUOT */ ERR_CATCH, 286 }; 287 288 public syserr() 289 { 290 ERRINFO *e; 291 292 e = &errinfo[errno]; 293 if (e->func == ERR_CATCH) { 294 if (errno < sys_nerr) { 295 panic(sys_errlist[errno]); 296 } else { 297 panic("errno %d", errno); 298 } 299 } else if (e->func != ERR_IGNORE) { 300 (*e->func)(); 301 } 302 } 303 304 /* 305 * Change the action on receipt of an error. 306 */ 307 308 public INTFUNC *onsyserr(n, f) 309 int n; 310 INTFUNC *f; 311 { 312 INTFUNC *g = errinfo[n].func; 313 314 errinfo[n].func = f; 315 return(g); 316 } 317 318 /* 319 * Main driver of error message reporting. 320 */ 321 322 /* VARARGS2 */ 323 private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 324 String errname; 325 Boolean shouldquit; 326 String s; 327 { 328 fflush(stdout); 329 if (shouldquit and cmdname != nil(String)) { 330 fprintf(stderr, "%s: ", cmdname); 331 } 332 if (errfilename != nil(Filename)) { 333 fprintf(stderr, "%s: ", errfilename); 334 } 335 if (errlineno > 0) { 336 fprintf(stderr, "%d: ", errlineno); 337 } 338 if (errname != nil(String)) { 339 fprintf(stderr, "%s: ", errname); 340 } 341 fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 342 putc('\n', stderr); 343 if (shouldquit) { 344 quit(1); 345 } 346 } 347 348 /* 349 * Errors are a little worse, they mean something is wrong, 350 * but not so bad that processing can't continue. 351 * 352 * The routine "erecover" is called to recover from the error, 353 * a default routine is provided that does nothing. 354 */ 355 356 /* VARARGS1 */ 357 public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 358 String s; 359 { 360 extern erecover(); 361 362 errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 363 erecover(); 364 } 365 366 /* 367 * Non-recoverable user error. 368 */ 369 370 /* VARARGS1 */ 371 public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 372 String s; 373 { 374 errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 375 } 376 377 /* 378 * Panics indicate an internal program error. 379 */ 380 381 /* VARARGS1 */ 382 public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 383 String s; 384 { 385 errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 386 } 387 388 /* 389 * Compare n-byte areas pointed to by s1 and s2 390 * if n is 0 then compare up until one has a null byte. 391 */ 392 393 public int cmp(s1, s2, n) 394 register char *s1, *s2; 395 register unsigned int n; 396 { 397 if (s1 == nil(char *) || s2 == nil(char *)) { 398 panic("cmp: nil pointer"); 399 } 400 if (n == 0) { 401 while (*s1 == *s2++) { 402 if (*s1++ == '\0') { 403 return(0); 404 } 405 } 406 return(*s1 - *(s2-1)); 407 } else { 408 for (; n != 0; n--) { 409 if (*s1++ != *s2++) { 410 return(*(s1-1) - *(s2-1)); 411 } 412 } 413 return(0); 414 } 415 } 416 417 /* 418 * Move n bytes from src to dest. 419 * If n is 0 move until a null is found. 420 */ 421 422 public mov(src, dest, n) 423 register char *src, *dest; 424 register int n; 425 { 426 if (src == nil(char *)) { 427 panic("mov: nil source"); 428 } 429 if (dest == nil(char *)) { 430 panic("mov: nil destination"); 431 } 432 if (n > 0) { 433 for (; n != 0; n--) { 434 *dest++ = *src++; 435 } 436 } else { 437 while ((*dest++ = *src++) != '\0'); 438 } 439 } 440