1 /*- 2 * Copyright (c) 1982, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)library.c 8.2 (Berkeley) 05/27/94"; 10 #endif /* not lint */ 11 12 /* 13 * General purpose routines. 14 */ 15 16 #include <stdio.h> 17 #include <errno.h> 18 #include "defs.h" 19 20 #define public 21 #define private static 22 #define and && 23 #define nil(type) ((type) 0) 24 25 typedef char *String; 26 typedef FILE *File; 27 typedef String Filename; 28 typedef char Boolean; 29 30 #undef FILE 31 32 String cmdname; /* name of command for error messages */ 33 Filename errfilename; /* current file associated with error */ 34 short errlineno; /* line number associated with error */ 35 36 typedef int INTFUNC(); 37 38 typedef struct { 39 INTFUNC *func; 40 } ERRINFO; 41 42 #define ERR_IGNORE ((INTFUNC *) 0) 43 #define ERR_CATCH ((INTFUNC *) 1) 44 45 public INTFUNC *onsyserr(); 46 47 /* 48 * Call a program. 49 * 50 * Three entries: 51 * 52 * call, callv - call a program and wait for it, returning status 53 * backv - call a program and don't wait, returning process id 54 * 55 * The command's standard input and output are passed as FILE's. 56 */ 57 58 59 #define MAXNARGS 100 /* unchecked upper limit on max num of arguments */ 60 #define BADEXEC 127 /* exec fails */ 61 62 #define ischild(pid) ((pid) == 0) 63 64 /* VARARGS3 */ 65 public int call(name, in, out, args) 66 String name; 67 File in; 68 File out; 69 String args; 70 { 71 String *ap, *argp; 72 String argv[MAXNARGS]; 73 74 argp = &argv[0]; 75 *argp++ = name; 76 ap = &args; 77 while (*ap != nil(String)) { 78 *argp++ = *ap++; 79 } 80 *argp = nil(String); 81 return callv(name, in, out, argv); 82 } 83 84 public int callv(name, in, out, argv) 85 String name; 86 File in; 87 File out; 88 String *argv; 89 { 90 int pid, status; 91 92 pid = backv(name, in, out, argv); 93 pwait(pid, &status); 94 return status; 95 } 96 97 public int backv(name, in, out, argv) 98 String name; 99 File in; 100 File out; 101 String *argv; 102 { 103 int pid; 104 105 fflush(stdout); 106 if (ischild(pid = fork())) { 107 fswap(0, fileno(in)); 108 fswap(1, fileno(out)); 109 (void) onsyserr(EACCES, ERR_IGNORE); 110 execvp(name, argv); 111 _exit(BADEXEC); 112 } 113 return pid; 114 } 115 116 /* 117 * Swap file numbers so as to redirect standard input and output. 118 */ 119 120 private fswap(oldfd, newfd) 121 int oldfd; 122 int newfd; 123 { 124 if (oldfd != newfd) { 125 close(oldfd); 126 dup(newfd); 127 close(newfd); 128 } 129 } 130 131 /* 132 * Invoke a shell on a command line. 133 */ 134 135 #define DEF_SHELL "csh" 136 137 public shell(s) 138 String s; 139 { 140 extern String getenv(); 141 String sh; 142 143 if ((sh = getenv("SHELL")) == nil(String)) { 144 sh = DEF_SHELL; 145 } 146 call(sh, stdin, stdout, "-c", s, 0); 147 } 148 149 /* 150 * Wait for a process the right way. We wait for a particular 151 * process and if any others come along in between, we remember them 152 * in case they are eventually waited for. 153 * 154 * This routine is not very efficient when the number of processes 155 * to be remembered is large. 156 */ 157 158 typedef struct pidlist { 159 int pid; 160 int status; 161 struct pidlist *next; 162 } Pidlist; 163 164 private Pidlist *pidlist, *pfind(); 165 166 public pwait(pid, statusp) 167 int pid, *statusp; 168 { 169 Pidlist *p; 170 int pnum, status; 171 172 p = pfind(pid); 173 if (p != nil(Pidlist *)) { 174 *statusp = p->status; 175 dispose(p); 176 return; 177 } 178 while ((pnum = wait(&status)) != pid && pnum >= 0) { 179 p = alloc(1, Pidlist); 180 p->pid = pnum; 181 p->status = status; 182 p->next = pidlist; 183 pidlist = p; 184 } 185 if (pnum < 0) { 186 p = pfind(pid); 187 if (p == nil(Pidlist *)) { 188 panic("pwait: pid %d not found", pid); 189 } 190 *statusp = p->status; 191 dispose(p); 192 } else { 193 *statusp = status; 194 } 195 #ifdef tahoe 196 chkret(p, status); 197 #endif 198 } 199 200 /* 201 * Look for the given process id on the pidlist. 202 * 203 * Unlink it from list if found. 204 */ 205 206 private Pidlist *pfind(pid) 207 int pid; 208 { 209 register Pidlist *p, *prev; 210 211 prev = nil(Pidlist *); 212 for (p = pidlist; p != nil(Pidlist *); p = p->next) { 213 if (p->pid == pid) { 214 break; 215 } 216 prev = p; 217 } 218 if (p != nil(Pidlist *)) { 219 if (prev == nil(Pidlist *)) { 220 pidlist = p->next; 221 } else { 222 prev->next = p->next; 223 } 224 } 225 return p; 226 } 227 228 /* 229 * System call error handler. 230 * 231 * The syserr routine is called when a system call is about to 232 * set the c-bit to report an error. Certain errors are caught 233 * and cause the process to print a message and immediately exit. 234 */ 235 236 extern int sys_nerr; 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