305 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
	
		
			8 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
| This file is trap.def, from which is created trap.c.
 | |
| It implements the builtin "trap" in Bash.
 | |
| 
 | |
| Copyright (C) 1987-2015 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Bash, the Bourne Again SHell.
 | |
| 
 | |
| Bash is free software: you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation, either version 3 of the License, or
 | |
| (at your option) any later version.
 | |
| 
 | |
| Bash is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| $PRODUCES trap.c
 | |
| 
 | |
| $BUILTIN trap
 | |
| $FUNCTION trap_builtin
 | |
| $SHORT_DOC trap [-lp] [[arg] signal_spec ...]
 | |
| Trap signals and other events.
 | |
| 
 | |
| Defines and activates handlers to be run when the shell receives signals
 | |
| or other conditions.
 | |
| 
 | |
| ARG is a command to be read and executed when the shell receives the
 | |
| signal(s) SIGNAL_SPEC.  If ARG is absent (and a single SIGNAL_SPEC
 | |
| is supplied) or `-', each specified signal is reset to its original
 | |
| value.  If ARG is the null string each SIGNAL_SPEC is ignored by the
 | |
| shell and by the commands it invokes.
 | |
| 
 | |
| If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell.  If
 | |
| a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.  If
 | |
| a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
 | |
| script run by the . or source builtins finishes executing.  A SIGNAL_SPEC
 | |
| of ERR means to execute ARG each time a command's failure would cause the
 | |
| shell to exit when the -e option is enabled.
 | |
| 
 | |
| If no arguments are supplied, trap prints the list of commands associated
 | |
| with each signal.
 | |
| 
 | |
| Options:
 | |
|   -l	print a list of signal names and their corresponding numbers
 | |
|   -p	display the trap commands associated with each SIGNAL_SPEC
 | |
| 
 | |
| Each SIGNAL_SPEC is either a signal name in <signal.h> or a signal number.
 | |
| Signal names are case insensitive and the SIG prefix is optional.  A
 | |
| signal may be sent to the shell with "kill -signal $$".
 | |
| 
 | |
| Exit Status:
 | |
| Returns success unless a SIGSPEC is invalid or an invalid option is given.
 | |
| $END
 | |
| 
 | |
| #include <config.h>
 | |
| 
 | |
| #if defined (HAVE_UNISTD_H)
 | |
| #  ifdef _MINIX
 | |
| #    include <sys/types.h>
 | |
| #  endif
 | |
| #  include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #include "../bashtypes.h"
 | |
| #include <signal.h>
 | |
| #include <stdio.h>
 | |
| #include "../bashansi.h"
 | |
| 
 | |
| #include "../shell.h"
 | |
| #include "../trap.h"
 | |
| #include "common.h"
 | |
| #include "bashgetopt.h"
 | |
| 
 | |
| static void showtrap __P((int));
 | |
| static int display_traps __P((WORD_LIST *));
 | |
| 
 | |
| /* The trap command:
 | |
| 
 | |
|    trap <arg> <signal ...>
 | |
|    trap <signal ...>
 | |
|    trap -l
 | |
|    trap -p [sigspec ...]
 | |
|    trap [--]
 | |
| 
 | |
|    Set things up so that ARG is executed when SIGNAL(s) N is received.
 | |
|    If ARG is the empty string, then ignore the SIGNAL(s).  If there is
 | |
|    no ARG, then set the trap for SIGNAL(s) to its original value.  Just
 | |
|    plain "trap" means to print out the list of commands associated with
 | |
|    each signal number.  Single arg of "-l" means list the signal names. */
 | |
| 
 | |
| /* Possible operations to perform on the list of signals.*/
 | |
| #define SET 0			/* Set this signal to first_arg. */
 | |
| #define REVERT 1		/* Revert to this signals original value. */
 | |
| #define IGNORE 2		/* Ignore this signal. */
 | |
| 
 | |
| extern int posixly_correct, subshell_environment;
 | |
| 
 | |
| int
 | |
| trap_builtin (list)
 | |
|      WORD_LIST *list;
 | |
| {
 | |
|   int list_signal_names, display, result, opt;
 | |
| 
 | |
|   list_signal_names = display = 0;
 | |
|   result = EXECUTION_SUCCESS;
 | |
| 
 | |
|   reset_internal_getopt ();
 | |
|   while ((opt = internal_getopt (list, "lp")) != -1)
 | |
|     {
 | |
|       switch (opt)
 | |
| 	{
 | |
| 	case 'l':
 | |
| 	  list_signal_names++;
 | |
| 	  break;
 | |
| 	case 'p':
 | |
| 	  display++;
 | |
| 	  break;
 | |
| 	CASE_HELPOPT;
 | |
| 	default:
 | |
| 	  builtin_usage ();
 | |
| 	  return (EX_USAGE);
 | |
| 	}
 | |
|     }
 | |
|   list = loptend;
 | |
| 
 | |
|   opt = DSIG_NOCASE|DSIG_SIGPREFIX;	/* flags for decode_signal */
 | |
| 
 | |
|   if (list_signal_names)
 | |
|     return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1)));
 | |
|   else if (display || list == 0)
 | |
|     {
 | |
|       initialize_terminating_signals ();
 | |
|       get_all_original_signals ();
 | |
|       return (sh_chkwrite (display_traps (list)));
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       char *first_arg;
 | |
|       int operation, sig, first_signal;
 | |
| 
 | |
|       operation = SET;
 | |
|       first_arg = list->word->word;
 | |
|       first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
 | |
| 
 | |
|       /* Backwards compatibility.  XXX - question about whether or not we
 | |
| 	 should throw an error if an all-digit argument doesn't correspond
 | |
| 	 to a valid signal number (e.g., if it's `50' on a system with only
 | |
| 	 32 signals).  */
 | |
|       if (first_signal)
 | |
| 	operation = REVERT;
 | |
|       /* When in posix mode, the historical behavior of looking for a
 | |
| 	 missing first argument is disabled.  To revert to the original
 | |
| 	 signal handling disposition, use `-' as the first argument. */
 | |
|       else if (posixly_correct == 0 && first_arg && *first_arg &&
 | |
| 		(*first_arg != '-' || first_arg[1]) &&
 | |
| 		signal_object_p (first_arg, opt) && list->next == 0)
 | |
| 	operation = REVERT;
 | |
|       else
 | |
| 	{
 | |
| 	  list = list->next;
 | |
| 	  if (list == 0)
 | |
| 	    {
 | |
| 	      builtin_usage ();
 | |
| 	      return (EX_USAGE);
 | |
| 	    }
 | |
| 	  else if (*first_arg == '\0')
 | |
| 	    operation = IGNORE;
 | |
| 	  else if (first_arg[0] == '-' && !first_arg[1])
 | |
| 	    operation = REVERT;
 | |
| 	}
 | |
| 
 | |
|       /* If we're in a command substitution, we haven't freed the trap strings
 | |
| 	 (though we reset the signal handlers).  If we're setting a trap to
 | |
| 	 handle a signal here, free the rest of the trap strings since they
 | |
| 	 don't apply any more. */
 | |
|       if (subshell_environment & SUBSHELL_RESETTRAP)
 | |
| 	{
 | |
| 	  free_trap_strings ();
 | |
| 	  subshell_environment &= ~SUBSHELL_RESETTRAP;
 | |
| 	}
 | |
| 
 | |
|       while (list)
 | |
| 	{
 | |
| 	  sig = decode_signal (list->word->word, opt);
 | |
| 
 | |
| 	  if (sig == NO_SIG)
 | |
| 	    {
 | |
| 	      sh_invalidsig (list->word->word);
 | |
| 	      result = EXECUTION_FAILURE;
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      switch (operation)
 | |
| 		{
 | |
| 		  case SET:
 | |
| 		    set_signal (sig, first_arg);
 | |
| 		    break;
 | |
| 
 | |
| 		  case REVERT:
 | |
| 		    restore_default_signal (sig);
 | |
| 
 | |
| 		    /* Signals that the shell treats specially need special
 | |
| 		       handling. */
 | |
| 		    switch (sig)
 | |
| 		      {
 | |
| 		      case SIGINT:
 | |
| 			/* XXX - should we do this if original disposition
 | |
| 			   was SIG_IGN? */
 | |
| 			if (interactive)
 | |
| 			  set_signal_handler (SIGINT, sigint_sighandler);
 | |
| 			else
 | |
| 			  set_signal_handler (SIGINT, termsig_sighandler);
 | |
| 			break;
 | |
| 
 | |
| 		      case SIGQUIT:
 | |
| 			/* Always ignore SIGQUIT. */
 | |
| 			set_signal_handler (SIGQUIT, SIG_IGN);
 | |
| 			break;
 | |
| 		      case SIGTERM:
 | |
| #if defined (JOB_CONTROL)
 | |
| 		      case SIGTTIN:
 | |
| 		      case SIGTTOU:
 | |
| 		      case SIGTSTP:
 | |
| #endif /* JOB_CONTROL */
 | |
| 			if (interactive)
 | |
| 			  set_signal_handler (sig, SIG_IGN);
 | |
| 			break;
 | |
| 		      }
 | |
| 		    break;
 | |
| 
 | |
| 		  case IGNORE:
 | |
| 		    ignore_signal (sig);
 | |
| 		    break;
 | |
| 		}
 | |
| 	    }
 | |
| 	  list = list->next;
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   return (result);
 | |
| }
 | |
| 
 | |
| static void
 | |
| showtrap (i)
 | |
|      int i;
 | |
| {
 | |
|   char *t, *p, *sn;
 | |
| 
 | |
|   p = trap_list[i];
 | |
|   if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0)
 | |
|     return;
 | |
|   else if (signal_is_hard_ignored (i))
 | |
|     t = (char *)NULL;
 | |
|   else
 | |
|     t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
 | |
| 
 | |
|   sn = signal_name (i);
 | |
|   /* Make sure that signals whose names are unknown (for whatever reason)
 | |
|      are printed as signal numbers. */
 | |
|   if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
 | |
|     printf ("trap -- %s %d\n", t ? t : "''", i);
 | |
|   else if (posixly_correct)
 | |
|     {
 | |
|       if (STREQN (sn, "SIG", 3))
 | |
| 	printf ("trap -- %s %s\n", t ? t : "''", sn+3);
 | |
|       else
 | |
| 	printf ("trap -- %s %s\n", t ? t : "''", sn);
 | |
|     }
 | |
|   else
 | |
|     printf ("trap -- %s %s\n", t ? t : "''", sn);
 | |
| 
 | |
|   FREE (t);
 | |
| }
 | |
| 
 | |
| static int
 | |
| display_traps (list)
 | |
|      WORD_LIST *list;
 | |
| {
 | |
|   int result, i;
 | |
| 
 | |
|   if (list == 0)
 | |
|     {
 | |
|       for (i = 0; i < BASH_NSIG; i++)
 | |
| 	showtrap (i);
 | |
|       return (EXECUTION_SUCCESS);
 | |
|     }
 | |
| 
 | |
|   for (result = EXECUTION_SUCCESS; list; list = list->next)
 | |
|     {
 | |
|       i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
 | |
|       if (i == NO_SIG)
 | |
| 	{
 | |
| 	  sh_invalidsig (list->word->word);
 | |
| 	  result = EXECUTION_FAILURE;
 | |
| 	}
 | |
|       else
 | |
| 	showtrap (i);
 | |
|     }
 | |
| 
 | |
|   return (result);
 | |
| }
 | 
