1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * 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 5.2 (Berkeley) 4/12/91";*/ 39 static char rcsid[] = "$Id: trap.c,v 1.5 1993/08/06 21:50:18 mycroft 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 56 57 /* 58 * Sigmode records the current value of the signal handlers for the various 59 * modes. A value of zero means that the current handler is not known. 60 * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 61 */ 62 63 #define S_DFL 1 /* default signal handling (SIG_DFL) */ 64 #define S_CATCH 2 /* signal is caught */ 65 #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 66 #define S_HARD_IGN 4 /* signal is ignored permenantly */ 67 68 69 extern char nullstr[1]; /* null string */ 70 71 char *trap[NSIG]; /* trap handler commands */ 72 MKINIT char sigmode[NSIG]; /* current value of signal */ 73 char gotsig[NSIG]; /* indicates specified signal received */ 74 int pendingsigs; /* indicates some signal received */ 75 76 /* 77 * The trap builtin. 78 */ 79 80 trapcmd(argc, argv) char **argv; { 81 char *action; 82 char **ap; 83 int signo; 84 85 if (argc <= 1) { 86 for (signo = 0 ; signo < NSIG ; signo++) { 87 if (trap[signo] != NULL) 88 out1fmt("%d: %s\n", signo, trap[signo]); 89 } 90 return 0; 91 } 92 ap = argv + 1; 93 if (is_number(*ap)) 94 action = NULL; 95 else 96 action = *ap++; 97 while (*ap) { 98 if ((signo = number(*ap)) < 0 || signo >= NSIG) 99 error("%s: bad trap", *ap); 100 INTOFF; 101 if (action) 102 action = savestr(action); 103 if (trap[signo]) 104 ckfree(trap[signo]); 105 trap[signo] = action; 106 if (signo != 0) 107 setsignal(signo); 108 INTON; 109 ap++; 110 } 111 return 0; 112 } 113 114 115 116 /* 117 * Clear traps on a fork. 118 */ 119 120 void 121 clear_traps() { 122 char **tp; 123 124 for (tp = trap ; tp < &trap[NSIG] ; tp++) { 125 if (*tp && **tp) { /* trap not NULL or SIG_IGN */ 126 INTOFF; 127 ckfree(*tp); 128 *tp = NULL; 129 if (tp != &trap[0]) 130 setsignal(tp - trap); 131 INTON; 132 } 133 } 134 } 135 136 137 138 /* 139 * Set the signal handler for the specified signal. The routine figures 140 * out what it should be set to. 141 */ 142 143 int 144 setsignal(signo) { 145 int action; 146 sig_t sigact; 147 char *t; 148 extern void onsig(); 149 150 if ((t = trap[signo]) == NULL) 151 action = S_DFL; 152 else if (*t != '\0') 153 action = S_CATCH; 154 else 155 action = S_IGN; 156 if (rootshell && action == S_DFL) { 157 switch (signo) { 158 case SIGINT: 159 if (iflag) 160 action = S_CATCH; 161 break; 162 case SIGQUIT: 163 #ifdef DEBUG 164 { 165 extern int debug; 166 167 if (debug) 168 break; 169 } 170 #endif 171 /* FALLTHROUGH */ 172 case SIGTERM: 173 if (iflag) 174 action = S_IGN; 175 break; 176 #if JOBS 177 case SIGTSTP: 178 case SIGTTOU: 179 if (jflag) 180 action = S_IGN; 181 break; 182 #endif 183 } 184 } 185 t = &sigmode[signo]; 186 if (*t == 0) { /* current setting unknown */ 187 /* 188 * There is a race condition here if action is not S_IGN. 189 * A signal can be ignored that shouldn't be. 190 */ 191 if ((int)(sigact = signal(signo, SIG_IGN)) == -1) 192 error("Signal system call failed"); 193 if (sigact == SIG_IGN) { 194 *t = S_HARD_IGN; 195 } else { 196 *t = S_IGN; 197 } 198 } 199 if (*t == S_HARD_IGN || *t == action) 200 return 0; 201 switch (action) { 202 case S_DFL: sigact = SIG_DFL; break; 203 case S_CATCH: sigact = onsig; break; 204 case S_IGN: sigact = SIG_IGN; break; 205 } 206 *t = action; 207 return (int)signal(signo, sigact); 208 } 209 210 211 /* 212 * Ignore a signal. 213 */ 214 215 void 216 ignoresig(signo) { 217 if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { 218 signal(signo, SIG_IGN); 219 } 220 sigmode[signo] = S_HARD_IGN; 221 } 222 223 224 #ifdef mkinit 225 INCLUDE <sys/signal.h> 226 INCLUDE "trap.h" 227 228 SHELLPROC { 229 char *sm; 230 231 clear_traps(); 232 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 233 if (*sm == S_IGN) 234 *sm = S_HARD_IGN; 235 } 236 } 237 #endif 238 239 240 241 /* 242 * Signal handler. 243 */ 244 245 void 246 onsig(signo) { 247 signal(signo, onsig); 248 if (signo == SIGINT && trap[SIGINT] == NULL) { 249 onint(); 250 return; 251 } 252 gotsig[signo] = 1; 253 pendingsigs++; 254 } 255 256 257 258 /* 259 * Called to execute a trap. Perhaps we should avoid entering new trap 260 * handlers while we are executing a trap handler. 261 */ 262 263 void 264 dotrap() { 265 int i; 266 int savestatus; 267 268 for (;;) { 269 for (i = 1 ; ; i++) { 270 if (i >= NSIG) 271 goto done; 272 if (gotsig[i]) 273 break; 274 } 275 gotsig[i] = 0; 276 savestatus=exitstatus; 277 evalstring(trap[i]); 278 exitstatus=savestatus; 279 } 280 done: 281 pendingsigs = 0; 282 } 283 284 285 286 /* 287 * Controls whether the shell is interactive or not. 288 */ 289 290 int is_interactive; 291 292 void 293 setinteractive(on) { 294 if (on == is_interactive) 295 return; 296 setsignal(SIGINT); 297 setsignal(SIGQUIT); 298 setsignal(SIGTERM); 299 is_interactive = on; 300 } 301 302 303 304 /* 305 * Called to exit the shell. 306 */ 307 308 void 309 exitshell(status) { 310 struct jmploc loc1, loc2; 311 char *p; 312 313 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 314 if (setjmp(loc1.loc)) goto l1; 315 if (setjmp(loc2.loc)) goto l2; 316 handler = &loc1; 317 if ((p = trap[0]) != NULL && *p != '\0') { 318 trap[0] = NULL; 319 evalstring(p); 320 } 321 l1: handler = &loc2; /* probably unnecessary */ 322 flushall(); 323 #if JOBS 324 setjobctl(0); 325 #endif 326 l2: _exit(status); 327 } 328