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