Home | History | Annotate | Line # | Download | only in sh
error.c revision 1.15
      1 /*	$NetBSD: error.c,v 1.15 1996/10/16 14:35:42 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1991, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Kenneth Almquist.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  */
     38 
     39 #ifndef lint
     40 #if 0
     41 static char sccsid[] = "@(#)error.c	8.2 (Berkeley) 5/4/95";
     42 #else
     43 static char rcsid[] = "$NetBSD: error.c,v 1.15 1996/10/16 14:35:42 christos Exp $";
     44 #endif
     45 #endif /* not lint */
     46 
     47 /*
     48  * Errors and exceptions.
     49  */
     50 
     51 #include "shell.h"
     52 #include "main.h"
     53 #include "options.h"
     54 #include "output.h"
     55 #include "error.h"
     56 #include "show.h"
     57 #include <signal.h>
     58 #include <unistd.h>
     59 #include <errno.h>
     60 
     61 
     62 /*
     63  * Code to handle exceptions in C.
     64  */
     65 
     66 struct jmploc *handler;
     67 int exception;
     68 volatile int suppressint;
     69 volatile int intpending;
     70 char *commandname;
     71 
     72 
     73 static void exverror __P((int, char *, va_list));
     74 
     75 /*
     76  * Called to raise an exception.  Since C doesn't include exceptions, we
     77  * just do a longjmp to the exception handler.  The type of exception is
     78  * stored in the global variable "exception".
     79  */
     80 
     81 void
     82 exraise(e)
     83 	int e;
     84 {
     85 	if (handler == NULL)
     86 		abort();
     87 	exception = e;
     88 	longjmp(handler->loc, 1);
     89 }
     90 
     91 
     92 /*
     93  * Called from trap.c when a SIGINT is received.  (If the user specifies
     94  * that SIGINT is to be trapped or ignored using the trap builtin, then
     95  * this routine is not called.)  Suppressint is nonzero when interrupts
     96  * are held using the INTOFF macro.  The call to _exit is necessary because
     97  * there is a short period after a fork before the signal handlers are
     98  * set to the appropriate value for the child.  (The test for iflag is
     99  * just defensive programming.)
    100  */
    101 
    102 void
    103 onint() {
    104 	sigset_t sigset;
    105 
    106 	if (suppressint) {
    107 		intpending++;
    108 		return;
    109 	}
    110 	intpending = 0;
    111 	sigemptyset(&sigset);
    112 	sigprocmask(SIG_SETMASK, &sigset, NULL);
    113 	if (rootshell && iflag)
    114 		exraise(EXINT);
    115 	else
    116 		_exit(128 + SIGINT);
    117 }
    118 
    119 
    120 /*
    121  * Exverror is called to raise the error exception.  If the first argument
    122  * is not NULL then error prints an error message using printf style
    123  * formatting.  It then raises the error exception.
    124  */
    125 static void
    126 exverror(cond, msg, ap)
    127 	int cond;
    128 	char *msg;
    129 	va_list ap;
    130 {
    131 	CLEAR_PENDING_INT;
    132 	INTOFF;
    133 
    134 #ifdef DEBUG
    135 	if (msg)
    136 		TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
    137 	else
    138 		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
    139 #endif
    140 	if (msg) {
    141 		if (commandname)
    142 			outfmt(&errout, "%s: ", commandname);
    143 		doformat(&errout, msg, ap);
    144 		out2c('\n');
    145 	}
    146 	flushall();
    147 	exraise(cond);
    148 }
    149 
    150 
    151 #if __STDC__
    152 void
    153 error(char *msg, ...)
    154 #else
    155 void
    156 error(va_alist)
    157 	va_dcl
    158 #endif
    159 {
    160 #if !__STDC__
    161 	char *msg;
    162 #endif
    163 	va_list ap;
    164 #if __STDC__
    165 	va_start(ap, msg);
    166 #else
    167 	va_start(ap);
    168 	msg = va_arg(ap, char *);
    169 #endif
    170 	exverror(EXERROR, msg, ap);
    171 	va_end(ap);
    172 }
    173 
    174 
    175 #if __STDC__
    176 void
    177 exerror(int cond, char *msg, ...)
    178 #else
    179 void
    180 exerror(va_alist)
    181 	va_dcl
    182 #endif
    183 {
    184 #if !__STDC__
    185 	int cond;
    186 	char *msg;
    187 #endif
    188 	va_list ap;
    189 #if __STDC__
    190 	va_start(ap, msg);
    191 #else
    192 	va_start(ap);
    193 	cond = va_arg(ap, int);
    194 	msg = va_arg(ap, char *);
    195 #endif
    196 	exverror(cond, msg, ap);
    197 	va_end(ap);
    198 }
    199 
    200 
    201 
    202 /*
    203  * Table of error messages.
    204  */
    205 
    206 struct errname {
    207 	short errcode;		/* error number */
    208 	short action;		/* operation which encountered the error */
    209 	char *msg;		/* text describing the error */
    210 };
    211 
    212 
    213 #define ALL (E_OPEN|E_CREAT|E_EXEC)
    214 
    215 STATIC const struct errname errormsg[] = {
    216 	{ EINTR,	ALL,	"interrupted" },
    217 	{ EACCES,	ALL,	"permission denied" },
    218 	{ EIO,		ALL,	"I/O error" },
    219 	{ ENOENT,	E_OPEN,	"no such file" },
    220 	{ ENOENT,	E_CREAT,"directory nonexistent" },
    221 	{ ENOENT,	E_EXEC,	"not found" },
    222 	{ ENOTDIR,	E_OPEN,	"no such file" },
    223 	{ ENOTDIR,	E_CREAT,"directory nonexistent" },
    224 	{ ENOTDIR,	E_EXEC,	"not found" },
    225 	{ EISDIR,	ALL,	"is a directory" },
    226 #ifdef notdef
    227 	{ EMFILE,	ALL,	"too many open files" },
    228 #endif
    229 	{ ENFILE,	ALL,	"file table overflow" },
    230 	{ ENOSPC,	ALL,	"file system full" },
    231 #ifdef EDQUOT
    232 	{ EDQUOT,	ALL,	"disk quota exceeded" },
    233 #endif
    234 #ifdef ENOSR
    235 	{ ENOSR,	ALL,	"no streams resources" },
    236 #endif
    237 	{ ENXIO,	ALL,	"no such device or address" },
    238 	{ EROFS,	ALL,	"read-only file system" },
    239 	{ ETXTBSY,	ALL,	"text busy" },
    240 #ifdef SYSV
    241 	{ EAGAIN,	E_EXEC,	"not enough memory" },
    242 #endif
    243 	{ ENOMEM,	ALL,	"not enough memory" },
    244 #ifdef ENOLINK
    245 	{ ENOLINK,	ALL,	"remote access failed" },
    246 #endif
    247 #ifdef EMULTIHOP
    248 	{ EMULTIHOP,	ALL,	"remote access failed" },
    249 #endif
    250 #ifdef ECOMM
    251 	{ ECOMM,	ALL,	"remote access failed" },
    252 #endif
    253 #ifdef ESTALE
    254 	{ ESTALE,	ALL,	"remote access failed" },
    255 #endif
    256 #ifdef ETIMEDOUT
    257 	{ ETIMEDOUT,	ALL,	"remote access failed" },
    258 #endif
    259 #ifdef ELOOP
    260 	{ ELOOP,	ALL,	"symbolic link loop" },
    261 #endif
    262 	{ E2BIG,	E_EXEC,	"argument list too long" },
    263 #ifdef ELIBACC
    264 	{ ELIBACC,	E_EXEC,	"shared library missing" },
    265 #endif
    266 	{ 0,		0,	NULL },
    267 };
    268 
    269 
    270 /*
    271  * Return a string describing an error.  The returned string may be a
    272  * pointer to a static buffer that will be overwritten on the next call.
    273  * Action describes the operation that got the error.
    274  */
    275 
    276 char *
    277 errmsg(e, action)
    278 	int e;
    279 	int action;
    280 {
    281 	struct errname const *ep;
    282 	static char buf[12];
    283 
    284 	for (ep = errormsg ; ep->errcode ; ep++) {
    285 		if (ep->errcode == e && (ep->action & action) != 0)
    286 			return ep->msg;
    287 	}
    288 	fmtstr(buf, sizeof buf, "error %d", e);
    289 	return buf;
    290 }
    291