trap.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 static char sccsid[] = "@(#)trap.c      5.2 (Berkeley) 4/12/91";
00039 #endif /* not lint */
00040 
00041 #include "shell.h"
00042 #include "main.h"
00043 #include "nodes.h"      /* for other headers */
00044 #include "eval.h"
00045 #include "jobs.h"
00046 #include "options.h"
00047 #include "syntax.h"
00048 #include "signames.h"
00049 #include "output.h"
00050 #include "memalloc.h"
00051 #include "error.h"
00052 #include "trap.h"
00053 #include "mystring.h"
00054 #include <sys/types.h>
00055 #include <signal.h>
00056 
00057 
00058 /*
00059  * Sigmode records the current value of the signal handlers for the various
00060  * modes.  A value of zero means that the current handler is not known.
00061  * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
00062  */
00063 
00064 #define S_DFL 1                 /* default signal handling (SIG_DFL) */
00065 #define S_CATCH 2               /* signal is caught */
00066 #define S_IGN 3                 /* signal is ignored (SIG_IGN) */
00067 #define S_HARD_IGN 4            /* signal is ignored permenantly */
00068 
00069 
00070 extern char nullstr[1];         /* null string */
00071 
00072 char *trap[MAXSIG+1];           /* trap handler commands */
00073 MKINIT char sigmode[MAXSIG];    /* current value of signal */
00074 char gotsig[MAXSIG];            /* indicates specified signal received */
00075 int pendingsigs;                        /* indicates some signal received */
00076 
00077 /*
00078  * The trap builtin.
00079  */
00080 
00081 trapcmd(argc, argv)  char **argv; {
00082         char *action;
00083         char **ap;
00084         int signo;
00085 
00086         if (argc <= 1) {
00087                 for (signo = 0 ; signo <= MAXSIG ; signo++) {
00088                         if (trap[signo] != NULL)
00089                                 out1fmt("%d: %s\n", signo, trap[signo]);
00090                 }
00091                 return 0;
00092         }
00093         ap = argv + 1;
00094         if (is_number(*ap))
00095                 action = NULL;
00096         else
00097                 action = *ap++;
00098         while (*ap) {
00099                 if ((signo = number(*ap)) < 0 || signo > MAXSIG)
00100                         error("%s: bad trap", *ap);
00101                 INTOFF;
00102                 if (action)
00103                         action = savestr(action);
00104                 if (trap[signo])
00105                         ckfree(trap[signo]);
00106                 trap[signo] = action;
00107                 if (signo != 0)
00108                         setsignal(signo);
00109                 INTON;
00110                 ap++;
00111         }
00112         return 0;
00113 }
00114 
00115 
00116 
00117 /*
00118  * Clear traps on a fork.
00119  */
00120 
00121 void
00122 clear_traps() {
00123         char **tp;
00124 
00125         for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) {
00126                 if (*tp && **tp) {      /* trap not NULL or SIG_IGN */
00127                         INTOFF;
00128                         ckfree(*tp);
00129                         *tp = NULL;
00130                         if (tp != &trap[0])
00131                                 setsignal(tp - trap);
00132                         INTON;
00133                 }
00134         }
00135 }
00136 
00137 
00138 
00139 /*
00140  * Set the signal handler for the specified signal.  The routine figures
00141  * out what it should be set to.
00142  */
00143 
00144 int
00145 setsignal(signo) {
00146         int action;
00147         sig_t sigact;
00148         char *t;
00149         extern void onsig();
00150 
00151         if ((t = trap[signo]) == NULL)
00152                 action = S_DFL;
00153         else if (*t != '\0')
00154                 action = S_CATCH;
00155         else
00156                 action = S_IGN;
00157         if (rootshell && action == S_DFL) {
00158                 switch (signo) {
00159                 case SIGINT:
00160                         if (iflag)
00161                                 action = S_CATCH;
00162                         break;
00163                 case SIGQUIT:
00164 #if DEBUG
00165                         {
00166                         extern int debug;
00167 
00168                         if (debug)
00169                                 break;
00170                         }
00171 #endif
00172                         /* FALLTHROUGH */
00173                 case SIGTERM:
00174                         if (iflag)
00175                                 action = S_IGN;
00176                         break;
00177 #if JOBS
00178                 case SIGTSTP:
00179                 case SIGTTOU:
00180                         if (jflag)
00181                                 action = S_IGN;
00182                         break;
00183 #endif
00184                 }
00185         }
00186         t = &sigmode[signo - 1];
00187         if (*t == 0) {  /* current setting unknown */
00188                 /*
00189                  * There is a race condition here if action is not S_IGN.
00190                  * A signal can be ignored that shouldn't be.
00191                  */
00192                 if ((int)(sigact = signal(signo, SIG_IGN)) == -1)
00193                         error("Signal system call failed");
00194                 if (sigact == SIG_IGN) {
00195                         *t = S_HARD_IGN;
00196                 } else {
00197                         *t = S_IGN;
00198                 }
00199         }
00200         if (*t == S_HARD_IGN || *t == action)
00201                 return 0;
00202         switch (action) {
00203                 case S_DFL:     sigact = SIG_DFL;       break;
00204                 case S_CATCH:   sigact = onsig;         break;
00205                 case S_IGN:     sigact = SIG_IGN;       break;
00206         }
00207         *t = action;
00208         return (int)signal(signo, sigact);
00209 }
00210 
00211 
00212 /*
00213  * Ignore a signal.
00214  */
00215 
00216 void
00217 ignoresig(signo) {
00218         if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
00219                 signal(signo, SIG_IGN);
00220         }
00221         sigmode[signo - 1] = S_HARD_IGN;
00222 }
00223 
00224 
00225 #ifdef mkinit
00226 INCLUDE "signames.h"
00227 INCLUDE "trap.h"
00228 
00229 SHELLPROC {
00230         char *sm;
00231 
00232         clear_traps();
00233         for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) {
00234                 if (*sm == S_IGN)
00235                         *sm = S_HARD_IGN;
00236         }
00237 }
00238 #endif
00239 
00240 
00241 
00242 /*
00243  * Signal handler.
00244  */
00245 
00246 void
00247 onsig(signo) {
00248         signal(signo, onsig);
00249         if (signo == SIGINT && trap[SIGINT] == NULL) {
00250                 onint();
00251                 return;
00252         }
00253         gotsig[signo - 1] = 1;
00254         pendingsigs++;
00255 }
00256 
00257 
00258 
00259 /*
00260  * Called to execute a trap.  Perhaps we should avoid entering new trap
00261  * handlers while we are executing a trap handler.
00262  */
00263 
00264 void
00265 dotrap() {
00266         int i;
00267         int savestatus;
00268 
00269         for (;;) {
00270                 for (i = 1 ; ; i++) {
00271                         if (gotsig[i - 1])
00272                                 break;
00273                         if (i >= MAXSIG)
00274                                 goto done;
00275                 }
00276                 gotsig[i - 1] = 0;
00277                 savestatus=exitstatus;
00278                 evalstring(trap[i]);
00279                 exitstatus=savestatus;
00280         }
00281 done:
00282         pendingsigs = 0;
00283 }
00284 
00285 
00286 
00287 /*
00288  * Controls whether the shell is interactive or not.
00289  */
00290 
00291 int is_interactive;
00292 
00293 void
00294 setinteractive(on) {
00295         if (on == is_interactive)
00296                 return;
00297         setsignal(SIGINT);
00298         setsignal(SIGQUIT);
00299         setsignal(SIGTERM);
00300         is_interactive = on;
00301 }
00302 
00303 
00304 
00305 /*
00306  * Called to exit the shell.
00307  */
00308 
00309 void
00310 exitshell(status) {
00311         struct jmploc loc1, loc2;
00312         char *p;
00313 
00314         TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
00315         if (setjmp(loc1.loc))  goto l1;
00316         if (setjmp(loc2.loc))  goto l2;
00317         handler = &loc1;
00318         if ((p = trap[0]) != NULL && *p != '\0') {
00319                 trap[0] = NULL;
00320                 evalstring(p);
00321         }
00322 l1:   handler = &loc2;                  /* probably unnecessary */
00323         flushall();
00324 #if JOBS
00325         setjobctl(0);
00326 #endif
00327 l2:   _exit(status);
00328 }

Generated on Fri Apr 14 22:56:41 2006 for minix by  doxygen 1.4.6