trap.c revision 1556
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 351556Srgrimes */ 361556Srgrimes 371556Srgrimes#ifndef lint 381556Srgrimesstatic char sccsid[] = "@(#)trap.c 8.1 (Berkeley) 5/31/93"; 391556Srgrimes#endif /* not lint */ 401556Srgrimes 411556Srgrimes#include "shell.h" 421556Srgrimes#include "main.h" 431556Srgrimes#include "nodes.h" /* for other headers */ 441556Srgrimes#include "eval.h" 451556Srgrimes#include "jobs.h" 461556Srgrimes#include "options.h" 471556Srgrimes#include "syntax.h" 481556Srgrimes#include "signames.h" 491556Srgrimes#include "output.h" 501556Srgrimes#include "memalloc.h" 511556Srgrimes#include "error.h" 521556Srgrimes#include "trap.h" 531556Srgrimes#include "mystring.h" 541556Srgrimes#include <signal.h> 551556Srgrimes 561556Srgrimes 571556Srgrimes/* 581556Srgrimes * Sigmode records the current value of the signal handlers for the various 591556Srgrimes * modes. A value of zero means that the current handler is not known. 601556Srgrimes * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 611556Srgrimes */ 621556Srgrimes 631556Srgrimes#define S_DFL 1 /* default signal handling (SIG_DFL) */ 641556Srgrimes#define S_CATCH 2 /* signal is caught */ 651556Srgrimes#define S_IGN 3 /* signal is ignored (SIG_IGN) */ 661556Srgrimes#define S_HARD_IGN 4 /* signal is ignored permenantly */ 671556Srgrimes#define S_RESET 5 /* temporary - to reset a hard ignored sig */ 681556Srgrimes 691556Srgrimes 701556Srgrimesextern char nullstr[1]; /* null string */ 711556Srgrimes 721556Srgrimeschar *trap[MAXSIG+1]; /* trap handler commands */ 731556SrgrimesMKINIT char sigmode[MAXSIG]; /* current value of signal */ 741556Srgrimeschar gotsig[MAXSIG]; /* indicates specified signal received */ 751556Srgrimesint pendingsigs; /* indicates some signal received */ 761556Srgrimes 771556Srgrimes/* 781556Srgrimes * The trap builtin. 791556Srgrimes */ 801556Srgrimes 811556Srgrimestrapcmd(argc, argv) char **argv; { 821556Srgrimes char *action; 831556Srgrimes char **ap; 841556Srgrimes int signo; 851556Srgrimes 861556Srgrimes if (argc <= 1) { 871556Srgrimes for (signo = 0 ; signo <= MAXSIG ; signo++) { 881556Srgrimes if (trap[signo] != NULL) 891556Srgrimes out1fmt("%d: %s\n", signo, trap[signo]); 901556Srgrimes } 911556Srgrimes return 0; 921556Srgrimes } 931556Srgrimes ap = argv + 1; 941556Srgrimes if (is_number(*ap)) 951556Srgrimes action = NULL; 961556Srgrimes else 971556Srgrimes action = *ap++; 981556Srgrimes while (*ap) { 991556Srgrimes if ((signo = number(*ap)) < 0 || signo > MAXSIG) 1001556Srgrimes error("%s: bad trap", *ap); 1011556Srgrimes INTOFF; 1021556Srgrimes if (action) 1031556Srgrimes action = savestr(action); 1041556Srgrimes if (trap[signo]) 1051556Srgrimes ckfree(trap[signo]); 1061556Srgrimes trap[signo] = action; 1071556Srgrimes if (signo != 0) 1081556Srgrimes setsignal(signo); 1091556Srgrimes INTON; 1101556Srgrimes ap++; 1111556Srgrimes } 1121556Srgrimes return 0; 1131556Srgrimes} 1141556Srgrimes 1151556Srgrimes 1161556Srgrimes 1171556Srgrimes/* 1181556Srgrimes * Clear traps on a fork. 1191556Srgrimes */ 1201556Srgrimes 1211556Srgrimesvoid 1221556Srgrimesclear_traps() { 1231556Srgrimes char **tp; 1241556Srgrimes 1251556Srgrimes for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) { 1261556Srgrimes if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 1271556Srgrimes INTOFF; 1281556Srgrimes ckfree(*tp); 1291556Srgrimes *tp = NULL; 1301556Srgrimes if (tp != &trap[0]) 1311556Srgrimes setsignal(tp - trap); 1321556Srgrimes INTON; 1331556Srgrimes } 1341556Srgrimes } 1351556Srgrimes} 1361556Srgrimes 1371556Srgrimes 1381556Srgrimes 1391556Srgrimes/* 1401556Srgrimes * Set the signal handler for the specified signal. The routine figures 1411556Srgrimes * out what it should be set to. 1421556Srgrimes */ 1431556Srgrimes 1441556Srgrimesint 1451556Srgrimessetsignal(signo) { 1461556Srgrimes int action; 1471556Srgrimes sig_t sigact; 1481556Srgrimes char *t; 1491556Srgrimes extern void onsig(); 1501556Srgrimes extern sig_t getsigaction(); 1511556Srgrimes 1521556Srgrimes if ((t = trap[signo]) == NULL) 1531556Srgrimes action = S_DFL; 1541556Srgrimes else if (*t != '\0') 1551556Srgrimes action = S_CATCH; 1561556Srgrimes else 1571556Srgrimes action = S_IGN; 1581556Srgrimes if (rootshell && action == S_DFL) { 1591556Srgrimes switch (signo) { 1601556Srgrimes case SIGINT: 1611556Srgrimes if (iflag) 1621556Srgrimes action = S_CATCH; 1631556Srgrimes break; 1641556Srgrimes case SIGQUIT: 1651556Srgrimes#ifdef DEBUG 1661556Srgrimes { 1671556Srgrimes extern int debug; 1681556Srgrimes 1691556Srgrimes if (debug) 1701556Srgrimes break; 1711556Srgrimes } 1721556Srgrimes#endif 1731556Srgrimes /* FALLTHROUGH */ 1741556Srgrimes case SIGTERM: 1751556Srgrimes if (iflag) 1761556Srgrimes action = S_IGN; 1771556Srgrimes break; 1781556Srgrimes#if JOBS 1791556Srgrimes case SIGTSTP: 1801556Srgrimes case SIGTTOU: 1811556Srgrimes if (mflag) 1821556Srgrimes action = S_IGN; 1831556Srgrimes break; 1841556Srgrimes#endif 1851556Srgrimes } 1861556Srgrimes } 1871556Srgrimes t = &sigmode[signo - 1]; 1881556Srgrimes if (*t == 0) { 1891556Srgrimes /* 1901556Srgrimes * current setting unknown 1911556Srgrimes */ 1921556Srgrimes sigact = getsigaction(signo); 1931556Srgrimes if (sigact == SIG_IGN) { 1941556Srgrimes if (mflag && (signo == SIGTSTP || 1951556Srgrimes signo == SIGTTIN || signo == SIGTTOU)) { 1961556Srgrimes *t = S_IGN; /* don't hard ignore these */ 1971556Srgrimes } else 1981556Srgrimes *t = S_HARD_IGN; 1991556Srgrimes } else { 2001556Srgrimes *t = S_RESET; /* force to be set */ 2011556Srgrimes } 2021556Srgrimes } 2031556Srgrimes if (*t == S_HARD_IGN || *t == action) 2041556Srgrimes return 0; 2051556Srgrimes switch (action) { 2061556Srgrimes case S_DFL: sigact = SIG_DFL; break; 2071556Srgrimes case S_CATCH: sigact = onsig; break; 2081556Srgrimes case S_IGN: sigact = SIG_IGN; break; 2091556Srgrimes } 2101556Srgrimes *t = action; 2111556Srgrimes return (int)signal(signo, sigact); 2121556Srgrimes} 2131556Srgrimes 2141556Srgrimes/* 2151556Srgrimes * Return the current setting for sig w/o changing it. 2161556Srgrimes */ 2171556Srgrimessig_t 2181556Srgrimesgetsigaction(signo) { 2191556Srgrimes struct sigaction sa; 2201556Srgrimes 2211556Srgrimes if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 2221556Srgrimes error("Sigaction system call failed"); 2231556Srgrimes 2241556Srgrimes return sa.sa_handler; 2251556Srgrimes} 2261556Srgrimes 2271556Srgrimes/* 2281556Srgrimes * Ignore a signal. 2291556Srgrimes */ 2301556Srgrimes 2311556Srgrimesvoid 2321556Srgrimesignoresig(signo) { 2331556Srgrimes if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 2341556Srgrimes signal(signo, SIG_IGN); 2351556Srgrimes } 2361556Srgrimes sigmode[signo - 1] = S_HARD_IGN; 2371556Srgrimes} 2381556Srgrimes 2391556Srgrimes 2401556Srgrimes#ifdef mkinit 2411556SrgrimesINCLUDE "signames.h" 2421556SrgrimesINCLUDE "trap.h" 2431556Srgrimes 2441556SrgrimesSHELLPROC { 2451556Srgrimes char *sm; 2461556Srgrimes 2471556Srgrimes clear_traps(); 2481556Srgrimes for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) { 2491556Srgrimes if (*sm == S_IGN) 2501556Srgrimes *sm = S_HARD_IGN; 2511556Srgrimes } 2521556Srgrimes} 2531556Srgrimes#endif 2541556Srgrimes 2551556Srgrimes 2561556Srgrimes 2571556Srgrimes/* 2581556Srgrimes * Signal handler. 2591556Srgrimes */ 2601556Srgrimes 2611556Srgrimesvoid 2621556Srgrimesonsig(signo) { 2631556Srgrimes signal(signo, onsig); 2641556Srgrimes if (signo == SIGINT && trap[SIGINT] == NULL) { 2651556Srgrimes onint(); 2661556Srgrimes return; 2671556Srgrimes } 2681556Srgrimes gotsig[signo - 1] = 1; 2691556Srgrimes pendingsigs++; 2701556Srgrimes} 2711556Srgrimes 2721556Srgrimes 2731556Srgrimes 2741556Srgrimes/* 2751556Srgrimes * Called to execute a trap. Perhaps we should avoid entering new trap 2761556Srgrimes * handlers while we are executing a trap handler. 2771556Srgrimes */ 2781556Srgrimes 2791556Srgrimesvoid 2801556Srgrimesdotrap() { 2811556Srgrimes int i; 2821556Srgrimes int savestatus; 2831556Srgrimes 2841556Srgrimes for (;;) { 2851556Srgrimes for (i = 1 ; ; i++) { 2861556Srgrimes if (gotsig[i - 1]) 2871556Srgrimes break; 2881556Srgrimes if (i >= MAXSIG) 2891556Srgrimes goto done; 2901556Srgrimes } 2911556Srgrimes gotsig[i - 1] = 0; 2921556Srgrimes savestatus=exitstatus; 2931556Srgrimes evalstring(trap[i]); 2941556Srgrimes exitstatus=savestatus; 2951556Srgrimes } 2961556Srgrimesdone: 2971556Srgrimes pendingsigs = 0; 2981556Srgrimes} 2991556Srgrimes 3001556Srgrimes 3011556Srgrimes 3021556Srgrimes/* 3031556Srgrimes * Controls whether the shell is interactive or not. 3041556Srgrimes */ 3051556Srgrimes 3061556Srgrimes 3071556Srgrimesvoid 3081556Srgrimessetinteractive(on) { 3091556Srgrimes static int is_interactive; 3101556Srgrimes 3111556Srgrimes if (on == is_interactive) 3121556Srgrimes return; 3131556Srgrimes setsignal(SIGINT); 3141556Srgrimes setsignal(SIGQUIT); 3151556Srgrimes setsignal(SIGTERM); 3161556Srgrimes is_interactive = on; 3171556Srgrimes} 3181556Srgrimes 3191556Srgrimes 3201556Srgrimes 3211556Srgrimes/* 3221556Srgrimes * Called to exit the shell. 3231556Srgrimes */ 3241556Srgrimes 3251556Srgrimesvoid 3261556Srgrimesexitshell(status) { 3271556Srgrimes struct jmploc loc1, loc2; 3281556Srgrimes char *p; 3291556Srgrimes 3301556Srgrimes TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 3311556Srgrimes if (setjmp(loc1.loc)) { 3321556Srgrimes goto l1; 3331556Srgrimes } 3341556Srgrimes if (setjmp(loc2.loc)) { 3351556Srgrimes goto l2; 3361556Srgrimes } 3371556Srgrimes handler = &loc1; 3381556Srgrimes if ((p = trap[0]) != NULL && *p != '\0') { 3391556Srgrimes trap[0] = NULL; 3401556Srgrimes evalstring(p); 3411556Srgrimes } 3421556Srgrimesl1: handler = &loc2; /* probably unnecessary */ 3431556Srgrimes flushall(); 3441556Srgrimes#if JOBS 3451556Srgrimes setjobctl(0); 3461556Srgrimes#endif 3471556Srgrimesl2: _exit(status); 3481556Srgrimes} 349