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 37 #ifndef lint 38 /*static char sccsid[] = "from: @(#)trap.c 8.1 (Berkeley) 5/31/93";*/ 39 static char *rcsid = "$Id: trap.c,v 1.10 1994/12/05 19:07:57 cgd Exp $"; 40 #endif /* not lint */ 41 42 #include "shell.h" 43 #include "main.h" 44 #include "nodes.h" /* for other headers */ 45 #include "eval.h" 46 #include "jobs.h" 47 #include "options.h" 48 #include "syntax.h" 49 #include "output.h" 50 #include "memalloc.h" 51 #include "error.h" 52 #include "trap.h" 53 #include "mystring.h" 54 #include <signal.h> 55 #include <unistd.h> 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 permenantly */ 68 #define S_RESET 5 /* temporary - to reset a hard ignored sig */ 69 70 71 extern char nullstr[1]; /* null string */ 72 73 char *trap[NSIG+1]; /* trap handler commands */ 74 MKINIT char sigmode[NSIG]; /* current value of signal */ 75 char gotsig[NSIG]; /* indicates specified signal received */ 76 int pendingsigs; /* indicates some signal received */ 77 78 /* 79 * The trap builtin. 80 */ 81 82 int 83 trapcmd(argc, argv) 84 int argc; 85 char **argv; 86 { 87 char *action; 88 char **ap; 89 int signo; 90 91 if (argc <= 1) { 92 for (signo = 0 ; signo <= NSIG ; signo++) { 93 if (trap[signo] != NULL) 94 out1fmt("%d: %s\n", signo, trap[signo]); 95 } 96 return 0; 97 } 98 ap = argv + 1; 99 if (is_number(*ap)) 100 action = NULL; 101 else 102 action = *ap++; 103 while (*ap) { 104 if ((signo = number(*ap)) < 0 || signo > NSIG) 105 error("%s: bad trap", *ap); 106 INTOFF; 107 if (action) 108 action = savestr(action); 109 if (trap[signo]) 110 ckfree(trap[signo]); 111 trap[signo] = action; 112 if (signo != 0) 113 setsignal(signo); 114 INTON; 115 ap++; 116 } 117 return 0; 118 } 119 120 121 122 /* 123 * Clear traps on a fork. 124 */ 125 126 void 127 clear_traps() { 128 char **tp; 129 130 for (tp = trap ; tp <= &trap[NSIG] ; tp++) { 131 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 132 INTOFF; 133 ckfree(*tp); 134 *tp = NULL; 135 if (tp != &trap[0]) 136 setsignal(tp - trap); 137 INTON; 138 } 139 } 140 } 141 142 143 144 /* 145 * Set the signal handler for the specified signal. The routine figures 146 * out what it should be set to. 147 */ 148 149 int 150 setsignal(signo) 151 int signo; 152 { 153 int action; 154 sig_t sigact; 155 char *t; 156 extern void onsig(); 157 extern sig_t getsigaction(); 158 159 if ((t = trap[signo]) == NULL) 160 action = S_DFL; 161 else if (*t != '\0') 162 action = S_CATCH; 163 else 164 action = S_IGN; 165 if (rootshell && action == S_DFL) { 166 switch (signo) { 167 case SIGINT: 168 if (iflag) 169 action = S_CATCH; 170 break; 171 case SIGQUIT: 172 #ifdef DEBUG 173 { 174 extern int debug; 175 176 if (debug) 177 break; 178 } 179 #endif 180 /* FALLTHROUGH */ 181 case SIGTERM: 182 if (iflag) 183 action = S_IGN; 184 break; 185 #if JOBS 186 case SIGTSTP: 187 case SIGTTOU: 188 if (mflag) 189 action = S_IGN; 190 break; 191 #endif 192 } 193 } 194 t = &sigmode[signo - 1]; 195 if (*t == 0) { 196 /* 197 * current setting unknown 198 */ 199 sigact = getsigaction(signo); 200 if (sigact == SIG_IGN) { 201 if (mflag && (signo == SIGTSTP || 202 signo == SIGTTIN || signo == SIGTTOU)) { 203 *t = S_IGN; /* don't hard ignore these */ 204 } else 205 *t = S_HARD_IGN; 206 } else { 207 *t = S_RESET; /* force to be set */ 208 } 209 } 210 if (*t == S_HARD_IGN || *t == action) 211 return 0; 212 switch (action) { 213 case S_DFL: sigact = SIG_DFL; break; 214 case S_CATCH: sigact = onsig; break; 215 case S_IGN: sigact = SIG_IGN; break; 216 } 217 *t = action; 218 return (int)signal(signo, sigact); 219 } 220 221 /* 222 * Return the current setting for sig w/o changing it. 223 */ 224 sig_t 225 getsigaction(signo) 226 int signo; 227 { 228 struct sigaction sa; 229 230 if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 231 error("Sigaction system call failed"); 232 233 return sa.sa_handler; 234 } 235 236 /* 237 * Ignore a signal. 238 */ 239 240 void 241 ignoresig(signo) 242 int signo; 243 { 244 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 245 signal(signo, SIG_IGN); 246 } 247 sigmode[signo - 1] = S_HARD_IGN; 248 } 249 250 251 #ifdef mkinit 252 INCLUDE <signal.h> 253 INCLUDE "trap.h" 254 255 SHELLPROC { 256 char *sm; 257 258 clear_traps(); 259 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 260 if (*sm == S_IGN) 261 *sm = S_HARD_IGN; 262 } 263 } 264 #endif 265 266 267 268 /* 269 * Signal handler. 270 */ 271 272 void 273 onsig(signo) 274 int signo; 275 { 276 signal(signo, onsig); 277 if (signo == SIGINT && trap[SIGINT] == NULL) { 278 onint(); 279 return; 280 } 281 gotsig[signo - 1] = 1; 282 pendingsigs++; 283 } 284 285 286 287 /* 288 * Called to execute a trap. Perhaps we should avoid entering new trap 289 * handlers while we are executing a trap handler. 290 */ 291 292 void 293 dotrap() { 294 int i; 295 int savestatus; 296 297 for (;;) { 298 for (i = 1 ; ; i++) { 299 if (gotsig[i - 1]) 300 break; 301 if (i >= NSIG) 302 goto done; 303 } 304 gotsig[i - 1] = 0; 305 savestatus=exitstatus; 306 evalstring(trap[i]); 307 exitstatus=savestatus; 308 } 309 done: 310 pendingsigs = 0; 311 } 312 313 314 315 /* 316 * Controls whether the shell is interactive or not. 317 */ 318 319 320 void 321 setinteractive(on) 322 int on; 323 { 324 static int is_interactive; 325 326 if (on == is_interactive) 327 return; 328 setsignal(SIGINT); 329 setsignal(SIGQUIT); 330 setsignal(SIGTERM); 331 is_interactive = on; 332 } 333 334 335 336 /* 337 * Called to exit the shell. 338 */ 339 340 void 341 exitshell(status) 342 int status; 343 { 344 struct jmploc loc1, loc2; 345 char *p; 346 347 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 348 if (setjmp(loc1.loc)) { 349 goto l1; 350 } 351 if (setjmp(loc2.loc)) { 352 goto l2; 353 } 354 handler = &loc1; 355 if ((p = trap[0]) != NULL && *p != '\0') { 356 trap[0] = NULL; 357 evalstring(p); 358 } 359 l1: handler = &loc2; /* probably unnecessary */ 360 flushall(); 361 #if JOBS 362 setjobctl(0); 363 #endif 364 l2: _exit(status); 365 } 366