1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1997-2005
5 *	Herbert Xu <herbert@gondor.apana.org.au>.  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/*
36 * Errors and exceptions.
37 */
38
39#include <signal.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43#include <stdio.h>
44#include <string.h>
45
46#include "shell.h"
47#include "main.h"
48#include "options.h"
49#include "output.h"
50#include "error.h"
51#include "show.h"
52#include "eval.h"
53#include "parser.h"
54#include "system.h"
55
56
57/*
58 * Code to handle exceptions in C.
59 */
60
61struct jmploc *handler;
62int exception;
63int suppressint;
64volatile sig_atomic_t intpending;
65int errlinno;
66
67
68static void exverror(int, const char *, va_list)
69    __attribute__((__noreturn__));
70
71/*
72 * Called to raise an exception.  Since C doesn't include exceptions, we
73 * just do a longjmp to the exception handler.  The type of exception is
74 * stored in the global variable "exception".
75 */
76
77void
78exraise(int e)
79{
80#ifdef DEBUG
81	if (handler == NULL)
82		abort();
83#endif
84	INTOFF;
85
86	exception = e;
87	longjmp(handler->loc, 1);
88}
89
90
91/*
92 * Called from trap.c when a SIGINT is received.  (If the user specifies
93 * that SIGINT is to be trapped or ignored using the trap builtin, then
94 * this routine is not called.)  Suppressint is nonzero when interrupts
95 * are held using the INTOFF macro.  (The test for iflag is just
96 * defensive programming.)
97 */
98
99void
100onint(void) {
101
102	intpending = 0;
103	sigclearmask();
104	if (!(rootshell && iflag)) {
105		signal(SIGINT, SIG_DFL);
106		raise(SIGINT);
107	}
108	exitstatus = SIGINT + 128;
109	exraise(EXINT);
110	/* NOTREACHED */
111}
112
113static void
114exvwarning2(const char *msg, va_list ap)
115{
116	struct output *errs;
117	const char *name;
118	const char *fmt;
119
120	errs = out2;
121	name = arg0 ? arg0 : "sh";
122	if (!commandname)
123		fmt = "%s: %d: ";
124	else
125		fmt = "%s: %d: %s: ";
126	outfmt(errs, fmt, name, errlinno, commandname);
127	doformat(errs, msg, ap);
128#if FLUSHERR
129	outc('\n', errs);
130#else
131	outcslow('\n', errs);
132#endif
133}
134
135#define exvwarning(a, b, c) exvwarning2(b, c)
136
137/*
138 * Exverror is called to raise the error exception.  If the second 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#ifdef DEBUG
146	if (msg) {
147		va_list aq;
148		TRACE(("exverror(%d, \"", cond));
149		va_copy(aq, ap);
150		TRACEV((msg, aq));
151		va_end(aq);
152		TRACE(("\") pid=%d\n", getpid()));
153	} else
154		TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
155	if (msg)
156#endif
157		exvwarning(-1, msg, ap);
158
159	flushall();
160	exraise(cond);
161	/* NOTREACHED */
162}
163
164
165void
166sh_error(const char *msg, ...)
167{
168	va_list ap;
169
170	exitstatus = 2;
171
172	va_start(ap, msg);
173	exverror(EXERROR, msg, ap);
174	/* NOTREACHED */
175	va_end(ap);
176}
177
178
179void
180exerror(int cond, const char *msg, ...)
181{
182	va_list ap;
183
184	va_start(ap, msg);
185	exverror(cond, msg, ap);
186	/* NOTREACHED */
187	va_end(ap);
188}
189
190/*
191 * error/warning routines for external builtins
192 */
193
194void
195sh_warnx(const char *fmt, ...)
196{
197	va_list ap;
198
199	va_start(ap, fmt);
200	exvwarning(-1, fmt, ap);
201	va_end(ap);
202}
203
204
205/*
206 * Return a string describing an error.  The returned string may be a
207 * pointer to a static buffer that will be overwritten on the next call.
208 * Action describes the operation that got the error.
209 */
210
211const char *
212errmsg(int e, int action)
213{
214	if (e != ENOENT && e != ENOTDIR)
215		return strerror(e);
216
217	if (action & E_OPEN)
218		return "No such file";
219	else if (action & E_CREAT)
220		return "Directory nonexistent";
221	else
222		return "not found";
223}
224
225
226#ifdef REALLY_SMALL
227void
228__inton() {
229	if (--suppressint == 0 && intpending) {
230		onint();
231	}
232}
233#endif
234