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
exraise(e)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
onint()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
error2(a,b)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
error(char * msg,...)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 *
errmsg(e,action)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