Home | History | Annotate | Line # | Download | only in sh
error.c revision 1.21
      1 /*	$NetBSD: error.c,v 1.21 1999/04/05 15:00:28 mycroft 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 #include <sys/cdefs.h>
     40 #ifndef lint
     41 #if 0
     42 static char sccsid[] = "@(#)error.c	8.2 (Berkeley) 5/4/95";
     43 #else
     44 __RCSID("$NetBSD: error.c,v 1.21 1999/04/05 15:00:28 mycroft Exp $");
     45 #endif
     46 #endif /* not lint */
     47 
     48 /*
     49  * Errors and exceptions.
     50  */
     51 
     52 #include <signal.h>
     53 #include <unistd.h>
     54 #include <errno.h>
     55 
     56 #include "shell.h"
     57 #include "main.h"
     58 #include "options.h"
     59 #include "output.h"
     60 #include "error.h"
     61 #include "show.h"
     62 
     63 
     64 /*
     65  * Code to handle exceptions in C.
     66  */
     67 
     68 struct jmploc *handler;
     69 int exception;
     70 volatile int suppressint;
     71 volatile int intpending;
     72 char *commandname;
     73 
     74 
     75 static void exverror __P((int, char *, va_list)) __attribute__((__noreturn__));
     76 
     77 /*
     78  * Called to raise an exception.  Since C doesn't include exceptions, we
     79  * just do a longjmp to the exception handler.  The type of exception is
     80  * stored in the global variable "exception".
     81  */
     82 
     83 void
     84 exraise(e)
     85 	int e;
     86 {
     87 	if (handler == NULL)
     88 		abort();
     89 	exception = e;
     90 	longjmp(handler->loc, 1);
     91 }
     92 
     93 
     94 /*
     95  * Called from trap.c when a SIGINT is received.  (If the user specifies
     96  * that SIGINT is to be trapped or ignored using the trap builtin, then
     97  * this routine is not called.)  Suppressint is nonzero when interrupts
     98  * are held using the INTOFF macro.  The call to _exit is necessary because
     99  * there is a short period after a fork before the signal handlers are
    100  * set to the appropriate value for the child.  (The test for iflag is
    101  * just defensive programming.)
    102  */
    103 
    104 void
    105 onint() {
    106 	sigset_t sigset;
    107 
    108 	if (suppressint) {
    109 		intpending++;
    110 		return;
    111 	}
    112 	intpending = 0;
    113 	sigemptyset(&sigset);
    114 	sigprocmask(SIG_SETMASK, &sigset, NULL);
    115 	if (rootshell && iflag)
    116 		exraise(EXINT);
    117 	else {
    118 		signal(SIGINT, SIG_DFL);
    119 		raise(SIGINT);
    120 	}
    121 	/* NOTREACHED */
    122 }
    123 
    124 
    125 /*
    126  * Exverror is called to raise the error exception.  If the first argument
    127  * is not NULL then error prints an error message using printf style
    128  * formatting.  It then raises the error exception.
    129  */
    130 static void
    131 exverror(cond, msg, ap)
    132 	int cond;
    133 	char *msg;
    134 	va_list ap;
    135 {
    136 	CLEAR_PENDING_INT;
    137 	INTOFF;
    138 
    139 #ifdef DEBUG
    140 	if (msg)
    141 		TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
    142 	else
    143 		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
    144 #endif
    145 	if (msg) {
    146 		if (commandname)
    147 			outfmt(&errout, "%s: ", commandname);
    148 		doformat(&errout, msg, ap);
    149 		out2c('\n');
    150 	}
    151 	flushall();
    152 	exraise(cond);
    153 	/* NOTREACHED */
    154 }
    155 
    156 
    157 #ifdef __STDC__
    158 void
    159 error(char *msg, ...)
    160 #else
    161 void
    162 error(va_alist)
    163 	va_dcl
    164 #endif
    165 {
    166 #ifndef __STDC__
    167 	char *msg;
    168 #endif
    169 	va_list ap;
    170 #ifdef __STDC__
    171 	va_start(ap, msg);
    172 #else
    173 	va_start(ap);
    174 	msg = va_arg(ap, char *);
    175 #endif
    176 	exverror(EXERROR, msg, ap);
    177 	/* NOTREACHED */
    178 	va_end(ap);
    179 }
    180 
    181 
    182 #ifdef __STDC__
    183 void
    184 exerror(int cond, char *msg, ...)
    185 #else
    186 void
    187 exerror(va_alist)
    188 	va_dcl
    189 #endif
    190 {
    191 #ifndef __STDC__
    192 	int cond;
    193 	char *msg;
    194 #endif
    195 	va_list ap;
    196 #ifdef __STDC__
    197 	va_start(ap, msg);
    198 #else
    199 	va_start(ap);
    200 	cond = va_arg(ap, int);
    201 	msg = va_arg(ap, char *);
    202 #endif
    203 	exverror(cond, msg, ap);
    204 	/* NOTREACHED */
    205 	va_end(ap);
    206 }
    207 
    208 
    209 
    210 /*
    211  * Table of error messages.
    212  */
    213 
    214 struct errname {
    215 	short errcode;		/* error number */
    216 	short action;		/* operation which encountered the error */
    217 	char *msg;		/* text describing the error */
    218 };
    219 
    220 
    221 #define ALL (E_OPEN|E_CREAT|E_EXEC)
    222 
    223 STATIC const struct errname errormsg[] = {
    224 	{ EINTR,	ALL,	"interrupted" },
    225 	{ EACCES,	ALL,	"permission denied" },
    226 	{ EIO,		ALL,	"I/O error" },
    227 	{ ENOENT,	E_OPEN,	"no such file" },
    228 	{ ENOENT,	E_CREAT,"directory nonexistent" },
    229 	{ ENOENT,	E_EXEC,	"not found" },
    230 	{ ENOTDIR,	E_OPEN,	"no such file" },
    231 	{ ENOTDIR,	E_CREAT,"directory nonexistent" },
    232 	{ ENOTDIR,	E_EXEC,	"not found" },
    233 	{ EISDIR,	ALL,	"is a directory" },
    234 #ifdef notdef
    235 	{ EMFILE,	ALL,	"too many open files" },
    236 #endif
    237 	{ ENFILE,	ALL,	"file table overflow" },
    238 	{ ENOSPC,	ALL,	"file system full" },
    239 #ifdef EDQUOT
    240 	{ EDQUOT,	ALL,	"disk quota exceeded" },
    241 #endif
    242 #ifdef ENOSR
    243 	{ ENOSR,	ALL,	"no streams resources" },
    244 #endif
    245 	{ ENXIO,	ALL,	"no such device or address" },
    246 	{ EROFS,	ALL,	"read-only file system" },
    247 	{ ETXTBSY,	ALL,	"text busy" },
    248 #ifdef SYSV
    249 	{ EAGAIN,	E_EXEC,	"not enough memory" },
    250 #endif
    251 	{ ENOMEM,	ALL,	"not enough memory" },
    252 #ifdef ENOLINK
    253 	{ ENOLINK,	ALL,	"remote access failed" },
    254 #endif
    255 #ifdef EMULTIHOP
    256 	{ EMULTIHOP,	ALL,	"remote access failed" },
    257 #endif
    258 #ifdef ECOMM
    259 	{ ECOMM,	ALL,	"remote access failed" },
    260 #endif
    261 #ifdef ESTALE
    262 	{ ESTALE,	ALL,	"remote access failed" },
    263 #endif
    264 #ifdef ETIMEDOUT
    265 	{ ETIMEDOUT,	ALL,	"remote access failed" },
    266 #endif
    267 #ifdef ELOOP
    268 	{ ELOOP,	ALL,	"symbolic link loop" },
    269 #endif
    270 	{ E2BIG,	E_EXEC,	"argument list too long" },
    271 #ifdef ELIBACC
    272 	{ ELIBACC,	E_EXEC,	"shared library missing" },
    273 #endif
    274 	{ 0,		0,	NULL },
    275 };
    276 
    277 
    278 /*
    279  * Return a string describing an error.  The returned string may be a
    280  * pointer to a static buffer that will be overwritten on the next call.
    281  * Action describes the operation that got the error.
    282  */
    283 
    284 char *
    285 errmsg(e, action)
    286 	int e;
    287 	int action;
    288 {
    289 	struct errname const *ep;
    290 	static char buf[12];
    291 
    292 	for (ep = errormsg ; ep->errcode ; ep++) {
    293 		if (ep->errcode == e && (ep->action & action) != 0)
    294 			return ep->msg;
    295 	}
    296 	fmtstr(buf, sizeof buf, "error %d", e);
    297 	return buf;
    298 }
    299