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