1 /* 2 * signal handling 3 */ 4 5 /* Kludge to avoid bogus re-declaration of sigtraps[] error on AIX 3.2.5 */ 6 #define FROM_TRAP_C 7 #include "sh.h" 8 9 /* Table is indexed by signal number 10 * 11 * The script siglist.sh generates siglist.out, which is a sorted, complete 12 * list of signals 13 */ 14 Trap sigtraps[SIGNALS+1] = { 15 { SIGEXIT_, "EXIT", "Signal 0" }, 16 { 1 , "HUP", "Hangup" }, 17 { 2 , "INT", "Interrupt" }, 18 { 3 , "QUIT", "Quit" }, 19 { 4 , "ILL", "Illegal instruction" }, 20 { 5 , "ABRT", "Abort" }, 21 { 6 , "FPE", "Floating point exception" }, 22 { 7 , "KILL", "Killed" }, 23 { 8 , "SEGV", "Memory fault" }, 24 { 9 , "PIPE", "Broken pipe" }, 25 { 10 , "ALRM", "Alarm clock" }, 26 { 11 , "TERM", "Terminated" }, 27 { 12 , "USR1", "User defined signal 1" }, 28 { 13 , "USR2", "User defined signal 2" }, 29 { 14 , "BUS", "Bus error" }, 30 { 15 , "CHLD", "Child exited" }, 31 { 16 , "CONT", "Continued" }, 32 { 17 , "STOP", "Stopped (signal)" }, 33 { 18 , "TSTP", "Stopped" }, 34 { 19 , "TTIN", "Stopped (tty input)" }, 35 { 20 , "TTOU", "Stopped (tty output)" }, 36 { SIGERR_, "ERR", "Error handler" }, 37 }; 38 39 static struct sigaction Sigact_ign, Sigact_trap; 40 41 void 42 inittraps() 43 { 44 #ifdef HAVE_SYS_SIGLIST 45 # ifndef SYS_SIGLIST_DECLARED 46 extern char *sys_siglist[]; 47 # endif 48 int i; 49 50 /* Use system description, if available, for unknown signals... */ 51 for (i = 0; i < NSIG; i++) 52 if (!sigtraps[i].name && sys_siglist[i] && sys_siglist[i][0]) 53 sigtraps[i].mess = sys_siglist[i]; 54 #endif /* HAVE_SYS_SIGLIST */ 55 56 sigemptyset(&Sigact_ign.sa_mask); 57 Sigact_ign.sa_flags = KSH_SA_FLAGS; 58 Sigact_ign.sa_handler = SIG_IGN; 59 Sigact_trap = Sigact_ign; 60 Sigact_trap.sa_handler = trapsig; 61 62 sigtraps[SIGINT].flags |= TF_DFL_INTR | TF_TTY_INTR; 63 sigtraps[SIGQUIT].flags |= TF_DFL_INTR | TF_TTY_INTR; 64 sigtraps[SIGTERM].flags |= TF_DFL_INTR;/* not fatal for interactive */ 65 sigtraps[SIGHUP].flags |= TF_FATAL; 66 sigtraps[SIGCHLD].flags |= TF_SHELL_USES; 67 68 /* these are always caught so we can clean up any temproary files. */ 69 setsig(&sigtraps[SIGINT], trapsig, SS_RESTORE_ORIG); 70 setsig(&sigtraps[SIGQUIT], trapsig, SS_RESTORE_ORIG); 71 setsig(&sigtraps[SIGTERM], trapsig, SS_RESTORE_ORIG); 72 setsig(&sigtraps[SIGHUP], trapsig, SS_RESTORE_ORIG); 73 } 74 75 #ifdef KSH 76 static RETSIGTYPE alarm_catcher ARGS((int sig)); 77 78 void 79 alarm_init() 80 { 81 sigtraps[SIGALRM].flags |= TF_SHELL_USES; 82 setsig(&sigtraps[SIGALRM], alarm_catcher, 83 SS_RESTORE_ORIG|SS_FORCE|SS_SHTRAP); 84 } 85 86 static RETSIGTYPE 87 alarm_catcher(sig) 88 int sig; 89 { 90 if (ksh_tmout_state == TMOUT_READING) { 91 int left = alarm(0); 92 93 if (left == 0) { 94 ksh_tmout_state = TMOUT_LEAVING; 95 intrsig = 1; 96 } else 97 alarm(left); 98 } 99 return RETSIGVAL; 100 } 101 #endif /* KSH */ 102 103 Trap * 104 gettrap(name, igncase) 105 const char *name; 106 int igncase; 107 { 108 int i; 109 register Trap *p; 110 111 if (digit(*name)) { 112 int n; 113 114 if (getn(name, &n) && 0 <= n && n < SIGNALS) 115 return &sigtraps[n]; 116 return NULL; 117 } 118 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) 119 if (p->name && (igncase ? strcasecmp(p->name, name) == 0 120 : strcmp(p->name, name) == 0)) 121 return p; 122 return NULL; 123 } 124 125 /* 126 * trap signal handler 127 */ 128 RETSIGTYPE 129 trapsig(i) 130 int i; 131 { 132 Trap *p = &sigtraps[i]; 133 134 trap = p->set = 1; 135 if (p->flags & TF_DFL_INTR) 136 intrsig = 1; 137 if ((p->flags & TF_FATAL) && !p->trap) { 138 fatal_trap = 1; 139 intrsig = 1; 140 } 141 if (p->shtrap) 142 (*p->shtrap)(i); 143 #ifdef V7_SIGNALS 144 if (sigtraps[i].cursig == trapsig) /* this for SIGCHLD,SIGALRM */ 145 sigaction(i, &Sigact_trap, (struct sigaction *) 0); 146 #endif /* V7_SIGNALS */ 147 return RETSIGVAL; 148 } 149 150 /* called when we want to allow the user to ^C out of something - won't 151 * work if user has trapped SIGINT. 152 */ 153 void 154 intrcheck() 155 { 156 if (intrsig) 157 runtraps(TF_DFL_INTR|TF_FATAL); 158 } 159 160 /* called after EINTR to check if a signal with normally causes process 161 * termination has been received. 162 */ 163 int 164 fatal_trap_check() 165 { 166 int i; 167 Trap *p; 168 169 /* todo: should check if signal is fatal, not the TF_DFL_INTR flag */ 170 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) 171 if (p->set && (p->flags & (TF_DFL_INTR|TF_FATAL))) 172 /* return value is used as an exit code */ 173 return 128 + p->signal; 174 return 0; 175 } 176 177 /* Returns the signal number of any pending traps: ie, a signal which has 178 * occured for which a trap has been set or for which the TF_DFL_INTR flag 179 * is set. 180 */ 181 int 182 trap_pending() 183 { 184 int i; 185 Trap *p; 186 187 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) 188 if (p->set && ((p->trap && p->trap[0]) 189 || ((p->flags & (TF_DFL_INTR|TF_FATAL)) 190 && !p->trap))) 191 return p->signal; 192 return 0; 193 } 194 195 /* 196 * run any pending traps. If intr is set, only run traps that 197 * can interrupt commands. 198 */ 199 void 200 runtraps(flag) 201 int flag; 202 { 203 int i; 204 register Trap *p; 205 206 #ifdef KSH 207 if (ksh_tmout_state == TMOUT_LEAVING) { 208 ksh_tmout_state = TMOUT_EXECUTING; 209 warningf(FALSE, "timed out waiting for input"); 210 unwind(LEXIT); 211 } else 212 /* XXX: this means the alarm will have no effect if a trap 213 * is caught after the alarm() was started...not good. 214 */ 215 ksh_tmout_state = TMOUT_EXECUTING; 216 #endif /* KSH */ 217 if (!flag) 218 trap = 0; 219 if (flag & TF_DFL_INTR) 220 intrsig = 0; 221 if (flag & TF_FATAL) 222 fatal_trap = 0; 223 for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) 224 if (p->set && (!flag 225 || ((p->flags & flag) && p->trap == (char *) 0))) 226 runtrap(p); 227 } 228 229 void 230 runtrap(p) 231 Trap *p; 232 { 233 int i = p->signal; 234 char *trapstr = p->trap; 235 int oexstat; 236 int UNINITIALIZED(old_changed); 237 238 p->set = 0; 239 if (trapstr == (char *) 0) { /* SIG_DFL */ 240 if (p->flags & TF_FATAL) { 241 /* eg, SIGHUP */ 242 exstat = 128 + i; 243 unwind(LLEAVE); 244 } 245 if (p->flags & TF_DFL_INTR) { 246 /* eg, SIGINT, SIGQUIT, SIGTERM, etc. */ 247 exstat = 128 + i; 248 unwind(LINTR); 249 } 250 return; 251 } 252 if (trapstr[0] == '\0') /* SIG_IGN */ 253 return; 254 if (i == SIGEXIT_ || i == SIGERR_) { /* avoid recursion on these */ 255 old_changed = p->flags & TF_CHANGED; 256 p->flags &= ~TF_CHANGED; 257 p->trap = (char *) 0; 258 } 259 oexstat = exstat; 260 /* Note: trapstr is fully parsed before anything is executed, thus 261 * no problem with afree(p->trap) in settrap() while still in use. 262 */ 263 command(trapstr); 264 exstat = oexstat; 265 if (i == SIGEXIT_ || i == SIGERR_) { 266 if (p->flags & TF_CHANGED) 267 /* don't clear TF_CHANGED */ 268 afree(trapstr, APERM); 269 else 270 p->trap = trapstr; 271 p->flags |= old_changed; 272 } 273 } 274 275 /* clear pending traps and reset user's trap handlers; used after fork(2) */ 276 void 277 cleartraps() 278 { 279 int i; 280 Trap *p; 281 282 trap = 0; 283 intrsig = 0; 284 fatal_trap = 0; 285 for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) { 286 p->set = 0; 287 if ((p->flags & TF_USER_SET) && (p->trap && p->trap[0])) 288 settrap(p, (char *) 0); 289 } 290 } 291 292 /* restore signals just before an exec(2) */ 293 void 294 restoresigs() 295 { 296 int i; 297 Trap *p; 298 299 for (i = SIGNALS+1, p = sigtraps; --i >= 0; p++) 300 if (p->flags & (TF_EXEC_IGN|TF_EXEC_DFL)) 301 setsig(p, (p->flags & TF_EXEC_IGN) ? SIG_IGN : SIG_DFL, 302 SS_RESTORE_CURR|SS_FORCE); 303 } 304 305 void 306 settrap(p, s) 307 Trap *p; 308 char *s; 309 { 310 handler_t f; 311 312 if (p->trap) 313 afree(p->trap, APERM); 314 p->trap = str_save(s, APERM); /* handles s == 0 */ 315 p->flags |= TF_CHANGED; 316 f = !s ? SIG_DFL : s[0] ? trapsig : SIG_IGN; 317 318 p->flags |= TF_USER_SET; 319 if ((p->flags & (TF_DFL_INTR|TF_FATAL)) && f == SIG_DFL) 320 f = trapsig; 321 else if (p->flags & TF_SHELL_USES) { 322 if (!(p->flags & TF_ORIG_IGN) || Flag(FTALKING)) { 323 /* do what user wants at exec time */ 324 p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); 325 if (f == SIG_IGN) 326 p->flags |= TF_EXEC_IGN; 327 else 328 p->flags |= TF_EXEC_DFL; 329 } 330 /* assumes handler already set to what shell wants it 331 * (normally trapsig, but could be j_sigchld() or SIG_IGN) 332 */ 333 return; 334 } 335 336 /* todo: should we let user know signal is ignored? how? */ 337 setsig(p, f, SS_RESTORE_CURR|SS_USER); 338 } 339 340 /* Called by c_print() when writing to a co-process to ensure SIGPIPE won't 341 * kill shell (unless user catches it and exits) 342 */ 343 int 344 block_pipe() 345 { 346 int restore_dfl = 0; 347 Trap *p = &sigtraps[SIGPIPE]; 348 349 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) { 350 setsig(p, SIG_IGN, SS_RESTORE_CURR); 351 if (p->flags & TF_ORIG_DFL) 352 restore_dfl = 1; 353 } else if (p->cursig == SIG_DFL) { 354 setsig(p, SIG_IGN, SS_RESTORE_CURR); 355 restore_dfl = 1; /* restore to SIG_DFL */ 356 } 357 return restore_dfl; 358 } 359 360 /* Called by c_print() to undo whatever block_pipe() did */ 361 void 362 restore_pipe(restore_dfl) 363 int restore_dfl; 364 { 365 if (restore_dfl) 366 setsig(&sigtraps[SIGPIPE], SIG_DFL, SS_RESTORE_CURR); 367 } 368 369 /* Set action for a signal. Action may not be set if original 370 * action was SIG_IGN, depending on the value of flags and 371 * FTALKING. 372 */ 373 int 374 setsig(p, f, flags) 375 Trap *p; 376 handler_t f; 377 int flags; 378 { 379 struct sigaction sigact; 380 381 if (p->signal == SIGEXIT_ || p->signal == SIGERR_) 382 return 1; 383 384 /* First time setting this signal? If so, get and note the current 385 * setting. 386 */ 387 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) { 388 sigaction(p->signal, &Sigact_ign, &sigact); 389 p->flags |= sigact.sa_handler == SIG_IGN ? 390 TF_ORIG_IGN : TF_ORIG_DFL; 391 p->cursig = SIG_IGN; 392 } 393 394 /* Generally, an ignored signal stays ignored, except if 395 * - the user of an interactive shell wants to change it 396 * - the shell wants for force a change 397 */ 398 if ((p->flags & TF_ORIG_IGN) && !(flags & SS_FORCE) 399 && (!(flags & SS_USER) || !Flag(FTALKING))) 400 return 0; 401 402 setexecsig(p, flags & SS_RESTORE_MASK); 403 404 /* This is here 'cause there should be a way of clearing shtraps, but 405 * don't know if this is a sane way of doing it. At the moment, 406 * all users of shtrap are lifetime users (SIGCHLD, SIGALRM, SIGWINCH). 407 */ 408 if (!(flags & SS_USER)) 409 p->shtrap = (handler_t) 0; 410 if (flags & SS_SHTRAP) { 411 p->shtrap = f; 412 f = trapsig; 413 } 414 415 if (p->cursig != f) { 416 p->cursig = f; 417 sigemptyset(&sigact.sa_mask); 418 sigact.sa_flags = KSH_SA_FLAGS; 419 sigact.sa_handler = f; 420 sigaction(p->signal, &sigact, (struct sigaction *) 0); 421 } 422 423 return 1; 424 } 425 426 /* control what signal is set to before an exec() */ 427 void 428 setexecsig(p, restore) 429 Trap *p; 430 int restore; 431 { 432 /* XXX debugging */ 433 if (!(p->flags & (TF_ORIG_IGN|TF_ORIG_DFL))) 434 internal_errorf(1, "setexecsig: unset signal %d(%s)", 435 p->signal, p->name); 436 437 /* restore original value for exec'd kids */ 438 p->flags &= ~(TF_EXEC_IGN|TF_EXEC_DFL); 439 switch (restore & SS_RESTORE_MASK) { 440 case SS_RESTORE_CURR: /* leave things as they currently are */ 441 break; 442 case SS_RESTORE_ORIG: 443 p->flags |= p->flags & TF_ORIG_IGN ? TF_EXEC_IGN : TF_EXEC_DFL; 444 break; 445 case SS_RESTORE_DFL: 446 p->flags |= TF_EXEC_DFL; 447 break; 448 case SS_RESTORE_IGN: 449 p->flags |= TF_EXEC_IGN; 450 break; 451 } 452 } 453