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