1 1.45 kre /* $NetBSD: error.c,v 1.45 2023/03/19 17:55:57 kre Exp $ */ 2 1.11 cgd 3 1.1 cgd /*- 4 1.6 jtc * Copyright (c) 1991, 1993 5 1.6 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.31 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.17 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.11 cgd #if 0 38 1.14 christos static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95"; 39 1.11 cgd #else 40 1.45 kre __RCSID("$NetBSD: error.c,v 1.45 2023/03/19 17:55:57 kre Exp $"); 41 1.11 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.1 cgd /* 45 1.1 cgd * Errors and exceptions. 46 1.1 cgd */ 47 1.1 cgd 48 1.18 christos #include <signal.h> 49 1.23 matt #include <stdlib.h> 50 1.18 christos #include <unistd.h> 51 1.18 christos #include <errno.h> 52 1.27 mycroft #include <stdio.h> 53 1.28 christos #include <string.h> 54 1.18 christos 55 1.1 cgd #include "shell.h" 56 1.37 dholland #include "eval.h" /* for commandname */ 57 1.1 cgd #include "main.h" 58 1.1 cgd #include "options.h" 59 1.1 cgd #include "output.h" 60 1.1 cgd #include "error.h" 61 1.14 christos #include "show.h" 62 1.1 cgd 63 1.1 cgd 64 1.1 cgd /* 65 1.1 cgd * Code to handle exceptions in C. 66 1.1 cgd */ 67 1.1 cgd 68 1.1 cgd struct jmploc *handler; 69 1.1 cgd int exception; 70 1.1 cgd volatile int suppressint; 71 1.1 cgd volatile int intpending; 72 1.43 kre volatile int errors_suppressed; 73 1.43 kre const char * volatile currentcontext; 74 1.43 kre 75 1.1 cgd 76 1.1 cgd 77 1.35 dogcow static void exverror(int, const char *, va_list) __dead; 78 1.15 christos 79 1.1 cgd /* 80 1.1 cgd * Called to raise an exception. Since C doesn't include exceptions, we 81 1.1 cgd * just do a longjmp to the exception handler. The type of exception is 82 1.1 cgd * stored in the global variable "exception". 83 1.1 cgd */ 84 1.1 cgd 85 1.1 cgd void 86 1.28 christos exraise(int e) 87 1.9 cgd { 88 1.42 kre CTRACE(DBG_ERRS, ("exraise(%d)\n", e)); 89 1.1 cgd if (handler == NULL) 90 1.1 cgd abort(); 91 1.1 cgd exception = e; 92 1.1 cgd longjmp(handler->loc, 1); 93 1.1 cgd } 94 1.1 cgd 95 1.1 cgd 96 1.1 cgd /* 97 1.1 cgd * Called from trap.c when a SIGINT is received. (If the user specifies 98 1.1 cgd * that SIGINT is to be trapped or ignored using the trap builtin, then 99 1.1 cgd * this routine is not called.) Suppressint is nonzero when interrupts 100 1.1 cgd * are held using the INTOFF macro. The call to _exit is necessary because 101 1.1 cgd * there is a short period after a fork before the signal handlers are 102 1.1 cgd * set to the appropriate value for the child. (The test for iflag is 103 1.1 cgd * just defensive programming.) 104 1.1 cgd */ 105 1.1 cgd 106 1.1 cgd void 107 1.28 christos onint(void) 108 1.28 christos { 109 1.29 kleink sigset_t nsigset; 110 1.12 mycroft 111 1.1 cgd if (suppressint) { 112 1.28 christos intpending = 1; 113 1.1 cgd return; 114 1.1 cgd } 115 1.1 cgd intpending = 0; 116 1.29 kleink sigemptyset(&nsigset); 117 1.29 kleink sigprocmask(SIG_SETMASK, &nsigset, NULL); 118 1.1 cgd if (rootshell && iflag) 119 1.1 cgd exraise(EXINT); 120 1.21 mycroft else { 121 1.21 mycroft signal(SIGINT, SIG_DFL); 122 1.21 mycroft raise(SIGINT); 123 1.21 mycroft } 124 1.19 mycroft /* NOTREACHED */ 125 1.1 cgd } 126 1.1 cgd 127 1.38 joerg static __printflike(2, 0) void 128 1.28 christos exvwarning(int sv_errno, const char *msg, va_list ap) 129 1.28 christos { 130 1.28 christos /* Partially emulate line buffered output so that: 131 1.28 christos * printf '%d\n' 1 a 2 132 1.28 christos * and 133 1.28 christos * printf '%d %d %d\n' 1 a 2 134 1.28 christos * both generate sensible text when stdout and stderr are merged. 135 1.28 christos */ 136 1.41 kre if (output.buf != NULL && output.nextc != output.buf && 137 1.41 kre output.nextc[-1] == '\n') 138 1.28 christos flushout(&output); 139 1.43 kre 140 1.43 kre if (errors_suppressed) 141 1.43 kre return; 142 1.43 kre 143 1.28 christos if (commandname) 144 1.28 christos outfmt(&errout, "%s: ", commandname); 145 1.33 christos else 146 1.33 christos outfmt(&errout, "%s: ", getprogname()); 147 1.43 kre if (currentcontext != NULL) 148 1.43 kre outfmt(&errout, "%s: ", currentcontext); 149 1.28 christos if (msg != NULL) { 150 1.28 christos doformat(&errout, msg, ap); 151 1.28 christos if (sv_errno >= 0) 152 1.28 christos outfmt(&errout, ": "); 153 1.28 christos } 154 1.28 christos if (sv_errno >= 0) 155 1.28 christos outfmt(&errout, "%s", strerror(sv_errno)); 156 1.28 christos out2c('\n'); 157 1.28 christos flushout(&errout); 158 1.28 christos } 159 1.1 cgd 160 1.1 cgd /* 161 1.28 christos * Exverror is called to raise the error exception. If the second argument 162 1.1 cgd * is not NULL then error prints an error message using printf style 163 1.1 cgd * formatting. It then raises the error exception. 164 1.1 cgd */ 165 1.38 joerg static __printflike(2, 0) void 166 1.28 christos exverror(int cond, const char *msg, va_list ap) 167 1.15 christos { 168 1.15 christos CLEAR_PENDING_INT; 169 1.15 christos INTOFF; 170 1.15 christos 171 1.15 christos #ifdef DEBUG 172 1.30 dsl if (msg) { 173 1.40 kre CTRACE(DBG_ERRS, ("exverror(%d, \"", cond)); 174 1.40 kre CTRACEV(DBG_ERRS, (msg, ap)); 175 1.40 kre CTRACE(DBG_ERRS, ("\") pid=%d\n", getpid())); 176 1.30 dsl } else 177 1.40 kre CTRACE(DBG_ERRS, ("exverror(%d, NULL) pid=%d\n", cond, 178 1.40 kre getpid())); 179 1.15 christos #endif 180 1.28 christos if (msg) 181 1.28 christos exvwarning(-1, msg, ap); 182 1.28 christos 183 1.15 christos flushall(); 184 1.15 christos exraise(cond); 185 1.19 mycroft /* NOTREACHED */ 186 1.15 christos } 187 1.15 christos 188 1.1 cgd 189 1.1 cgd void 190 1.22 christos error(const char *msg, ...) 191 1.14 christos { 192 1.1 cgd va_list ap; 193 1.25 wiz 194 1.39 kre /* 195 1.39 kre * On error, we certainly never want exit(0)... 196 1.39 kre */ 197 1.39 kre if (exerrno == 0) 198 1.39 kre exerrno = 1; 199 1.15 christos va_start(ap, msg); 200 1.15 christos exverror(EXERROR, msg, ap); 201 1.20 mycroft /* NOTREACHED */ 202 1.15 christos va_end(ap); 203 1.15 christos } 204 1.15 christos 205 1.14 christos 206 1.15 christos void 207 1.22 christos exerror(int cond, const char *msg, ...) 208 1.15 christos { 209 1.15 christos va_list ap; 210 1.25 wiz 211 1.1 cgd va_start(ap, msg); 212 1.15 christos exverror(cond, msg, ap); 213 1.20 mycroft /* NOTREACHED */ 214 1.1 cgd va_end(ap); 215 1.1 cgd } 216 1.1 cgd 217 1.28 christos /* 218 1.28 christos * error/warning routines for external builtins 219 1.28 christos */ 220 1.28 christos 221 1.28 christos void 222 1.28 christos sh_exit(int rval) 223 1.28 christos { 224 1.44 kre VTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS, ("sh_exit(%d)\n", rval)); 225 1.28 christos exerrno = rval & 255; 226 1.28 christos exraise(EXEXEC); 227 1.28 christos } 228 1.28 christos 229 1.28 christos void 230 1.28 christos sh_err(int status, const char *fmt, ...) 231 1.28 christos { 232 1.28 christos va_list ap; 233 1.28 christos 234 1.28 christos va_start(ap, fmt); 235 1.28 christos exvwarning(errno, fmt, ap); 236 1.28 christos va_end(ap); 237 1.28 christos sh_exit(status); 238 1.28 christos } 239 1.28 christos 240 1.28 christos void 241 1.28 christos sh_verr(int status, const char *fmt, va_list ap) 242 1.28 christos { 243 1.28 christos exvwarning(errno, fmt, ap); 244 1.28 christos sh_exit(status); 245 1.28 christos } 246 1.28 christos 247 1.28 christos void 248 1.28 christos sh_errx(int status, const char *fmt, ...) 249 1.28 christos { 250 1.28 christos va_list ap; 251 1.28 christos 252 1.28 christos va_start(ap, fmt); 253 1.28 christos exvwarning(-1, fmt, ap); 254 1.28 christos va_end(ap); 255 1.28 christos sh_exit(status); 256 1.28 christos } 257 1.28 christos 258 1.28 christos void 259 1.28 christos sh_verrx(int status, const char *fmt, va_list ap) 260 1.28 christos { 261 1.28 christos exvwarning(-1, fmt, ap); 262 1.28 christos sh_exit(status); 263 1.28 christos } 264 1.28 christos 265 1.28 christos void 266 1.28 christos sh_warn(const char *fmt, ...) 267 1.28 christos { 268 1.28 christos va_list ap; 269 1.28 christos 270 1.28 christos va_start(ap, fmt); 271 1.28 christos exvwarning(errno, fmt, ap); 272 1.28 christos va_end(ap); 273 1.28 christos } 274 1.28 christos 275 1.28 christos void 276 1.28 christos sh_vwarn(const char *fmt, va_list ap) 277 1.28 christos { 278 1.28 christos exvwarning(errno, fmt, ap); 279 1.28 christos } 280 1.28 christos 281 1.28 christos void 282 1.28 christos sh_warnx(const char *fmt, ...) 283 1.28 christos { 284 1.28 christos va_list ap; 285 1.28 christos 286 1.28 christos va_start(ap, fmt); 287 1.28 christos exvwarning(-1, fmt, ap); 288 1.28 christos va_end(ap); 289 1.28 christos } 290 1.28 christos 291 1.28 christos void 292 1.28 christos sh_vwarnx(const char *fmt, va_list ap) 293 1.28 christos { 294 1.28 christos exvwarning(-1, fmt, ap); 295 1.28 christos } 296 1.1 cgd 297 1.1 cgd 298 1.1 cgd /* 299 1.1 cgd * Table of error messages. 300 1.1 cgd */ 301 1.1 cgd 302 1.1 cgd struct errname { 303 1.1 cgd short errcode; /* error number */ 304 1.1 cgd short action; /* operation which encountered the error */ 305 1.22 christos const char *msg; /* text describing the error */ 306 1.1 cgd }; 307 1.1 cgd 308 1.1 cgd 309 1.1 cgd #define ALL (E_OPEN|E_CREAT|E_EXEC) 310 1.1 cgd 311 1.1 cgd STATIC const struct errname errormsg[] = { 312 1.14 christos { EINTR, ALL, "interrupted" }, 313 1.45 kre { EACCES, E_EXEC, "no execute permission" }, 314 1.14 christos { EACCES, ALL, "permission denied" }, 315 1.14 christos { EIO, ALL, "I/O error" }, 316 1.24 christos { EEXIST, ALL, "file exists" }, 317 1.14 christos { ENOENT, E_OPEN, "no such file" }, 318 1.14 christos { ENOENT, E_CREAT,"directory nonexistent" }, 319 1.14 christos { ENOENT, E_EXEC, "not found" }, 320 1.14 christos { ENOTDIR, E_OPEN, "no such file" }, 321 1.14 christos { ENOTDIR, E_CREAT,"directory nonexistent" }, 322 1.14 christos { ENOTDIR, E_EXEC, "not found" }, 323 1.14 christos { EISDIR, ALL, "is a directory" }, 324 1.26 christos #ifdef EMFILE 325 1.14 christos { EMFILE, ALL, "too many open files" }, 326 1.14 christos #endif 327 1.14 christos { ENFILE, ALL, "file table overflow" }, 328 1.14 christos { ENOSPC, ALL, "file system full" }, 329 1.1 cgd #ifdef EDQUOT 330 1.14 christos { EDQUOT, ALL, "disk quota exceeded" }, 331 1.1 cgd #endif 332 1.1 cgd #ifdef ENOSR 333 1.14 christos { ENOSR, ALL, "no streams resources" }, 334 1.1 cgd #endif 335 1.14 christos { ENXIO, ALL, "no such device or address" }, 336 1.14 christos { EROFS, ALL, "read-only file system" }, 337 1.14 christos { ETXTBSY, ALL, "text busy" }, 338 1.26 christos #ifdef EAGAIN 339 1.14 christos { EAGAIN, E_EXEC, "not enough memory" }, 340 1.1 cgd #endif 341 1.14 christos { ENOMEM, ALL, "not enough memory" }, 342 1.1 cgd #ifdef ENOLINK 343 1.14 christos { ENOLINK, ALL, "remote access failed" }, 344 1.1 cgd #endif 345 1.1 cgd #ifdef EMULTIHOP 346 1.14 christos { EMULTIHOP, ALL, "remote access failed" }, 347 1.1 cgd #endif 348 1.1 cgd #ifdef ECOMM 349 1.14 christos { ECOMM, ALL, "remote access failed" }, 350 1.1 cgd #endif 351 1.1 cgd #ifdef ESTALE 352 1.14 christos { ESTALE, ALL, "remote access failed" }, 353 1.1 cgd #endif 354 1.1 cgd #ifdef ETIMEDOUT 355 1.14 christos { ETIMEDOUT, ALL, "remote access failed" }, 356 1.1 cgd #endif 357 1.1 cgd #ifdef ELOOP 358 1.14 christos { ELOOP, ALL, "symbolic link loop" }, 359 1.1 cgd #endif 360 1.32 garbled #ifdef ENAMETOOLONG 361 1.32 garbled { ENAMETOOLONG, ALL, "file name too long" }, 362 1.32 garbled #endif 363 1.14 christos { E2BIG, E_EXEC, "argument list too long" }, 364 1.1 cgd #ifdef ELIBACC 365 1.14 christos { ELIBACC, E_EXEC, "shared library missing" }, 366 1.1 cgd #endif 367 1.14 christos { 0, 0, NULL }, 368 1.1 cgd }; 369 1.1 cgd 370 1.1 cgd 371 1.1 cgd /* 372 1.1 cgd * Return a string describing an error. The returned string may be a 373 1.1 cgd * pointer to a static buffer that will be overwritten on the next call. 374 1.1 cgd * Action describes the operation that got the error. 375 1.1 cgd */ 376 1.1 cgd 377 1.22 christos const char * 378 1.28 christos errmsg(int e, int action) 379 1.10 cgd { 380 1.1 cgd struct errname const *ep; 381 1.1 cgd static char buf[12]; 382 1.1 cgd 383 1.1 cgd for (ep = errormsg ; ep->errcode ; ep++) { 384 1.1 cgd if (ep->errcode == e && (ep->action & action) != 0) 385 1.1 cgd return ep->msg; 386 1.1 cgd } 387 1.1 cgd fmtstr(buf, sizeof buf, "error %d", e); 388 1.1 cgd return buf; 389 1.1 cgd } 390