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