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