error.c revision 213811
1209502Sjchandra/*-
2209502Sjchandra * Copyright (c) 1991, 1993
3209502Sjchandra *	The Regents of the University of California.  All rights reserved.
4209502Sjchandra *
5209502Sjchandra * This code is derived from software contributed to Berkeley by
6209502Sjchandra * Kenneth Almquist.
7209502Sjchandra *
8209502Sjchandra * Redistribution and use in source and binary forms, with or without
9209502Sjchandra * modification, are permitted provided that the following conditions
10209502Sjchandra * are met:
11209502Sjchandra * 1. Redistributions of source code must retain the above copyright
12209502Sjchandra *    notice, this list of conditions and the following disclaimer.
13209502Sjchandra * 2. Redistributions in binary form must reproduce the above copyright
14209502Sjchandra *    notice, this list of conditions and the following disclaimer in the
15209502Sjchandra *    documentation and/or other materials provided with the distribution.
16209502Sjchandra * 4. Neither the name of the University nor the names of its contributors
17209502Sjchandra *    may be used to endorse or promote products derived from this software
18209502Sjchandra *    without specific prior written permission.
19209502Sjchandra *
20217626Sjchandra * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21211280Sjchandra * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22217636Sjchandra * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23209502Sjchandra * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24209502Sjchandra * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25209502Sjchandra * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26209502Sjchandra * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27217626Sjchandra * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28217630Sjchandra * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29217626Sjchandra * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30209502Sjchandra * SUCH DAMAGE.
31209502Sjchandra */
32209502Sjchandra
33217630Sjchandra#ifndef lint
34209502Sjchandra#if 0
35209502Sjchandrastatic char sccsid[] = "@(#)error.c	8.2 (Berkeley) 5/4/95";
36209502Sjchandra#endif
37209502Sjchandra#endif /* not lint */
38209502Sjchandra#include <sys/cdefs.h>
39209502Sjchandra__FBSDID("$FreeBSD: head/bin/sh/error.c 213811 2010-10-13 22:18:03Z obrien $");
40209502Sjchandra
41209502Sjchandra/*
42209502Sjchandra * Errors and exceptions.
43209502Sjchandra */
44209502Sjchandra
45209502Sjchandra#include "shell.h"
46209502Sjchandra#include "main.h"
47209502Sjchandra#include "options.h"
48209502Sjchandra#include "output.h"
49209502Sjchandra#include "error.h"
50215085Sjchandra#include "nodes.h" /* show.h needs nodes.h */
51209502Sjchandra#include "show.h"
52209502Sjchandra#include "trap.h"
53209502Sjchandra#include <signal.h>
54209502Sjchandra#include <stdlib.h>
55217630Sjchandra#include <unistd.h>
56217630Sjchandra#include <errno.h>
57217630Sjchandra
58209502Sjchandra
59209502Sjchandra/*
60209502Sjchandra * Code to handle exceptions in C.
61209502Sjchandra */
62209502Sjchandra
63209502Sjchandrastruct jmploc *handler;
64210026Simpvolatile sig_atomic_t exception;
65210026Simpvolatile sig_atomic_t suppressint;
66210026Simpvolatile sig_atomic_t intpending;
67210026Simpchar *commandname;
68209502Sjchandra
69209502Sjchandra
70209502Sjchandrastatic void exverror(int, const char *, va_list) __printf0like(2, 0) __dead2;
71209502Sjchandra
72209502Sjchandra/*
73209502Sjchandra * Called to raise an exception.  Since C doesn't include exceptions, we
74217630Sjchandra * just do a longjmp to the exception handler.  The type of exception is
75209502Sjchandra * stored in the global variable "exception".
76209502Sjchandra *
77217630Sjchandra * Interrupts are disabled; they should be reenabled when the exception is
78217630Sjchandra * caught.
79217630Sjchandra */
80217630Sjchandra
81209502Sjchandravoid
82209502Sjchandraexraise(int e)
83209502Sjchandra{
84209502Sjchandra	INTOFF;
85209502Sjchandra	if (handler == NULL)
86209502Sjchandra		abort();
87209502Sjchandra	exception = e;
88209502Sjchandra	longjmp(handler->loc, 1);
89209502Sjchandra}
90209502Sjchandra
91209502Sjchandra
92209502Sjchandra/*
93209502Sjchandra * Called from trap.c when a SIGINT is received.  (If the user specifies
94209502Sjchandra * that SIGINT is to be trapped or ignored using the trap builtin, then
95209502Sjchandra * this routine is not called.)  Suppressint is nonzero when interrupts
96215085Sjchandra * are held using the INTOFF macro.  If SIGINTs are not suppressed and
97209502Sjchandra * the shell is not a root shell, then we want to be terminated if we
98209502Sjchandra * get here, as if we were terminated directly by a SIGINT.  Arrange for
99209502Sjchandra * this here.
100209502Sjchandra */
101209502Sjchandra
102209502Sjchandravoid
103209502Sjchandraonint(void)
104209502Sjchandra{
105209502Sjchandra	sigset_t sigs;
106209502Sjchandra
107209502Sjchandra	/*
108209502Sjchandra	 * The !in_dotrap here is safe.  The only way we can arrive here
109209502Sjchandra	 * with in_dotrap set is that a trap handler set SIGINT to SIG_DFL
110209502Sjchandra	 * and killed itself.
111209502Sjchandra	 */
112209502Sjchandra
113209502Sjchandra	if (suppressint && !in_dotrap) {
114209502Sjchandra		intpending++;
115217630Sjchandra		return;
116217630Sjchandra	}
117217630Sjchandra	intpending = 0;
118217630Sjchandra	sigemptyset(&sigs);
119217630Sjchandra	sigprocmask(SIG_SETMASK, &sigs, NULL);
120217630Sjchandra
121217630Sjchandra	/*
122209502Sjchandra	 * This doesn't seem to be needed, since main() emits a newline.
123209502Sjchandra	 */
124209502Sjchandra#if 0
125209502Sjchandra	if (tcgetpgrp(0) == getpid())
126209502Sjchandra		write(STDERR_FILENO, "\n", 1);
127209502Sjchandra#endif
128	if (rootshell && iflag)
129		exraise(EXINT);
130	else {
131		signal(SIGINT, SIG_DFL);
132		kill(getpid(), SIGINT);
133	}
134}
135
136
137/*
138 * Exverror is called to raise the error exception.  If the first argument
139 * is not NULL then error prints an error message using printf style
140 * formatting.  It then raises the error exception.
141 */
142static void
143exverror(int cond, const char *msg, va_list ap)
144{
145	/*
146	 * An interrupt trumps an error.  Certain places catch error
147	 * exceptions or transform them to a plain nonzero exit code
148	 * in child processes, and if an error exception can be handled,
149	 * an interrupt can be handled as well.
150	 *
151	 * exraise() will disable interrupts for the exception handler.
152	 */
153	FORCEINTON;
154
155#ifdef DEBUG
156	if (msg)
157		TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
158	else
159		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
160#endif
161	if (msg) {
162		if (commandname)
163			outfmt(out2, "%s: ", commandname);
164		doformat(out2, msg, ap);
165		out2c('\n');
166	}
167	flushall();
168	exraise(cond);
169}
170
171
172void
173error(const char *msg, ...)
174{
175	va_list ap;
176	va_start(ap, msg);
177	exverror(EXERROR, msg, ap);
178	va_end(ap);
179}
180
181
182void
183exerror(int cond, const char *msg, ...)
184{
185	va_list ap;
186	va_start(ap, msg);
187	exverror(cond, msg, ap);
188	va_end(ap);
189}
190