1/* trap.c, created from trap.def. */
2#line 23 "trap.def"
3
4#line 42 "trap.def"
5
6#include <config.h>
7
8#if defined (HAVE_UNISTD_H)
9#  ifdef _MINIX
10#    include <sys/types.h>
11#  endif
12#  include <unistd.h>
13#endif
14
15#include "../bashtypes.h"
16#include <signal.h>
17#include <stdio.h>
18#include "../bashansi.h"
19
20#include "../shell.h"
21#include "../trap.h"
22#include "common.h"
23#include "bashgetopt.h"
24
25static void showtrap __P((int));
26static int display_traps __P((WORD_LIST *));
27
28/* The trap command:
29
30   trap <arg> <signal ...>
31   trap <signal ...>
32   trap -l
33   trap -p [sigspec ...]
34   trap [--]
35
36   Set things up so that ARG is executed when SIGNAL(s) N is recieved.
37   If ARG is the empty string, then ignore the SIGNAL(s).  If there is
38   no ARG, then set the trap for SIGNAL(s) to its original value.  Just
39   plain "trap" means to print out the list of commands associated with
40   each signal number.  Single arg of "-l" means list the signal names. */
41
42/* Possible operations to perform on the list of signals.*/
43#define SET 0			/* Set this signal to first_arg. */
44#define REVERT 1		/* Revert to this signals original value. */
45#define IGNORE 2		/* Ignore this signal. */
46
47extern int posixly_correct;
48
49int
50trap_builtin (list)
51     WORD_LIST *list;
52{
53  int list_signal_names, display, result, opt;
54
55  list_signal_names = display = 0;
56  result = EXECUTION_SUCCESS;
57  reset_internal_getopt ();
58  while ((opt = internal_getopt (list, "lp")) != -1)
59    {
60      switch (opt)
61	{
62	case 'l':
63	  list_signal_names++;
64	  break;
65	case 'p':
66	  display++;
67	  break;
68	default:
69	  builtin_usage ();
70	  return (EX_USAGE);
71	}
72    }
73  list = loptend;
74
75  opt = DSIG_NOCASE|DSIG_SIGPREFIX;	/* flags for decode_signal */
76
77  if (list_signal_names)
78    return (display_signal_list ((WORD_LIST *)NULL, 1));
79  else if (display || list == 0)
80    return (display_traps (list));
81  else
82    {
83      char *first_arg;
84      int operation, sig, first_signal;
85
86      operation = SET;
87      first_arg = list->word->word;
88      first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
89
90      /* Backwards compatibility.  XXX - question about whether or not we
91	 should throw an error if an all-digit argument doesn't correspond
92	 to a valid signal number (e.g., if it's `50' on a system with only
93	 32 signals).  */
94      if (first_signal)
95	operation = REVERT;
96      /* When in posix mode, the historical behavior of looking for a
97	 missing first argument is disabled.  To revert to the original
98	 signal handling disposition, use `-' as the first argument. */
99      else if (posixly_correct == 0 && first_arg && *first_arg &&
100		(*first_arg != '-' || first_arg[1]) &&
101		signal_object_p (first_arg, opt) && list->next == 0)
102	operation = REVERT;
103      else
104	{
105	  list = list->next;
106	  if (list == 0)
107	    {
108	      builtin_usage ();
109	      return (EX_USAGE);
110	    }
111	  else if (*first_arg == '\0')
112	    operation = IGNORE;
113	  else if (first_arg[0] == '-' && !first_arg[1])
114	    operation = REVERT;
115	}
116
117      while (list)
118	{
119	  sig = decode_signal (list->word->word, opt);
120
121	  if (sig == NO_SIG)
122	    {
123	      sh_invalidsig (list->word->word);
124	      result = EXECUTION_FAILURE;
125	    }
126	  else
127	    {
128	      switch (operation)
129		{
130		  case SET:
131		    set_signal (sig, first_arg);
132		    break;
133
134		  case REVERT:
135		    restore_default_signal (sig);
136
137		    /* Signals that the shell treats specially need special
138		       handling. */
139		    switch (sig)
140		      {
141		      case SIGINT:
142			if (interactive)
143			  set_signal_handler (SIGINT, sigint_sighandler);
144			else
145			  set_signal_handler (SIGINT, termsig_sighandler);
146			break;
147
148		      case SIGQUIT:
149			/* Always ignore SIGQUIT. */
150			set_signal_handler (SIGQUIT, SIG_IGN);
151			break;
152		      case SIGTERM:
153#if defined (JOB_CONTROL)
154		      case SIGTTIN:
155		      case SIGTTOU:
156		      case SIGTSTP:
157#endif /* JOB_CONTROL */
158			if (interactive)
159			  set_signal_handler (sig, SIG_IGN);
160			break;
161		      }
162		    break;
163
164		  case IGNORE:
165		    ignore_signal (sig);
166		    break;
167		}
168	    }
169	  list = list->next;
170	}
171    }
172
173  return (result);
174}
175
176static void
177showtrap (i)
178     int i;
179{
180  char *t, *p, *sn;
181
182  p = trap_list[i];
183  if (p == (char *)DEFAULT_SIG)
184    return;
185
186  t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
187  sn = signal_name (i);
188  /* Make sure that signals whose names are unknown (for whatever reason)
189     are printed as signal numbers. */
190  if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
191    printf ("trap -- %s %d\n", t ? t : "''", i);
192  else if (posixly_correct)
193    {
194      if (STREQN (sn, "SIG", 3))
195	printf ("trap -- %s %s\n", t ? t : "''", sn+3);
196      else
197	printf ("trap -- %s %s\n", t ? t : "''", sn);
198    }
199  else
200    printf ("trap -- %s %s\n", t ? t : "''", sn);
201
202  FREE (t);
203}
204
205static int
206display_traps (list)
207     WORD_LIST *list;
208{
209  int result, i;
210
211  if (list == 0)
212    {
213      for (i = 0; i < BASH_NSIG; i++)
214	showtrap (i);
215      return (EXECUTION_SUCCESS);
216    }
217
218  for (result = EXECUTION_SUCCESS; list; list = list->next)
219    {
220      i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
221      if (i == NO_SIG)
222	{
223	  sh_invalidsig (list->word->word);
224	  result = EXECUTION_FAILURE;
225	}
226      else
227	showtrap (i);
228    }
229
230  return (result);
231}
232