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