error.c revision 1.22 1 /* $NetBSD: error.c,v 1.22 1999/07/09 03:05:49 christos 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.22 1999/07/09 03:05:49 christos 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, const char *, va_list))
76 __attribute__((__noreturn__));
77
78 /*
79 * Called to raise an exception. Since C doesn't include exceptions, we
80 * just do a longjmp to the exception handler. The type of exception is
81 * stored in the global variable "exception".
82 */
83
84 void
85 exraise(e)
86 int e;
87 {
88 if (handler == NULL)
89 abort();
90 exception = e;
91 longjmp(handler->loc, 1);
92 }
93
94
95 /*
96 * Called from trap.c when a SIGINT is received. (If the user specifies
97 * that SIGINT is to be trapped or ignored using the trap builtin, then
98 * this routine is not called.) Suppressint is nonzero when interrupts
99 * are held using the INTOFF macro. The call to _exit is necessary because
100 * there is a short period after a fork before the signal handlers are
101 * set to the appropriate value for the child. (The test for iflag is
102 * just defensive programming.)
103 */
104
105 void
106 onint() {
107 sigset_t sigset;
108
109 if (suppressint) {
110 intpending++;
111 return;
112 }
113 intpending = 0;
114 sigemptyset(&sigset);
115 sigprocmask(SIG_SETMASK, &sigset, NULL);
116 if (rootshell && iflag)
117 exraise(EXINT);
118 else {
119 signal(SIGINT, SIG_DFL);
120 raise(SIGINT);
121 }
122 /* NOTREACHED */
123 }
124
125
126 /*
127 * Exverror is called to raise the error exception. If the first argument
128 * is not NULL then error prints an error message using printf style
129 * formatting. It then raises the error exception.
130 */
131 static void
132 exverror(cond, msg, ap)
133 int cond;
134 const char *msg;
135 va_list ap;
136 {
137 CLEAR_PENDING_INT;
138 INTOFF;
139
140 #ifdef DEBUG
141 if (msg)
142 TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
143 else
144 TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
145 #endif
146 if (msg) {
147 if (commandname)
148 outfmt(&errout, "%s: ", commandname);
149 doformat(&errout, msg, ap);
150 out2c('\n');
151 }
152 flushall();
153 exraise(cond);
154 /* NOTREACHED */
155 }
156
157
158 #ifdef __STDC__
159 void
160 error(const char *msg, ...)
161 #else
162 void
163 error(va_alist)
164 va_dcl
165 #endif
166 {
167 #ifndef __STDC__
168 const char *msg;
169 #endif
170 va_list ap;
171 #ifdef __STDC__
172 va_start(ap, msg);
173 #else
174 va_start(ap);
175 msg = va_arg(ap, const char *);
176 #endif
177 exverror(EXERROR, msg, ap);
178 /* NOTREACHED */
179 va_end(ap);
180 }
181
182
183 #ifdef __STDC__
184 void
185 exerror(int cond, const char *msg, ...)
186 #else
187 void
188 exerror(va_alist)
189 va_dcl
190 #endif
191 {
192 #ifndef __STDC__
193 int cond;
194 const char *msg;
195 #endif
196 va_list ap;
197 #ifdef __STDC__
198 va_start(ap, msg);
199 #else
200 va_start(ap);
201 cond = va_arg(ap, int);
202 msg = va_arg(ap, const char *);
203 #endif
204 exverror(cond, msg, ap);
205 /* NOTREACHED */
206 va_end(ap);
207 }
208
209
210
211 /*
212 * Table of error messages.
213 */
214
215 struct errname {
216 short errcode; /* error number */
217 short action; /* operation which encountered the error */
218 const char *msg; /* text describing the error */
219 };
220
221
222 #define ALL (E_OPEN|E_CREAT|E_EXEC)
223
224 STATIC const struct errname errormsg[] = {
225 { EINTR, ALL, "interrupted" },
226 { EACCES, ALL, "permission denied" },
227 { EIO, ALL, "I/O error" },
228 { ENOENT, E_OPEN, "no such file" },
229 { ENOENT, E_CREAT,"directory nonexistent" },
230 { ENOENT, E_EXEC, "not found" },
231 { ENOTDIR, E_OPEN, "no such file" },
232 { ENOTDIR, E_CREAT,"directory nonexistent" },
233 { ENOTDIR, E_EXEC, "not found" },
234 { EISDIR, ALL, "is a directory" },
235 #ifdef notdef
236 { EMFILE, ALL, "too many open files" },
237 #endif
238 { ENFILE, ALL, "file table overflow" },
239 { ENOSPC, ALL, "file system full" },
240 #ifdef EDQUOT
241 { EDQUOT, ALL, "disk quota exceeded" },
242 #endif
243 #ifdef ENOSR
244 { ENOSR, ALL, "no streams resources" },
245 #endif
246 { ENXIO, ALL, "no such device or address" },
247 { EROFS, ALL, "read-only file system" },
248 { ETXTBSY, ALL, "text busy" },
249 #ifdef SYSV
250 { EAGAIN, E_EXEC, "not enough memory" },
251 #endif
252 { ENOMEM, ALL, "not enough memory" },
253 #ifdef ENOLINK
254 { ENOLINK, ALL, "remote access failed" },
255 #endif
256 #ifdef EMULTIHOP
257 { EMULTIHOP, ALL, "remote access failed" },
258 #endif
259 #ifdef ECOMM
260 { ECOMM, ALL, "remote access failed" },
261 #endif
262 #ifdef ESTALE
263 { ESTALE, ALL, "remote access failed" },
264 #endif
265 #ifdef ETIMEDOUT
266 { ETIMEDOUT, ALL, "remote access failed" },
267 #endif
268 #ifdef ELOOP
269 { ELOOP, ALL, "symbolic link loop" },
270 #endif
271 { E2BIG, E_EXEC, "argument list too long" },
272 #ifdef ELIBACC
273 { ELIBACC, E_EXEC, "shared library missing" },
274 #endif
275 { 0, 0, NULL },
276 };
277
278
279 /*
280 * Return a string describing an error. The returned string may be a
281 * pointer to a static buffer that will be overwritten on the next call.
282 * Action describes the operation that got the error.
283 */
284
285 const char *
286 errmsg(e, action)
287 int e;
288 int action;
289 {
290 struct errname const *ep;
291 static char buf[12];
292
293 for (ep = errormsg ; ep->errcode ; ep++) {
294 if (ep->errcode == e && (ep->action & action) != 0)
295 return ep->msg;
296 }
297 fmtstr(buf, sizeof buf, "error %d", e);
298 return buf;
299 }
300