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