1 1.58 kre /* $NetBSD: trap.c,v 1.58 2024/10/09 13:43:33 kre Exp $ */ 2 1.12 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.29 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.12 cgd #if 0 38 1.15 christos static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; 39 1.12 cgd #else 40 1.58 kre __RCSID("$NetBSD: trap.c,v 1.58 2024/10/09 13:43:33 kre Exp $"); 41 1.12 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.13 christos #include <signal.h> 45 1.13 christos #include <unistd.h> 46 1.13 christos #include <stdlib.h> 47 1.40 kre #include <stdio.h> 48 1.47 kre #include <errno.h> 49 1.52 kre #include <limits.h> 50 1.50 kre #include <termios.h> 51 1.47 kre 52 1.50 kre #undef CEOF /* from <termios.h> but concflicts with sh use */ 53 1.50 kre 54 1.50 kre #include <sys/ioctl.h> 55 1.47 kre #include <sys/resource.h> 56 1.13 christos 57 1.1 cgd #include "shell.h" 58 1.1 cgd #include "main.h" 59 1.1 cgd #include "nodes.h" /* for other headers */ 60 1.1 cgd #include "eval.h" 61 1.1 cgd #include "jobs.h" 62 1.13 christos #include "show.h" 63 1.1 cgd #include "options.h" 64 1.35 christos #include "builtins.h" 65 1.1 cgd #include "syntax.h" 66 1.1 cgd #include "output.h" 67 1.1 cgd #include "memalloc.h" 68 1.1 cgd #include "error.h" 69 1.1 cgd #include "trap.h" 70 1.1 cgd #include "mystring.h" 71 1.31 christos #include "var.h" 72 1.1 cgd 73 1.57 kre #ifndef SMALL 74 1.57 kre #include "myhistedit.h" 75 1.57 kre #endif 76 1.1 cgd 77 1.1 cgd /* 78 1.1 cgd * Sigmode records the current value of the signal handlers for the various 79 1.1 cgd * modes. A value of zero means that the current handler is not known. 80 1.1 cgd * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 81 1.1 cgd */ 82 1.1 cgd 83 1.1 cgd #define S_DFL 1 /* default signal handling (SIG_DFL) */ 84 1.1 cgd #define S_CATCH 2 /* signal is caught */ 85 1.1 cgd #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 86 1.1 cgd #define S_HARD_IGN 4 /* signal is ignored permenantly */ 87 1.6 jtc #define S_RESET 5 /* temporary - to reset a hard ignored sig */ 88 1.1 cgd 89 1.1 cgd 90 1.8 jtc MKINIT char sigmode[NSIG]; /* current value of signal */ 91 1.47 kre static volatile sig_atomic_t gotsig[NSIG];/* indicates specified signal received */ 92 1.47 kre volatile sig_atomic_t pendingsigs; /* indicates some signal received */ 93 1.47 kre 94 1.47 kre int traps_invalid; /* in a subshell, but trap[] not yet cleared */ 95 1.47 kre static char * volatile trap[NSIG]; /* trap handler commands */ 96 1.47 kre static int in_dotrap; 97 1.47 kre static int last_trapsig; 98 1.47 kre 99 1.47 kre static int exiting; /* exitshell() has been done */ 100 1.47 kre static int exiting_status; /* the status to use for exit() */ 101 1.1 cgd 102 1.28 christos static int getsigaction(int, sig_t *); 103 1.40 kre STATIC const char *trap_signame(int); 104 1.46 kre void printsignals(struct output *, int); 105 1.26 wulf 106 1.26 wulf /* 107 1.26 wulf * return the signal number described by `p' (as a number or a name) 108 1.26 wulf * or -1 if it isn't one 109 1.26 wulf */ 110 1.26 wulf 111 1.58 kre int 112 1.28 christos signame_to_signum(const char *p) 113 1.26 wulf { 114 1.26 wulf int i; 115 1.26 wulf 116 1.26 wulf if (is_number(p)) 117 1.26 wulf return number(p); 118 1.26 wulf 119 1.26 wulf if (strcasecmp(p, "exit") == 0 ) 120 1.26 wulf return 0; 121 1.54 kre 122 1.46 kre i = signalnumber(p); 123 1.46 kre if (i == 0) 124 1.46 kre i = -1; 125 1.46 kre return i; 126 1.26 wulf } 127 1.26 wulf 128 1.26 wulf /* 129 1.40 kre * return the name of a signal used by the "trap" command 130 1.40 kre */ 131 1.40 kre STATIC const char * 132 1.40 kre trap_signame(int signo) 133 1.40 kre { 134 1.40 kre static char nbuf[12]; 135 1.46 kre const char *p; 136 1.40 kre 137 1.40 kre if (signo == 0) 138 1.40 kre return "EXIT"; 139 1.46 kre p = signalname(signo); 140 1.40 kre if (p != NULL) 141 1.40 kre return p; 142 1.40 kre (void)snprintf(nbuf, sizeof nbuf, "%d", signo); 143 1.40 kre return nbuf; 144 1.40 kre } 145 1.40 kre 146 1.50 kre #ifdef SMALL 147 1.40 kre /* 148 1.26 wulf * Print a list of valid signal names 149 1.26 wulf */ 150 1.46 kre void 151 1.46 kre printsignals(struct output *out, int len) 152 1.26 wulf { 153 1.26 wulf int n; 154 1.26 wulf 155 1.46 kre if (len != 0) 156 1.46 kre outc(' ', out); 157 1.26 wulf for (n = 1; n < NSIG; n++) { 158 1.46 kre outfmt(out, "%s", trap_signame(n)); 159 1.54 kre if ((n == NSIG/2) || n == (NSIG - 1)) 160 1.46 kre outstr("\n", out); 161 1.26 wulf else 162 1.46 kre outc(' ', out); 163 1.26 wulf } 164 1.26 wulf } 165 1.50 kre #else /* !SMALL */ 166 1.50 kre /* 167 1.50 kre * Print the names of all the signals (neatly) to fp 168 1.50 kre * "len" gives the number of chars already printed to 169 1.50 kre * the current output line (in kill.c, always 0) 170 1.50 kre */ 171 1.50 kre void 172 1.50 kre printsignals(struct output *out, int len) 173 1.50 kre { 174 1.50 kre int sig; 175 1.50 kre int nl, pad; 176 1.50 kre const char *name; 177 1.50 kre int termwidth = 80; 178 1.50 kre 179 1.50 kre if ((name = bltinlookup("COLUMNS", 1)) != NULL) 180 1.50 kre termwidth = (int)strtol(name, NULL, 10); 181 1.50 kre else if (isatty(1)) { 182 1.50 kre struct winsize win; 183 1.50 kre 184 1.50 kre if (ioctl(1, TIOCGWINSZ, &win) == 0 && win.ws_col > 0) 185 1.50 kre termwidth = win.ws_col; 186 1.50 kre } 187 1.50 kre 188 1.50 kre if (posix) 189 1.50 kre pad = 1; 190 1.50 kre else 191 1.50 kre pad = (len | 7) + 1 - len; 192 1.50 kre 193 1.50 kre for (sig = 0; (sig = signalnext(sig)) != 0; ) { 194 1.50 kre name = signalname(sig); 195 1.50 kre if (name == NULL) 196 1.50 kre continue; 197 1.50 kre 198 1.50 kre nl = strlen(name); 199 1.50 kre 200 1.50 kre if (len > 0 && nl + len + pad >= termwidth) { 201 1.50 kre outc('\n', out); 202 1.50 kre len = 0; 203 1.50 kre pad = 0; 204 1.50 kre } else if (pad > 0 && len != 0) 205 1.50 kre outfmt(out, "%*s", pad, ""); 206 1.50 kre else 207 1.50 kre pad = 0; 208 1.50 kre 209 1.50 kre len += nl + pad; 210 1.50 kre if (!posix) 211 1.50 kre pad = (nl | 7) + 1 - nl; 212 1.50 kre else 213 1.50 kre pad = 1; 214 1.50 kre 215 1.50 kre outstr(name, out); 216 1.50 kre } 217 1.50 kre if (len != 0) 218 1.50 kre outc('\n', out); 219 1.50 kre } 220 1.50 kre #endif /* SMALL */ 221 1.15 christos 222 1.1 cgd /* 223 1.1 cgd * The trap builtin. 224 1.1 cgd */ 225 1.1 cgd 226 1.10 cgd int 227 1.28 christos trapcmd(int argc, char **argv) 228 1.10 cgd { 229 1.1 cgd char *action; 230 1.1 cgd char **ap; 231 1.1 cgd int signo; 232 1.39 kre int errs = 0; 233 1.40 kre int printonly = 0; 234 1.39 kre 235 1.39 kre ap = argv + 1; 236 1.39 kre 237 1.47 kre CTRACE(DBG_TRAP, ("trapcmd: ")); 238 1.55 kre if (argc == 3 && strcmp(ap[1], "--") == 0) 239 1.55 kre argc--; 240 1.39 kre if (argc == 2 && strcmp(*ap, "-l") == 0) { 241 1.47 kre CTRACE(DBG_TRAP, ("-l\n")); 242 1.46 kre out1str("EXIT"); 243 1.46 kre printsignals(out1, 4); 244 1.39 kre return 0; 245 1.39 kre } 246 1.40 kre if (argc == 2 && strcmp(*ap, "-") == 0) { 247 1.47 kre CTRACE(DBG_TRAP, ("-\n")); 248 1.40 kre for (signo = 0; signo < NSIG; signo++) { 249 1.40 kre if (trap[signo] == NULL) 250 1.40 kre continue; 251 1.40 kre INTOFF; 252 1.40 kre ckfree(trap[signo]); 253 1.40 kre trap[signo] = NULL; 254 1.40 kre if (signo != 0) 255 1.40 kre setsignal(signo, 0); 256 1.40 kre INTON; 257 1.40 kre } 258 1.47 kre traps_invalid = 0; 259 1.40 kre return 0; 260 1.40 kre } 261 1.55 kre if (argc >= 2 && (strcmp(*ap, "-p") == 0 || strcmp(*ap, "-P") == 0)) { 262 1.55 kre CTRACE(DBG_TRAP, ("%s ", *ap)); 263 1.55 kre printonly = 1 + (ap[0][1] == 'p'); 264 1.40 kre ap++; 265 1.40 kre argc--; 266 1.40 kre } 267 1.39 kre 268 1.39 kre if (argc > 1 && strcmp(*ap, "--") == 0) { 269 1.39 kre argc--; 270 1.39 kre ap++; 271 1.39 kre } 272 1.1 cgd 273 1.55 kre if (printonly == 1 && argc < 2) 274 1.55 kre goto usage; 275 1.55 kre 276 1.1 cgd if (argc <= 1) { 277 1.40 kre int count; 278 1.40 kre 279 1.47 kre CTRACE(DBG_TRAP, ("*all*\n")); 280 1.40 kre if (printonly) { 281 1.52 kre for (count = 0, signo = 0 ; signo < NSIG ; signo++) { 282 1.52 kre if (signo == SIGKILL || signo == SIGSTOP) 283 1.52 kre continue; 284 1.40 kre if (trap[signo] == NULL) { 285 1.40 kre if (count == 0) 286 1.40 kre out1str("trap -- -"); 287 1.40 kre out1fmt(" %s", trap_signame(signo)); 288 1.40 kre /* oh! unlucky 13 */ 289 1.40 kre if (++count >= 13) { 290 1.40 kre out1str("\n"); 291 1.40 kre count = 0; 292 1.40 kre } 293 1.40 kre } 294 1.52 kre } 295 1.40 kre if (count) 296 1.40 kre out1str("\n"); 297 1.40 kre } 298 1.40 kre 299 1.52 kre /* 300 1.52 kre * We don't need do deal with SIGSTOP or SIGKILL as a 301 1.52 kre * special case anywhere here, as they cannot be 302 1.52 kre * ignored or caught - the only possibility is default 303 1.52 kre */ 304 1.40 kre for (count = 0, signo = 0 ; signo < NSIG ; signo++) 305 1.40 kre if (trap[signo] != NULL && trap[signo][0] == '\0') { 306 1.40 kre if (count == 0) 307 1.40 kre out1str("trap -- ''"); 308 1.40 kre out1fmt(" %s", trap_signame(signo)); 309 1.40 kre /* 310 1.40 kre * the prefix is 10 bytes, with 4 byte 311 1.40 kre * signal names (common) we have room in 312 1.40 kre * the 70 bytes left on a normal line for 313 1.40 kre * 70/(4+1) signals, that's 14, but to 314 1.40 kre * allow for the occasional longer sig name 315 1.40 kre * we output one less... 316 1.40 kre */ 317 1.40 kre if (++count >= 13) { 318 1.40 kre out1str("\n"); 319 1.40 kre count = 0; 320 1.40 kre } 321 1.40 kre } 322 1.40 kre if (count) 323 1.40 kre out1str("\n"); 324 1.40 kre 325 1.40 kre for (signo = 0 ; signo < NSIG ; signo++) 326 1.40 kre if (trap[signo] != NULL && trap[signo][0] != '\0') { 327 1.40 kre out1str("trap -- "); 328 1.31 christos print_quoted(trap[signo]); 329 1.40 kre out1fmt(" %s\n", trap_signame(signo)); 330 1.31 christos } 331 1.40 kre 332 1.1 cgd return 0; 333 1.1 cgd } 334 1.47 kre CTRACE(DBG_TRAP, ("\n")); 335 1.26 wulf 336 1.26 wulf action = NULL; 337 1.26 wulf 338 1.47 kre if (!printonly && traps_invalid) 339 1.47 kre free_traps(); 340 1.47 kre 341 1.40 kre if (!printonly && !is_number(*ap)) { 342 1.39 kre if ((*ap)[0] == '-' && (*ap)[1] == '\0') 343 1.39 kre ap++; /* reset to default */ 344 1.39 kre else 345 1.39 kre action = *ap++; /* can be '' for "ignore" */ 346 1.39 kre argc--; 347 1.39 kre } 348 1.26 wulf 349 1.39 kre if (argc < 2) { /* there must be at least 1 condition */ 350 1.55 kre usage: 351 1.39 kre out2str("Usage: trap [-l]\n" 352 1.40 kre " trap -p [condition ...]\n" 353 1.55 kre " trap -P condition ...\n" 354 1.39 kre " trap action condition ...\n" 355 1.39 kre " trap N condition ...\n"); 356 1.39 kre return 2; 357 1.26 wulf } 358 1.26 wulf 359 1.39 kre 360 1.1 cgd while (*ap) { 361 1.39 kre signo = signame_to_signum(*ap); 362 1.26 wulf 363 1.40 kre if (signo < 0 || signo >= NSIG) { 364 1.39 kre /* This is not a fatal error, so sayeth posix */ 365 1.39 kre outfmt(out2, "trap: '%s' bad condition\n", *ap); 366 1.39 kre errs = 1; 367 1.40 kre ap++; 368 1.40 kre continue; 369 1.40 kre } 370 1.40 kre ap++; 371 1.40 kre 372 1.40 kre if (printonly) { 373 1.52 kre /* 374 1.52 kre * we allow SIGSTOP and SIGKILL to be obtained 375 1.52 kre * (action will always be "-") here, if someone 376 1.52 kre * really wants to get that particular output 377 1.52 kre */ 378 1.55 kre if (printonly == 1) { 379 1.55 kre if (trap[signo] != NULL) 380 1.55 kre out1fmt("%s\n", trap[signo]); 381 1.55 kre } else { 382 1.55 kre out1str("trap -- "); 383 1.55 kre if (trap[signo] == NULL) 384 1.55 kre out1str("-"); 385 1.55 kre else 386 1.55 kre print_quoted(trap[signo]); 387 1.55 kre out1fmt(" %s\n", trap_signame(signo)); 388 1.55 kre } 389 1.40 kre continue; 390 1.39 kre } 391 1.26 wulf 392 1.52 kre if ((signo == SIGKILL || signo == SIGSTOP) && action != NULL) { 393 1.52 kre #ifndef SMALL 394 1.52 kre /* 395 1.52 kre * Don't bother with the error message in a SMALL shell 396 1.52 kre * just ignore req and return error status silently 397 1.52 kre * (POSIX says this is an "undefined" operation so 398 1.52 kre * whatever we do is OK!) 399 1.52 kre * 400 1.52 kre * When we do generate an error, make it attempt match 401 1.52 kre * the user's operand, as best we can reasonably. 402 1.52 kre */ 403 1.52 kre outfmt(out2, "trap: '%s%s' cannot be %s\n", 404 1.52 kre (!is_alpha(ap[-1][0]) || 405 1.52 kre strncasecmp(ap[-1], "sig", 3) == 0) ? "" : 406 1.52 kre is_upper(ap[-1][0]) ? "SIG" : "sig", 407 1.52 kre ap[-1], *action ? "caught" : "ignored"); 408 1.52 kre #endif 409 1.52 kre errs = 1; 410 1.52 kre continue; 411 1.52 kre } 412 1.52 kre 413 1.1 cgd INTOFF; 414 1.1 cgd if (action) 415 1.1 cgd action = savestr(action); 416 1.26 wulf 417 1.47 kre VTRACE(DBG_TRAP, ("trap for %d from %s%s%s to %s%s%s\n", signo, 418 1.47 kre trap[signo] ? "'" : "", trap[signo] ? trap[signo] : "-", 419 1.47 kre trap[signo] ? "'" : "", action ? "'" : "", 420 1.47 kre action ? action : "-", action ? "'" : "")); 421 1.47 kre 422 1.1 cgd if (trap[signo]) 423 1.1 cgd ckfree(trap[signo]); 424 1.26 wulf 425 1.1 cgd trap[signo] = action; 426 1.26 wulf 427 1.1 cgd if (signo != 0) 428 1.27 christos setsignal(signo, 0); 429 1.1 cgd INTON; 430 1.1 cgd } 431 1.39 kre return errs; 432 1.1 cgd } 433 1.1 cgd 434 1.1 cgd 435 1.1 cgd 436 1.1 cgd /* 437 1.27 christos * Clear traps on a fork or vfork. 438 1.27 christos * Takes one arg vfork, to tell it to not be destructive of 439 1.27 christos * the parents variables. 440 1.1 cgd */ 441 1.1 cgd void 442 1.28 christos clear_traps(int vforked) 443 1.27 christos { 444 1.47 kre char * volatile *tp; 445 1.47 kre 446 1.47 kre VTRACE(DBG_TRAP, ("clear_traps(%d)\n", vforked)); 447 1.47 kre if (!vforked) 448 1.47 kre traps_invalid = 1; 449 1.1 cgd 450 1.47 kre for (tp = &trap[1] ; tp < &trap[NSIG] ; tp++) { 451 1.1 cgd if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 452 1.1 cgd INTOFF; 453 1.47 kre setsignal(tp - trap, vforked == 1); 454 1.1 cgd INTON; 455 1.1 cgd } 456 1.1 cgd } 457 1.47 kre if (vforked == 2) 458 1.47 kre free_traps(); 459 1.47 kre } 460 1.47 kre 461 1.47 kre void 462 1.47 kre free_traps(void) 463 1.47 kre { 464 1.47 kre char * volatile *tp; 465 1.47 kre 466 1.47 kre VTRACE(DBG_TRAP, ("free_traps%s\n", traps_invalid ? "(invalid)" : "")); 467 1.47 kre INTOFF; 468 1.47 kre for (tp = trap ; tp < &trap[NSIG] ; tp++) 469 1.47 kre if (*tp && **tp) { 470 1.47 kre ckfree(*tp); 471 1.47 kre *tp = NULL; 472 1.47 kre } 473 1.47 kre traps_invalid = 0; 474 1.47 kre INTON; 475 1.1 cgd } 476 1.1 cgd 477 1.45 kre /* 478 1.45 kre * See if there are any defined traps 479 1.45 kre */ 480 1.45 kre int 481 1.45 kre have_traps(void) 482 1.45 kre { 483 1.47 kre char * volatile *tp; 484 1.47 kre 485 1.47 kre if (traps_invalid) 486 1.47 kre return 0; 487 1.1 cgd 488 1.45 kre for (tp = trap ; tp < &trap[NSIG] ; tp++) 489 1.45 kre if (*tp && **tp) /* trap not NULL or SIG_IGN */ 490 1.45 kre return 1; 491 1.45 kre return 0; 492 1.45 kre } 493 1.1 cgd 494 1.1 cgd /* 495 1.1 cgd * Set the signal handler for the specified signal. The routine figures 496 1.1 cgd * out what it should be set to. 497 1.1 cgd */ 498 1.47 kre void 499 1.28 christos setsignal(int signo, int vforked) 500 1.10 cgd { 501 1.1 cgd int action; 502 1.32 christos sig_t sigact = SIG_DFL, sig; 503 1.27 christos char *t, tsig; 504 1.1 cgd 505 1.51 kre if (traps_invalid || (t = trap[signo]) == NULL) 506 1.1 cgd action = S_DFL; 507 1.1 cgd else if (*t != '\0') 508 1.1 cgd action = S_CATCH; 509 1.1 cgd else 510 1.1 cgd action = S_IGN; 511 1.47 kre 512 1.47 kre VTRACE(DBG_TRAP, ("setsignal(%d%s) -> %d", signo, 513 1.47 kre vforked ? ", VF" : "", action)); 514 1.27 christos if (rootshell && !vforked && action == S_DFL) { 515 1.1 cgd switch (signo) { 516 1.1 cgd case SIGINT: 517 1.21 christos if (iflag || minusc || sflag == 0) 518 1.1 cgd action = S_CATCH; 519 1.1 cgd break; 520 1.1 cgd case SIGQUIT: 521 1.1 cgd #ifdef DEBUG 522 1.1 cgd if (debug) 523 1.1 cgd break; 524 1.1 cgd #endif 525 1.1 cgd /* FALLTHROUGH */ 526 1.1 cgd case SIGTERM: 527 1.47 kre if (rootshell && iflag) 528 1.1 cgd action = S_IGN; 529 1.1 cgd break; 530 1.1 cgd #if JOBS 531 1.1 cgd case SIGTSTP: 532 1.1 cgd case SIGTTOU: 533 1.47 kre if (rootshell && mflag) 534 1.1 cgd action = S_IGN; 535 1.1 cgd break; 536 1.1 cgd #endif 537 1.1 cgd } 538 1.1 cgd } 539 1.14 christos 540 1.47 kre /* 541 1.47 kre * Never let users futz with SIGCHLD 542 1.47 kre * instead we will give them pseudo SIGCHLD's 543 1.47 kre * when background jobs complete. 544 1.47 kre */ 545 1.47 kre if (signo == SIGCHLD) 546 1.47 kre action = S_DFL; 547 1.47 kre 548 1.47 kre VTRACE(DBG_TRAP, (" -> %d", action)); 549 1.47 kre 550 1.47 kre t = &sigmode[signo]; 551 1.27 christos tsig = *t; 552 1.27 christos if (tsig == 0) { 553 1.16 christos /* 554 1.16 christos * current setting unknown 555 1.1 cgd */ 556 1.15 christos if (!getsigaction(signo, &sigact)) { 557 1.15 christos /* 558 1.15 christos * Pretend it worked; maybe we should give a warning 559 1.15 christos * here, but other shells don't. We don't alter 560 1.15 christos * sigmode, so that we retry every time. 561 1.15 christos */ 562 1.47 kre VTRACE(DBG_TRAP, (" getsigaction (%d)\n", errno)); 563 1.47 kre return; 564 1.15 christos } 565 1.47 kre VTRACE(DBG_TRAP, (" [%s]%s%s", sigact==SIG_IGN ? "IGN" : 566 1.47 kre sigact==SIG_DFL ? "DFL" : "caught", 567 1.47 kre iflag ? "i" : "", mflag ? "m" : "")); 568 1.47 kre 569 1.1 cgd if (sigact == SIG_IGN) { 570 1.32 christos /* 571 1.33 christos * POSIX 3.14.13 states that non-interactive shells 572 1.33 christos * should ignore trap commands for signals that were 573 1.33 christos * ignored upon entry, and leaves the behavior 574 1.33 christos * unspecified for interactive shells. On interactive 575 1.33 christos * shells, or if job control is on, and we have a job 576 1.33 christos * control related signal, we allow the trap to work. 577 1.33 christos * 578 1.33 christos * This change allows us to be POSIX compliant, and 579 1.33 christos * at the same time override the default behavior if 580 1.33 christos * we need to by setting the interactive flag. 581 1.32 christos */ 582 1.33 christos if ((mflag && (signo == SIGTSTP || 583 1.33 christos signo == SIGTTIN || signo == SIGTTOU)) || iflag) { 584 1.33 christos tsig = S_IGN; 585 1.33 christos } else 586 1.33 christos tsig = S_HARD_IGN; 587 1.1 cgd } else { 588 1.27 christos tsig = S_RESET; /* force to be set */ 589 1.1 cgd } 590 1.1 cgd } 591 1.47 kre VTRACE(DBG_TRAP, (" tsig=%d\n", tsig)); 592 1.47 kre 593 1.27 christos if (tsig == S_HARD_IGN || tsig == action) 594 1.47 kre return; 595 1.47 kre 596 1.1 cgd switch (action) { 597 1.1 cgd case S_DFL: sigact = SIG_DFL; break; 598 1.54 kre case S_CATCH: sigact = onsig; break; 599 1.1 cgd case S_IGN: sigact = SIG_IGN; break; 600 1.1 cgd } 601 1.47 kre 602 1.32 christos sig = signal(signo, sigact); 603 1.47 kre 604 1.32 christos if (sig != SIG_ERR) { 605 1.32 christos sigset_t ss; 606 1.47 kre 607 1.32 christos if (!vforked) 608 1.32 christos *t = action; 609 1.47 kre 610 1.32 christos if (action == S_CATCH) 611 1.32 christos (void)siginterrupt(signo, 1); 612 1.32 christos /* 613 1.32 christos * If our parent accidentally blocked signals for 614 1.32 christos * us make sure we unblock them 615 1.32 christos */ 616 1.32 christos (void)sigemptyset(&ss); 617 1.32 christos (void)sigaddset(&ss, signo); 618 1.32 christos (void)sigprocmask(SIG_UNBLOCK, &ss, NULL); 619 1.32 christos } 620 1.47 kre return; 621 1.1 cgd } 622 1.1 cgd 623 1.6 jtc /* 624 1.6 jtc * Return the current setting for sig w/o changing it. 625 1.6 jtc */ 626 1.15 christos static int 627 1.28 christos getsigaction(int signo, sig_t *sigact) 628 1.10 cgd { 629 1.6 jtc struct sigaction sa; 630 1.6 jtc 631 1.6 jtc if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 632 1.15 christos return 0; 633 1.15 christos *sigact = (sig_t) sa.sa_handler; 634 1.15 christos return 1; 635 1.6 jtc } 636 1.1 cgd 637 1.1 cgd /* 638 1.1 cgd * Ignore a signal. 639 1.1 cgd */ 640 1.1 cgd 641 1.1 cgd void 642 1.28 christos ignoresig(int signo, int vforked) 643 1.10 cgd { 644 1.47 kre if (sigmode[signo] == 0) 645 1.47 kre setsignal(signo, vforked); 646 1.47 kre 647 1.47 kre VTRACE(DBG_TRAP, ("ignoresig(%d%s)\n", signo, vforked ? ", VF" : "")); 648 1.47 kre if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 649 1.1 cgd signal(signo, SIG_IGN); 650 1.47 kre if (!vforked) 651 1.47 kre sigmode[signo] = S_IGN; 652 1.1 cgd } 653 1.47 kre } 654 1.47 kre 655 1.47 kre char * 656 1.47 kre child_trap(void) 657 1.47 kre { 658 1.47 kre char * p; 659 1.47 kre 660 1.47 kre p = trap[SIGCHLD]; 661 1.47 kre 662 1.51 kre if (traps_invalid || (p != NULL && *p == '\0')) 663 1.47 kre p = NULL; 664 1.47 kre 665 1.47 kre return p; 666 1.1 cgd } 667 1.1 cgd 668 1.1 cgd 669 1.1 cgd #ifdef mkinit 670 1.8 jtc INCLUDE <signal.h> 671 1.1 cgd INCLUDE "trap.h" 672 1.47 kre INCLUDE "shell.h" 673 1.47 kre INCLUDE "show.h" 674 1.1 cgd 675 1.1 cgd SHELLPROC { 676 1.1 cgd char *sm; 677 1.1 cgd 678 1.47 kre INTOFF; 679 1.47 kre clear_traps(2); 680 1.8 jtc for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 681 1.47 kre if (*sm == S_IGN) { 682 1.1 cgd *sm = S_HARD_IGN; 683 1.49 kre VTRACE(DBG_TRAP, ("SHELLPROC: %d -> hard_ign\n", 684 1.49 kre (sm - sigmode))); 685 1.47 kre } 686 1.1 cgd } 687 1.47 kre INTON; 688 1.1 cgd } 689 1.1 cgd #endif 690 1.1 cgd 691 1.1 cgd 692 1.1 cgd 693 1.1 cgd /* 694 1.1 cgd * Signal handler. 695 1.1 cgd */ 696 1.1 cgd 697 1.1 cgd void 698 1.28 christos onsig(int signo) 699 1.10 cgd { 700 1.52 kre int sav_err = errno; 701 1.52 kre 702 1.52 kre CTRACE(DBG_SIG, ("onsig(%d), had: pendingsigs %d%s, gotsig[%d]=%d\n", 703 1.52 kre signo, pendingsigs, intpending ? " (SIGINT-pending)" : "", 704 1.52 kre signo, gotsig[signo])); 705 1.41 kre 706 1.47 kre /* This should not be needed. 707 1.1 cgd signal(signo, onsig); 708 1.47 kre */ 709 1.47 kre 710 1.51 kre if (signo == SIGINT && (traps_invalid || trap[SIGINT] == NULL)) { 711 1.52 kre VTRACE(DBG_SIG, ("onsig(SIGINT), doing it now\n")); 712 1.54 kre if (suppressint && !in_dotrap) 713 1.52 kre intpending = 1; 714 1.52 kre else 715 1.52 kre onint(); 716 1.52 kre errno = sav_err; 717 1.1 cgd return; 718 1.1 cgd } 719 1.47 kre 720 1.47 kre /* 721 1.47 kre * if the signal will do nothing, no point reporting it 722 1.47 kre */ 723 1.51 kre if (!traps_invalid && trap[signo] != NULL && trap[signo][0] != '\0' && 724 1.47 kre signo != SIGCHLD) { 725 1.47 kre gotsig[signo] = 1; 726 1.47 kre pendingsigs++; 727 1.52 kre if (iflag && signo == SIGINT) { 728 1.52 kre if (!suppressint) { 729 1.52 kre VTRACE(DBG_SIG, 730 1.52 kre ("onsig: -i gotsig[INT]->%d pendingsigs->%d BANG\n", 731 1.52 kre gotsig[SIGINT], pendingsigs)); 732 1.52 kre onint(); 733 1.52 kre errno = sav_err; 734 1.52 kre return; 735 1.52 kre } 736 1.52 kre intpending = 1; 737 1.52 kre } 738 1.52 kre VTRACE(DBG_SIG, ("onsig: gotsig[%d]->%d pendingsigs->%d%s\n", 739 1.52 kre signo, gotsig[signo], pendingsigs, 740 1.52 kre intpending ? " (SIGINT pending)":"")); 741 1.47 kre } 742 1.52 kre errno = sav_err; 743 1.1 cgd } 744 1.1 cgd 745 1.1 cgd 746 1.1 cgd 747 1.1 cgd /* 748 1.1 cgd * Called to execute a trap. Perhaps we should avoid entering new trap 749 1.1 cgd * handlers while we are executing a trap handler. 750 1.1 cgd */ 751 1.1 cgd 752 1.1 cgd void 753 1.28 christos dotrap(void) 754 1.28 christos { 755 1.1 cgd int i; 756 1.47 kre char *tr; 757 1.1 cgd int savestatus; 758 1.47 kre struct skipsave saveskip; 759 1.47 kre 760 1.52 kre CTRACE(DBG_TRAP|DBG_SIG, ("dotrap[%d]: %d pending, traps %sinvalid\n", 761 1.52 kre in_dotrap, pendingsigs, traps_invalid ? "" : "not ")); 762 1.52 kre 763 1.47 kre in_dotrap++; 764 1.1 cgd for (;;) { 765 1.47 kre pendingsigs = 0; 766 1.1 cgd for (i = 1 ; ; i++) { 767 1.52 kre if (i >= NSIG) { 768 1.52 kre in_dotrap--; 769 1.52 kre VTRACE(DBG_TRAP|DBG_SIG, ("dotrap[%d] done\n", 770 1.52 kre in_dotrap)); 771 1.40 kre return; 772 1.52 kre } 773 1.40 kre if (gotsig[i]) 774 1.6 jtc break; 775 1.1 cgd } 776 1.40 kre gotsig[i] = 0; 777 1.47 kre 778 1.47 kre if (traps_invalid) 779 1.47 kre continue; 780 1.47 kre 781 1.47 kre tr = trap[i]; 782 1.47 kre 783 1.47 kre CTRACE(DBG_TRAP|DBG_SIG, ("dotrap %d: %s%s%s\n", i, 784 1.47 kre tr ? "\"" : "", tr ? tr : "NULL", tr ? "\"" : "")); 785 1.47 kre 786 1.47 kre if (tr != NULL) { 787 1.47 kre last_trapsig = i; 788 1.47 kre save_skipstate(&saveskip); 789 1.47 kre savestatus = exitstatus; 790 1.47 kre 791 1.44 kre tr = savestr(tr); /* trap code may free trap[i] */ 792 1.44 kre evalstring(tr, 0); 793 1.44 kre ckfree(tr); 794 1.47 kre 795 1.47 kre if (current_skipstate() == SKIPNONE || 796 1.47 kre saveskip.state != SKIPNONE) { 797 1.47 kre restore_skipstate(&saveskip); 798 1.47 kre exitstatus = savestatus; 799 1.47 kre } 800 1.44 kre } 801 1.1 cgd } 802 1.1 cgd } 803 1.1 cgd 804 1.37 christos int 805 1.37 christos lastsig(void) 806 1.37 christos { 807 1.37 christos int i; 808 1.1 cgd 809 1.40 kre for (i = NSIG; --i > 0; ) 810 1.40 kre if (gotsig[i]) 811 1.37 christos return i; 812 1.37 christos return SIGINT; /* XXX */ 813 1.37 christos } 814 1.1 cgd 815 1.1 cgd /* 816 1.1 cgd * Controls whether the shell is interactive or not. 817 1.1 cgd */ 818 1.1 cgd 819 1.1 cgd 820 1.1 cgd void 821 1.28 christos setinteractive(int on) 822 1.10 cgd { 823 1.6 jtc static int is_interactive; 824 1.6 jtc 825 1.1 cgd if (on == is_interactive) 826 1.1 cgd return; 827 1.27 christos setsignal(SIGINT, 0); 828 1.27 christos setsignal(SIGQUIT, 0); 829 1.27 christos setsignal(SIGTERM, 0); 830 1.1 cgd is_interactive = on; 831 1.1 cgd } 832 1.1 cgd 833 1.1 cgd 834 1.1 cgd 835 1.1 cgd /* 836 1.1 cgd * Called to exit the shell. 837 1.1 cgd */ 838 1.47 kre void 839 1.47 kre exitshell(int status) 840 1.47 kre { 841 1.47 kre CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 842 1.47 kre ("pid %d: exitshell(%d)\n", getpid(), status)); 843 1.47 kre 844 1.47 kre exiting = 1; 845 1.47 kre exiting_status = status; 846 1.47 kre exitshell_savedstatus(); 847 1.47 kre } 848 1.1 cgd 849 1.1 cgd void 850 1.47 kre exitshell_savedstatus(void) 851 1.10 cgd { 852 1.47 kre struct jmploc loc; 853 1.1 cgd char *p; 854 1.47 kre volatile int sig = 0; 855 1.47 kre int s; 856 1.47 kre sigset_t sigs; 857 1.1 cgd 858 1.41 kre CTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 859 1.54 kre ("pid %d: exitshell_savedstatus()%s $?=%d xs=%d dt=%d ts=%d\n", 860 1.47 kre getpid(), exiting ? " exiting" : "", exitstatus, 861 1.47 kre exiting_status, in_dotrap, last_trapsig)); 862 1.47 kre 863 1.47 kre if (!exiting) { 864 1.47 kre if (in_dotrap && last_trapsig) { 865 1.47 kre sig = last_trapsig; 866 1.47 kre exiting_status = sig + 128; 867 1.47 kre } else 868 1.47 kre exiting_status = exitstatus; 869 1.47 kre } 870 1.47 kre exitstatus = exiting_status; 871 1.47 kre 872 1.53 kre if (pendingsigs && !setjmp(loc.loc)) { 873 1.53 kre handler = &loc; 874 1.53 kre 875 1.53 kre dotrap(); 876 1.53 kre } 877 1.53 kre 878 1.47 kre if (!setjmp(loc.loc)) { 879 1.47 kre handler = &loc; 880 1.47 kre 881 1.47 kre if (!traps_invalid && (p = trap[0]) != NULL && *p != '\0') { 882 1.47 kre reset_eval(); 883 1.47 kre trap[0] = NULL; 884 1.47 kre VTRACE(DBG_TRAP, ("exit trap: \"%s\"\n", p)); 885 1.47 kre evalstring(p, 0); 886 1.47 kre } 887 1.47 kre } 888 1.41 kre 889 1.47 kre INTOFF; /* we're done, no more interrupts. */ 890 1.47 kre 891 1.57 kre #ifndef SMALL 892 1.57 kre if (rootshell) 893 1.57 kre save_sh_history(); 894 1.57 kre #endif 895 1.57 kre 896 1.47 kre if (!setjmp(loc.loc)) { 897 1.47 kre handler = &loc; /* probably unnecessary */ 898 1.47 kre flushall(); 899 1.47 kre #if JOBS 900 1.47 kre setjobctl(0); 901 1.47 kre #endif 902 1.6 jtc } 903 1.47 kre 904 1.47 kre if ((s = sig) != 0 && s != SIGSTOP && s != SIGTSTP && s != SIGTTIN && 905 1.47 kre s != SIGTTOU) { 906 1.47 kre struct rlimit nocore; 907 1.47 kre 908 1.47 kre /* 909 1.47 kre * if the signal is of the core dump variety, don't... 910 1.47 kre */ 911 1.47 kre nocore.rlim_cur = nocore.rlim_max = 0; 912 1.47 kre (void) setrlimit(RLIMIT_CORE, &nocore); 913 1.47 kre 914 1.47 kre signal(s, SIG_DFL); 915 1.47 kre sigemptyset(&sigs); 916 1.47 kre sigaddset(&sigs, s); 917 1.47 kre sigprocmask(SIG_UNBLOCK, &sigs, NULL); 918 1.47 kre 919 1.56 kre VTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 920 1.56 kre ("exitshell_savedstatus(): pid %d Death by signal %d\n", 921 1.56 kre getpid(), s)); 922 1.47 kre kill(getpid(), s); 923 1.1 cgd } 924 1.56 kre VTRACE(DBG_ERRS|DBG_PROCS|DBG_CMDS|DBG_TRAP, 925 1.56 kre ("exitshell_savedstatus(): pid %d exiting(%d)\n", 926 1.56 kre getpid(), exiting_status)); 927 1.47 kre _exit(exiting_status); 928 1.18 mycroft /* NOTREACHED */ 929 1.1 cgd } 930