1/* 2 * signals.c - signals handling code 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1992-1997 Paul Falstad 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Paul Falstad or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Paul Falstad and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Paul Falstad and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Paul Falstad and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zsh.mdh" 31#include "signals.pro" 32 33/* Array describing the state of each signal: an element contains * 34 * 0 for the default action or some ZSIG_* flags ored together. */ 35 36/**/ 37mod_export int sigtrapped[VSIGCOUNT]; 38 39/* 40 * Trap programme lists for each signal. 41 * 42 * If (sigtrapped[sig] & ZSIG_FUNC) is set, this isn't used. 43 * The corresponding shell function is used instead. 44 * 45 * Otherwise, if sigtrapped[sig] is not zero, this is NULL when a signal 46 * is to be ignored, and if not NULL contains the programme list to be 47 * eval'd. 48 */ 49 50/**/ 51mod_export Eprog siglists[VSIGCOUNT]; 52 53/* Total count of trapped signals */ 54 55/**/ 56mod_export int nsigtrapped; 57 58/* Variables used by signal queueing */ 59 60/**/ 61mod_export int queueing_enabled, queue_front, queue_rear; 62/**/ 63mod_export int signal_queue[MAX_QUEUE_SIZE]; 64/**/ 65mod_export sigset_t signal_mask_queue[MAX_QUEUE_SIZE]; 66 67/* Variables used by trap queueing */ 68 69/**/ 70mod_export int trap_queueing_enabled, trap_queue_front, trap_queue_rear; 71/**/ 72mod_export int trap_queue[MAX_QUEUE_SIZE]; 73 74/* This is only used on machines that don't understand signal sets. * 75 * On SYSV machines this will represent the signals that are blocked * 76 * (held) using sighold. On machines which can't block signals at * 77 * all, we will simulate this by ignoring them and remembering them * 78 * in this variable. */ 79#if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS) 80static sigset_t blocked_set; 81#endif 82 83#ifdef POSIX_SIGNALS 84# define signal_jmp_buf sigjmp_buf 85# define signal_setjmp(b) sigsetjmp((b),1) 86# define signal_longjmp(b,n) siglongjmp((b),(n)) 87#else 88# define signal_jmp_buf jmp_buf 89# define signal_setjmp(b) setjmp(b) 90# define signal_longjmp(b,n) longjmp((b),(n)) 91#endif 92 93#ifdef NO_SIGNAL_BLOCKING 94# define signal_process(sig) signal_ignore(sig) 95# define signal_reset(sig) install_handler(sig) 96#else 97# define signal_process(sig) ; 98# define signal_reset(sig) ; 99#endif 100 101/* Install signal handler for given signal. * 102 * If possible, we want to make sure that interrupted * 103 * system calls are not restarted. */ 104 105/**/ 106mod_export void 107install_handler(int sig) 108{ 109#ifdef POSIX_SIGNALS 110 struct sigaction act; 111 112 act.sa_handler = (SIGNAL_HANDTYPE) zhandler; 113 sigemptyset(&act.sa_mask); /* only block sig while in handler */ 114 act.sa_flags = 0; 115# ifdef SA_INTERRUPT /* SunOS 4.x */ 116 if (interact) 117 act.sa_flags |= SA_INTERRUPT; /* make sure system calls are not restarted */ 118# endif 119 sigaction(sig, &act, (struct sigaction *)NULL); 120#else 121# ifdef BSD_SIGNALS 122 struct sigvec vec; 123 124 vec.sv_handler = (SIGNAL_HANDTYPE) zhandler; 125 vec.sv_mask = sigmask(sig); /* mask out this signal while in handler */ 126# ifdef SV_INTERRUPT 127 vec.sv_flags = SV_INTERRUPT; /* make sure system calls are not restarted */ 128# endif 129 sigvec(sig, &vec, (struct sigvec *)NULL); 130# else 131# ifdef SYSV_SIGNALS 132 /* we want sigset rather than signal because it will * 133 * block sig while in handler. signal usually doesn't */ 134 sigset(sig, zhandler); 135# else /* NO_SIGNAL_BLOCKING (bummer) */ 136 signal(sig, zhandler); 137 138# endif /* SYSV_SIGNALS */ 139# endif /* BSD_SIGNALS */ 140#endif /* POSIX_SIGNALS */ 141} 142 143/* enable ^C interrupts */ 144 145/**/ 146mod_export void 147intr(void) 148{ 149 if (interact) 150 install_handler(SIGINT); 151} 152 153/* disable ^C interrupts */ 154 155#if 0 /**/ 156void 157nointr(void) 158{ 159 if (interact) 160 signal_ignore(SIGINT); 161} 162#endif 163 164/* temporarily block ^C interrupts */ 165 166/**/ 167mod_export void 168holdintr(void) 169{ 170 if (interact) 171 signal_block(signal_mask(SIGINT)); 172} 173 174/* release ^C interrupts */ 175 176/**/ 177mod_export void 178noholdintr(void) 179{ 180 if (interact) 181 signal_unblock(signal_mask(SIGINT)); 182} 183 184/* create a signal mask containing * 185 * only the given signal */ 186 187/**/ 188mod_export sigset_t 189signal_mask(int sig) 190{ 191 sigset_t set; 192 193 sigemptyset(&set); 194 if (sig) 195 sigaddset(&set, sig); 196 return set; 197} 198 199/* Block the signals in the given signal * 200 * set. Return the old signal set. */ 201 202/**/ 203#ifndef BSD_SIGNALS 204 205/**/ 206mod_export sigset_t 207signal_block(sigset_t set) 208{ 209 sigset_t oset; 210 211#ifdef POSIX_SIGNALS 212 sigprocmask(SIG_BLOCK, &set, &oset); 213 214#else 215# ifdef SYSV_SIGNALS 216 int i; 217 218 oset = blocked_set; 219 for (i = 1; i <= NSIG; ++i) { 220 if (sigismember(&set, i) && !sigismember(&blocked_set, i)) { 221 sigaddset(&blocked_set, i); 222 sighold(i); 223 } 224 } 225# else /* NO_SIGNAL_BLOCKING */ 226/* We will just ignore signals if the system doesn't have * 227 * the ability to block them. */ 228 int i; 229 230 oset = blocked_set; 231 for (i = 1; i <= NSIG; ++i) { 232 if (sigismember(&set, i) && !sigismember(&blocked_set, i)) { 233 sigaddset(&blocked_set, i); 234 signal_ignore(i); 235 } 236 } 237# endif /* SYSV_SIGNALS */ 238#endif /* POSIX_SIGNALS */ 239 240 return oset; 241} 242 243/**/ 244#endif /* BSD_SIGNALS */ 245 246/* Unblock the signals in the given signal * 247 * set. Return the old signal set. */ 248 249/**/ 250mod_export sigset_t 251signal_unblock(sigset_t set) 252{ 253 sigset_t oset; 254 255#ifdef POSIX_SIGNALS 256 sigprocmask(SIG_UNBLOCK, &set, &oset); 257#else 258# ifdef BSD_SIGNALS 259 sigfillset(&oset); 260 oset = sigsetmask(oset); 261 sigsetmask(oset & ~set); 262# else 263# ifdef SYSV_SIGNALS 264 int i; 265 266 oset = blocked_set; 267 for (i = 1; i <= NSIG; ++i) { 268 if (sigismember(&set, i) && sigismember(&blocked_set, i)) { 269 sigdelset(&blocked_set, i); 270 sigrelse(i); 271 } 272 } 273# else /* NO_SIGNAL_BLOCKING */ 274/* On systems that can't block signals, we are just ignoring them. So * 275 * to unblock signals, we just reenable the signal handler for them. */ 276 int i; 277 278 oset = blocked_set; 279 for (i = 1; i <= NSIG; ++i) { 280 if (sigismember(&set, i) && sigismember(&blocked_set, i)) { 281 sigdelset(&blocked_set, i); 282 install_handler(i); 283 } 284 } 285# endif /* SYSV_SIGNALS */ 286# endif /* BSD_SIGNALS */ 287#endif /* POSIX_SIGNALS */ 288 289 return oset; 290} 291 292/* set the process signal mask to * 293 * be the given signal mask */ 294 295/**/ 296mod_export sigset_t 297signal_setmask(sigset_t set) 298{ 299 sigset_t oset; 300 301#ifdef POSIX_SIGNALS 302 sigprocmask(SIG_SETMASK, &set, &oset); 303#else 304# ifdef BSD_SIGNALS 305 oset = sigsetmask(set); 306# else 307# ifdef SYSV_SIGNALS 308 int i; 309 310 oset = blocked_set; 311 for (i = 1; i <= NSIG; ++i) { 312 if (sigismember(&set, i) && !sigismember(&blocked_set, i)) { 313 sigaddset(&blocked_set, i); 314 sighold(i); 315 } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) { 316 sigdelset(&blocked_set, i); 317 sigrelse(i); 318 } 319 } 320# else /* NO_SIGNAL_BLOCKING */ 321 int i; 322 323 oset = blocked_set; 324 for (i = 1; i < NSIG; ++i) { 325 if (sigismember(&set, i) && !sigismember(&blocked_set, i)) { 326 sigaddset(&blocked_set, i); 327 signal_ignore(i); 328 } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) { 329 sigdelset(&blocked_set, i); 330 install_handler(i); 331 } 332 } 333# endif /* SYSV_SIGNALS */ 334# endif /* BSD_SIGNALS */ 335#endif /* POSIX_SIGNALS */ 336 337 return oset; 338} 339 340#if defined(NO_SIGNAL_BLOCKING) 341static int suspend_longjmp = 0; 342static signal_jmp_buf suspend_jmp_buf; 343#endif 344 345/**/ 346int 347signal_suspend(UNUSED(int sig), int wait_cmd) 348{ 349 int ret; 350 351#if defined(POSIX_SIGNALS) || defined(BSD_SIGNALS) 352 sigset_t set; 353# if defined(POSIX_SIGNALS) && defined(BROKEN_POSIX_SIGSUSPEND) 354 sigset_t oset; 355# endif 356 357 sigemptyset(&set); 358 359 /* SIGINT from the terminal driver needs to interrupt "wait" 360 * and to cause traps to fire, but otherwise should not be 361 * handled by the shell until after any foreground job has 362 * a chance to decide whether to exit on that signal. 363 */ 364 if (!(wait_cmd || isset(TRAPSASYNC) || 365 (sigtrapped[SIGINT] & ~ZSIG_IGNORED))) 366 sigaddset(&set, SIGINT); 367#endif /* POSIX_SIGNALS || BSD_SIGNALS */ 368 369#ifdef POSIX_SIGNALS 370# ifdef BROKEN_POSIX_SIGSUSPEND 371 sigprocmask(SIG_SETMASK, &set, &oset); 372 pause(); 373 sigprocmask(SIG_SETMASK, &oset, NULL); 374# else /* not BROKEN_POSIX_SIGSUSPEND */ 375 ret = sigsuspend(&set); 376# endif /* BROKEN_POSIX_SIGSUSPEND */ 377#else /* not POSIX_SIGNALS */ 378# ifdef BSD_SIGNALS 379 ret = sigpause(set); 380# else 381# ifdef SYSV_SIGNALS 382 ret = sigpause(sig); 383 384# else /* NO_SIGNAL_BLOCKING */ 385 /* need to use signal_longjmp to make this race-free * 386 * between the child_unblock() and pause() */ 387 if (signal_setjmp(suspend_jmp_buf) == 0) { 388 suspend_longjmp = 1; /* we want to signal_longjmp after catching signal */ 389 child_unblock(); /* do we need to do wait_cmd stuff as well? */ 390 ret = pause(); 391 } 392 suspend_longjmp = 0; /* turn off using signal_longjmp since we are past * 393 * the pause() function. */ 394# endif /* SYSV_SIGNALS */ 395# endif /* BSD_SIGNALS */ 396#endif /* POSIX_SIGNALS */ 397 398 return ret; 399} 400 401/* last signal we handled: race prone, or what? */ 402/**/ 403int last_signal; 404 405/* 406 * Wait for any processes that have changed state. 407 * 408 * The main use for this is in the SIGCHLD handler. However, 409 * we also use it to pick up status changes of jobs when 410 * updating jobs. 411 */ 412/**/ 413void 414wait_for_processes(void) 415{ 416 /* keep WAITING until no more child processes to reap */ 417 for (;;) { 418 /* save the errno, since WAIT may change it */ 419 int old_errno = errno; 420 int status; 421 Job jn; 422 Process pn; 423 pid_t pid; 424 pid_t *procsubpid = &cmdoutpid; 425 int *procsubval = &cmdoutval; 426 int cont = 0; 427 struct execstack *es = exstack; 428 429 /* 430 * Reap the child process. 431 * If we want usage information, we need to use wait3. 432 */ 433#if defined(HAVE_WAIT3) || defined(HAVE_WAITPID) 434# ifdef WCONTINUED 435# define WAITFLAGS (WNOHANG|WUNTRACED|WCONTINUED) 436# else 437# define WAITFLAGS (WNOHANG|WUNTRACED) 438# endif 439#endif 440#ifdef HAVE_WAIT3 441# ifdef HAVE_GETRUSAGE 442 struct rusage ru; 443 444 pid = wait3((void *)&status, WAITFLAGS, &ru); 445# else 446 pid = wait3((void *)&status, WAITFLAGS, NULL); 447# endif 448#else 449# ifdef HAVE_WAITPID 450 pid = waitpid(-1, &status, WAITFLAGS); 451# else 452 pid = wait(&status); 453# endif 454#endif 455 456 if (!pid) /* no more children to reap */ 457 break; 458 459 /* check if child returned was from process substitution */ 460 for (;;) { 461 if (pid == *procsubpid) { 462 *procsubpid = 0; 463 if (WIFSIGNALED(status)) 464 *procsubval = (0200 | WTERMSIG(status)); 465 else 466 *procsubval = WEXITSTATUS(status); 467 use_cmdoutval = 1; 468 get_usage(); 469 cont = 1; 470 break; 471 } 472 if (!es) 473 break; 474 procsubpid = &es->cmdoutpid; 475 procsubval = &es->cmdoutval; 476 es = es->next; 477 } 478 if (cont) 479 continue; 480 481 /* check for WAIT error */ 482 if (pid == -1) { 483 if (errno != ECHILD) 484 zerr("wait failed: %e", errno); 485 /* WAIT changed errno, so restore the original */ 486 errno = old_errno; 487 break; 488 } 489 490 /* 491 * Find the process and job containing this pid and 492 * update it. 493 */ 494 if (findproc(pid, &jn, &pn, 0)) { 495 if (((jn->stat & STAT_BUILTIN) || 496 (list_pipe && 497 (thisjob == -1 || 498 (jobtab[thisjob].stat & STAT_BUILTIN)))) && 499 WIFSTOPPED(status) && WSTOPSIG(status) == SIGTSTP) { 500 killjb(jn, SIGCONT); 501 zwarn("job can't be suspended"); 502 } else { 503#if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE) 504 struct timezone dummy_tz; 505 gettimeofday(&pn->endtime, &dummy_tz); 506 pn->status = status; 507 pn->ti = ru; 508#else 509 update_process(pn, status); 510#endif 511 } 512 update_job(jn); 513 } else if (findproc(pid, &jn, &pn, 1)) { 514 pn->status = status; 515 update_job(jn); 516 } else { 517 /* If not found, update the shell record of time spent by 518 * children in sub processes anyway: otherwise, this 519 * will get added on to the next found process that 520 * terminates. 521 */ 522 get_usage(); 523 } 524 /* 525 * Remember the status associated with $!, so we can 526 * wait for it even if it's exited. This value is 527 * only used if we can't find the PID in the job table, 528 * so it doesn't matter that the value we save here isn't 529 * useful until the process has exited. 530 */ 531 if (pn != NULL && pid == lastpid && lastpid_status != -1L) 532 lastpid_status = lastval2; 533 } 534} 535 536/* the signal handler */ 537 538/**/ 539mod_export RETSIGTYPE 540zhandler(int sig) 541{ 542 sigset_t newmask, oldmask; 543 544#if defined(NO_SIGNAL_BLOCKING) 545 int do_jump; 546 signal_jmp_buf jump_to; 547#endif 548 549 last_signal = sig; 550 signal_process(sig); 551 552 sigfillset(&newmask); 553 /* Block all signals temporarily */ 554 oldmask = signal_block(newmask); 555 556#if defined(NO_SIGNAL_BLOCKING) 557 /* do we need to longjmp to signal_suspend */ 558 do_jump = suspend_longjmp; 559 /* In case a SIGCHLD somehow arrives */ 560 suspend_longjmp = 0; 561 562 /* Traps can cause nested signal_suspend() */ 563 if (sig == SIGCHLD) { 564 if (do_jump) { 565 /* Copy suspend_jmp_buf */ 566 jump_to = suspend_jmp_buf; 567 } 568 } 569#endif 570 571 /* Are we queueing signals now? */ 572 if (queueing_enabled) { 573 int temp_rear = ++queue_rear % MAX_QUEUE_SIZE; 574 575 DPUTS(temp_rear == queue_front, "BUG: signal queue full"); 576 /* Make sure it's not full (extremely unlikely) */ 577 if (temp_rear != queue_front) { 578 /* ok, not full, so add to queue */ 579 queue_rear = temp_rear; 580 /* save signal caught */ 581 signal_queue[queue_rear] = sig; 582 /* save current signal mask */ 583 signal_mask_queue[queue_rear] = oldmask; 584 } 585 signal_reset(sig); 586 return; 587 } 588 589 /* Reset signal mask, signal traps ok now */ 590 signal_setmask(oldmask); 591 592 switch (sig) { 593 case SIGCHLD: 594 wait_for_processes(); 595 break; 596 597 case SIGHUP: 598 if (!handletrap(SIGHUP)) { 599 stopmsg = 1; 600 zexit(SIGHUP, 1); 601 } 602 break; 603 604 case SIGINT: 605 if (!handletrap(SIGINT)) { 606 if ((isset(PRIVILEGED) || isset(RESTRICTED)) && 607 isset(INTERACTIVE) && noerrexit < 0) 608 zexit(SIGINT, 1); 609 if (list_pipe || chline || simple_pline) { 610 breaks = loops; 611 errflag = 1; 612 inerrflush(); 613 check_cursh_sig(SIGINT); 614 } 615 } 616 break; 617 618#ifdef SIGWINCH 619 case SIGWINCH: 620 adjustwinsize(1); /* check window size and adjust */ 621 (void) handletrap(SIGWINCH); 622 break; 623#endif 624 625 case SIGALRM: 626 if (!handletrap(SIGALRM)) { 627 int idle = ttyidlegetfn(NULL); 628 int tmout = getiparam("TMOUT"); 629 if (idle >= 0 && idle < tmout) 630 alarm(tmout - idle); 631 else { 632 errflag = noerrs = 0; 633 zwarn("timeout"); 634 stopmsg = 1; 635 zexit(SIGALRM, 1); 636 } 637 } 638 break; 639 640 default: 641 (void) handletrap(sig); 642 break; 643 } /* end of switch(sig) */ 644 645 signal_reset(sig); 646 647/* This is used to make signal_suspend() race-free */ 648#if defined(NO_SIGNAL_BLOCKING) 649 if (do_jump) 650 signal_longjmp(jump_to, 1); 651#endif 652 653} /* handler */ 654 655 656/* SIGHUP any jobs left running */ 657 658/**/ 659void 660killrunjobs(int from_signal) 661{ 662 int i, killed = 0; 663 664 if (unset(HUP)) 665 return; 666 for (i = 1; i <= maxjob; i++) 667 if ((from_signal || i != thisjob) && (jobtab[i].stat & STAT_LOCKED) && 668 !(jobtab[i].stat & STAT_NOPRINT) && 669 !(jobtab[i].stat & STAT_STOPPED)) { 670 if (jobtab[i].gleader != getpid() && 671 killpg(jobtab[i].gleader, SIGHUP) != -1) 672 killed++; 673 } 674 if (killed) 675 zwarn("warning: %d jobs SIGHUPed", killed); 676} 677 678 679/* send a signal to a job (simply involves kill if monitoring is on) */ 680 681/**/ 682int 683killjb(Job jn, int sig) 684{ 685 Process pn; 686 int err = 0; 687 688 if (jobbing) { 689 if (jn->stat & STAT_SUPERJOB) { 690 if (sig == SIGCONT) { 691 for (pn = jobtab[jn->other].procs; pn; pn = pn->next) 692 if (killpg(pn->pid, sig) == -1) 693 if (kill(pn->pid, sig) == -1 && errno != ESRCH) 694 err = -1; 695 696 for (pn = jn->procs; pn->next; pn = pn->next) 697 if (kill(pn->pid, sig) == -1 && errno != ESRCH) 698 err = -1; 699 700 if (!jobtab[jn->other].procs && pn) 701 if (kill(pn->pid, sig) == -1 && errno != ESRCH) 702 err = -1; 703 704 return err; 705 } 706 if (killpg(jobtab[jn->other].gleader, sig) == -1 && errno != ESRCH) 707 err = -1; 708 709 if (killpg(jn->gleader, sig) == -1 && errno != ESRCH) 710 err = -1; 711 712 return err; 713 } 714 else 715 return killpg(jn->gleader, sig); 716 } 717 for (pn = jn->procs; pn; pn = pn->next) 718 if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH && sig != 0) 719 return -1; 720 return err; 721} 722 723/* 724 * List for saving traps. We don't usually have that many traps 725 * at once, so just use a linked list. 726 */ 727struct savetrap { 728 int sig, flags, local; 729 void *list; 730}; 731 732static LinkList savetraps; 733static int dontsavetrap; 734 735/* 736 * Save the current trap by copying it. This does nothing to 737 * the existing value of sigtrapped or siglists. 738 */ 739 740static void 741dosavetrap(int sig, int level) 742{ 743 struct savetrap *st; 744 st = (struct savetrap *)zalloc(sizeof(*st)); 745 st->sig = sig; 746 st->local = level; 747 if ((st->flags = sigtrapped[sig]) & ZSIG_FUNC) { 748 /* 749 * Get the old function: this assumes we haven't added 750 * the new one yet. 751 */ 752 Shfunc shf, newshf = NULL; 753 if ((shf = (Shfunc)gettrapnode(sig, 1))) { 754 /* Copy the node for saving */ 755 newshf = (Shfunc) zalloc(sizeof(*newshf)); 756 newshf->node.nam = ztrdup(shf->node.nam); 757 newshf->node.flags = shf->node.flags; 758 newshf->funcdef = dupeprog(shf->funcdef, 0); 759 newshf->filename = ztrdup(shf->filename); 760 if (shf->sticky) { 761 newshf->sticky = sticky_emulation_dup(shf->sticky, 0); 762 } else 763 newshf->sticky = 0; 764 if (shf->node.flags & PM_UNDEFINED) 765 newshf->funcdef->shf = newshf; 766 } 767#ifdef DEBUG 768 else dputs("BUG: no function present with function trap flag set."); 769#endif 770 DPUTS(siglists[sig], "BUG: function signal has eval list, too."); 771 st->list = newshf; 772 } else if (sigtrapped[sig]) { 773 st->list = siglists[sig] ? dupeprog(siglists[sig], 0) : NULL; 774 } else { 775 DPUTS(siglists[sig], "BUG: siglists not null for untrapped signal"); 776 st->list = NULL; 777 } 778 if (!savetraps) 779 savetraps = znewlinklist(); 780 /* 781 * Put this at the front of the list 782 */ 783 zinsertlinknode(savetraps, (LinkNode)savetraps, st); 784} 785 786 787/* 788 * Set a trap: note this does not handle manipulation of 789 * the function table for TRAPNAL functions. 790 * 791 * sig is the signal number. 792 * 793 * l is the list to be eval'd for a trap defined with the "trap" 794 * builtin and should be NULL for a function trap. 795 * 796 * flags includes any additional flags to be or'd into sigtrapped[sig], 797 * in particular ZSIG_FUNC; the basic flags will be assigned within 798 * settrap. 799 */ 800 801/**/ 802mod_export int 803settrap(int sig, Eprog l, int flags) 804{ 805 if (sig == -1) 806 return 1; 807 if (jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN)) { 808 zerr("can't trap SIG%s in interactive shells", sigs[sig]); 809 return 1; 810 } 811 812 /* 813 * Call unsettrap() unconditionally, to make sure trap is saved 814 * if necessary. 815 */ 816 queue_signals(); 817 unsettrap(sig); 818 819 DPUTS((flags & ZSIG_FUNC) && l, 820 "BUG: trap function has passed eval list, too"); 821 siglists[sig] = l; 822 if (!(flags & ZSIG_FUNC) && empty_eprog(l)) { 823 sigtrapped[sig] = ZSIG_IGNORED; 824 if (sig && sig <= SIGCOUNT && 825#ifdef SIGWINCH 826 sig != SIGWINCH && 827#endif 828 sig != SIGCHLD) 829 signal_ignore(sig); 830 } else { 831 nsigtrapped++; 832 sigtrapped[sig] = ZSIG_TRAPPED; 833 if (sig && sig <= SIGCOUNT && 834#ifdef SIGWINCH 835 sig != SIGWINCH && 836#endif 837 sig != SIGCHLD) 838 install_handler(sig); 839 } 840 /* 841 * Note that introducing the locallevel does not affect whether 842 * sigtrapped[sig] is zero or not, i.e. a test without a mask 843 * works just the same. 844 */ 845 sigtrapped[sig] |= (locallevel << ZSIG_SHIFT) | flags; 846 unqueue_signals(); 847 return 0; 848} 849 850/**/ 851void 852unsettrap(int sig) 853{ 854 HashNode hn; 855 856 queue_signals(); 857 hn = removetrap(sig); 858 if (hn) 859 shfunctab->freenode(hn); 860 unqueue_signals(); 861} 862 863/**/ 864HashNode 865removetrap(int sig) 866{ 867 int trapped; 868 869 if (sig == -1 || 870 (jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN))) 871 return NULL; 872 873 queue_signals(); 874 trapped = sigtrapped[sig]; 875 /* 876 * Note that we save the trap here even if there isn't an existing 877 * one, to aid in removing this one. However, if there's 878 * already one at the current locallevel we just overwrite it. 879 */ 880 if (!dontsavetrap && 881 (sig == SIGEXIT ? !isset(POSIXTRAPS) : isset(LOCALTRAPS)) && 882 locallevel && 883 (!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT))) 884 dosavetrap(sig, locallevel); 885 886 if (!trapped) { 887 unqueue_signals(); 888 return NULL; 889 } 890 if (sigtrapped[sig] & ZSIG_TRAPPED) 891 nsigtrapped--; 892 sigtrapped[sig] = 0; 893 if (sig == SIGINT && interact) { 894 /* PWS 1995/05/16: added test for interactive, also noholdintr() * 895 * as subshells ignoring SIGINT have it blocked from delivery */ 896 intr(); 897 noholdintr(); 898 } else if (sig == SIGHUP) 899 install_handler(sig); 900 else if (sig && sig <= SIGCOUNT && 901#ifdef SIGWINCH 902 sig != SIGWINCH && 903#endif 904 sig != SIGCHLD) 905 signal_default(sig); 906 907 /* 908 * At this point we free the appropriate structs. If we don't 909 * want that to happen then either the function should already have been 910 * removed from shfunctab, or the entry in siglists should have been set 911 * to NULL. This is no longer necessary for saving traps as that 912 * copies the structures, so here we are remove the originals. 913 * That causes a little inefficiency, but a good deal more reliability. 914 */ 915 if (trapped & ZSIG_FUNC) { 916 HashNode node = gettrapnode(sig, 1); 917 918 /* 919 * As in dosavetrap(), don't call removeshfuncnode() because 920 * that calls back into unsettrap(); 921 */ 922 if (node) 923 removehashnode(shfunctab, node->nam); 924 unqueue_signals(); 925 926 return node; 927 } else if (siglists[sig]) { 928 freeeprog(siglists[sig]); 929 siglists[sig] = NULL; 930 } 931 unqueue_signals(); 932 933 return NULL; 934} 935 936/**/ 937void 938starttrapscope(void) 939{ 940 /* No special SIGEXIT behaviour inside another trap. */ 941 if (intrap) 942 return; 943 944 /* 945 * SIGEXIT needs to be restored at the current locallevel, 946 * so give it the next higher one. dosavetrap() is called 947 * automatically where necessary. 948 */ 949 if (sigtrapped[SIGEXIT] && !isset(POSIXTRAPS)) { 950 locallevel++; 951 unsettrap(SIGEXIT); 952 locallevel--; 953 } 954} 955 956/* 957 * Reset traps after the end of a function: must be called after 958 * endparamscope() so that the locallevel has been decremented. 959 */ 960 961/**/ 962void 963endtrapscope(void) 964{ 965 LinkNode ln; 966 struct savetrap *st; 967 int exittr = 0; 968 void *exitfn = NULL; 969 970 /* 971 * Remember the exit trap, but don't run it until 972 * after all the other traps have been put back. 973 * Don't do this inside another trap. 974 */ 975 if (!intrap && 976 !isset(POSIXTRAPS) && (exittr = sigtrapped[SIGEXIT])) { 977 if (exittr & ZSIG_FUNC) { 978 exitfn = removehashnode(shfunctab, "TRAPEXIT"); 979 } else { 980 exitfn = siglists[SIGEXIT]; 981 siglists[SIGEXIT] = NULL; 982 } 983 if (sigtrapped[SIGEXIT] & ZSIG_TRAPPED) 984 nsigtrapped--; 985 sigtrapped[SIGEXIT] = 0; 986 } 987 988 if (savetraps) { 989 while ((ln = firstnode(savetraps)) && 990 (st = (struct savetrap *) ln->dat) && 991 st->local > locallevel) { 992 int sig = st->sig; 993 994 remnode(savetraps, ln); 995 996 if (st->flags && (st->list != NULL)) { 997 /* prevent settrap from saving this */ 998 dontsavetrap++; 999 if (st->flags & ZSIG_FUNC) 1000 settrap(sig, NULL, ZSIG_FUNC); 1001 else 1002 settrap(sig, (Eprog) st->list, 0); 1003 dontsavetrap--; 1004 /* 1005 * counting of nsigtrapped should presumably be handled 1006 * in settrap... 1007 */ 1008 DPUTS((sigtrapped[sig] ^ st->flags) & ZSIG_TRAPPED, 1009 "BUG: settrap didn't restore correct ZSIG_TRAPPED"); 1010 if ((sigtrapped[sig] = st->flags) & ZSIG_FUNC) 1011 shfunctab->addnode(shfunctab, ((Shfunc)st->list)->node.nam, 1012 (Shfunc) st->list); 1013 } else if (sigtrapped[sig]) 1014 unsettrap(sig); 1015 1016 zfree(st, sizeof(*st)); 1017 } 1018 } 1019 1020 if (exittr) { 1021 if (!isset(POSIXTRAPS)) 1022 dotrapargs(SIGEXIT, &exittr, exitfn); 1023 if (exittr & ZSIG_FUNC) 1024 shfunctab->freenode((HashNode)exitfn); 1025 else 1026 freeeprog(exitfn); 1027 } 1028 DPUTS(!locallevel && savetraps && firstnode(savetraps), 1029 "BUG: still saved traps outside all function scope"); 1030} 1031 1032 1033/* 1034 * Decide whether a trap needs handling. 1035 * If so, see if the trap should be run now or queued. 1036 * Return 1 if the trap has been or will be handled. 1037 * This only needs to be called in place of dotrap() in the 1038 * signal handler, since it's only while waiting for children 1039 * to exit that we queue traps. 1040 */ 1041/**/ 1042static int 1043handletrap(int sig) 1044{ 1045 if (!sigtrapped[sig]) 1046 return 0; 1047 1048 if (trap_queueing_enabled) 1049 { 1050 /* Code borrowed from signal queueing */ 1051 int temp_rear = ++trap_queue_rear % MAX_QUEUE_SIZE; 1052 1053 DPUTS(temp_rear == trap_queue_front, "BUG: trap queue full"); 1054 /* If queue is not full... */ 1055 if (temp_rear != trap_queue_front) { 1056 trap_queue_rear = temp_rear; 1057 trap_queue[trap_queue_rear] = sig; 1058 } 1059 return 1; 1060 } 1061 1062 dotrap(sig); 1063 1064 if (sig == SIGALRM) 1065 { 1066 int tmout; 1067 /* 1068 * Reset the alarm. 1069 * It seems slightly more natural to do this when the 1070 * trap is run, rather than when it's queued, since 1071 * the user doesn't see the latter. 1072 */ 1073 if ((tmout = getiparam("TMOUT"))) 1074 alarm(tmout); 1075 } 1076 1077 return 1; 1078} 1079 1080 1081/* 1082 * Queue traps if they shouldn't be run asynchronously, i.e. 1083 * we're not in the wait builtin and TRAPSASYNC isn't set, when 1084 * waiting for children to exit. 1085 * 1086 * Note that unlike signal queuing this should only be called 1087 * in single matching pairs and can't be nested. It is 1088 * only needed when waiting for a job or process to finish. 1089 * 1090 * There is presumably a race setting this up: we shouldn't be running 1091 * traps between forking a foreground process and this point, either. 1092 */ 1093/**/ 1094void 1095queue_traps(int wait_cmd) 1096{ 1097 if (!isset(TRAPSASYNC) && !wait_cmd) { 1098 /* 1099 * Traps need to be handled synchronously, so 1100 * enable queueing. 1101 */ 1102 trap_queueing_enabled = 1; 1103 } 1104} 1105 1106 1107/* 1108 * Disable trap queuing and run the traps. 1109 */ 1110/**/ 1111void 1112unqueue_traps(void) 1113{ 1114 trap_queueing_enabled = 0; 1115 while (trap_queue_front != trap_queue_rear) { 1116 trap_queue_front = (trap_queue_front + 1) % MAX_QUEUE_SIZE; 1117 (void) handletrap(trap_queue[trap_queue_front]); 1118 } 1119} 1120 1121 1122/* Execute a trap function for a given signal, possibly 1123 * with non-standard sigtrapped & siglists values 1124 */ 1125 1126/* Are we already executing a trap? */ 1127/**/ 1128int intrap; 1129 1130/* Is the current trap a function? */ 1131 1132/**/ 1133int trapisfunc; 1134 1135/* 1136 * If the current trap is not a function, at what function depth 1137 * did the trap get called? 1138 */ 1139/**/ 1140int traplocallevel; 1141 1142/* 1143 * sig is the signal number. 1144 * *sigtr is the value to be taken as the field in sigtrapped (since 1145 * that may have changed by this point if we are exiting). 1146 * sigfn is an Eprog with a non-function eval list, or a Shfunc 1147 * with a function trap. It may be NULL with an ignored signal. 1148 */ 1149 1150/**/ 1151static void 1152dotrapargs(int sig, int *sigtr, void *sigfn) 1153{ 1154 LinkList args; 1155 char *name, num[4]; 1156 int obreaks = breaks; 1157 int oretflag = retflag; 1158 int isfunc; 1159 int traperr, new_trap_state, new_trap_return; 1160 1161 /* if signal is being ignored or the trap function * 1162 * is NULL, then return * 1163 * * 1164 * Also return if errflag is set. In fact, the code in the * 1165 * function will test for this, but this way we keep status flags * 1166 * intact without working too hard. Special cases (e.g. calling * 1167 * a trap for SIGINT after the error flag was set) are handled * 1168 * by the calling code. (PWS 1995/06/08). * 1169 * * 1170 * This test is now replicated in dotrap(). */ 1171 if ((*sigtr & ZSIG_IGNORED) || !sigfn || errflag) 1172 return; 1173 1174 /* 1175 * Never execute special (synchronous) traps inside other traps. 1176 * This can cause unexpected code execution when more than one 1177 * of these is set. 1178 * 1179 * The down side is that it's harder to debug traps. I don't think 1180 * that's a big issue. 1181 */ 1182 if (intrap) { 1183 switch (sig) { 1184 case SIGEXIT: 1185 case SIGDEBUG: 1186 case SIGZERR: 1187 return; 1188 } 1189 } 1190 1191 intrap++; 1192 *sigtr |= ZSIG_IGNORED; 1193 1194 lexsave(); 1195 /* execsave will save the old trap_return and trap_state */ 1196 execsave(); 1197 breaks = retflag = 0; 1198 traplocallevel = locallevel; 1199 runhookdef(BEFORETRAPHOOK, NULL); 1200 if (*sigtr & ZSIG_FUNC) { 1201 int osc = sfcontext, old_incompfunc = incompfunc; 1202 HashNode hn = gettrapnode(sig, 0); 1203 1204 args = znewlinklist(); 1205 /* 1206 * In case of multiple names, try to get 1207 * a hint of the name in use from the function table. 1208 * In special cases, e.g. EXIT traps, the function 1209 * has already been removed. Then it's OK to 1210 * use the standard name. 1211 */ 1212 if (hn) { 1213 name = ztrdup(hn->nam); 1214 } else { 1215 name = (char *) zalloc(5 + strlen(sigs[sig])); 1216 sprintf(name, "TRAP%s", sigs[sig]); 1217 } 1218 zaddlinknode(args, name); 1219 sprintf(num, "%d", sig); 1220 zaddlinknode(args, num); 1221 1222 trap_return = -1; /* incremented by doshfunc */ 1223 trap_state = TRAP_STATE_PRIMED; 1224 trapisfunc = isfunc = 1; 1225 1226 sfcontext = SFC_SIGNAL; 1227 incompfunc = 0; 1228 doshfunc((Shfunc)sigfn, args, 1); 1229 sfcontext = osc; 1230 incompfunc= old_incompfunc; 1231 freelinklist(args, (FreeFunc) NULL); 1232 zsfree(name); 1233 } else { 1234 trap_return = -2; /* not incremented, used at current level */ 1235 trap_state = TRAP_STATE_PRIMED; 1236 trapisfunc = isfunc = 0; 1237 1238 execode((Eprog)sigfn, 1, 0, "trap"); 1239 } 1240 runhookdef(AFTERTRAPHOOK, NULL); 1241 1242 traperr = errflag; 1243 1244 /* Grab values before they are restored */ 1245 new_trap_state = trap_state; 1246 new_trap_return = trap_return; 1247 1248 execrestore(); 1249 lexrestore(); 1250 1251 if (new_trap_state == TRAP_STATE_FORCE_RETURN && 1252 /* zero return from function isn't special */ 1253 !(isfunc && new_trap_return == 0)) { 1254 if (isfunc) { 1255 breaks = loops; 1256 errflag = 1; 1257 } 1258 lastval = new_trap_return; 1259 /* return triggered */ 1260 retflag = 1; 1261 } else { 1262 if (traperr && !EMULATION(EMULATE_SH)) 1263 lastval = 1; 1264 if (try_tryflag) 1265 errflag = traperr; 1266 breaks += obreaks; 1267 /* return not triggered: restore old flag */ 1268 retflag = oretflag; 1269 if (breaks > loops) 1270 breaks = loops; 1271 } 1272 1273 /* 1274 * If zle was running while the trap was executed, see if we 1275 * need to restore the display. 1276 */ 1277 if (zleactive && resetneeded) 1278 zleentry(ZLE_CMD_REFRESH); 1279 1280 if (*sigtr != ZSIG_IGNORED) 1281 *sigtr &= ~ZSIG_IGNORED; 1282 intrap--; 1283} 1284 1285/* Standard call to execute a trap for a given signal. */ 1286 1287/**/ 1288void 1289dotrap(int sig) 1290{ 1291 void *funcprog; 1292 1293 if (sigtrapped[sig] & ZSIG_FUNC) { 1294 HashNode hn = gettrapnode(sig, 0); 1295 if (hn) 1296 funcprog = hn; 1297 else { 1298#ifdef DEBUG 1299 dputs("BUG: running function trap which has escaped."); 1300#endif 1301 funcprog = NULL; 1302 } 1303 } else 1304 funcprog = siglists[sig]; 1305 1306 /* 1307 * Copied from dotrapargs(). 1308 * (In fact, the gain from duplicating this appears to be virtually 1309 * zero. Not sure why it's here.) 1310 */ 1311 if ((sigtrapped[sig] & ZSIG_IGNORED) || !funcprog || errflag) 1312 return; 1313 1314 dotrapargs(sig, sigtrapped+sig, funcprog); 1315} 1316