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