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