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