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