Home | History | Annotate | Line # | Download | only in sh
error.c revision 1.29
      1 /*	$NetBSD: error.c,v 1.29 2003/01/16 09:38:43 kleink 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.29 2003/01/16 09:38:43 kleink 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 #include <stdio.h>
     57 #include <string.h>
     58 
     59 #include "shell.h"
     60 #include "main.h"
     61 #include "options.h"
     62 #include "output.h"
     63 #include "error.h"
     64 #include "show.h"
     65 
     66 
     67 /*
     68  * Code to handle exceptions in C.
     69  */
     70 
     71 struct jmploc *handler;
     72 int exception;
     73 volatile int suppressint;
     74 volatile int intpending;
     75 char *commandname;
     76 
     77 
     78 static void exverror(int, const char *, va_list)
     79     __attribute__((__noreturn__));
     80 
     81 /*
     82  * Called to raise an exception.  Since C doesn't include exceptions, we
     83  * just do a longjmp to the exception handler.  The type of exception is
     84  * stored in the global variable "exception".
     85  */
     86 
     87 void
     88 exraise(int e)
     89 {
     90 	if (handler == NULL)
     91 		abort();
     92 	exception = e;
     93 	longjmp(handler->loc, 1);
     94 }
     95 
     96 
     97 /*
     98  * Called from trap.c when a SIGINT is received.  (If the user specifies
     99  * that SIGINT is to be trapped or ignored using the trap builtin, then
    100  * this routine is not called.)  Suppressint is nonzero when interrupts
    101  * are held using the INTOFF macro.  The call to _exit is necessary because
    102  * there is a short period after a fork before the signal handlers are
    103  * set to the appropriate value for the child.  (The test for iflag is
    104  * just defensive programming.)
    105  */
    106 
    107 void
    108 onint(void)
    109 {
    110 	sigset_t nsigset;
    111 
    112 	if (suppressint) {
    113 		intpending = 1;
    114 		return;
    115 	}
    116 	intpending = 0;
    117 	sigemptyset(&nsigset);
    118 	sigprocmask(SIG_SETMASK, &nsigset, NULL);
    119 	if (rootshell && iflag)
    120 		exraise(EXINT);
    121 	else {
    122 		signal(SIGINT, SIG_DFL);
    123 		raise(SIGINT);
    124 	}
    125 	/* NOTREACHED */
    126 }
    127 
    128 static void
    129 exvwarning(int sv_errno, const char *msg, va_list ap)
    130 {
    131 	/* Partially emulate line buffered output so that:
    132 	 *	printf '%d\n' 1 a 2
    133 	 * and
    134 	 *	printf '%d %d %d\n' 1 a 2
    135 	 * both generate sensible text when stdout and stderr are merged.
    136 	 */
    137 	if (output.nextc != output.buf && output.nextc[-1] == '\n')
    138 		flushout(&output);
    139 	if (commandname)
    140 		outfmt(&errout, "%s: ", commandname);
    141 	if (msg != NULL) {
    142 		doformat(&errout, msg, ap);
    143 		if (sv_errno >= 0)
    144 			outfmt(&errout, ": ");
    145 	}
    146 	if (sv_errno >= 0)
    147 		outfmt(&errout, "%s", strerror(sv_errno));
    148 	out2c('\n');
    149 	flushout(&errout);
    150 }
    151 
    152 /*
    153  * Exverror is called to raise the error exception.  If the second argument
    154  * is not NULL then error prints an error message using printf style
    155  * formatting.  It then raises the error exception.
    156  */
    157 static void
    158 exverror(int cond, const char *msg, va_list ap)
    159 {
    160 	CLEAR_PENDING_INT;
    161 	INTOFF;
    162 
    163 #ifdef DEBUG
    164 	if (msg)
    165 		TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
    166 	else
    167 		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
    168 #endif
    169 	if (msg)
    170 		exvwarning(-1, msg, ap);
    171 
    172 	flushall();
    173 	exraise(cond);
    174 	/* NOTREACHED */
    175 }
    176 
    177 
    178 void
    179 error(const char *msg, ...)
    180 {
    181 	va_list ap;
    182 
    183 	va_start(ap, msg);
    184 	exverror(EXERROR, msg, ap);
    185 	/* NOTREACHED */
    186 	va_end(ap);
    187 }
    188 
    189 
    190 void
    191 exerror(int cond, const char *msg, ...)
    192 {
    193 	va_list ap;
    194 
    195 	va_start(ap, msg);
    196 	exverror(cond, msg, ap);
    197 	/* NOTREACHED */
    198 	va_end(ap);
    199 }
    200 
    201 /*
    202  * error/warning routines for external builtins
    203  */
    204 
    205 void
    206 sh_exit(int rval)
    207 {
    208 	exerrno = rval & 255;
    209 	exraise(EXEXEC);
    210 }
    211 
    212 void
    213 sh_err(int status, const char *fmt, ...)
    214 {
    215 	va_list ap;
    216 
    217 	va_start(ap, fmt);
    218 	exvwarning(errno, fmt, ap);
    219 	va_end(ap);
    220 	sh_exit(status);
    221 }
    222 
    223 void
    224 sh_verr(int status, const char *fmt, va_list ap)
    225 {
    226 	exvwarning(errno, fmt, ap);
    227 	sh_exit(status);
    228 }
    229 
    230 void
    231 sh_errx(int status, const char *fmt, ...)
    232 {
    233 	va_list ap;
    234 
    235 	va_start(ap, fmt);
    236 	exvwarning(-1, fmt, ap);
    237 	va_end(ap);
    238 	sh_exit(status);
    239 }
    240 
    241 void
    242 sh_verrx(int status, const char *fmt, va_list ap)
    243 {
    244 	exvwarning(-1, fmt, ap);
    245 	sh_exit(status);
    246 }
    247 
    248 void
    249 sh_warn(const char *fmt, ...)
    250 {
    251 	va_list ap;
    252 
    253 	va_start(ap, fmt);
    254 	exvwarning(errno, fmt, ap);
    255 	va_end(ap);
    256 }
    257 
    258 void
    259 sh_vwarn(const char *fmt, va_list ap)
    260 {
    261 	exvwarning(errno, fmt, ap);
    262 }
    263 
    264 void
    265 sh_warnx(const char *fmt, ...)
    266 {
    267 	va_list ap;
    268 
    269 	va_start(ap, fmt);
    270 	exvwarning(-1, fmt, ap);
    271 	va_end(ap);
    272 }
    273 
    274 void
    275 sh_vwarnx(const char *fmt, va_list ap)
    276 {
    277 	exvwarning(-1, fmt, ap);
    278 }
    279 
    280 
    281 /*
    282  * Table of error messages.
    283  */
    284 
    285 struct errname {
    286 	short errcode;		/* error number */
    287 	short action;		/* operation which encountered the error */
    288 	const char *msg;	/* text describing the error */
    289 };
    290 
    291 
    292 #define ALL (E_OPEN|E_CREAT|E_EXEC)
    293 
    294 STATIC const struct errname errormsg[] = {
    295 	{ EINTR,	ALL,	"interrupted" },
    296 	{ EACCES,	ALL,	"permission denied" },
    297 	{ EIO,		ALL,	"I/O error" },
    298 	{ EEXIST,	ALL,	"file exists" },
    299 	{ ENOENT,	E_OPEN,	"no such file" },
    300 	{ ENOENT,	E_CREAT,"directory nonexistent" },
    301 	{ ENOENT,	E_EXEC,	"not found" },
    302 	{ ENOTDIR,	E_OPEN,	"no such file" },
    303 	{ ENOTDIR,	E_CREAT,"directory nonexistent" },
    304 	{ ENOTDIR,	E_EXEC,	"not found" },
    305 	{ EISDIR,	ALL,	"is a directory" },
    306 #ifdef EMFILE
    307 	{ EMFILE,	ALL,	"too many open files" },
    308 #endif
    309 	{ ENFILE,	ALL,	"file table overflow" },
    310 	{ ENOSPC,	ALL,	"file system full" },
    311 #ifdef EDQUOT
    312 	{ EDQUOT,	ALL,	"disk quota exceeded" },
    313 #endif
    314 #ifdef ENOSR
    315 	{ ENOSR,	ALL,	"no streams resources" },
    316 #endif
    317 	{ ENXIO,	ALL,	"no such device or address" },
    318 	{ EROFS,	ALL,	"read-only file system" },
    319 	{ ETXTBSY,	ALL,	"text busy" },
    320 #ifdef EAGAIN
    321 	{ EAGAIN,	E_EXEC,	"not enough memory" },
    322 #endif
    323 	{ ENOMEM,	ALL,	"not enough memory" },
    324 #ifdef ENOLINK
    325 	{ ENOLINK,	ALL,	"remote access failed" },
    326 #endif
    327 #ifdef EMULTIHOP
    328 	{ EMULTIHOP,	ALL,	"remote access failed" },
    329 #endif
    330 #ifdef ECOMM
    331 	{ ECOMM,	ALL,	"remote access failed" },
    332 #endif
    333 #ifdef ESTALE
    334 	{ ESTALE,	ALL,	"remote access failed" },
    335 #endif
    336 #ifdef ETIMEDOUT
    337 	{ ETIMEDOUT,	ALL,	"remote access failed" },
    338 #endif
    339 #ifdef ELOOP
    340 	{ ELOOP,	ALL,	"symbolic link loop" },
    341 #endif
    342 	{ E2BIG,	E_EXEC,	"argument list too long" },
    343 #ifdef ELIBACC
    344 	{ ELIBACC,	E_EXEC,	"shared library missing" },
    345 #endif
    346 	{ 0,		0,	NULL },
    347 };
    348 
    349 
    350 /*
    351  * Return a string describing an error.  The returned string may be a
    352  * pointer to a static buffer that will be overwritten on the next call.
    353  * Action describes the operation that got the error.
    354  */
    355 
    356 const char *
    357 errmsg(int e, int action)
    358 {
    359 	struct errname const *ep;
    360 	static char buf[12];
    361 
    362 	for (ep = errormsg ; ep->errcode ; ep++) {
    363 		if (ep->errcode == e && (ep->action & action) != 0)
    364 			return ep->msg;
    365 	}
    366 	fmtstr(buf, sizeof buf, "error %d", e);
    367 	return buf;
    368 }
    369