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