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