1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. 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 #include <signal.h> 36 #include <unistd.h> 37 #include <stdlib.h> 38 39 #include "shell.h" 40 #include "main.h" 41 #include "nodes.h" /* for other headers */ 42 #include "eval.h" 43 #include "jobs.h" 44 #include "show.h" 45 #include "options.h" 46 #include "syntax.h" 47 #include "output.h" 48 #include "memalloc.h" 49 #include "error.h" 50 #include "trap.h" 51 #include "mystring.h" 52 #include "builtins.h" 53 #ifndef NO_HISTORY 54 #include "myhistedit.h" 55 #endif 56 57 58 /* 59 * Sigmode records the current value of the signal handlers for the various 60 * modes. A value of zero means that the current handler is not known. 61 * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 62 */ 63 64 #define S_DFL 1 /* default signal handling (SIG_DFL) */ 65 #define S_CATCH 2 /* signal is caught */ 66 #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 67 #define S_HARD_IGN 4 /* signal is ignored permanently */ 68 #define S_RESET 5 /* temporary - to reset a hard ignored sig */ 69 70 71 static char sigmode[NSIG]; /* current value of signal */ 72 volatile sig_atomic_t pendingsig; /* indicates some signal received */ 73 volatile sig_atomic_t pendingsig_waitcmd; /* indicates wait builtin should be interrupted */ 74 static int in_dotrap; /* do we execute in a trap handler? */ 75 static char *volatile trap[NSIG]; /* trap handler commands */ 76 static volatile sig_atomic_t gotsig[NSIG]; 77 /* indicates specified signal received */ 78 static int ignore_sigchld; /* Used while handling SIGCHLD traps. */ 79 static int last_trapsig; 80 81 static int exiting; /* exitshell() has been called */ 82 static int exiting_exitstatus; /* value passed to exitshell() */ 83 84 static int getsigaction(int, sig_t *); 85 86 87 /* 88 * Map a string to a signal number. 89 * 90 * Note: the signal number may exceed NSIG. 91 */ 92 static int 93 sigstring_to_signum(char *sig) 94 { 95 96 if (is_number(sig)) { 97 int signo; 98 99 signo = atoi(sig); 100 return ((signo >= 0 && signo < NSIG) ? signo : (-1)); 101 } else if (strcasecmp(sig, "EXIT") == 0) { 102 return (0); 103 } else { 104 int n; 105 106 if (strncasecmp(sig, "SIG", 3) == 0) 107 sig += 3; 108 for (n = 1; n < sys_nsig; n++) 109 if (sys_signame[n] && 110 strcasecmp(sys_signame[n], sig) == 0) 111 return (n); 112 } 113 return (-1); 114 } 115 116 117 /* 118 * Print a list of valid signal names. 119 */ 120 static void 121 printsignals(void) 122 { 123 int n, outlen; 124 125 outlen = 0; 126 for (n = 1; n < sys_nsig; n++) { 127 if (sys_signame[n]) { 128 out1fmt("%s", sys_signame[n]); 129 outlen += strlen(sys_signame[n]); 130 } else { 131 out1fmt("%d", n); 132 outlen += 3; /* good enough */ 133 } 134 ++outlen; 135 if (outlen > 71 || n == sys_nsig - 1) { 136 out1str("\n"); 137 outlen = 0; 138 } else { 139 out1c(' '); 140 } 141 } 142 } 143 144 145 /* 146 * The trap builtin. 147 */ 148 int 149 trapcmd(int argc __unused, char **argv) 150 { 151 char *action; 152 int signo; 153 int errors = 0; 154 int i; 155 156 while ((i = nextopt("l")) != '\0') { 157 switch (i) { 158 case 'l': 159 printsignals(); 160 return (0); 161 } 162 } 163 argv = argptr; 164 165 if (*argv == NULL) { 166 for (signo = 0 ; signo < sys_nsig ; signo++) { 167 if (signo < NSIG && trap[signo] != NULL) { 168 out1str("trap -- "); 169 out1qstr(trap[signo]); 170 if (signo == 0) { 171 out1str(" EXIT\n"); 172 } else if (sys_signame[signo]) { 173 out1fmt(" %s\n", sys_signame[signo]); 174 } else { 175 out1fmt(" %d\n", signo); 176 } 177 } 178 } 179 return 0; 180 } 181 action = NULL; 182 if (*argv && !is_number(*argv)) { 183 if (strcmp(*argv, "-") == 0) 184 argv++; 185 else { 186 action = *argv; 187 argv++; 188 } 189 } 190 for (; *argv; argv++) { 191 if ((signo = sigstring_to_signum(*argv)) == -1) { 192 warning("bad signal %s", *argv); 193 errors = 1; 194 continue; 195 } 196 INTOFF; 197 if (action) 198 action = savestr(action); 199 if (trap[signo]) 200 ckfree(trap[signo]); 201 trap[signo] = action; 202 if (signo != 0) 203 setsignal(signo); 204 INTON; 205 } 206 return errors; 207 } 208 209 210 /* 211 * Clear traps on a fork. 212 */ 213 void 214 clear_traps(void) 215 { 216 char *volatile *tp; 217 218 for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 219 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 220 INTOFF; 221 ckfree(*tp); 222 *tp = NULL; 223 if (tp != &trap[0]) 224 setsignal(tp - trap); 225 INTON; 226 } 227 } 228 } 229 230 231 /* 232 * Check if we have any traps enabled. 233 */ 234 int 235 have_traps(void) 236 { 237 char *volatile *tp; 238 239 for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) { 240 if (*tp && **tp) /* trap not NULL or SIG_IGN */ 241 return 1; 242 } 243 return 0; 244 } 245 246 /* 247 * Set the signal handler for the specified signal. The routine figures 248 * out what it should be set to. 249 */ 250 void 251 setsignal(int signo) 252 { 253 int action; 254 sig_t sigact = SIG_DFL; 255 struct sigaction sa; 256 char *t; 257 258 if ((t = trap[signo]) == NULL) 259 action = S_DFL; 260 else if (*t != '\0') 261 action = S_CATCH; 262 else 263 action = S_IGN; 264 if (action == S_DFL) { 265 switch (signo) { 266 case SIGINT: 267 action = S_CATCH; 268 break; 269 case SIGQUIT: 270 #ifdef DEBUG 271 if (debug) 272 break; 273 #endif 274 action = S_CATCH; 275 break; 276 case SIGTERM: 277 if (rootshell && iflag) 278 action = S_IGN; 279 break; 280 #if JOBS 281 case SIGTSTP: 282 case SIGTTOU: 283 if (rootshell && mflag) 284 action = S_IGN; 285 break; 286 #endif 287 } 288 } 289 290 t = &sigmode[signo]; 291 if (*t == 0) { 292 /* 293 * current setting unknown 294 */ 295 if (!getsigaction(signo, &sigact)) { 296 /* 297 * Pretend it worked; maybe we should give a warning 298 * here, but other shells don't. We don't alter 299 * sigmode, so that we retry every time. 300 */ 301 return; 302 } 303 if (sigact == SIG_IGN) { 304 if (mflag && (signo == SIGTSTP || 305 signo == SIGTTIN || signo == SIGTTOU)) { 306 *t = S_IGN; /* don't hard ignore these */ 307 } else 308 *t = S_HARD_IGN; 309 } else { 310 *t = S_RESET; /* force to be set */ 311 } 312 } 313 if (*t == S_HARD_IGN || *t == action) 314 return; 315 switch (action) { 316 case S_DFL: sigact = SIG_DFL; break; 317 case S_CATCH: sigact = onsig; break; 318 case S_IGN: sigact = SIG_IGN; break; 319 } 320 *t = action; 321 sa.sa_handler = sigact; 322 sa.sa_flags = 0; 323 sigemptyset(&sa.sa_mask); 324 sigaction(signo, &sa, NULL); 325 } 326 327 328 /* 329 * Return the current setting for sig w/o changing it. 330 */ 331 static int 332 getsigaction(int signo, sig_t *sigact) 333 { 334 struct sigaction sa; 335 336 if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 337 return 0; 338 *sigact = (sig_t) sa.sa_handler; 339 return 1; 340 } 341 342 343 /* 344 * Ignore a signal. 345 */ 346 void 347 ignoresig(int signo) 348 { 349 350 if (sigmode[signo] == 0) 351 setsignal(signo); 352 if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 353 signal(signo, SIG_IGN); 354 sigmode[signo] = S_IGN; 355 } 356 } 357 358 359 int 360 issigchldtrapped(void) 361 { 362 363 return (trap[SIGCHLD] != NULL && *trap[SIGCHLD] != '\0'); 364 } 365 366 367 /* 368 * Signal handler. 369 */ 370 void 371 onsig(int signo) 372 { 373 374 if (signo == SIGINT && trap[SIGINT] == NULL) { 375 if (suppressint) 376 SET_PENDING_INT; 377 else 378 onint(); 379 return; 380 } 381 382 /* If we are currently in a wait builtin, prepare to break it */ 383 if (signo == SIGINT || signo == SIGQUIT) 384 pendingsig_waitcmd = signo; 385 386 if (trap[signo] != NULL && trap[signo][0] != '\0' && 387 (signo != SIGCHLD || !ignore_sigchld)) { 388 gotsig[signo] = 1; 389 pendingsig = signo; 390 pendingsig_waitcmd = signo; 391 } 392 } 393 394 395 /* 396 * Called to execute a trap. Perhaps we should avoid entering new trap 397 * handlers while we are executing a trap handler. 398 */ 399 void 400 dotrap(void) 401 { 402 struct stackmark smark; 403 int i; 404 int savestatus, prev_evalskip, prev_skipcount; 405 406 in_dotrap++; 407 for (;;) { 408 pendingsig = 0; 409 pendingsig_waitcmd = 0; 410 for (i = 1; i < NSIG; i++) { 411 if (gotsig[i]) { 412 gotsig[i] = 0; 413 if (trap[i]) { 414 /* 415 * Ignore SIGCHLD to avoid infinite 416 * recursion if the trap action does 417 * a fork. 418 */ 419 if (i == SIGCHLD) 420 ignore_sigchld++; 421 422 /* 423 * Backup current evalskip 424 * state and reset it before 425 * executing a trap, so that the 426 * trap is not disturbed by an 427 * ongoing break/continue/return 428 * statement. 429 */ 430 prev_evalskip = evalskip; 431 prev_skipcount = skipcount; 432 evalskip = 0; 433 434 last_trapsig = i; 435 savestatus = exitstatus; 436 setstackmark(&smark); 437 evalstring(stsavestr(trap[i]), 0); 438 popstackmark(&smark); 439 440 /* 441 * If such a command was not 442 * already in progress, allow a 443 * break/continue/return in the 444 * trap action to have an effect 445 * outside of it. 446 */ 447 if (evalskip == 0 || 448 prev_evalskip != 0) { 449 evalskip = prev_evalskip; 450 skipcount = prev_skipcount; 451 exitstatus = savestatus; 452 } 453 454 if (i == SIGCHLD) 455 ignore_sigchld--; 456 } 457 break; 458 } 459 } 460 if (i >= NSIG) 461 break; 462 } 463 in_dotrap--; 464 } 465 466 467 void 468 trap_init(void) 469 { 470 setsignal(SIGINT); 471 setsignal(SIGQUIT); 472 } 473 474 475 /* 476 * Controls whether the shell is interactive or not based on iflag. 477 */ 478 void 479 setinteractive(void) 480 { 481 setsignal(SIGTERM); 482 } 483 484 485 /* 486 * Called to exit the shell. 487 */ 488 void 489 exitshell(int status) 490 { 491 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 492 exiting = 1; 493 exiting_exitstatus = status; 494 exitshell_savedstatus(); 495 } 496 497 void 498 exitshell_savedstatus(void) 499 { 500 struct jmploc loc1, loc2; 501 char *p; 502 int sig = 0; 503 sigset_t sigs; 504 505 if (!exiting) { 506 if (in_dotrap && last_trapsig) { 507 sig = last_trapsig; 508 exiting_exitstatus = sig + 128; 509 } else 510 exiting_exitstatus = oexitstatus; 511 } 512 exitstatus = oexitstatus = exiting_exitstatus; 513 if (!setjmp(loc1.loc)) { 514 handler = &loc1; 515 if ((p = trap[0]) != NULL && *p != '\0') { 516 /* 517 * Reset evalskip, or the trap on EXIT could be 518 * interrupted if the last command was a "return". 519 */ 520 evalskip = 0; 521 trap[0] = NULL; 522 FORCEINTON; 523 evalstring(p, 0); 524 } 525 } 526 if (!setjmp(loc2.loc)) { 527 handler = &loc2; /* probably unnecessary */ 528 FORCEINTON; 529 flushall(); 530 #if JOBS 531 setjobctl(0); 532 #endif 533 #ifndef NO_HISTORY 534 histsave(); 535 #endif 536 } 537 if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN && 538 sig != SIGTTOU) { 539 signal(sig, SIG_DFL); 540 sigemptyset(&sigs); 541 sigaddset(&sigs, sig); 542 sigprocmask(SIG_UNBLOCK, &sigs, NULL); 543 kill(getpid(), sig); 544 /* If the default action is to ignore, fall back to _exit(). */ 545 } 546 _exit(exiting_exitstatus); 547 } 548