error.c revision 36150
1214501Srpaulo/*-
2214501Srpaulo * Copyright (c) 1991, 1993
3214501Srpaulo *	The Regents of the University of California.  All rights reserved.
4214501Srpaulo *
5214501Srpaulo * This code is derived from software contributed to Berkeley by
6214501Srpaulo * Kenneth Almquist.
7214501Srpaulo *
8214501Srpaulo * Redistribution and use in source and binary forms, with or without
9214501Srpaulo * modification, are permitted provided that the following conditions
10214501Srpaulo * are met:
11214501Srpaulo * 1. Redistributions of source code must retain the above copyright
12214501Srpaulo *    notice, this list of conditions and the following disclaimer.
13214501Srpaulo * 2. Redistributions in binary form must reproduce the above copyright
14214501Srpaulo *    notice, this list of conditions and the following disclaimer in the
15214501Srpaulo *    documentation and/or other materials provided with the distribution.
16214501Srpaulo * 3. All advertising materials mentioning features or use of this software
17214501Srpaulo *    must display the following acknowledgement:
18214501Srpaulo *	This product includes software developed by the University of
19214501Srpaulo *	California, Berkeley and its contributors.
20214501Srpaulo * 4. Neither the name of the University nor the names of its contributors
21214501Srpaulo *    may be used to endorse or promote products derived from this software
22214501Srpaulo *    without specific prior written permission.
23214501Srpaulo *
24214501Srpaulo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25214501Srpaulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26214501Srpaulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27214501Srpaulo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28214501Srpaulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29214501Srpaulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30214501Srpaulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31214501Srpaulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32214501Srpaulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33214501Srpaulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34214501Srpaulo * SUCH DAMAGE.
35214501Srpaulo */
36214501Srpaulo
37214501Srpaulo#ifndef lint
38214501Srpaulo#if 0
39214501Srpaulostatic char sccsid[] = "@(#)error.c	8.2 (Berkeley) 5/4/95";
40214501Srpaulo#endif
41214501Srpaulostatic const char rcsid[] =
42214501Srpaulo	"$Id$";
43214501Srpaulo#endif /* not lint */
44214501Srpaulo
45214501Srpaulo/*
46214501Srpaulo * Errors and exceptions.
47214501Srpaulo */
48214501Srpaulo
49214501Srpaulo#include "shell.h"
50214501Srpaulo#include "main.h"
51214501Srpaulo#include "options.h"
52214501Srpaulo#include "output.h"
53214501Srpaulo#include "error.h"
54214501Srpaulo#include "show.h"
55214501Srpaulo#include <signal.h>
56214501Srpaulo#include <unistd.h>
57214501Srpaulo#include <errno.h>
58214501Srpaulo
59214501Srpaulo
60214501Srpaulo/*
61214501Srpaulo * Code to handle exceptions in C.
62214501Srpaulo */
63214501Srpaulo
64214501Srpaulostruct jmploc *handler;
65214501Srpauloint exception;
66214501Srpaulovolatile int suppressint;
67214501Srpaulovolatile int intpending;
68214501Srpaulochar *commandname;
69214501Srpaulo
70214501Srpaulo
71214501Srpaulostatic void exverror __P((int, char *, va_list));
72214501Srpaulo
73214501Srpaulo/*
74214501Srpaulo * Called to raise an exception.  Since C doesn't include exceptions, we
75214501Srpaulo * just do a longjmp to the exception handler.  The type of exception is
76214501Srpaulo * stored in the global variable "exception".
77214501Srpaulo */
78214501Srpaulo
79214501Srpaulovoid
80214501Srpauloexraise(e)
81214501Srpaulo	int e;
82214501Srpaulo{
83214501Srpaulo	if (handler == NULL)
84214501Srpaulo		abort();
85214501Srpaulo	exception = e;
86214501Srpaulo	longjmp(handler->loc, 1);
87214501Srpaulo}
88214501Srpaulo
89214501Srpaulo
90214501Srpaulo/*
91214501Srpaulo * Called from trap.c when a SIGINT is received.  (If the user specifies
92214501Srpaulo * that SIGINT is to be trapped or ignored using the trap builtin, then
93214501Srpaulo * this routine is not called.)  Suppressint is nonzero when interrupts
94214501Srpaulo * are held using the INTOFF macro.  The call to _exit is necessary because
95214501Srpaulo * there is a short period after a fork before the signal handlers are
96214501Srpaulo * set to the appropriate value for the child.  (The test for iflag is
97214501Srpaulo * just defensive programming.)
98214501Srpaulo */
99214501Srpaulo
100214501Srpaulovoid
101214501Srpauloonint() {
102214501Srpaulo	sigset_t sigset;
103214501Srpaulo
104214501Srpaulo	if (suppressint) {
105214501Srpaulo		intpending++;
106214501Srpaulo		return;
107214501Srpaulo	}
108214501Srpaulo	intpending = 0;
109214501Srpaulo	sigemptyset(&sigset);
110214501Srpaulo	sigprocmask(SIG_SETMASK, &sigset, NULL);
111214501Srpaulo	out2str("\n");
112214501Srpaulo	if (rootshell && iflag)
113214501Srpaulo		exraise(EXINT);
114214501Srpaulo	else
115214501Srpaulo		_exit(128 + SIGINT);
116214501Srpaulo}
117214501Srpaulo
118214501Srpaulo
119214501Srpaulo/*
120214501Srpaulo * Exverror is called to raise the error exception.  If the first argument
121214501Srpaulo * is not NULL then error prints an error message using printf style
122214501Srpaulo * formatting.  It then raises the error exception.
123214501Srpaulo */
124214501Srpaulostatic void
125214501Srpauloexverror(cond, msg, ap)
126214501Srpaulo	int cond;
127214501Srpaulo	char *msg;
128214501Srpaulo	va_list ap;
129214501Srpaulo{
130214501Srpaulo	CLEAR_PENDING_INT;
131214501Srpaulo	INTOFF;
132214501Srpaulo
133214501Srpaulo#ifdef DEBUG
134214501Srpaulo	if (msg)
135214501Srpaulo		TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
136214501Srpaulo	else
137214501Srpaulo		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
138214501Srpaulo#endif
139214501Srpaulo	if (msg) {
140214501Srpaulo		if (commandname)
141214501Srpaulo			outfmt(&errout, "%s: ", commandname);
142214501Srpaulo		doformat(&errout, msg, ap);
143214501Srpaulo		out2c('\n');
144214501Srpaulo	}
145214501Srpaulo	flushall();
146214501Srpaulo	exraise(cond);
147214501Srpaulo}
148214501Srpaulo
149214501Srpaulo
150214501Srpaulo#ifdef __STDC__
151214501Srpaulovoid
152214501Srpauloerror(char *msg, ...)
153214501Srpaulo#else
154214501Srpaulovoid
155214501Srpauloerror(va_alist)
156214501Srpaulo	va_dcl
157214501Srpaulo#endif
158214501Srpaulo{
159214501Srpaulo#ifndef __STDC__
160214501Srpaulo	char *msg;
161214501Srpaulo#endif
162214501Srpaulo	va_list ap;
163214501Srpaulo#ifdef __STDC__
164214501Srpaulo	va_start(ap, msg);
165214501Srpaulo#else
166214501Srpaulo	va_start(ap);
167214501Srpaulo	msg = va_arg(ap, char *);
168214501Srpaulo#endif
169214501Srpaulo	exverror(EXERROR, msg, ap);
170214501Srpaulo	va_end(ap);
171214501Srpaulo}
172214501Srpaulo
173214501Srpaulo
174214501Srpaulo#ifdef __STDC__
175214501Srpaulovoid
176214501Srpauloexerror(int cond, char *msg, ...)
177214501Srpaulo#else
178214501Srpaulovoid
179214501Srpauloexerror(va_alist)
180214501Srpaulo	va_dcl
181214501Srpaulo#endif
182214501Srpaulo{
183214501Srpaulo#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
205struct 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
214STATIC 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
275char *
276errmsg(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