139dc2a6fa6b6bc20c1c10c48529f52a85dde454
[platform/upstream/bash.git] / trap.c
1 /* trap.c -- Not the trap command, but useful functions for manipulating
2    those objects.  The trap command is in builtins/trap.def. */
3
4 /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
5
6    This file is part of GNU Bash, the Bourne Again SHell.
7
8    Bash is free software; you can redistribute it and/or modify it under
9    the terms of the GNU General Public License as published by the Free
10    Software Foundation; either version 1, or (at your option) any later
11    version.
12
13    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14    WARRANTY; without even the implied warranty of MERCHANTABILITY or
15    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16    for more details.
17
18    You should have received a copy of the GNU General Public License along
19    with Bash; see the file COPYING.  If not, write to the Free Software
20    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include "config.h"
23
24 #include <stdio.h>
25
26 #include "bashtypes.h"
27 #include "trap.h"
28
29 #if defined (HAVE_STRING_H)
30 #  include <string.h>
31 #else /* !HAVE_STRING_H */
32 #  include <strings.h>
33 #endif /* !HAVE_STRING_H */
34
35 #if defined (HAVE_UNISTD_H)
36 #  include <unistd.h>
37 #endif
38
39 #include "shell.h"
40 #include "signames.h"
41 #include "builtins/common.h"
42
43 /* Flags which describe the current handling state of a signal. */
44 #define SIG_INHERITED   0x0     /* Value inherited from parent. */
45 #define SIG_TRAPPED     0x1     /* Currently trapped. */
46 #define SIG_HARD_IGNORE 0x2     /* Signal was ignored on shell entry. */
47 #define SIG_SPECIAL     0x4     /* Treat this signal specially. */
48 #define SIG_NO_TRAP     0x8     /* Signal cannot be trapped. */
49 #define SIG_INPROGRESS  0x10    /* Signal handler currently executing. */
50 #define SIG_CHANGED     0x20    /* Trap value changed in trap handler. */
51 #define SIG_IGNORED     0x40    /* The signal is currently being ignored. */
52
53 /* An array of such flags, one for each signal, describing what the
54    shell will do with a signal.  DEBUG_TRAP == NSIG; some code below
55    assumes this. */
56 static int sigmodes[NSIG+1];
57
58 static void change_signal (), restore_signal ();
59
60 /* Variables used here but defined in other files. */
61 extern int interactive_shell, interactive;
62 extern int interrupt_immediately;
63 extern int last_command_exit_value;
64
65 /* The list of things to do originally, before we started trapping. */
66 SigHandler *original_signals[NSIG];
67
68 /* For each signal, a slot for a string, which is a command to be
69    executed when that signal is recieved.  The slot can also contain
70    DEFAULT_SIG, which means do whatever you were going to do before
71    you were so rudely interrupted, or IGNORE_SIG, which says ignore
72    this signal. */
73 char *trap_list[NSIG+1];
74
75 /* A bitmap of signals received for which we have trap handlers. */
76 int pending_traps[NSIG];
77
78 /* Set to the number of the signal we're running the trap for + 1.
79    Used in execute_cmd.c and builtins/common.c to clean up when
80    parse_and_execute does not return normally after executing the
81    trap command (e.g., when `return' is executed in the trap command). */
82 int running_trap;
83
84 /* A value which can never be the target of a trap handler. */
85 #define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
86
87 void
88 initialize_traps ()
89 {
90   register int i;
91
92   trap_list[EXIT_TRAP] = trap_list[DEBUG_TRAP] = (char *)NULL;
93   sigmodes[EXIT_TRAP] = sigmodes[DEBUG_TRAP] = SIG_INHERITED;
94   original_signals[EXIT_TRAP] = IMPOSSIBLE_TRAP_HANDLER;
95
96   for (i = 1; i < NSIG; i++)
97     {
98       pending_traps[i] = 0;
99       trap_list[i] = (char *)DEFAULT_SIG;
100       sigmodes[i] = SIG_INHERITED;
101       original_signals[i] = IMPOSSIBLE_TRAP_HANDLER;
102     }
103
104   /* Show which signals are treated specially by the shell. */
105 #if defined (SIGCHLD)
106   original_signals[SIGCHLD] =
107     (SigHandler *) set_signal_handler (SIGCHLD, SIG_DFL);
108   set_signal_handler (SIGCHLD, original_signals[SIGCHLD]);
109   sigmodes[SIGCHLD] |= (SIG_SPECIAL | SIG_NO_TRAP);
110 #endif /* SIGCHLD */
111
112   original_signals[SIGINT] =
113     (SigHandler *) set_signal_handler (SIGINT, SIG_DFL);
114   set_signal_handler (SIGINT, original_signals[SIGINT]);
115   sigmodes[SIGINT] |= SIG_SPECIAL;
116
117   original_signals[SIGQUIT] =
118     (SigHandler *) set_signal_handler (SIGQUIT, SIG_DFL);
119   set_signal_handler (SIGQUIT, original_signals[SIGQUIT]);
120   sigmodes[SIGQUIT] |= SIG_SPECIAL;
121
122   if (interactive)
123     {
124       original_signals[SIGTERM] =
125         (SigHandler *)set_signal_handler (SIGTERM, SIG_DFL);
126       set_signal_handler (SIGTERM, original_signals[SIGTERM]);
127       sigmodes[SIGTERM] |= SIG_SPECIAL;
128     }
129 }
130
131 /* Return the print name of this signal. */
132 char *
133 signal_name (sig)
134      int sig;
135 {
136   return ((sig > NSIG || sig < 0) ? "bad signal number" : signal_names[sig]);
137 }
138
139 /* Turn a string into a signal number, or a number into
140    a signal number.  If STRING is "2", "SIGINT", or "INT",
141    then (int)2 is returned.  Return NO_SIG if STRING doesn't
142    contain a valid signal descriptor. */
143 int
144 decode_signal (string)
145      char *string;
146 {
147   long sig;
148
149   if (legal_number (string, &sig))
150     return ((sig >= 0 && sig <= NSIG) ? (int)sig : NO_SIG);
151
152   for (sig = 0; sig <= NSIG; sig++)
153     if (strcasecmp (string, signal_names[sig]) == 0 ||
154         strcasecmp (string, &(signal_names[sig])[3]) == 0)
155       return ((int)sig);
156
157   return (NO_SIG);
158 }
159
160 /* Non-zero when we catch a trapped signal. */
161 static int catch_flag;
162
163 void
164 run_pending_traps ()
165 {
166   register int sig;
167   int old_exit_value;
168
169   if (catch_flag == 0)          /* simple optimization */
170     return;
171
172   catch_flag = 0;
173
174   /* Preserve $? when running trap. */
175   old_exit_value = last_command_exit_value;
176
177   for (sig = 1; sig < NSIG; sig++)
178     {
179       /* XXX this could be made into a counter by using
180          while (pending_traps[sig]--) instead of the if statement. */
181       if (pending_traps[sig])
182         {
183 #if defined (HAVE_POSIX_SIGNALS)
184           sigset_t set, oset;
185
186           sigemptyset (&set);
187           sigemptyset (&oset);
188
189           sigaddset (&set, sig);
190           sigprocmask (SIG_BLOCK, &set, &oset);
191 #else
192 #  if defined (HAVE_BSD_SIGNALS)
193           int oldmask = sigblock (sigmask (sig));
194 #  endif
195 #endif /* HAVE_POSIX_SIGNALS */
196
197           if (sig == SIGINT)
198             {
199               run_interrupt_trap ();
200               CLRINTERRUPT;
201             }
202           else
203             parse_and_execute (savestring (trap_list[sig]), "trap", 0);
204
205           pending_traps[sig] = 0;
206
207 #if defined (HAVE_POSIX_SIGNALS)
208           sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
209 #else
210 #  if defined (HAVE_BSD_SIGNALS)
211           sigsetmask (oldmask);
212 #  endif
213 #endif /* POSIX_VERSION */
214         }
215     }
216
217   last_command_exit_value = old_exit_value;
218 }
219
220 sighandler
221 trap_handler (sig)
222      int sig;
223 {
224   if ((sig >= NSIG) ||
225       (trap_list[sig] == (char *)DEFAULT_SIG) ||
226       (trap_list[sig] == (char *)IGNORE_SIG))
227     programming_error ("trap_handler: bad signal %d", sig);
228   else
229     {
230 #if defined (MUST_REINSTALL_SIGHANDLERS)
231       set_signal_handler (sig, trap_handler);
232 #endif /* MUST_REINSTALL_SIGHANDLERS */
233
234       catch_flag = 1;
235       pending_traps[sig]++;
236
237       if (interrupt_immediately)
238         run_pending_traps ();
239     }
240
241   SIGRETURN (0);
242 }
243
244 #if defined (JOB_CONTROL) && defined (SIGCHLD)
245 /* Make COMMAND_STRING be executed when SIGCHLD is caught. */
246 void
247 set_sigchld_trap (command_string)
248      char *command_string;
249 {
250   set_signal (SIGCHLD, command_string);
251 }
252
253 /* Make COMMAND_STRING be executed when SIGCHLD is caught iff the current
254    SIGCHLD trap handler is DEFAULT_SIG. */
255 void
256 maybe_set_sigchld_trap (command_string)
257      char *command_string;
258 {
259   if ((sigmodes[SIGCHLD] & SIG_TRAPPED) == 0)
260     set_signal (SIGCHLD, command_string);
261 }
262 #endif /* JOB_CONTROL && SIGCHLD */
263
264 void
265 set_debug_trap (command)
266      char *command;
267 {
268   set_signal (DEBUG_TRAP, command);
269 }
270
271 void
272 set_sigint_trap (command)
273      char *command;
274 {
275   set_signal (SIGINT, command);
276 }
277
278 /* Reset the SIGINT handler so that subshells that are doing `shellsy'
279    things, like waiting for command substitution or executing commands
280    in explicit subshells ( ( cmd ) ), can catch interrupts properly. */
281 SigHandler *
282 set_sigint_handler ()
283 {
284   if (sigmodes[SIGINT] & SIG_HARD_IGNORE)
285     return ((SigHandler *)SIG_IGN);
286
287   else if (sigmodes[SIGINT] & SIG_IGNORED)
288     return ((SigHandler *)set_signal_handler (SIGINT, SIG_IGN)); /* XXX */
289
290   else if (sigmodes[SIGINT] & SIG_TRAPPED)
291     return ((SigHandler *)set_signal_handler (SIGINT, trap_handler));
292
293   /* The signal is not trapped, so set the handler to the shell's special
294      interrupt handler. */
295   else if (interactive) /* XXX - was interactive_shell */
296     return (set_signal_handler (SIGINT, sigint_sighandler));
297   else
298     return (set_signal_handler (SIGINT, termination_unwind_protect));
299 }
300
301 /* Set SIG to call STRING as a command. */
302 void
303 set_signal (sig, string)
304      int sig;
305      char *string;
306 {
307   if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
308     {
309       change_signal (sig, savestring (string));
310       return;
311     }
312
313   /* A signal ignored on entry to the shell cannot be trapped or reset, but
314      no error is reported when attempting to do so.  -- Posix.2 */
315   if (sigmodes[sig] & SIG_HARD_IGNORE)
316     return;
317
318   /* Make sure we have original_signals[sig] if the signal has not yet
319      been trapped. */
320   if ((sigmodes[sig] & SIG_TRAPPED) == 0)
321     {
322       /* If we aren't sure of the original value, check it. */
323       if (original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER)
324         {
325           original_signals[sig] = (SigHandler *)set_signal_handler (sig, SIG_DFL);
326           set_signal_handler (sig, original_signals[sig]);
327         }
328
329       /* Signals ignored on entry to the shell cannot be trapped or reset. */
330       if (original_signals[sig] == SIG_IGN)
331         {
332           sigmodes[sig] |= SIG_HARD_IGNORE;
333           return;
334         }
335     }
336
337   /* Only change the system signal handler if SIG_NO_TRAP is not set.
338      The trap command string is changed in either case.  The shell signal
339      handlers for SIGINT and SIGCHLD run the user specified traps in an
340      environment in which it is safe to do so. */
341   if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
342     {
343       set_signal_handler (sig, SIG_IGN);
344       change_signal (sig, savestring (string));
345       set_signal_handler (sig, trap_handler);
346     }
347   else
348     change_signal (sig, savestring (string));
349 }
350
351 static void
352 free_trap_command (sig)
353      int sig;
354 {
355   if ((sigmodes[sig] & SIG_TRAPPED) && trap_list[sig] &&
356       (trap_list[sig] != (char *)IGNORE_SIG) &&
357       (trap_list[sig] != (char *)DEFAULT_SIG) &&
358       (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER))
359     free (trap_list[sig]);
360 }
361
362 /* If SIG has a string assigned to it, get rid of it.  Then give it
363    VALUE. */
364 static void
365 change_signal (sig, value)
366      int sig;
367      char *value;
368 {
369   free_trap_command (sig);
370   trap_list[sig] = value;
371
372   sigmodes[sig] |= SIG_TRAPPED;
373   if (value == (char *)IGNORE_SIG)
374     sigmodes[sig] |= SIG_IGNORED;
375   else
376     sigmodes[sig] &= ~SIG_IGNORED;
377   if (sigmodes[sig] & SIG_INPROGRESS)
378     sigmodes[sig] |= SIG_CHANGED;
379 }
380
381 #define GET_ORIGINAL_SIGNAL(sig) \
382   if (sig && sig < NSIG && original_signals[sig] == IMPOSSIBLE_TRAP_HANDLER) \
383     get_original_signal (sig)
384
385 static void
386 get_original_signal (sig)
387      int sig;
388 {
389   /* If we aren't sure the of the original value, then get it. */
390   if (original_signals[sig] == (SigHandler *)IMPOSSIBLE_TRAP_HANDLER)
391     {
392       original_signals[sig] =
393         (SigHandler *) set_signal_handler (sig, SIG_DFL);
394       set_signal_handler (sig, original_signals[sig]);
395
396       /* Signals ignored on entry to the shell cannot be trapped. */
397       if (original_signals[sig] == SIG_IGN)
398         sigmodes[sig] |= SIG_HARD_IGNORE;
399     }
400 }
401
402 /* Restore the default action for SIG; i.e., the action the shell
403    would have taken before you used the trap command.  This is called
404    from trap_builtin (), which takes care to restore the handlers for
405    the signals the shell treats specially. */
406 void
407 restore_default_signal (sig)
408      int sig;
409 {
410   if (sig == DEBUG_TRAP || sig == EXIT_TRAP)
411     {
412       free_trap_command (sig);
413       trap_list[sig] = (char *)NULL;
414       sigmodes[sig] &= ~SIG_TRAPPED;
415       return;
416     }
417
418   GET_ORIGINAL_SIGNAL (sig);
419
420   /* A signal ignored on entry to the shell cannot be trapped or reset, but
421      no error is reported when attempting to do so.  Thanks Posix.2. */
422   if (sigmodes[sig] & SIG_HARD_IGNORE)
423     return;
424
425   /* If we aren't trapping this signal, don't bother doing anything else. */
426   if ((sigmodes[sig] & SIG_TRAPPED) == 0)
427     return;
428
429   /* Only change the signal handler for SIG if it allows it. */
430   if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
431     set_signal_handler (sig, original_signals[sig]);
432
433   /* Change the trap command in either case. */
434   change_signal (sig, (char *)DEFAULT_SIG);
435
436   /* Mark the signal as no longer trapped. */
437   sigmodes[sig] &= ~SIG_TRAPPED;
438 }
439
440 /* Make this signal be ignored. */
441 void
442 ignore_signal (sig)
443      int sig;
444 {
445   if ((sig == EXIT_TRAP || sig == DEBUG_TRAP) && ((sigmodes[sig] & SIG_IGNORED) == 0))
446     {
447       change_signal (sig, (char *)IGNORE_SIG);
448       return;
449     }
450
451   GET_ORIGINAL_SIGNAL (sig);
452
453   /* A signal ignored on entry to the shell cannot be trapped or reset.
454      No error is reported when the user attempts to do so. */
455   if (sigmodes[sig] & SIG_HARD_IGNORE)
456     return;
457
458   /* If already trapped and ignored, no change necessary. */
459   if (sigmodes[sig] & SIG_IGNORED)
460     return;
461
462   /* Only change the signal handler for SIG if it allows it. */
463   if ((sigmodes[sig] & SIG_NO_TRAP) == 0)
464     set_signal_handler (sig, SIG_IGN);
465
466   /* Change the trap command in either case. */
467   change_signal (sig, (char *)IGNORE_SIG);
468 }
469
470 /* Handle the calling of "trap 0".  The only sticky situation is when
471    the command to be executed includes an "exit".  This is why we have
472    to provide our own place for top_level to jump to. */
473 int
474 run_exit_trap ()
475 {
476   char *trap_command;
477   int code, old_exit_value;
478
479   old_exit_value = last_command_exit_value;
480
481   /* Run the trap only if signal 0 is trapped and not ignored, and we are not
482      currently running in the trap handler (call to exit in the list of
483      commands given to trap 0). */
484   if ((sigmodes[EXIT_TRAP] & SIG_TRAPPED) &&
485       (sigmodes[EXIT_TRAP] & (SIG_IGNORED|SIG_INPROGRESS)) == 0)
486     {
487       trap_command = savestring (trap_list[EXIT_TRAP]);
488       sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
489       sigmodes[EXIT_TRAP] |= SIG_INPROGRESS;
490
491       code = setjmp (top_level);
492
493       if (code == 0)
494         parse_and_execute (trap_command, "exit trap", 0);
495       else if (code == EXITPROG)
496         return (last_command_exit_value);
497       else
498         return (old_exit_value);
499     }
500
501   return (old_exit_value);
502 }
503
504 void
505 run_trap_cleanup (sig)
506      int sig;
507 {
508   sigmodes[sig] &= ~(SIG_INPROGRESS|SIG_CHANGED);
509 }
510
511 /* Run a trap command for SIG.  SIG is one of the signals the shell treats
512    specially. */
513 static void
514 _run_trap_internal (sig, tag)
515      int sig;
516      char *tag;
517 {
518   char *trap_command, *old_trap;
519   int old_exit_value;
520
521   /* Run the trap only if SIG is trapped and not ignored, and we are not
522      currently executing in the trap handler. */
523   if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0) &&
524       (trap_list[sig] != (char *)IMPOSSIBLE_TRAP_HANDLER) &&
525       ((sigmodes[sig] & SIG_INPROGRESS) == 0))
526     {
527       old_trap = trap_list[sig];
528       sigmodes[sig] |= SIG_INPROGRESS;
529       sigmodes[sig] &= ~SIG_CHANGED;            /* just to be sure */
530       trap_command =  savestring (old_trap);
531
532       running_trap = sig + 1;
533       old_exit_value = last_command_exit_value;
534       parse_and_execute (trap_command, tag, 0);
535       last_command_exit_value = old_exit_value;
536       running_trap = 0;
537
538       sigmodes[sig] &= ~SIG_INPROGRESS;
539
540       if (sigmodes[sig] & SIG_CHANGED)
541         {
542           free (old_trap);
543           sigmodes[sig] &= ~SIG_CHANGED;
544         }
545     }
546 }
547
548 void
549 run_debug_trap ()
550 {
551   if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS) == 0)
552     _run_trap_internal (DEBUG_TRAP, "debug trap");
553 }
554
555 /* Run a trap set on SIGINT.  This is called from throw_to_top_level (), and
556    declared here to localize the trap functions. */
557 void
558 run_interrupt_trap ()
559 {
560   _run_trap_internal (SIGINT, "interrupt trap");
561 }
562
563 /* Free all the allocated strings in the list of traps and reset the trap
564    values to the default. */
565 void
566 free_trap_strings ()
567 {
568   register int i;
569
570   for (i = 0; i < NSIG+1; i++)
571     {
572       free_trap_command (i);
573       trap_list[i] = (char *)DEFAULT_SIG;
574       sigmodes[i] &= ~SIG_TRAPPED;
575     }
576   trap_list[DEBUG_TRAP] = trap_list[EXIT_TRAP] = (char *)NULL;
577 }
578
579 /* Reset the handler for SIG to the original value. */
580 static void
581 reset_signal (sig)
582      int sig;
583 {
584   set_signal_handler (sig, original_signals[sig]);
585 }
586
587 /* Set the handler signal SIG to the original and free any trap
588    command associated with it. */
589 static void
590 restore_signal (sig)
591      int sig;
592 {
593   set_signal_handler (sig, original_signals[sig]);
594   change_signal (sig, (char *)DEFAULT_SIG);
595   sigmodes[sig] &= ~SIG_TRAPPED;
596 }
597
598 static void
599 reset_or_restore_signal_handlers (reset)
600      VFunction *reset;
601 {
602   register int i;
603
604   /* Take care of the exit trap first */
605   if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
606     {
607       free_trap_command (EXIT_TRAP);
608       trap_list[EXIT_TRAP] = (char *)NULL;
609       sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
610     }
611   for (i = 1; i < NSIG; i++)
612     {
613       if (sigmodes[i] & SIG_TRAPPED)
614         {
615           if (trap_list[i] == (char *)IGNORE_SIG)
616             set_signal_handler (i, SIG_IGN);
617           else
618             (*reset) (i);
619         }
620       else if (sigmodes[i] & SIG_SPECIAL)
621         (*reset) (i);
622     }
623 }
624
625 void
626 reset_signal_handlers ()
627 {
628   reset_or_restore_signal_handlers (reset_signal);
629 }
630
631 /* Reset all trapped signals to their original values.  Signals set to be
632    ignored with trap '' SIGNAL should be ignored, so we make sure that they
633    are.  Called by child processes after they are forked. */
634 void
635 restore_original_signals ()
636 {
637   reset_or_restore_signal_handlers (restore_signal);
638 }
639
640 /* If a trap handler exists for signal SIG, then call it; otherwise just
641    return failure. */
642 int
643 maybe_call_trap_handler (sig)
644      int sig;
645 {
646   /* Call the trap handler for SIG if the signal is trapped and not ignored. */
647   if ((sigmodes[sig] & SIG_TRAPPED) && ((sigmodes[sig] & SIG_IGNORED) == 0))
648     {
649       switch (sig)
650         {
651         case SIGINT:
652           run_interrupt_trap ();
653           break;
654         case EXIT_TRAP:
655           run_exit_trap ();
656           break;
657         case DEBUG_TRAP:
658           run_debug_trap ();
659           break;
660         default:
661           trap_handler (sig);
662           break;
663         }
664       return (1);
665     }
666   else
667     return (0);
668 }
669
670 int
671 signal_is_trapped (sig)
672      int sig;
673 {
674   return (sigmodes[sig] & SIG_TRAPPED);
675 }
676
677 int
678 signal_is_special (sig)
679      int sig;
680 {
681   return (sigmodes[sig] & SIG_SPECIAL);
682 }
683
684 int
685 signal_is_ignored (sig)
686      int sig;
687 {
688   return (sigmodes[sig] & SIG_IGNORED);
689 }
690
691 void
692 set_signal_ignored (sig)
693      int sig;
694 {
695   sigmodes[sig] |= SIG_HARD_IGNORE;
696   original_signals[sig] = SIG_IGN;
697 }