1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * %sccs.include.redist.c% 9 */ 10 11 #ifndef lint 12 static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 05/04/95"; 13 #endif /* not lint */ 14 15 /* 16 * Errors and exceptions. 17 */ 18 19 #include "shell.h" 20 #include "main.h" 21 #include "options.h" 22 #include "output.h" 23 #include "error.h" 24 #include "show.h" 25 #include <signal.h> 26 #include <unistd.h> 27 #include <errno.h> 28 29 30 /* 31 * Code to handle exceptions in C. 32 */ 33 34 struct jmploc *handler; 35 int exception; 36 volatile int suppressint; 37 volatile int intpending; 38 char *commandname; 39 40 41 /* 42 * Called to raise an exception. Since C doesn't include exceptions, we 43 * just do a longjmp to the exception handler. The type of exception is 44 * stored in the global variable "exception". 45 */ 46 47 void 48 exraise(e) 49 int e; 50 { 51 if (handler == NULL) 52 abort(); 53 exception = e; 54 longjmp(handler->loc, 1); 55 } 56 57 58 /* 59 * Called from trap.c when a SIGINT is received. (If the user specifies 60 * that SIGINT is to be trapped or ignored using the trap builtin, then 61 * this routine is not called.) Suppressint is nonzero when interrupts 62 * are held using the INTOFF macro. The call to _exit is necessary because 63 * there is a short period after a fork before the signal handlers are 64 * set to the appropriate value for the child. (The test for iflag is 65 * just defensive programming.) 66 */ 67 68 void 69 onint() { 70 sigset_t sigset; 71 72 if (suppressint) { 73 intpending++; 74 return; 75 } 76 intpending = 0; 77 sigemptyset(&sigset); 78 sigprocmask(SIG_SETMASK, &sigset, NULL); 79 if (rootshell && iflag) 80 exraise(EXINT); 81 else 82 _exit(128 + SIGINT); 83 } 84 85 86 87 void 88 error2(a, b) 89 char *a, *b; 90 { 91 error("%s: %s", a, b); 92 } 93 94 95 /* 96 * Error is called to raise the error exception. If the first argument 97 * is not NULL then error prints an error message using printf style 98 * formatting. It then raises the error exception. 99 */ 100 101 #if __STDC__ 102 void 103 error(char *msg, ...) 104 #else 105 void 106 error(va_alist) 107 va_dcl 108 #endif 109 { 110 #if !__STDC__ 111 char *msg; 112 #endif 113 va_list ap; 114 CLEAR_PENDING_INT; 115 INTOFF; 116 117 #if __STDC__ 118 va_start(ap, msg); 119 #else 120 va_start(ap); 121 msg = va_arg(ap, char *); 122 #endif 123 #ifdef DEBUG 124 if (msg) 125 TRACE(("error(\"%s\") pid=%d\n", msg, getpid())); 126 else 127 TRACE(("error(NULL) pid=%d\n", getpid())); 128 #endif 129 if (msg) { 130 if (commandname) 131 outfmt(&errout, "%s: ", commandname); 132 doformat(&errout, msg, ap); 133 out2c('\n'); 134 } 135 va_end(ap); 136 flushall(); 137 exraise(EXERROR); 138 } 139 140 141 142 /* 143 * Table of error messages. 144 */ 145 146 struct errname { 147 short errcode; /* error number */ 148 short action; /* operation which encountered the error */ 149 char *msg; /* text describing the error */ 150 }; 151 152 153 #define ALL (E_OPEN|E_CREAT|E_EXEC) 154 155 STATIC const struct errname errormsg[] = { 156 { EINTR, ALL, "interrupted" }, 157 { EACCES, ALL, "permission denied" }, 158 { EIO, ALL, "I/O error" }, 159 { ENOENT, E_OPEN, "no such file" }, 160 { ENOENT, E_CREAT,"directory nonexistent" }, 161 { ENOENT, E_EXEC, "not found" }, 162 { ENOTDIR, E_OPEN, "no such file" }, 163 { ENOTDIR, E_CREAT,"directory nonexistent" }, 164 { ENOTDIR, E_EXEC, "not found" }, 165 { EISDIR, ALL, "is a directory" }, 166 #ifdef notdef 167 { EMFILE, ALL, "too many open files" }, 168 #endif 169 { ENFILE, ALL, "file table overflow" }, 170 { ENOSPC, ALL, "file system full" }, 171 #ifdef EDQUOT 172 { EDQUOT, ALL, "disk quota exceeded" }, 173 #endif 174 #ifdef ENOSR 175 { ENOSR, ALL, "no streams resources" }, 176 #endif 177 { ENXIO, ALL, "no such device or address" }, 178 { EROFS, ALL, "read-only file system" }, 179 { ETXTBSY, ALL, "text busy" }, 180 #ifdef SYSV 181 { EAGAIN, E_EXEC, "not enough memory" }, 182 #endif 183 { ENOMEM, ALL, "not enough memory" }, 184 #ifdef ENOLINK 185 { ENOLINK, ALL, "remote access failed" }, 186 #endif 187 #ifdef EMULTIHOP 188 { EMULTIHOP, ALL, "remote access failed" }, 189 #endif 190 #ifdef ECOMM 191 { ECOMM, ALL, "remote access failed" }, 192 #endif 193 #ifdef ESTALE 194 { ESTALE, ALL, "remote access failed" }, 195 #endif 196 #ifdef ETIMEDOUT 197 { ETIMEDOUT, ALL, "remote access failed" }, 198 #endif 199 #ifdef ELOOP 200 { ELOOP, ALL, "symbolic link loop" }, 201 #endif 202 { E2BIG, E_EXEC, "argument list too long" }, 203 #ifdef ELIBACC 204 { ELIBACC, E_EXEC, "shared library missing" }, 205 #endif 206 { 0, 0, NULL }, 207 }; 208 209 210 /* 211 * Return a string describing an error. The returned string may be a 212 * pointer to a static buffer that will be overwritten on the next call. 213 * Action describes the operation that got the error. 214 */ 215 216 char * 217 errmsg(e, action) 218 int e; 219 int action; 220 { 221 struct errname const *ep; 222 static char buf[12]; 223 224 for (ep = errormsg ; ep->errcode ; ep++) { 225 if (ep->errcode == e && (ep->action & action) != 0) 226 return ep->msg; 227 } 228 fmtstr(buf, sizeof buf, "error %d", e); 229 return buf; 230 } 231