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.4 (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 /* 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 171 if (signo == SIGKILL) 172 /* Pretend it worked */ 173 return 0; 174 175 t = &sigmode[signo - 1]; 176 if (*t == 0) { 177 /* 178 * current setting unknown 179 */ 180 sigact = getsigaction(signo); 181 if (sigact == SIG_IGN) { 182 if (mflag && (signo == SIGTSTP || 183 signo == SIGTTIN || signo == SIGTTOU)) { 184 *t = S_IGN; /* don't hard ignore these */ 185 } else 186 *t = S_HARD_IGN; 187 } else { 188 *t = S_RESET; /* force to be set */ 189 } 190 } 191 if (*t == S_HARD_IGN || *t == action) 192 return 0; 193 switch (action) { 194 case S_DFL: sigact = SIG_DFL; break; 195 case S_CATCH: sigact = onsig; break; 196 case S_IGN: sigact = SIG_IGN; break; 197 } 198 *t = action; 199 return (long)signal(signo, sigact); 200 } 201 202 /* 203 * Return the current setting for sig w/o changing it. 204 */ 205 sig_t 206 getsigaction(signo) 207 int signo; 208 { 209 struct sigaction sa; 210 211 if (sigaction(signo, (struct sigaction *)0, &sa) == -1) 212 error("Sigaction system call failed"); 213 214 return (sig_t) sa.sa_handler; 215 } 216 217 /* 218 * Ignore a signal. 219 */ 220 221 void 222 ignoresig(signo) 223 int signo; 224 { 225 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 226 signal(signo, SIG_IGN); 227 } 228 sigmode[signo - 1] = S_HARD_IGN; 229 } 230 231 232 #ifdef mkinit 233 INCLUDE <signal.h> 234 INCLUDE "trap.h" 235 236 SHELLPROC { 237 char *sm; 238 239 clear_traps(); 240 for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { 241 if (*sm == S_IGN) 242 *sm = S_HARD_IGN; 243 } 244 } 245 #endif 246 247 248 249 /* 250 * Signal handler. 251 */ 252 253 void 254 onsig(signo) 255 int signo; 256 { 257 signal(signo, onsig); 258 if (signo == SIGINT && trap[SIGINT] == NULL) { 259 onint(); 260 return; 261 } 262 gotsig[signo - 1] = 1; 263 pendingsigs++; 264 } 265 266 267 268 /* 269 * Called to execute a trap. Perhaps we should avoid entering new trap 270 * handlers while we are executing a trap handler. 271 */ 272 273 void 274 dotrap() { 275 int i; 276 int savestatus; 277 278 for (;;) { 279 for (i = 1 ; ; i++) { 280 if (gotsig[i - 1]) 281 break; 282 if (i >= NSIG) 283 goto done; 284 } 285 gotsig[i - 1] = 0; 286 savestatus=exitstatus; 287 evalstring(trap[i]); 288 exitstatus=savestatus; 289 } 290 done: 291 pendingsigs = 0; 292 } 293 294 295 296 /* 297 * Controls whether the shell is interactive or not. 298 */ 299 300 301 void 302 setinteractive(on) 303 int on; 304 { 305 static int is_interactive; 306 307 if (on == is_interactive) 308 return; 309 setsignal(SIGINT); 310 setsignal(SIGQUIT); 311 setsignal(SIGTERM); 312 is_interactive = on; 313 } 314 315 316 317 /* 318 * Called to exit the shell. 319 */ 320 321 void 322 exitshell(status) 323 int status; 324 { 325 struct jmploc loc1, loc2; 326 char *p; 327 328 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 329 if (setjmp(loc1.loc)) { 330 goto l1; 331 } 332 if (setjmp(loc2.loc)) { 333 goto l2; 334 } 335 handler = &loc1; 336 if ((p = trap[0]) != NULL && *p != '\0') { 337 trap[0] = NULL; 338 evalstring(p); 339 } 340 l1: handler = &loc2; /* probably unnecessary */ 341 flushall(); 342 #if JOBS 343 setjobctl(0); 344 #endif 345 l2: _exit(status); 346 } 347