1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $Id: trap.c,v 1.2 1994/09/24 02:58:18 davidg Exp $ 37 */ 38 39 #ifndef lint 40 static char sccsid[] = "@(#)trap.c 8.1 (Berkeley) 5/31/93"; 41 #endif /* not lint */ 42 43 #include "shell.h" 44 #include "main.h" 45 #include "nodes.h" /* for other headers */ 46 #include "eval.h" 47 #include "jobs.h" 48 #include "options.h" 49 #include "syntax.h" 50 #include "signames.h" 51 #include "output.h" 52 #include "memalloc.h" 53 #include "error.h" 54 #include "trap.h" 55 #include "mystring.h" 56 #include <signal.h> 57 58 59 /* 60 * Sigmode records the current value of the signal handlers for the various 61 * modes. A value of zero means that the current handler is not known. 62 * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 63 */ 64 65 #define S_DFL 1 /* default signal handling (SIG_DFL) */ 66 #define S_CATCH 2 /* signal is caught */ 67 #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 68 #define S_HARD_IGN 4 /* signal is ignored permenantly */ 69 #define S_RESET 5 /* temporary - to reset a hard ignored sig */ 70 71 72 extern char nullstr[1]; /* null string */ 73 74 char *trap[MAXSIG+1]; /* trap handler commands */ 75 MKINIT char sigmode[MAXSIG]; /* current value of signal */ 76 char gotsig[MAXSIG]; /* indicates specified signal received */ 77 int pendingsigs; /* indicates some signal received */ 78 79 /* 80 * The trap builtin. 81 */ 82 83 trapcmd(argc, argv) char **argv; { 84 char *action; 85 char **ap; 86 int signo; 87 88 if (argc <= 1) { 89 for (signo = 0 ; signo <= MAXSIG ; signo++) { 90 if (trap[signo] != NULL) 91 out1fmt("%d: %s\n", signo, trap[signo]); 92 } 93 return 0; 94 } 95 ap = argv + 1; 96 if (is_number(*ap)) 97 action = NULL; 98 else 99 action = *ap++; 100 while (*ap) { 101 if ((signo = number(*ap)) < 0 || signo > MAXSIG) 102 error("%s: bad trap", *ap); 103 INTOFF; 104 if (action) 105 action = savestr(action); 106 if (trap[signo]) 107 ckfree(trap[signo]); 108 trap[signo] = action; 109 if (signo != 0) 110 setsignal(signo); 111 INTON; 112 ap++; 113 } 114 return 0; 115 } 116 117 118 119 /* 120 * Clear traps on a fork. 121 */ 122 123 void 124 clear_traps() { 125 char **tp; 126 127 for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) { 128 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 129 INTOFF; 130 ckfree(*tp); 131 *tp = NULL; 132 if (tp != &trap[0]) 133 setsignal(tp - trap); 134 INTON; 135 } 136 } 137 } 138 139 140 141 /* 142 * Set the signal handler for the specified signal. The routine figures 143 * out what it should be set to. 144 */ 145 146 int 147 setsignal(signo) { 148 int action; 149 sig_t sigact; 150 char *t; 151 extern void onsig(); 152 extern sig_t getsigaction(); 153 154 if ((t = trap[signo]) == NULL) 155 action = S_DFL; 156 else if (*t != '\0') 157 action = S_CATCH; 158 else 159 action = S_IGN; 160 if (rootshell && action == S_DFL) { 161 switch (signo) { 162 case SIGINT: 163 if (iflag) 164 action = S_CATCH; 165 break; 166 case SIGQUIT: 167 #ifdef DEBUG 168 { 169 extern int debug; 170 171 if (debug) 172 break; 173 } 174 #endif 175 /* FALLTHROUGH */ 176 case SIGTERM: 177 if (iflag) 178 action = S_IGN; 179 break; 180 #if JOBS 181 case SIGTSTP: 182 case SIGTTOU: 183 if (mflag) 184 action = S_IGN; 185 break; 186 #endif 187 } 188 } 189 t = &sigmode[signo - 1]; 190 if (*t == 0) { 191 /* 192 * current setting unknown 193 */ 194 sigact = getsigaction(signo); 195 if (sigact == SIG_IGN) { 196 if (mflag && (signo == SIGTSTP || 197 signo == SIGTTIN || signo == SIGTTOU)) { 198 *t = S_IGN; /* don't hard ignore these */ 199 } else 200 *t = S_HARD_IGN; 201 } else { 202 *t = S_RESET; /* force to be set */ 203 } 204 } 205 if (*t == S_HARD_IGN || *t == action) 206 return 0; 207 switch (action) { 208 case S_DFL: sigact = SIG_DFL; break; 209 case S_CATCH: sigact = onsig; break; 210 case S_IGN: sigact = SIG_IGN; break; 211 } 212 *t = action; 213 return (int)signal(signo, sigact); 214 } 215 216 /* 217 * Return the current setting for sig w/o changing it. 218 */ 219 sig_t 220 getsigaction(signo) { 221 struct sigaction sa; 222 223 if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 224 error("Sigaction system call failed"); 225 226 return sa.sa_handler; 227 } 228 229 /* 230 * Ignore a signal. 231 */ 232 233 void 234 ignoresig(signo) { 235 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 236 signal(signo, SIG_IGN); 237 } 238 sigmode[signo - 1] = S_HARD_IGN; 239 } 240 241 242 #ifdef mkinit 243 INCLUDE "signames.h" 244 INCLUDE "trap.h" 245 246 SHELLPROC { 247 char *sm; 248 249 clear_traps(); 250 for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) { 251 if (*sm == S_IGN) 252 *sm = S_HARD_IGN; 253 } 254 } 255 #endif 256 257 258 259 /* 260 * Signal handler. 261 */ 262 263 void 264 onsig(signo) { 265 signal(signo, onsig); 266 if (signo == SIGINT && trap[SIGINT] == NULL) { 267 onint(); 268 return; 269 } 270 gotsig[signo - 1] = 1; 271 pendingsigs++; 272 } 273 274 275 276 /* 277 * Called to execute a trap. Perhaps we should avoid entering new trap 278 * handlers while we are executing a trap handler. 279 */ 280 281 void 282 dotrap() { 283 int i; 284 int savestatus; 285 286 for (;;) { 287 for (i = 1 ; ; i++) { 288 if (gotsig[i - 1]) 289 break; 290 if (i >= MAXSIG) 291 goto done; 292 } 293 gotsig[i - 1] = 0; 294 savestatus=exitstatus; 295 evalstring(trap[i]); 296 exitstatus=savestatus; 297 } 298 done: 299 pendingsigs = 0; 300 } 301 302 303 304 /* 305 * Controls whether the shell is interactive or not. 306 */ 307 308 309 void 310 setinteractive(on) { 311 static int is_interactive; 312 313 if (on == is_interactive) 314 return; 315 setsignal(SIGINT); 316 setsignal(SIGQUIT); 317 setsignal(SIGTERM); 318 is_interactive = on; 319 } 320 321 322 323 /* 324 * Called to exit the shell. 325 */ 326 327 void 328 exitshell(status) { 329 struct jmploc loc1, loc2; 330 char *p; 331 332 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 333 if (setjmp(loc1.loc)) { 334 goto l1; 335 } 336 if (setjmp(loc2.loc)) { 337 goto l2; 338 } 339 handler = &loc1; 340 if ((p = trap[0]) != NULL && *p != '\0') { 341 trap[0] = NULL; 342 evalstring(p); 343 } 344 l1: handler = &loc2; /* probably unnecessary */ 345 flushall(); 346 #if JOBS 347 setjobctl(0); 348 #endif 349 l2: _exit(status); 350 } 351