error.c revision 53891
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
351556Srgrimes */
361556Srgrimes
371556Srgrimes#ifndef lint
3836150Scharnier#if 0
3936150Scharnierstatic char sccsid[] = "@(#)error.c	8.2 (Berkeley) 5/4/95";
4036150Scharnier#endif
4136150Scharnierstatic const char rcsid[] =
4250471Speter  "$FreeBSD: head/bin/sh/error.c 53891 1999-11-29 19:11:01Z cracauer $";
431556Srgrimes#endif /* not lint */
441556Srgrimes
451556Srgrimes/*
461556Srgrimes * Errors and exceptions.
471556Srgrimes */
481556Srgrimes
491556Srgrimes#include "shell.h"
501556Srgrimes#include "main.h"
511556Srgrimes#include "options.h"
521556Srgrimes#include "output.h"
531556Srgrimes#include "error.h"
5453891Scracauer#include "nodes.h" /* show.h needs nodes.h */
5517987Speter#include "show.h"
5638521Scracauer#include "trap.h"
571556Srgrimes#include <signal.h>
5817987Speter#include <unistd.h>
591556Srgrimes#include <errno.h>
601556Srgrimes
611556Srgrimes
621556Srgrimes/*
631556Srgrimes * Code to handle exceptions in C.
641556Srgrimes */
651556Srgrimes
661556Srgrimesstruct jmploc *handler;
6738521Scracauervolatile sig_atomic_t exception;
6838530Scracauervolatile sig_atomic_t suppressint;
6938521Scracauervolatile sig_atomic_t intpending;
701556Srgrimeschar *commandname;
711556Srgrimes
721556Srgrimes
7320425Sstevestatic void exverror __P((int, char *, va_list));
7420425Ssteve
751556Srgrimes/*
761556Srgrimes * Called to raise an exception.  Since C doesn't include exceptions, we
771556Srgrimes * just do a longjmp to the exception handler.  The type of exception is
781556Srgrimes * stored in the global variable "exception".
791556Srgrimes */
801556Srgrimes
811556Srgrimesvoid
8220425Ssteveexraise(e)
8317987Speter	int e;
8417987Speter{
851556Srgrimes	if (handler == NULL)
861556Srgrimes		abort();
871556Srgrimes	exception = e;
881556Srgrimes	longjmp(handler->loc, 1);
891556Srgrimes}
901556Srgrimes
911556Srgrimes
921556Srgrimes/*
931556Srgrimes * Called from trap.c when a SIGINT is received.  (If the user specifies
941556Srgrimes * that SIGINT is to be trapped or ignored using the trap builtin, then
9538536Scracauer * this routine is not called.)  Suppressint is nonzero when interrupts
9638521Scracauer * are held using the INTOFF macro.  If SIGINTs are not suppressed and
9738521Scracauer * the shell is not a root shell, then we want to be terminated if we
9838521Scracauer * get here, as if we were terminated directly by a SIGINT.  Arrange for
9938521Scracauer * this here.
1001556Srgrimes */
1011556Srgrimes
1021556Srgrimesvoid
1031556Srgrimesonint() {
10417987Speter	sigset_t sigset;
10517987Speter
10638536Scracauer	/*
10738536Scracauer	 * The !in_dotrap here is safe.  The only way we can arrive here
10838536Scracauer	 * with in_dotrap set is that a trap handler set SIGINT to SIG_DFL
10938521Scracauer	 * and killed itself.
11038521Scracauer	 */
11138521Scracauer
11238521Scracauer	if (suppressint && !in_dotrap) {
1131556Srgrimes		intpending++;
1141556Srgrimes		return;
1151556Srgrimes	}
1161556Srgrimes	intpending = 0;
11717987Speter	sigemptyset(&sigset);
11817987Speter	sigprocmask(SIG_SETMASK, &sigset, NULL);
11938521Scracauer
12038536Scracauer	/*
12138536Scracauer	 * This doesn't seem to be needed, since main() emits a newline.
12238536Scracauer	 */
12338521Scracauer#if 0
12438521Scracauer	if (tcgetpgrp(0) == getpid())
12538521Scracauer		write(STDERR_FILENO, "\n", 1);
12638521Scracauer#endif
1271556Srgrimes	if (rootshell && iflag)
1281556Srgrimes		exraise(EXINT);
12938521Scracauer	else {
13038521Scracauer		signal(SIGINT, SIG_DFL);
13138521Scracauer		kill(getpid(), SIGINT);
13238521Scracauer	}
1331556Srgrimes}
1341556Srgrimes
1351556Srgrimes
1361556Srgrimes/*
13720425Ssteve * Exverror is called to raise the error exception.  If the first argument
1381556Srgrimes * is not NULL then error prints an error message using printf style
1391556Srgrimes * formatting.  It then raises the error exception.
1401556Srgrimes */
14120425Sstevestatic void
14220425Ssteveexverror(cond, msg, ap)
14320425Ssteve	int cond;
14420425Ssteve	char *msg;
14520425Ssteve	va_list ap;
14620425Ssteve{
14720425Ssteve	CLEAR_PENDING_INT;
14820425Ssteve	INTOFF;
1491556Srgrimes
15020425Ssteve#ifdef DEBUG
15120425Ssteve	if (msg)
15220425Ssteve		TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
15320425Ssteve	else
15420425Ssteve		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
15520425Ssteve#endif
15620425Ssteve	if (msg) {
15720425Ssteve		if (commandname)
15820425Ssteve			outfmt(&errout, "%s: ", commandname);
15920425Ssteve		doformat(&errout, msg, ap);
16020425Ssteve		out2c('\n');
16120425Ssteve	}
16220425Ssteve	flushall();
16320425Ssteve	exraise(cond);
16420425Ssteve}
16520425Ssteve
16620425Ssteve
16725222Ssteve#ifdef __STDC__
1681556Srgrimesvoid
16917987Spetererror(char *msg, ...)
1701556Srgrimes#else
1711556Srgrimesvoid
1721556Srgrimeserror(va_alist)
1731556Srgrimes	va_dcl
17417987Speter#endif
17517987Speter{
17625222Ssteve#ifndef __STDC__
1771556Srgrimes	char *msg;
1781556Srgrimes#endif
1791556Srgrimes	va_list ap;
18025222Ssteve#ifdef __STDC__
18120425Ssteve	va_start(ap, msg);
18220425Ssteve#else
18320425Ssteve	va_start(ap);
18420425Ssteve	msg = va_arg(ap, char *);
18520425Ssteve#endif
18620425Ssteve	exverror(EXERROR, msg, ap);
18720425Ssteve	va_end(ap);
18820425Ssteve}
18917987Speter
19020425Ssteve
19125222Ssteve#ifdef __STDC__
19220425Sstevevoid
19320425Ssteveexerror(int cond, char *msg, ...)
19420425Ssteve#else
19520425Sstevevoid
19620425Ssteveexerror(va_alist)
19720425Ssteve	va_dcl
19820425Ssteve#endif
19920425Ssteve{
20025222Ssteve#ifndef __STDC__
20120425Ssteve	int cond;
20220425Ssteve	char *msg;
20320425Ssteve#endif
20420425Ssteve	va_list ap;
20525222Ssteve#ifdef __STDC__
2061556Srgrimes	va_start(ap, msg);
2071556Srgrimes#else
2081556Srgrimes	va_start(ap);
20920425Ssteve	cond = va_arg(ap, int);
2101556Srgrimes	msg = va_arg(ap, char *);
2111556Srgrimes#endif
21220425Ssteve	exverror(cond, msg, ap);
2131556Srgrimes	va_end(ap);
2141556Srgrimes}
2151556Srgrimes
2161556Srgrimes
2171556Srgrimes
2181556Srgrimes/*
2191556Srgrimes * Table of error messages.
2201556Srgrimes */
2211556Srgrimes
2221556Srgrimesstruct errname {
2231556Srgrimes	short errcode;		/* error number */
2241556Srgrimes	short action;		/* operation which encountered the error */
2251556Srgrimes	char *msg;		/* text describing the error */
2261556Srgrimes};
2271556Srgrimes
2281556Srgrimes
2291556Srgrimes#define ALL (E_OPEN|E_CREAT|E_EXEC)
2301556Srgrimes
2311556SrgrimesSTATIC const struct errname errormsg[] = {
23217987Speter	{ EINTR,	ALL,	"interrupted" },
23317987Speter	{ EACCES,	ALL,	"permission denied" },
23417987Speter	{ EIO,		ALL,	"I/O error" },
23517987Speter	{ ENOENT,	E_OPEN,	"no such file" },
23617987Speter	{ ENOENT,	E_CREAT,"directory nonexistent" },
23717987Speter	{ ENOENT,	E_EXEC,	"not found" },
23817987Speter	{ ENOTDIR,	E_OPEN,	"no such file" },
23917987Speter	{ ENOTDIR,	E_CREAT,"directory nonexistent" },
24017987Speter	{ ENOTDIR,	E_EXEC,	"not found" },
24117987Speter	{ EISDIR,	ALL,	"is a directory" },
24217987Speter#ifdef notdef
24317987Speter	{ EMFILE,	ALL,	"too many open files" },
24417987Speter#endif
24517987Speter	{ ENFILE,	ALL,	"file table overflow" },
24617987Speter	{ ENOSPC,	ALL,	"file system full" },
2471556Srgrimes#ifdef EDQUOT
24817987Speter	{ EDQUOT,	ALL,	"disk quota exceeded" },
2491556Srgrimes#endif
2501556Srgrimes#ifdef ENOSR
25117987Speter	{ ENOSR,	ALL,	"no streams resources" },
2521556Srgrimes#endif
25317987Speter	{ ENXIO,	ALL,	"no such device or address" },
25417987Speter	{ EROFS,	ALL,	"read-only file system" },
25517987Speter	{ ETXTBSY,	ALL,	"text busy" },
2561556Srgrimes#ifdef SYSV
25717987Speter	{ EAGAIN,	E_EXEC,	"not enough memory" },
2581556Srgrimes#endif
25917987Speter	{ ENOMEM,	ALL,	"not enough memory" },
2601556Srgrimes#ifdef ENOLINK
26117987Speter	{ ENOLINK,	ALL,	"remote access failed" },
2621556Srgrimes#endif
2631556Srgrimes#ifdef EMULTIHOP
26417987Speter	{ EMULTIHOP,	ALL,	"remote access failed" },
2651556Srgrimes#endif
2661556Srgrimes#ifdef ECOMM
26717987Speter	{ ECOMM,	ALL,	"remote access failed" },
2681556Srgrimes#endif
2691556Srgrimes#ifdef ESTALE
27017987Speter	{ ESTALE,	ALL,	"remote access failed" },
2711556Srgrimes#endif
2721556Srgrimes#ifdef ETIMEDOUT
27317987Speter	{ ETIMEDOUT,	ALL,	"remote access failed" },
2741556Srgrimes#endif
2751556Srgrimes#ifdef ELOOP
27617987Speter	{ ELOOP,	ALL,	"symbolic link loop" },
2771556Srgrimes#endif
27817987Speter	{ E2BIG,	E_EXEC,	"argument list too long" },
2791556Srgrimes#ifdef ELIBACC
28017987Speter	{ ELIBACC,	E_EXEC,	"shared library missing" },
2811556Srgrimes#endif
28217987Speter	{ 0,		0,	NULL },
2831556Srgrimes};
2841556Srgrimes
2851556Srgrimes
2861556Srgrimes/*
2871556Srgrimes * Return a string describing an error.  The returned string may be a
2881556Srgrimes * pointer to a static buffer that will be overwritten on the next call.
2891556Srgrimes * Action describes the operation that got the error.
2901556Srgrimes */
2911556Srgrimes
2921556Srgrimeschar *
29320425Ssteveerrmsg(e, action)
29417987Speter	int e;
29517987Speter	int action;
29617987Speter{
2971556Srgrimes	struct errname const *ep;
2981556Srgrimes	static char buf[12];
2991556Srgrimes
3001556Srgrimes	for (ep = errormsg ; ep->errcode ; ep++) {
3011556Srgrimes		if (ep->errcode == e && (ep->action & action) != 0)
3021556Srgrimes			return ep->msg;
3031556Srgrimes	}
3041556Srgrimes	fmtstr(buf, sizeof buf, "error %d", e);
3051556Srgrimes	return buf;
3061556Srgrimes}
307