xref: /netbsd-src/bin/sh/error.c (revision 4b30c543a0b21e3ba94f2c569e9a82b4fdb2075f)
1 /*-
2  * Copyright (c) 1991 The Regents of the University of California.
3  * 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 /*static char sccsid[] = "from: @(#)error.c	5.1 (Berkeley) 3/7/91";*/
39 static char rcsid[] = "$Id: error.c,v 1.5 1993/09/05 17:32:05 mycroft Exp $";
40 #endif /* not lint */
41 
42 /*
43  * Errors and exceptions.
44  */
45 
46 #include "shell.h"
47 #include "main.h"
48 #include "options.h"
49 #include "output.h"
50 #include "error.h"
51 #include <signal.h>
52 #ifdef __STDC__
53 #include "stdarg.h"
54 #else
55 #include <varargs.h>
56 #endif
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 /*
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 	if (handler == NULL)
80 		abort();
81 	exception = e;
82 	longjmp(handler->loc, 1);
83 }
84 
85 
86 /*
87  * Called from trap.c when a SIGINT is received.  (If the user specifies
88  * that SIGINT is to be trapped or ignored using the trap builtin, then
89  * this routine is not called.)  Suppressint is nonzero when interrupts
90  * are held using the INTOFF macro.  The call to _exit is necessary because
91  * there is a short period after a fork before the signal handlers are
92  * set to the appropriate value for the child.  (The test for iflag is
93  * just defensive programming.)
94  */
95 
96 void
97 onint() {
98 	if (suppressint) {
99 		intpending++;
100 		return;
101 	}
102 	intpending = 0;
103 #ifdef BSD
104 	sigsetmask(0);
105 #endif
106 	if (rootshell && iflag)
107 		exraise(EXINT);
108 	else
109 		_exit(128 + SIGINT);
110 }
111 
112 
113 
114 void
115 error2(a, b)
116 	char *a, *b;
117 	{
118 	error("%s: %s", a, b);
119 }
120 
121 
122 /*
123  * Error is called to raise the error exception.  If the first argument
124  * is not NULL then error prints an error message using printf style
125  * formatting.  It then raises the error exception.
126  */
127 
128 #ifdef __STDC__
129 void
130 error(char *msg, ...) {
131 #else
132 void
133 error(va_alist)
134 	va_dcl
135 	{
136 	char *msg;
137 #endif
138 	va_list ap;
139 
140 	CLEAR_PENDING_INT;
141 	INTOFF;
142 #ifdef __STDC__
143 	va_start(ap, msg);
144 #else
145 	va_start(ap);
146 	msg = va_arg(ap, char *);
147 #endif
148 #ifdef DEBUG
149 	if (msg)
150 		TRACE(("error(\"%s\") pid=%d\n", msg, getpid()));
151 	else
152 		TRACE(("error(NULL) pid=%d\n", getpid()));
153 #endif
154 	if (msg) {
155 		if (commandname)
156 			outfmt(&errout, "%s: ", commandname);
157 		doformat(&errout, msg, ap);
158 		out2c('\n');
159 	}
160 	va_end(ap);
161 	flushall();
162 	exraise(EXERROR);
163 }
164 
165 
166 
167 /*
168  * Table of error messages.
169  */
170 
171 struct errname {
172 	short errcode;		/* error number */
173 	short action;		/* operation which encountered the error */
174 	char *msg;		/* text describing the error */
175 };
176 
177 
178 #define ALL (E_OPEN|E_CREAT|E_EXEC)
179 
180 STATIC const struct errname errormsg[] = {
181 	EINTR, ALL,		"interrupted",
182 	EACCES, ALL,		"permission denied",
183 	EIO, ALL,		"I/O error",
184 	ENOENT, E_OPEN,		"no such file",
185 	ENOENT, E_CREAT,	"directory nonexistent",
186 	ENOENT, E_EXEC,		"not found",
187 	ENOTDIR, E_OPEN,	"no such file",
188 	ENOTDIR, E_CREAT,	"directory nonexistent",
189 	ENOTDIR, E_EXEC,	"not found",
190 	EISDIR, ALL,		"is a directory",
191 /*    EMFILE, ALL,		"too many open files", */
192 	ENFILE, ALL,		"file table overflow",
193 	ENOSPC, ALL,		"file system full",
194 #ifdef EDQUOT
195 	EDQUOT, ALL,		"disk quota exceeded",
196 #endif
197 #ifdef ENOSR
198 	ENOSR, ALL,		"no streams resources",
199 #endif
200 	ENXIO, ALL,		"no such device or address",
201 	EROFS, ALL,		"read-only file system",
202 	ETXTBSY, ALL,		"text busy",
203 #ifdef SYSV
204 	EAGAIN, E_EXEC,		"not enough memory",
205 #endif
206 	ENOMEM, ALL,		"not enough memory",
207 #ifdef ENOLINK
208 	ENOLINK, ALL,		"remote access failed",
209 #endif
210 #ifdef EMULTIHOP
211 	EMULTIHOP, ALL,		"remote access failed",
212 #endif
213 #ifdef ECOMM
214 	ECOMM, ALL,		"remote access failed",
215 #endif
216 #ifdef ESTALE
217 	ESTALE, ALL,		"remote access failed",
218 #endif
219 #ifdef ETIMEDOUT
220 	ETIMEDOUT, ALL,		"remote access failed",
221 #endif
222 #ifdef ELOOP
223 	ELOOP, ALL,		"symbolic link loop",
224 #endif
225 	E2BIG, E_EXEC,		"argument list too long",
226 #ifdef ELIBACC
227 	ELIBACC, E_EXEC,	"shared library missing",
228 #endif
229 	0, 0,			NULL
230 };
231 
232 
233 /*
234  * Return a string describing an error.  The returned string may be a
235  * pointer to a static buffer that will be overwritten on the next call.
236  * Action describes the operation that got the error.
237  */
238 
239 char *
240 errmsg(e, action) {
241 	struct errname const *ep;
242 	static char buf[12];
243 
244 	for (ep = errormsg ; ep->errcode ; ep++) {
245 		if (ep->errcode == e && (ep->action & action) != 0)
246 			return ep->msg;
247 	}
248 	fmtstr(buf, sizeof buf, "error %d", e);
249 	return buf;
250 }
251