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