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
41 char *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
48 static 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 */
279 void
seterror(int id,...)280 seterror(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 */
314 void
stderror(int id,...)315 stderror(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