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