home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / sh / trap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-15  |  6.8 KB  |  328 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kenneth Almquist.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)trap.c    5.2 (Berkeley) 4/12/91";
  39. #endif /* not lint */
  40.  
  41. #include "shell.h"
  42. #include "main.h"
  43. #include "nodes.h"    /* for other headers */
  44. #include "eval.h"
  45. #include "jobs.h"
  46. #include "options.h"
  47. #include "syntax.h"
  48. #include "signames.h"
  49. #include "output.h"
  50. #include "memalloc.h"
  51. #include "error.h"
  52. #include "trap.h"
  53. #include "mystring.h"
  54. #include <signal.h>
  55.  
  56.  
  57. /*
  58.  * Sigmode records the current value of the signal handlers for the various
  59.  * modes.  A value of zero means that the current handler is not known.
  60.  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
  61.  */
  62.  
  63. #define S_DFL 1            /* default signal handling (SIG_DFL) */
  64. #define S_CATCH 2        /* signal is caught */
  65. #define S_IGN 3            /* signal is ignored (SIG_IGN) */
  66. #define S_HARD_IGN 4        /* signal is ignored permenantly */
  67.  
  68.  
  69. extern char nullstr[1];        /* null string */
  70.  
  71. char *trap[MAXSIG+1];        /* trap handler commands */
  72. MKINIT char sigmode[MAXSIG];    /* current value of signal */
  73. char gotsig[MAXSIG];        /* indicates specified signal received */
  74. int pendingsigs;            /* indicates some signal received */
  75.  
  76. /*
  77.  * The trap builtin.
  78.  */
  79.  
  80. trapcmd(argc, argv)  char **argv; {
  81.     char *action;
  82.     char **ap;
  83.     int signo;
  84.  
  85.     if (argc <= 1) {
  86.         for (signo = 0 ; signo <= MAXSIG ; signo++) {
  87.             if (trap[signo] != NULL)
  88.                 out1fmt("%d: %s\n", signo, trap[signo]);
  89.         }
  90.         return 0;
  91.     }
  92.     ap = argv + 1;
  93.     if (is_number(*ap))
  94.         action = NULL;
  95.     else
  96.         action = *ap++;
  97.     while (*ap) {
  98.         if ((signo = number(*ap)) < 0 || signo > MAXSIG)
  99.             error("%s: bad trap", *ap);
  100.         INTOFF;
  101.         if (action)
  102.             action = savestr(action);
  103.         if (trap[signo])
  104.             ckfree(trap[signo]);
  105.         trap[signo] = action;
  106.         if (signo != 0)
  107.             setsignal(signo);
  108.         INTON;
  109.         ap++;
  110.     }
  111.     return 0;
  112. }
  113.  
  114.  
  115.  
  116. /*
  117.  * Clear traps on a fork.
  118.  */
  119.  
  120. void
  121. clear_traps() {
  122.     char **tp;
  123.  
  124.     for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) {
  125.         if (*tp && **tp) {    /* trap not NULL or SIG_IGN */
  126.             INTOFF;
  127.             ckfree(*tp);
  128.             *tp = NULL;
  129.             if (tp != &trap[0])
  130.                 setsignal(tp - trap);
  131.             INTON;
  132.         }
  133.     }
  134. }
  135.  
  136.  
  137.  
  138. /*
  139.  * Set the signal handler for the specified signal.  The routine figures
  140.  * out what it should be set to.
  141.  */
  142.  
  143. int
  144. setsignal(signo) {
  145.     int action;
  146.     sig_t sigact;
  147.     char *t;
  148.     extern void onsig();
  149.  
  150.     if ((t = trap[signo]) == NULL)
  151.         action = S_DFL;
  152.     else if (*t != '\0')
  153.         action = S_CATCH;
  154.     else
  155.         action = S_IGN;
  156.     if (rootshell && action == S_DFL) {
  157.         switch (signo) {
  158.         case SIGINT:
  159.             if (iflag)
  160.                 action = S_CATCH;
  161.             break;
  162.         case SIGQUIT:
  163. #ifdef DEBUG
  164.             {
  165.             extern int debug;
  166.  
  167.             if (debug)
  168.                 break;
  169.             }
  170. #endif
  171.             /* FALLTHROUGH */
  172.         case SIGTERM:
  173.             if (iflag)
  174.                 action = S_IGN;
  175.             break;
  176. #if JOBS
  177.         case SIGTSTP:
  178.         case SIGTTOU:
  179.             if (jflag)
  180.                 action = S_IGN;
  181.             break;
  182. #endif
  183.         }
  184.     }
  185.     t = &sigmode[signo - 1];
  186.     if (*t == 0) {    /* current setting unknown */
  187.         /*
  188.          * There is a race condition here if action is not S_IGN.
  189.          * A signal can be ignored that shouldn't be.
  190.          */
  191.         if ((int)(sigact = signal(signo, SIG_IGN)) == -1)
  192.             error("Signal system call failed");
  193.         if (sigact == SIG_IGN) {
  194.             *t = S_HARD_IGN;
  195.         } else {
  196.             *t = S_IGN;
  197.         }
  198.     }
  199.     if (*t == S_HARD_IGN || *t == action)
  200.         return 0;
  201.     switch (action) {
  202.         case S_DFL:    sigact = SIG_DFL;    break;
  203.         case S_CATCH:      sigact = onsig;        break;
  204.         case S_IGN:    sigact = SIG_IGN;    break;
  205.     }
  206.     *t = action;
  207.     return (int)signal(signo, sigact);
  208. }
  209.  
  210.  
  211. /*
  212.  * Ignore a signal.
  213.  */
  214.  
  215. void
  216. ignoresig(signo) {
  217.     if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
  218.         signal(signo, SIG_IGN);
  219.     }
  220.     sigmode[signo - 1] = S_HARD_IGN;
  221. }
  222.  
  223.  
  224. #ifdef mkinit
  225. INCLUDE "signames.h"
  226. INCLUDE "trap.h"
  227.  
  228. SHELLPROC {
  229.     char *sm;
  230.  
  231.     clear_traps();
  232.     for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) {
  233.         if (*sm == S_IGN)
  234.             *sm = S_HARD_IGN;
  235.     }
  236. }
  237. #endif
  238.  
  239.  
  240.  
  241. /*
  242.  * Signal handler.
  243.  */
  244.  
  245. void
  246. onsig(signo) {
  247.     signal(signo, onsig);
  248.     if (signo == SIGINT && trap[SIGINT] == NULL) {
  249.         onint();
  250.         return;
  251.     }
  252.     gotsig[signo - 1] = 1;
  253.     pendingsigs++;
  254. }
  255.  
  256.  
  257.  
  258. /*
  259.  * Called to execute a trap.  Perhaps we should avoid entering new trap
  260.  * handlers while we are executing a trap handler.
  261.  */
  262.  
  263. void
  264. dotrap() {
  265.     int i;
  266.     int savestatus;
  267.  
  268.     for (;;) {
  269.         for (i = 1 ; ; i++) {
  270.             if (gotsig[i - 1])
  271.                 break;
  272.             if (i >= MAXSIG)
  273.                 goto done;
  274.         }
  275.         gotsig[i - 1] = 0;
  276.         savestatus=exitstatus;
  277.         evalstring(trap[i]);
  278.         exitstatus=savestatus;
  279.     }
  280. done:
  281.     pendingsigs = 0;
  282. }
  283.  
  284.  
  285.  
  286. /*
  287.  * Controls whether the shell is interactive or not.
  288.  */
  289.  
  290. int is_interactive;
  291.  
  292. void
  293. setinteractive(on) {
  294.     if (on == is_interactive)
  295.         return;
  296.     setsignal(SIGINT);
  297.     setsignal(SIGQUIT);
  298.     setsignal(SIGTERM);
  299.     is_interactive = on;
  300. }
  301.  
  302.  
  303.  
  304. /*
  305.  * Called to exit the shell.
  306.  */
  307.  
  308. void
  309. exitshell(status) {
  310.     struct jmploc loc1, loc2;
  311.     char *p;
  312.  
  313.     TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
  314.     if (setjmp(loc1.loc))  goto l1;
  315.     if (setjmp(loc2.loc))  goto l2;
  316.     handler = &loc1;
  317.     if ((p = trap[0]) != NULL && *p != '\0') {
  318.         trap[0] = NULL;
  319.         evalstring(p);
  320.     }
  321. l1:   handler = &loc2;            /* probably unnecessary */
  322.     flushall();
  323. #if JOBS
  324.     setjobctl(0);
  325. #endif
  326. l2:   _exit(status);
  327. }
  328.