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.2 (Berkeley) 04/12/91"; 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 "signames.h" 23 #include "output.h" 24 #include "memalloc.h" 25 #include "error.h" 26 #include "trap.h" 27 #include "mystring.h" 28 #include <signal.h> 29 30 31 /* 32 * Sigmode records the current value of the signal handlers for the various 33 * modes. A value of zero means that the current handler is not known. 34 * S_HARD_IGN indicates that the signal was ignored on entry to the shell, 35 */ 36 37 #define S_DFL 1 /* default signal handling (SIG_DFL) */ 38 #define S_CATCH 2 /* signal is caught */ 39 #define S_IGN 3 /* signal is ignored (SIG_IGN) */ 40 #define S_HARD_IGN 4 /* signal is ignored permenantly */ 41 42 43 extern char nullstr[1]; /* null string */ 44 45 char *trap[MAXSIG+1]; /* trap handler commands */ 46 MKINIT char sigmode[MAXSIG]; /* current value of signal */ 47 char gotsig[MAXSIG]; /* 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 <= MAXSIG ; 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 > MAXSIG) 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[MAXSIG] ; 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 124 if ((t = trap[signo]) == NULL) 125 action = S_DFL; 126 else if (*t != '\0') 127 action = S_CATCH; 128 else 129 action = S_IGN; 130 if (rootshell && action == S_DFL) { 131 switch (signo) { 132 case SIGINT: 133 if (iflag) 134 action = S_CATCH; 135 break; 136 case SIGQUIT: 137 #ifdef DEBUG 138 { 139 extern int debug; 140 141 if (debug) 142 break; 143 } 144 #endif 145 /* FALLTHROUGH */ 146 case SIGTERM: 147 if (iflag) 148 action = S_IGN; 149 break; 150 #if JOBS 151 case SIGTSTP: 152 case SIGTTOU: 153 if (jflag) 154 action = S_IGN; 155 break; 156 #endif 157 } 158 } 159 t = &sigmode[signo - 1]; 160 if (*t == 0) { /* current setting unknown */ 161 /* 162 * There is a race condition here if action is not S_IGN. 163 * A signal can be ignored that shouldn't be. 164 */ 165 if ((int)(sigact = signal(signo, SIG_IGN)) == -1) 166 error("Signal system call failed"); 167 if (sigact == SIG_IGN) { 168 *t = S_HARD_IGN; 169 } else { 170 *t = S_IGN; 171 } 172 } 173 if (*t == S_HARD_IGN || *t == action) 174 return 0; 175 switch (action) { 176 case S_DFL: sigact = SIG_DFL; break; 177 case S_CATCH: sigact = onsig; break; 178 case S_IGN: sigact = SIG_IGN; break; 179 } 180 *t = action; 181 return (int)signal(signo, sigact); 182 } 183 184 185 /* 186 * Ignore a signal. 187 */ 188 189 void 190 ignoresig(signo) { 191 if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { 192 signal(signo, SIG_IGN); 193 } 194 sigmode[signo - 1] = S_HARD_IGN; 195 } 196 197 198 #ifdef mkinit 199 INCLUDE "signames.h" 200 INCLUDE "trap.h" 201 202 SHELLPROC { 203 char *sm; 204 205 clear_traps(); 206 for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) { 207 if (*sm == S_IGN) 208 *sm = S_HARD_IGN; 209 } 210 } 211 #endif 212 213 214 215 /* 216 * Signal handler. 217 */ 218 219 void 220 onsig(signo) { 221 signal(signo, onsig); 222 if (signo == SIGINT && trap[SIGINT] == NULL) { 223 onint(); 224 return; 225 } 226 gotsig[signo - 1] = 1; 227 pendingsigs++; 228 } 229 230 231 232 /* 233 * Called to execute a trap. Perhaps we should avoid entering new trap 234 * handlers while we are executing a trap handler. 235 */ 236 237 void 238 dotrap() { 239 int i; 240 int savestatus; 241 242 for (;;) { 243 for (i = 1 ; ; i++) { 244 if (gotsig[i - 1]) 245 break; 246 if (i >= MAXSIG) 247 goto done; 248 } 249 gotsig[i - 1] = 0; 250 savestatus=exitstatus; 251 evalstring(trap[i]); 252 exitstatus=savestatus; 253 } 254 done: 255 pendingsigs = 0; 256 } 257 258 259 260 /* 261 * Controls whether the shell is interactive or not. 262 */ 263 264 int is_interactive; 265 266 void 267 setinteractive(on) { 268 if (on == is_interactive) 269 return; 270 setsignal(SIGINT); 271 setsignal(SIGQUIT); 272 setsignal(SIGTERM); 273 is_interactive = on; 274 } 275 276 277 278 /* 279 * Called to exit the shell. 280 */ 281 282 void 283 exitshell(status) { 284 struct jmploc loc1, loc2; 285 char *p; 286 287 TRACE(("exitshell(%d) pid=%d\n", status, getpid())); 288 if (setjmp(loc1.loc)) goto l1; 289 if (setjmp(loc2.loc)) goto l2; 290 handler = &loc1; 291 if ((p = trap[0]) != NULL && *p != '\0') { 292 trap[0] = NULL; 293 evalstring(p); 294 } 295 l1: handler = &loc2; /* probably unnecessary */ 296 flushall(); 297 #if JOBS 298 setjobctl(0); 299 #endif 300 l2: _exit(status); 301 } 302