Home | History | Annotate | Download | only in sh
      1 /*	$NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc 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. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>
     36 #ifndef lint
     37 #if 0
     38 static char sccsid[] = "@(#)error.c	8.2 (Berkeley) 5/4/95";
     39 #else
     40 __RCSID("$NetBSD: error.c,v 1.31 2003/08/07 09:05:30 agc Exp $");
     41 #endif
     42 #endif /* not lint */
     43 
     44 /*
     45  * Errors and exceptions.
     46  */
     47 
     48 #include <signal.h>
     49 #include <stdlib.h>
     50 #include <unistd.h>
     51 #include <errno.h>
     52 #include <stdio.h>
     53 #include <string.h>
     54 
     55 #include "shell.h"
     56 #include "main.h"
     57 #include "options.h"
     58 #include "output.h"
     59 #include "error.h"
     60 #include "show.h"
     61 
     62 #define signal bsd_signal
     63 /*
     64  * Code to handle exceptions in C.
     65  */
     66 
     67 struct jmploc *handler;
     68 int exception;
     69 volatile int suppressint;
     70 volatile int intpending;
     71 char *commandname;
     72 
     73 
     74 static void exverror(int, const char *, va_list)
     75     __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(int e)
     85 {
     86 	if (handler == NULL)
     87 		abort();
     88 	exception = e;
     89 	longjmp(handler->loc, 1);
     90 }
     91 
     92 
     93 /*
     94  * Called from trap.c when a SIGINT is received.  (If the user specifies
     95  * that SIGINT is to be trapped or ignored using the trap builtin, then
     96  * this routine is not called.)  Suppressint is nonzero when interrupts
     97  * are held using the INTOFF macro.  The call to _exit is necessary because
     98  * there is a short period after a fork before the signal handlers are
     99  * set to the appropriate value for the child.  (The test for iflag is
    100  * just defensive programming.)
    101  */
    102 
    103 void
    104 onint(void)
    105 {
    106 	sigset_t nsigset;
    107 
    108 	if (suppressint) {
    109 		intpending = 1;
    110 		return;
    111 	}
    112 	intpending = 0;
    113 	sigemptyset(&nsigset);
    114 	sigprocmask(SIG_SETMASK, &nsigset, NULL);
    115 	if (rootshell && iflag)
    116 		exraise(EXINT);
    117 	else {
    118 		signal(SIGINT, SIG_DFL);
    119 		raise(SIGINT);
    120 	}
    121 	/* NOTREACHED */
    122 }
    123 
    124 static void
    125 exvwarning(int sv_errno, const char *msg, va_list ap)
    126 {
    127 	/* Partially emulate line buffered output so that:
    128 	 *	printf '%d\n' 1 a 2
    129 	 * and
    130 	 *	printf '%d %d %d\n' 1 a 2
    131 	 * both generate sensible text when stdout and stderr are merged.
    132 	 */
    133 	if (output.nextc != output.buf && output.nextc[-1] == '\n')
    134 		flushout(&output);
    135 	if (commandname)
    136 		outfmt(&errout, "%s: ", commandname);
    137 	if (msg != NULL) {
    138 		doformat(&errout, msg, ap);
    139 		if (sv_errno >= 0)
    140 			outfmt(&errout, ": ");
    141 	}
    142 	if (sv_errno >= 0)
    143 		outfmt(&errout, "%s", strerror(sv_errno));
    144 	out2c('\n');
    145 	flushout(&errout);
    146 }
    147 
    148 /*
    149  * Exverror is called to raise the error exception.  If the second argument
    150  * is not NULL then error prints an error message using printf style
    151  * formatting.  It then raises the error exception.
    152  */
    153 static void
    154 exverror(int cond, const char *msg, va_list ap)
    155 {
    156 	CLEAR_PENDING_INT;
    157 	INTOFF;
    158 
    159 #ifdef DEBUG
    160 	if (msg) {
    161 		TRACE(("exverror(%d, \"", cond));
    162 		TRACEV((msg, ap));
    163 		TRACE(("\") pid=%d\n", getpid()));
    164 	} else
    165 		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
    166 #endif
    167 	if (msg)
    168 		exvwarning(-1, msg, ap);
    169 
    170 	flushall();
    171 	exraise(cond);
    172 	/* NOTREACHED */
    173 }
    174 
    175 
    176 void
    177 error(const char *msg, ...)
    178 {
    179 	va_list ap;
    180 
    181 	va_start(ap, msg);
    182 	exverror(EXERROR, msg, ap);
    183 	/* NOTREACHED */
    184 	va_end(ap);
    185 }
    186 
    187 
    188 void
    189 exerror(int cond, const char *msg, ...)
    190 {
    191 	va_list ap;
    192 
    193 	va_start(ap, msg);
    194 	exverror(cond, msg, ap);
    195 	/* NOTREACHED */
    196 	va_end(ap);
    197 }
    198 
    199 /*
    200  * error/warning routines for external builtins
    201  */
    202 
    203 void
    204 sh_exit(int rval)
    205 {
    206 	exerrno = rval & 255;
    207 	exraise(EXEXEC);
    208 }
    209 
    210 void
    211 sh_err(int status, const char *fmt, ...)
    212 {
    213 	va_list ap;
    214 
    215 	va_start(ap, fmt);
    216 	exvwarning(errno, fmt, ap);
    217 	va_end(ap);
    218 	sh_exit(status);
    219 }
    220 
    221 void
    222 sh_verr(int status, const char *fmt, va_list ap)
    223 {
    224 	exvwarning(errno, fmt, ap);
    225 	sh_exit(status);
    226 }
    227 
    228 void
    229 sh_errx(int status, const char *fmt, ...)
    230 {
    231 	va_list ap;
    232 
    233 	va_start(ap, fmt);
    234 	exvwarning(-1, fmt, ap);
    235 	va_end(ap);
    236 	sh_exit(status);
    237 }
    238 
    239 void
    240 sh_verrx(int status, const char *fmt, va_list ap)
    241 {
    242 	exvwarning(-1, fmt, ap);
    243 	sh_exit(status);
    244 }
    245 
    246 void
    247 sh_warn(const char *fmt, ...)
    248 {
    249 	va_list ap;
    250 
    251 	va_start(ap, fmt);
    252 	exvwarning(errno, fmt, ap);
    253 	va_end(ap);
    254 }
    255 
    256 void
    257 sh_vwarn(const char *fmt, va_list ap)
    258 {
    259 	exvwarning(errno, fmt, ap);
    260 }
    261 
    262 void
    263 sh_warnx(const char *fmt, ...)
    264 {
    265 	va_list ap;
    266 
    267 	va_start(ap, fmt);
    268 	exvwarning(-1, fmt, ap);
    269 	va_end(ap);
    270 }
    271 
    272 void
    273 sh_vwarnx(const char *fmt, va_list ap)
    274 {
    275 	exvwarning(-1, fmt, ap);
    276 }
    277 
    278 
    279 /*
    280  * Table of error messages.
    281  */
    282 
    283 struct errname {
    284 	short errcode;		/* error number */
    285 	short action;		/* operation which encountered the error */
    286 	const char *msg;	/* text describing the error */
    287 };
    288 
    289 
    290 #define ALL (E_OPEN|E_CREAT|E_EXEC)
    291 
    292 STATIC const struct errname errormsg[] = {
    293 	{ EINTR,	ALL,	"interrupted" },
    294 	{ EACCES,	ALL,	"permission denied" },
    295 	{ EIO,		ALL,	"I/O error" },
    296 	{ EEXIST,	ALL,	"file exists" },
    297 	{ ENOENT,	E_OPEN,	"no such file" },
    298 	{ ENOENT,	E_CREAT,"directory nonexistent" },
    299 	{ ENOENT,	E_EXEC,	"not found" },
    300 	{ ENOTDIR,	E_OPEN,	"no such file" },
    301 	{ ENOTDIR,	E_CREAT,"directory nonexistent" },
    302 	{ ENOTDIR,	E_EXEC,	"not found" },
    303 	{ EISDIR,	ALL,	"is a directory" },
    304 #ifdef EMFILE
    305 	{ EMFILE,	ALL,	"too many open files" },
    306 #endif
    307 	{ ENFILE,	ALL,	"file table overflow" },
    308 	{ ENOSPC,	ALL,	"file system full" },
    309 #ifdef EDQUOT
    310 	{ EDQUOT,	ALL,	"disk quota exceeded" },
    311 #endif
    312 #ifdef ENOSR
    313 	{ ENOSR,	ALL,	"no streams resources" },
    314 #endif
    315 	{ ENXIO,	ALL,	"no such device or address" },
    316 	{ EROFS,	ALL,	"read-only file system" },
    317 	{ ETXTBSY,	ALL,	"text busy" },
    318 #ifdef EAGAIN
    319 	{ EAGAIN,	E_EXEC,	"not enough memory" },
    320 #endif
    321 	{ ENOMEM,	ALL,	"not enough memory" },
    322 #ifdef ENOLINK
    323 	{ ENOLINK,	ALL,	"remote access failed" },
    324 #endif
    325 #ifdef EMULTIHOP
    326 	{ EMULTIHOP,	ALL,	"remote access failed" },
    327 #endif
    328 #ifdef ECOMM
    329 	{ ECOMM,	ALL,	"remote access failed" },
    330 #endif
    331 #ifdef ESTALE
    332 	{ ESTALE,	ALL,	"remote access failed" },
    333 #endif
    334 #ifdef ETIMEDOUT
    335 	{ ETIMEDOUT,	ALL,	"remote access failed" },
    336 #endif
    337 #ifdef ELOOP
    338 	{ ELOOP,	ALL,	"symbolic link loop" },
    339 #endif
    340 	{ E2BIG,	E_EXEC,	"argument list too long" },
    341 #ifdef ELIBACC
    342 	{ ELIBACC,	E_EXEC,	"shared library missing" },
    343 #endif
    344 	{ 0,		0,	NULL },
    345 };
    346 
    347 
    348 /*
    349  * Return a string describing an error.  The returned string may be a
    350  * pointer to a static buffer that will be overwritten on the next call.
    351  * Action describes the operation that got the error.
    352  */
    353 
    354 const char *
    355 errmsg(int e, int action)
    356 {
    357 	struct errname const *ep;
    358 	static char buf[12];
    359 
    360 	for (ep = errormsg ; ep->errcode ; ep++) {
    361 		if (ep->errcode == e && (ep->action & action) != 0)
    362 			return ep->msg;
    363 	}
    364 	fmtstr(buf, sizeof buf, "error %d", e);
    365 	return buf;
    366 }
    367