1/*	$OpenBSD: error.c,v 1.17 2018/09/18 17:48:22 millert Exp $	*/
2/*	$NetBSD: err.c,v 1.6 1995/03/21 09:02:47 cgd Exp $	*/
3
4/*-
5 * Copyright (c) 1980, 1991, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#include <sys/types.h>
34#include <stdlib.h>
35#include <unistd.h>
36#include <stdarg.h>
37
38#include "csh.h"
39#include "extern.h"
40
41char   *seterr = NULL;	/* Holds last error if there was one */
42
43#define ERR_FLAGS	0xf0000000
44#define ERR_NAME	0x10000000
45#define ERR_SILENT	0x20000000
46#define ERR_OLD		0x40000000
47
48static char *errorlist[] =
49{
50#define ERR_SYNTAX	0
51    "Syntax Error",
52#define ERR_NOTALLOWED	1
53    "%s is not allowed",
54#define ERR_WTOOLONG	2
55    "Word too long",
56#define ERR_LTOOLONG	3
57    "$< line too long",
58#define ERR_DOLZERO	4
59    "No file for $0",
60#define ERR_DOLQUEST	5
61    "$? not allowed here",
62#define ERR_INCBR	6
63    "Incomplete [] modifier",
64#define ERR_EXPORD	7
65    "$ expansion must end before ]",
66#define ERR_BADMOD	8
67    "Bad : modifier in $ (%c)",
68#define ERR_SUBSCRIPT	9
69    "Subscript error",
70#define ERR_BADNUM	10
71    "Badly formed number",
72#define ERR_NOMORE	11
73    "No more words",
74#define ERR_FILENAME	12
75    "Missing file name",
76#define ERR_GLOB	13
77    "Internal glob error",
78#define ERR_COMMAND	14
79    "Command not found",
80#define ERR_TOOFEW	15
81    "Too few arguments",
82#define ERR_TOOMANY	16
83    "Too many arguments",
84#define ERR_DANGER	17
85    "Too dangerous to alias that",
86#define ERR_EMPTYIF	18
87    "Empty if",
88#define ERR_IMPRTHEN	19
89    "Improper then",
90#define ERR_NOPAREN	20
91    "Words not parenthesized",
92#define ERR_NOTFOUND	21
93    "%s not found",
94#define ERR_MASK	22
95    "Improper mask",
96#define ERR_LIMIT	23
97    "No such limit",
98#define ERR_TOOLARGE	24
99    "Argument too large",
100#define ERR_SCALEF	25
101    "Improper or unknown scale factor",
102#define ERR_UNDVAR	26
103    "Undefined variable",
104#define ERR_DEEP	27
105    "Directory stack not that deep",
106#define ERR_BADSIG	28
107    "Bad signal number",
108#define ERR_UNKSIG	29
109    "Unknown signal; kill -l lists signals",
110#define ERR_VARBEGIN	30
111    "Variable name must begin with a letter",
112#define ERR_VARTOOLONG	31
113    "Variable name too long",
114#define ERR_VARALNUM	32
115    "Variable name must contain alphanumeric characters",
116#define ERR_JOBCONTROL	33
117    "No job control in this shell",
118#define ERR_EXPRESSION	34
119    "Expression Syntax",
120#define ERR_NOHOMEDIR	35
121    "No home directory",
122#define ERR_CANTCHANGE	36
123    "Can't change to home directory",
124#define ERR_NULLCOM	37
125    "Invalid null command",
126#define ERR_ASSIGN	38
127    "Assignment missing expression",
128#define ERR_UNKNOWNOP	39
129    "Unknown operator",
130#define ERR_AMBIG	40
131    "Ambiguous",
132#define ERR_EXISTS	41
133    "%s: File exists",
134#define ERR_INTR	42
135    "Interrupted",
136#define ERR_RANGE	43
137    "Subscript out of range",
138#define ERR_OVERFLOW	44
139    "Line overflow",
140#define ERR_VARMOD	45
141    "Unknown variable modifier",
142#define ERR_NOSUCHJOB	46
143    "No such job",
144#define ERR_TERMINAL	47
145    "Can't from terminal",
146#define ERR_NOTWHILE	48
147    "Not in while/foreach",
148#define ERR_NOPROC	49
149    "No more processes",
150#define ERR_NOMATCH	50
151    "No match",
152#define ERR_MISSING	51
153    "Missing %c",
154#define ERR_UNMATCHED	52
155    "Unmatched %c",
156#define ERR_NOMEM	53
157    "Out of memory",
158#define ERR_PIPE	54
159    "Can't make pipe",
160#define ERR_SYSTEM	55
161    "%s: %s",
162#define ERR_STRING	56
163    "%s",
164#define ERR_JOBS	57
165    "usage: jobs [-l]",
166#define ERR_JOBARGS	58
167    "Arguments should be jobs or process id's",
168#define ERR_JOBCUR	59
169    "No current job",
170#define ERR_JOBPREV	60
171    "No previous job",
172#define ERR_JOBPAT	61
173    "No job matches pattern",
174#define ERR_NESTING	62
175    "Fork nesting > %d; maybe `...` loop",
176#define ERR_JOBCTRLSUB	63
177    "No job control in subshells",
178#define ERR_BADPLPS	64
179    "Badly placed ()'s",
180#define ERR_STOPPED	65
181    "%sThere are suspended jobs",
182#define ERR_NODIR	66
183    "No other directory",
184#define ERR_EMPTY	67
185    "Directory stack empty",
186#define ERR_BADDIR	68
187    "Bad directory",
188#define ERR_DIRUS	69
189    "usage: %s [-lnv]%s",
190#define ERR_HFLAG	70
191    "No operand for -h flag",
192#define ERR_NOTLOGIN	71
193    "Not a login shell",
194#define ERR_DIV0	72
195    "Division by 0",
196#define ERR_MOD0	73
197    "Mod by 0",
198#define ERR_BADSCALE	74
199    "Bad scaling; did you mean \"%s\"?",
200#define ERR_SUSPLOG	75
201    "Can't suspend a login shell (yet)",
202#define ERR_UNKUSER	76
203    "Unknown user: %s",
204#define ERR_NOHOME	77
205    "No $home variable set",
206#define ERR_HISTUS	78
207    "usage: history [-hr] [n]",
208#define ERR_SPDOLLT	79
209    "$, ! or < not allowed with $# or $?",
210#define ERR_NEWLINE	80
211    "Newline in variable name",
212#define ERR_SPSTAR	81
213    "* not allowed with $# or $?",
214#define ERR_DIGIT	82
215    "$?<digit> or $#<digit> not allowed",
216#define ERR_VARILL	83
217    "Illegal variable name",
218#define ERR_NLINDEX	84
219    "Newline in variable index",
220#define ERR_EXPOVFL	85
221    "Expansion buffer overflow",
222#define ERR_VARSYN	86
223    "Variable syntax",
224#define ERR_BADBANG	87
225    "Bad ! form",
226#define ERR_NOSUBST	88
227    "No previous substitute",
228#define ERR_BADSUBST	89
229    "Bad substitute",
230#define ERR_LHS		90
231    "No previous left hand side",
232#define ERR_RHSLONG	91
233    "Right hand side too long",
234#define ERR_BADBANGMOD	92
235    "Bad ! modifier: %c",
236#define ERR_MODFAIL	93
237    "Modifier failed",
238#define ERR_SUBOVFL	94
239    "Substitution buffer overflow",
240#define ERR_BADBANGARG	95
241    "Bad ! arg selector",
242#define ERR_NOSEARCH	96
243    "No prev search",
244#define ERR_NOEVENT	97
245    "%s: Event not found",
246#define ERR_TOOMANYRP	98
247    "Too many )'s",
248#define ERR_TOOMANYLP	99
249    "Too many ('s",
250#define ERR_BADPLP	100
251    "Badly placed (",
252#define ERR_MISRED	101
253    "Missing name for redirect",
254#define ERR_OUTRED	102
255    "Ambiguous output redirect",
256#define ERR_REDPAR	103
257    "Can't << within ()'s",
258#define ERR_INRED	104
259    "Ambiguous input redirect",
260#define ERR_ALIASLOOP	105
261    "Alias loop",
262#define ERR_HISTLOOP	106
263    "!# History loop",
264#define ERR_ARCH	107
265    "%s: %s. Wrong Architecture",
266#define ERR_FILEINQ	108
267    "Malformed file inquiry",
268#define ERR_SELOVFL	109
269    "Selector overflow",
270#define ERR_INVALID	110
271    "Invalid Error"
272};
273
274/*
275 * The parser and scanner set up errors for later by calling seterr,
276 * which sets the variable err as a side effect; later to be tested,
277 * e.g. in process.
278 */
279void
280seterror(int id, ...)
281{
282    if (seterr == 0) {
283	char    berr[BUFSIZ];
284	va_list va;
285
286	va_start(va, id);
287	if (id < 0 || id >= sizeof(errorlist) / sizeof(errorlist[0]))
288	    id = ERR_INVALID;
289	vsnprintf(berr, sizeof(berr), errorlist[id], va);
290	va_end(va);
291
292	seterr = xstrdup(berr);
293    }
294}
295
296/*
297 * Print the error with the given id.
298 *
299 * Special ids:
300 *	ERR_SILENT: Print nothing.
301 *	ERR_OLD: Print the previously set error if one was there.
302 *		 otherwise return.
303 *	ERR_NAME: If this bit is set, print the name of the function
304 *		  in bname
305 *
306 * This routine always resets or exits.  The flag haderr
307 * is set so the routine who catches the unwind can propagate
308 * it if they want.
309 *
310 * Note that any open files at the point of error will eventually
311 * be closed in the routine process in sh.c which is the only
312 * place error unwinds are ever caught.
313 */
314void
315stderror(int id, ...)
316{
317    va_list va;
318    int     flags = id & ERR_FLAGS;
319
320    id &= ~ERR_FLAGS;
321
322    if ((flags & ERR_OLD) && seterr == NULL)
323	return;
324
325    if (id < 0 || id >= sizeof(errorlist) / sizeof(errorlist[0]))
326	id = ERR_INVALID;
327
328    (void) fflush(cshout);
329    (void) fflush(csherr);
330    haderr = 1;			/* Now to diagnostic output */
331    timflg = 0;			/* This isn't otherwise reset */
332
333
334    if (!(flags & ERR_SILENT)) {
335	if (flags & ERR_NAME)
336	    (void) fprintf(csherr, "%s: ", bname);
337	if ((flags & ERR_OLD))
338	    /* Old error. */
339	    (void) fprintf(csherr, "%s.\n", seterr);
340	else {
341	    va_start(va, id);
342	    (void) vfprintf(csherr, errorlist[id], va);
343	    va_end(va);
344	    (void) fprintf(csherr, ".\n");
345	}
346    }
347
348    free(seterr);
349    seterr = NULL;
350
351    blkfree(pargv);
352    pargv = NULL;
353    blkfree(gargv);
354    gargv = NULL;
355
356    (void) fflush(cshout);
357    (void) fflush(csherr);
358    didfds = 0;			/* Forget about 0,1,2 */
359    /*
360     * Go away if -e or we are a child shell
361     */
362    if (!exitset || exiterr || child)
363	xexit(1);
364
365    /*
366     * Reset the state of the input. This buffered seek to end of file will
367     * also clear the while/foreach stack.
368     */
369    btoeof();
370
371    set(STRstatus, Strsave(STR1));
372    if (tpgrp > 0)
373	(void) tcsetpgrp(FSHTTY, tpgrp);
374    reset();			/* Unwind */
375}
376