home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR24 / BASH_112.ZIP / BASH-112.TAR / bash-1.12 / trap.c < prev    next >
C/C++ Source or Header  |  1992-01-20  |  13KB  |  526 lines

  1. /* trap.c -- Not the trap command, but useful functions
  2.    for manipulating those objects.  The trap command is
  3.    in builtins.c */
  4.  
  5. /* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
  6.  
  7. This file is part of GNU Bash, the Bourne Again SHell.
  8.  
  9. Bash is free software; you can redistribute it and/or modify it under
  10. the terms of the GNU General Public License as published by the Free
  11. Software Foundation; either version 1, or (at your option) any later
  12. version.
  13.  
  14. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  15. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  17. for more details.
  18.  
  19. You should have received a copy of the GNU General Public License along
  20. with Bash; see the file COPYING.  If not, write to the Free Software
  21. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  22.  
  23. #include <sys/types.h>
  24. #include "trap.h"
  25. #include "shell.h"
  26.  
  27. extern int last_command_exit_value;
  28.  
  29. /* The list of things to do originally, before we started trapping. */
  30. SigHandler *original_signals[NSIG];
  31.  
  32. /* For each signal, a slot for a string, which is a command to be
  33.    executed when that signal is recieved.  The slot can also contain
  34.    DEFAULT_SIG, which means do whatever you were going to do before
  35.    you were so rudely interrupted, or IGNORE_SIG, which says ignore
  36.    this signal. */
  37. char *trap_list[NSIG];
  38.  
  39. /* A translation list so we can be polite to our users. */
  40. char *signal_names[NSIG];
  41.  
  42. /* A bitmap of signals received for which we have trap handlers. */
  43. int pending_traps[NSIG];
  44.  
  45. static int signal_names_initialized = 0;
  46.  
  47. initialize_traps ()
  48. {
  49.   register int i;
  50.  
  51.   if (!signal_names_initialized)
  52.     {
  53.       for (i = 1; i < NSIG; i++)
  54.         {
  55.       signal_names[i] = (char *)NULL;
  56.       pending_traps[i] = 0;
  57.         }
  58.  
  59.       /* `signal' 0 is what we do on exit. */
  60.       signal_names[0] = "EXIT";
  61.  
  62. #if defined (SIGHUP)        /* hangup */
  63.       signal_names[SIGHUP] = "SIGHUP";
  64. #endif
  65.  
  66. #if defined (SIGINT)        /* interrupt */
  67.       signal_names[SIGINT] = "SIGINT";
  68. #endif
  69.  
  70. #if defined (SIGQUIT)        /* quit */
  71.       signal_names[SIGQUIT] = "SIGQUIT";
  72. #endif
  73.  
  74. #if defined (SIGILL)        /* illegal instruction (not reset when caught) */
  75.       signal_names[SIGILL] = "SIGILL";
  76. #endif
  77.  
  78. #if defined (SIGTRAP)        /* trace trap (not reset when caught) */
  79.       signal_names[SIGTRAP] = "SIGTRAP";
  80. #endif
  81.  
  82. #if defined (SIGABRT)        /*  */
  83.       signal_names[SIGABRT] = "SIGABRT";
  84. #endif
  85.  
  86. #if defined (SIGIOT)        /* IOT instruction */
  87.       signal_names[SIGIOT] = "SIGIOT";
  88. #endif
  89.  
  90. #if defined (SIGEMT)        /* EMT instruction */
  91.       signal_names[SIGEMT] = "SIGEMT";
  92. #endif
  93.  
  94. #if defined (SIGFPE)        /* floating point exception */
  95.       signal_names[SIGFPE] = "SIGFPE";
  96. #endif
  97.  
  98. #if defined (SIGKILL)        /* kill (cannot be caught or ignored) */
  99.       signal_names[SIGKILL] = "SIGKILL";
  100. #endif
  101.  
  102. #if defined (SIGBUS)        /* bus error */
  103.       signal_names[SIGBUS] = "SIGBUS";
  104. #endif
  105.  
  106. #if defined (SIGSEGV)        /* segmentation violation */
  107.       signal_names[SIGSEGV] = "SIGSEGV";
  108. #endif
  109.  
  110. #if defined (SIGSYS)        /* bad argument to system call */
  111.       signal_names[SIGSYS] = "SIGSYS";
  112. #endif
  113.  
  114. #if defined (SIGPIPE)        /* write on a pipe with no one to read it */
  115.       signal_names[SIGPIPE] = "SIGPIPE";
  116. #endif
  117.  
  118. #if defined (SIGALRM)        /* alarm clock */
  119.       signal_names[SIGALRM] = "SIGALRM";
  120. #endif
  121.  
  122. #if defined (SIGTERM)        /* software termination signal from kill */
  123.       signal_names[SIGTERM] = "SIGTERM";
  124. #endif
  125.  
  126. #if defined (SIGCLD)        /* Like SIGCHLD.  */
  127.       signal_names[SIGCLD] = "SIGCLD";
  128. #endif
  129.  
  130. #if defined (SIGPWR)        /* Magic thing for some machines. */
  131.       signal_names[SIGPWR] = "SIGPWR";
  132. #endif
  133.  
  134. #if defined (SIGPOLL)        /* For keyboard input?  */
  135.       signal_names[SIGPOLL] = "SIGPOLL";
  136. #endif
  137.  
  138. #if defined (SIGURG)        /* urgent condition on IO channel */
  139.       signal_names[SIGURG] = "SIGURG";
  140. #endif
  141.  
  142. #if defined (SIGSTOP)        /* sendable stop signal not from tty */
  143.       signal_names[SIGSTOP] = "SIGSTOP";
  144. #endif
  145.  
  146. #if defined (SIGTSTP)        /* stop signal from tty */
  147.       signal_names[SIGTSTP] = "SIGTSTP";
  148. #endif
  149.  
  150. #if defined (SIGCONT)        /* continue a stopped process */
  151.       signal_names[SIGCONT] = "SIGCONT";
  152. #endif
  153.  
  154. #if defined (SIGCHLD)        /* to parent on child stop or exit */
  155.       signal_names[SIGCHLD] = "SIGCHLD";
  156. #endif
  157.  
  158. #if defined (SIGTTIN)        /* to readers pgrp upon background tty read */
  159.       signal_names[SIGTTIN] = "SIGTTIN";
  160. #endif
  161.  
  162. #if defined (SIGTTOU)        /* like TTIN for output if (tp->t_local<OSTOP) */
  163.       signal_names[SIGTTOU] = "SIGTTOU";
  164. #endif
  165.  
  166. #if defined (SIGIO)        /* input/output possible signal */
  167.       signal_names[SIGIO] = "SIGIO";
  168. #endif
  169.  
  170. #if defined (SIGXCPU)        /* exceeded CPU time limit */
  171.       signal_names[SIGXCPU] = "SIGXCPU";
  172. #endif
  173.  
  174. #if defined (SIGXFSZ)        /* exceeded file size limit */
  175.       signal_names[SIGXFSZ] = "SIGXFSZ";
  176. #endif
  177.  
  178. #if defined (SIGVTALRM)        /* virtual time alarm */
  179.       signal_names[SIGVTALRM] = "SIGVTALRM";
  180. #endif
  181.  
  182. #if defined (SIGPROF)        /* profiling time alarm */
  183.       signal_names[SIGPROF] = "SIGPROF";
  184. #endif
  185.  
  186. #if defined (SIGWINCH)        /* window changed */
  187.       signal_names[SIGWINCH] = "SIGWINCH";
  188. #endif
  189.  
  190. #if defined (SIGLOST)        /* resource lost (eg, record-lock lost) */
  191.       signal_names[SIGLOST] = "SIGLOST";
  192. #endif
  193.  
  194. #if defined (SIGUSR1)        /* user defined signal 1 */
  195.       signal_names[SIGUSR1] = "SIGUSR1";
  196. #endif
  197.  
  198. #if defined (SIGUSR2)        /* user defined signal 2 */
  199.       signal_names[SIGUSR2] = "SIGUSR2";
  200. #endif
  201.  
  202. #if defined (SIGMSG)    /* HFT input data pending */
  203.       signal_names[SIGMSG] = "SIGMSG";
  204. #endif
  205.  
  206. #if defined (SIGPWR)    /* power failure imminent (save your data) */
  207.       signal_names[SIGPWR] = "SIGPWR";
  208. #endif
  209.  
  210. #if defined (SIGDANGER)    /* system crash imminent */
  211.       signal_names[SIGDANGER] = "SIGDANGER";
  212. #endif
  213.  
  214. #if defined (SIGMIGRATE)    /* migrate process to another CPU */
  215.       signal_names[SIGMIGRATE] = "SIGMIGRATE";
  216. #endif
  217.  
  218. #if defined (SIGPRE)    /* programming error */
  219.       signal_names[SIGPRE] = "SIGPRE";
  220. #endif
  221.  
  222. #if defined (SIGGRANT)    /* HFT monitor mode granted */
  223.       signal_names[SIGGRANT] = "SIGGRANT";
  224. #endif
  225.  
  226. #if defined (SIGRETRACT)    /* HFT monitor mode retracted */
  227.       signal_names[SIGRETRACT] = "SIGRETRACT";
  228. #endif
  229.  
  230. #if defined (SIGSOUND)    /* HFT sound sequence has completed */
  231.       signal_names[SIGSOUND] = "SIGSOUND";
  232. #endif
  233.  
  234.       for (i = 0; i < NSIG; i++)
  235.     if (signal_names[i] == (char *)NULL)
  236.       {
  237.         signal_names[i] = (char *)xmalloc (10 + strlen ("SIGJUNK"));
  238.         sprintf (signal_names[i], "SIGJUNK(%d)", i);
  239.       }
  240.     }
  241.  
  242.  
  243.   trap_list[0] = (char *)NULL;
  244.  
  245.   for (i = 1; i < NSIG; i++)
  246.     {
  247.       trap_list[i] = (char *)DEFAULT_SIG;
  248.       original_signals[i] = (SigHandler *)signal (i, SIG_DFL);
  249.       signal (i, original_signals[i]);
  250.     }
  251. }
  252.  
  253. /* Return the print name of this signal. */
  254. char *
  255. signal_name (signal)
  256.      int signal;
  257. {
  258.   if (signal > NSIG)
  259.      return ("bad signal number");
  260.   else return (signal_names[signal]);
  261. }
  262.  
  263. /* Turn a string into a signal number, or a number into
  264.    a signal number.  If STRING is "2", "SIGINT", or "INT",
  265.    then (int)2 is returned.  Return NO_SIG if STRING doesn't
  266.    contain a valid signal descriptor. */
  267. int
  268. decode_signal (string)
  269.      char *string;
  270. {
  271.   int sig;
  272.  
  273.   if (sscanf (string, "%d", &sig) == 1)
  274.     {
  275.       if (sig < NSIG && sig >= 0)
  276.     return (sig);
  277.       else
  278.     return (NO_SIG);
  279.     }
  280.  
  281.   for (sig = 0; sig < NSIG; sig++)
  282.     if ((stricmp (string, signal_names[sig]) == 0) ||
  283.     (stricmp (string, &(signal_names[sig])[3]) == 0))
  284.       return (sig);
  285.  
  286.   return (NO_SIG);
  287. }
  288.  
  289. /* Non-zero when we catch a trapped signal. */
  290. static int catch_flag = 0;
  291.  
  292. #if !defined (USG) && !defined (USGr4)
  293. #define HAVE_BSD_SIGNALS
  294. #endif
  295.  
  296. run_pending_traps ()
  297. {
  298.   register int sig;
  299.   int old_exit_value;
  300.  
  301.   if (catch_flag == 0)        /* simple optimization */
  302.     return;
  303.  
  304.   catch_flag = 0;
  305.  
  306.   /* Preserve $? when running trap. */
  307.   old_exit_value = last_command_exit_value;
  308.  
  309.   for (sig = 0; sig < NSIG; sig++)
  310.     {
  311.       if (pending_traps[sig])
  312.     {
  313. #if defined (_POSIX_VERSION)
  314.       sigset_t set, oset;
  315.  
  316.       sigemptyset (&set);
  317.       sigemptyset (&oset);
  318.  
  319.       sigaddset (&set, sig);
  320.       sigprocmask (SIG_BLOCK, &set, &oset);
  321. #else
  322. #  if defined (HAVE_BSD_SIGNALS)
  323.       int oldmask = sigblock (sigmask (sig));
  324. #  endif
  325. #endif /* POSIX_VERSION */
  326.  
  327.       parse_and_execute (savestring (trap_list[sig]), "trap");
  328.       pending_traps[sig] = 0;
  329.  
  330. #if defined (_POSIX_VERSION)
  331.       sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
  332. #else
  333. #  if defined (HAVE_BSD_SIGNALS)
  334.       sigsetmask (oldmask);
  335. #  endif
  336. #endif /* POSIX_VERSION */
  337.     }
  338.     }
  339.  
  340.   last_command_exit_value = old_exit_value;
  341. }
  342.  
  343. sighandler
  344. trap_handler (sig)
  345.      int sig;
  346. {
  347.   extern int interrupt_immediately;
  348.  
  349.   if ((sig >= NSIG) ||
  350.       (trap_list[sig] == (char *)DEFAULT_SIG) ||
  351.       (trap_list[sig] == (char *)IGNORE_SIG))
  352.     programming_error ("trap_handler: Bad signal %d", sig);
  353.   else
  354.     {
  355.  
  356. #if defined (USG) && !defined (HAVE_BSD_SIGNALS)
  357.       signal (sig, trap_handler);
  358. #endif /* USG && !HAVE_BSD_SIGNALS */
  359.  
  360.       catch_flag = 1;
  361.       pending_traps[sig]++;
  362.  
  363.       if (interrupt_immediately)
  364.     run_pending_traps ();
  365.     }
  366. #if !defined (VOID_SIGHANDLER)
  367.   return (0);
  368. #endif /* VOID_SIGHANDLER */
  369. }
  370.  
  371. /* Set SIG to call STRING as a command. */
  372. void
  373. set_signal (sig, string)
  374.      int sig;
  375.      char *string;
  376. {
  377.   void change_signal ();
  378.  
  379.   /* A signal ignored on entry to the shell cannot be trapped or reset, but
  380.      no error is reported when attempting to do so.  -- Posix.2 */
  381.   if (original_signals[sig] == SIG_IGN)
  382.     return;
  383.  
  384. #if defined (SIGCHLD)
  385.   /* Don't change the function that catches SIGCHLD, but store the command
  386.      to be executed.  It will be run from jobs.c: flush_child(). */
  387.   if (sig &&
  388.       sig != SIGINT &&
  389.       sig != SIGCHLD)
  390. #else
  391.   if (sig && sig != SIGINT)
  392. #endif /* SIGCHLD */
  393.     signal (sig, SIG_IGN);
  394.  
  395.   change_signal (sig, savestring (string));
  396.  
  397. #if defined (SIGCHLD)
  398.   /* Don't change the function that catches SIGCHLD, but store the command
  399.      to be executed.  It will be run from jobs.c: flush_child().  Do the
  400.      same thing for SIGINT; the trap commands are run from
  401.      run_interrupt_trap (), which is called from throw_to_top_level (). */
  402.   if (sig &&
  403.       sig != SIGINT &&
  404.       sig != SIGCHLD)
  405. #else
  406.   if (sig && sig != SIGINT)
  407. #endif /* SIGCHLD */
  408.     signal (sig, trap_handler);
  409. }
  410.  
  411. /* If SIG has a string assigned to it, get rid of it.  Then give it
  412.    VALUE. */
  413. void
  414. change_signal (sig, value)
  415.      int sig;
  416.      char *value;
  417. {
  418.   if ((((int)trap_list[sig]) > 0) && (trap_list[sig] != (char *)IGNORE_SIG))
  419.     free (trap_list[sig]);
  420.   trap_list[sig] = value;
  421. }
  422.  
  423. /* Restore the default action for SIG; i.e., the action the shell
  424.    would have taken before you used the trap command. */
  425. void
  426. restore_default_signal (sig)
  427.      int sig;
  428. {
  429. #if defined (SIGCHLD)
  430.   /* Don't allow the signal catchers for SIGINT or SIGCHLD
  431.      to be overridden. */
  432.   if (sig != SIGINT && sig != SIGCHLD)
  433. #else
  434.   if (sig != SIGINT)
  435. #endif /* !SIGCHLD */
  436.     signal (sig, original_signals[sig]);
  437.  
  438.   change_signal (sig, (char *)DEFAULT_SIG);
  439. }
  440.  
  441. /* Make this signal be ignored. */
  442. void
  443. ignore_signal (sig)
  444.      int sig;
  445. {
  446. #ifdef SIGCHLD
  447.   /* Don't allow the SIGCHLD signal catcher to be overridden. */
  448.   if (sig != SIGCHLD)
  449. #endif
  450.     signal (sig, SIG_IGN);
  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. void
  458. run_exit_trap ()
  459. {
  460.   if ((trap_list[0] != (char *)DEFAULT_SIG) &&
  461.       (trap_list[0] != (char *)IGNORE_SIG))
  462.     {
  463.       char *trap_command = savestring (trap_list[0]);
  464.       int code, old_exit_value;
  465.  
  466.       old_exit_value = last_command_exit_value;
  467.       change_signal (0, (char *)NULL);
  468.       code = setjmp (top_level);
  469.  
  470.       if (code == 0)
  471.     parse_and_execute (trap_command, "trap");
  472.  
  473.       last_command_exit_value = old_exit_value;
  474.     }
  475. }
  476.       
  477. /* Reset all trapped signals to their original values.  Signals set to be
  478.    ignored with trap '' SIGNAL should be ignored, so we make sure that they
  479.    are. */
  480. void
  481. restore_original_signals ()
  482. {
  483.   register int i;
  484.  
  485.   for (i = 0; i < NSIG; i++)
  486.     {
  487.       if (trap_list[i] != (char *)DEFAULT_SIG)
  488.     {
  489.       if (trap_list[i] == (char *)IGNORE_SIG)
  490.         signal (i, SIG_IGN);
  491.       else
  492.         restore_default_signal (i);
  493.     }
  494.       else
  495.     {
  496.       /* If it's one of the signals the shell handles specially,
  497.          make sure it gets set back to the value it had when the
  498.          shell was started. */
  499.       if (i == SIGINT || i == SIGQUIT || i == SIGTERM)
  500.         restore_default_signal (i);
  501.     }
  502.     }
  503. }
  504.  
  505. /* Run a trap set on SIGINT.  This is called from throw_to_top_level (), and
  506.    declared here to localize the trap functions. */
  507. run_interrupt_trap ()
  508. {
  509.   char *command, *saved_command;
  510.   int old_exit_value;
  511.  
  512.   if ((trap_list[SIGINT] != (char *) DEFAULT_SIG) &&
  513.       (trap_list[SIGINT] != (char *) IGNORE_SIG))
  514.     {
  515.       command = savestring (trap_list[SIGINT]);
  516.  
  517.       old_exit_value = last_command_exit_value;
  518.       saved_command = trap_list[SIGINT];
  519.       unwind_protect_string (trap_list[SIGINT]);
  520.       trap_list[SIGINT] = (char *)NULL;
  521.       parse_and_execute (command, "interrupt trap");
  522.       trap_list[SIGINT] = saved_command;
  523.       last_command_exit_value = old_exit_value;
  524.     }
  525. }
  526.