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