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