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.1 (Berkeley) 06/06/93"; 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 extern char *sys_errlist[]; 238 239 /* 240 * Before calling syserr, the integer errno is set to contain the 241 * number of the error. 242 */ 243 244 extern int errno; 245 246 /* 247 * default error handling 248 */ 249 250 private ERRINFO errinfo[] ={ 251 /* no error */ ERR_IGNORE, 252 /* EPERM */ ERR_IGNORE, 253 /* ENOENT */ ERR_IGNORE, 254 /* ESRCH */ ERR_IGNORE, 255 /* EINTR */ ERR_CATCH, 256 /* EIO */ ERR_CATCH, 257 /* ENXIO */ ERR_CATCH, 258 /* E2BIG */ ERR_CATCH, 259 /* ENOEXEC */ ERR_CATCH, 260 /* EBADF */ ERR_IGNORE, 261 /* ECHILD */ ERR_CATCH, 262 /* EAGAIN */ ERR_CATCH, 263 /* ENOMEM */ ERR_CATCH, 264 /* EACCES */ ERR_CATCH, 265 /* EFAULT */ ERR_CATCH, 266 /* ENOTBLK */ ERR_CATCH, 267 /* EBUSY */ ERR_CATCH, 268 /* EEXIST */ ERR_CATCH, 269 /* EXDEV */ ERR_CATCH, 270 /* ENODEV */ ERR_CATCH, 271 /* ENOTDIR */ ERR_CATCH, 272 /* EISDIR */ ERR_CATCH, 273 /* EINVAL */ ERR_CATCH, 274 /* ENFILE */ ERR_CATCH, 275 /* EMFILE */ ERR_CATCH, 276 /* ENOTTY */ ERR_IGNORE, 277 /* ETXTBSY */ ERR_CATCH, 278 /* EFBIG */ ERR_CATCH, 279 /* ENOSPC */ ERR_CATCH, 280 /* ESPIPE */ ERR_CATCH, 281 /* EROFS */ ERR_CATCH, 282 /* EMLINK */ ERR_CATCH, 283 /* EPIPE */ ERR_CATCH, 284 /* EDOM */ ERR_CATCH, 285 /* ERANGE */ ERR_CATCH, 286 /* EQUOT */ ERR_CATCH, 287 }; 288 289 public syserr() 290 { 291 ERRINFO *e; 292 293 e = &errinfo[errno]; 294 if (e->func == ERR_CATCH) { 295 if (errno < sys_nerr) { 296 panic(sys_errlist[errno]); 297 } else { 298 panic("errno %d", errno); 299 } 300 } else if (e->func != ERR_IGNORE) { 301 (*e->func)(); 302 } 303 } 304 305 /* 306 * Change the action on receipt of an error. 307 */ 308 309 public INTFUNC *onsyserr(n, f) 310 int n; 311 INTFUNC *f; 312 { 313 INTFUNC *g = errinfo[n].func; 314 315 errinfo[n].func = f; 316 return(g); 317 } 318 319 /* 320 * Main driver of error message reporting. 321 */ 322 323 /* VARARGS2 */ 324 private errmsg(errname, shouldquit, s, a, b, c, d, e, f, g, h, i, j, k, l, m) 325 String errname; 326 Boolean shouldquit; 327 String s; 328 { 329 fflush(stdout); 330 if (shouldquit and cmdname != nil(String)) { 331 fprintf(stderr, "%s: ", cmdname); 332 } 333 if (errfilename != nil(Filename)) { 334 fprintf(stderr, "%s: ", errfilename); 335 } 336 if (errlineno > 0) { 337 fprintf(stderr, "%d: ", errlineno); 338 } 339 if (errname != nil(String)) { 340 fprintf(stderr, "%s: ", errname); 341 } 342 fprintf(stderr, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 343 putc('\n', stderr); 344 if (shouldquit) { 345 quit(1); 346 } 347 } 348 349 /* 350 * Errors are a little worse, they mean something is wrong, 351 * but not so bad that processing can't continue. 352 * 353 * The routine "erecover" is called to recover from the error, 354 * a default routine is provided that does nothing. 355 */ 356 357 /* VARARGS1 */ 358 public error(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 359 String s; 360 { 361 extern erecover(); 362 363 errmsg(nil(String), FALSE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 364 erecover(); 365 } 366 367 /* 368 * Non-recoverable user error. 369 */ 370 371 /* VARARGS1 */ 372 public fatal(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 373 String s; 374 { 375 errmsg("fatal error", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 376 } 377 378 /* 379 * Panics indicate an internal program error. 380 */ 381 382 /* VARARGS1 */ 383 public panic(s, a, b, c, d, e, f, g, h, i, j, k, l, m) 384 String s; 385 { 386 errmsg("panic", TRUE, s, a, b, c, d, e, f, g, h, i, j, k, l, m); 387 } 388 389 /* 390 * Compare n-byte areas pointed to by s1 and s2 391 * if n is 0 then compare up until one has a null byte. 392 */ 393 394 public int cmp(s1, s2, n) 395 register char *s1, *s2; 396 register unsigned int n; 397 { 398 if (s1 == nil(char *) || s2 == nil(char *)) { 399 panic("cmp: nil pointer"); 400 } 401 if (n == 0) { 402 while (*s1 == *s2++) { 403 if (*s1++ == '\0') { 404 return(0); 405 } 406 } 407 return(*s1 - *(s2-1)); 408 } else { 409 for (; n != 0; n--) { 410 if (*s1++ != *s2++) { 411 return(*(s1-1) - *(s2-1)); 412 } 413 } 414 return(0); 415 } 416 } 417 418 /* 419 * Move n bytes from src to dest. 420 * If n is 0 move until a null is found. 421 */ 422 423 public mov(src, dest, n) 424 register char *src, *dest; 425 register int n; 426 { 427 if (src == nil(char *)) { 428 panic("mov: nil source"); 429 } 430 if (dest == nil(char *)) { 431 panic("mov: nil destination"); 432 } 433 if (n > 0) { 434 for (; n != 0; n--) { 435 *dest++ = *src++; 436 } 437 } else { 438 while ((*dest++ = *src++) != '\0'); 439 } 440 } 441