error.c revision 1.21 1 /* $NetBSD: error.c,v 1.21 1999/04/05 15:00:28 mycroft Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95";
43 #else
44 __RCSID("$NetBSD: error.c,v 1.21 1999/04/05 15:00:28 mycroft Exp $");
45 #endif
46 #endif /* not lint */
47
48 /*
49 * Errors and exceptions.
50 */
51
52 #include <signal.h>
53 #include <unistd.h>
54 #include <errno.h>
55
56 #include "shell.h"
57 #include "main.h"
58 #include "options.h"
59 #include "output.h"
60 #include "error.h"
61 #include "show.h"
62
63
64 /*
65 * Code to handle exceptions in C.
66 */
67
68 struct jmploc *handler;
69 int exception;
70 volatile int suppressint;
71 volatile int intpending;
72 char *commandname;
73
74
75 static void exverror __P((int, char *, va_list)) __attribute__((__noreturn__));
76
77 /*
78 * Called to raise an exception. Since C doesn't include exceptions, we
79 * just do a longjmp to the exception handler. The type of exception is
80 * stored in the global variable "exception".
81 */
82
83 void
84 exraise(e)
85 int e;
86 {
87 if (handler == NULL)
88 abort();
89 exception = e;
90 longjmp(handler->loc, 1);
91 }
92
93
94 /*
95 * Called from trap.c when a SIGINT is received. (If the user specifies
96 * that SIGINT is to be trapped or ignored using the trap builtin, then
97 * this routine is not called.) Suppressint is nonzero when interrupts
98 * are held using the INTOFF macro. The call to _exit is necessary because
99 * there is a short period after a fork before the signal handlers are
100 * set to the appropriate value for the child. (The test for iflag is
101 * just defensive programming.)
102 */
103
104 void
105 onint() {
106 sigset_t sigset;
107
108 if (suppressint) {
109 intpending++;
110 return;
111 }
112 intpending = 0;
113 sigemptyset(&sigset);
114 sigprocmask(SIG_SETMASK, &sigset, NULL);
115 if (rootshell && iflag)
116 exraise(EXINT);
117 else {
118 signal(SIGINT, SIG_DFL);
119 raise(SIGINT);
120 }
121 /* NOTREACHED */
122 }
123
124
125 /*
126 * Exverror is called to raise the error exception. If the first argument
127 * is not NULL then error prints an error message using printf style
128 * formatting. It then raises the error exception.
129 */
130 static void
131 exverror(cond, msg, ap)
132 int cond;
133 char *msg;
134 va_list ap;
135 {
136 CLEAR_PENDING_INT;
137 INTOFF;
138
139 #ifdef DEBUG
140 if (msg)
141 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
142 else
143 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
144 #endif
145 if (msg) {
146 if (commandname)
147 outfmt(&errout, "%s: ", commandname);
148 doformat(&errout, msg, ap);
149 out2c('\n');
150 }
151 flushall();
152 exraise(cond);
153 /* NOTREACHED */
154 }
155
156
157 #ifdef __STDC__
158 void
159 error(char *msg, ...)
160 #else
161 void
162 error(va_alist)
163 va_dcl
164 #endif
165 {
166 #ifndef __STDC__
167 char *msg;
168 #endif
169 va_list ap;
170 #ifdef __STDC__
171 va_start(ap, msg);
172 #else
173 va_start(ap);
174 msg = va_arg(ap, char *);
175 #endif
176 exverror(EXERROR, msg, ap);
177 /* NOTREACHED */
178 va_end(ap);
179 }
180
181
182 #ifdef __STDC__
183 void
184 exerror(int cond, char *msg, ...)
185 #else
186 void
187 exerror(va_alist)
188 va_dcl
189 #endif
190 {
191 #ifndef __STDC__
192 int cond;
193 char *msg;
194 #endif
195 va_list ap;
196 #ifdef __STDC__
197 va_start(ap, msg);
198 #else
199 va_start(ap);
200 cond = va_arg(ap, int);
201 msg = va_arg(ap, char *);
202 #endif
203 exverror(cond, msg, ap);
204 /* NOTREACHED */
205 va_end(ap);
206 }
207
208
209
210 /*
211 * Table of error messages.
212 */
213
214 struct errname {
215 short errcode; /* error number */
216 short action; /* operation which encountered the error */
217 char *msg; /* text describing the error */
218 };
219
220
221 #define ALL (E_OPEN|E_CREAT|E_EXEC)
222
223 STATIC const struct errname errormsg[] = {
224 { EINTR, ALL, "interrupted" },
225 { EACCES, ALL, "permission denied" },
226 { EIO, ALL, "I/O error" },
227 { ENOENT, E_OPEN, "no such file" },
228 { ENOENT, E_CREAT,"directory nonexistent" },
229 { ENOENT, E_EXEC, "not found" },
230 { ENOTDIR, E_OPEN, "no such file" },
231 { ENOTDIR, E_CREAT,"directory nonexistent" },
232 { ENOTDIR, E_EXEC, "not found" },
233 { EISDIR, ALL, "is a directory" },
234 #ifdef notdef
235 { EMFILE, ALL, "too many open files" },
236 #endif
237 { ENFILE, ALL, "file table overflow" },
238 { ENOSPC, ALL, "file system full" },
239 #ifdef EDQUOT
240 { EDQUOT, ALL, "disk quota exceeded" },
241 #endif
242 #ifdef ENOSR
243 { ENOSR, ALL, "no streams resources" },
244 #endif
245 { ENXIO, ALL, "no such device or address" },
246 { EROFS, ALL, "read-only file system" },
247 { ETXTBSY, ALL, "text busy" },
248 #ifdef SYSV
249 { EAGAIN, E_EXEC, "not enough memory" },
250 #endif
251 { ENOMEM, ALL, "not enough memory" },
252 #ifdef ENOLINK
253 { ENOLINK, ALL, "remote access failed" },
254 #endif
255 #ifdef EMULTIHOP
256 { EMULTIHOP, ALL, "remote access failed" },
257 #endif
258 #ifdef ECOMM
259 { ECOMM, ALL, "remote access failed" },
260 #endif
261 #ifdef ESTALE
262 { ESTALE, ALL, "remote access failed" },
263 #endif
264 #ifdef ETIMEDOUT
265 { ETIMEDOUT, ALL, "remote access failed" },
266 #endif
267 #ifdef ELOOP
268 { ELOOP, ALL, "symbolic link loop" },
269 #endif
270 { E2BIG, E_EXEC, "argument list too long" },
271 #ifdef ELIBACC
272 { ELIBACC, E_EXEC, "shared library missing" },
273 #endif
274 { 0, 0, NULL },
275 };
276
277
278 /*
279 * Return a string describing an error. The returned string may be a
280 * pointer to a static buffer that will be overwritten on the next call.
281 * Action describes the operation that got the error.
282 */
283
284 char *
285 errmsg(e, action)
286 int e;
287 int action;
288 {
289 struct errname const *ep;
290 static char buf[12];
291
292 for (ep = errormsg ; ep->errcode ; ep++) {
293 if (ep->errcode == e && (ep->action & action) != 0)
294 return ep->msg;
295 }
296 fmtstr(buf, sizeof buf, "error %d", e);
297 return buf;
298 }
299