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