openenvutils/commandshell/shell/src/signals.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 // signals.c - signals handling code
       
     2 //
       
     3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     4 //
       
     5 /*
       
     6  * This file is part of zsh, the Z shell.
       
     7  *
       
     8  * Copyright (c) 1992-1997 Paul Falstad
       
     9  * All rights reserved.
       
    10  *
       
    11  * Permission is hereby granted, without written agreement and without
       
    12  * license or royalty fees, to use, copy, modify, and distribute this
       
    13  * software and to distribute modified versions of this software for any
       
    14  * purpose, provided that the above copyright notice and the following
       
    15  * two paragraphs appear in all copies of this software.
       
    16  *
       
    17  * In no event shall Paul Falstad or the Zsh Development Group be liable
       
    18  * to any party for direct, indirect, special, incidental, or consequential
       
    19  * damages arising out of the use of this software and its documentation,
       
    20  * even if Paul Falstad and the Zsh Development Group have been advised of
       
    21  * the possibility of such damage.
       
    22  *
       
    23  * Paul Falstad and the Zsh Development Group specifically disclaim any
       
    24  * warranties, including, but not limited to, the implied warranties of
       
    25  * merchantability and fitness for a particular purpose.  The software
       
    26  * provided hereunder is on an "as is" basis, and Paul Falstad and the
       
    27  * Zsh Development Group have no obligation to provide maintenance,
       
    28  * support, updates, enhancements, or modifications.
       
    29  *
       
    30  */
       
    31 
       
    32 #include "zsh.mdh"
       
    33 #include "signals.pro"
       
    34 
       
    35 #ifdef __SYMBIAN32__
       
    36 #include "dummy.h"
       
    37 #endif //__SYMBIAN32__
       
    38 
       
    39 #ifdef __SYMBIAN32__
       
    40 #ifdef __WINSCW__
       
    41 #pragma warn_unusedarg off
       
    42 #endif//__WINSCW__
       
    43 #endif//__SYMBIAN32__
       
    44 
       
    45 /* Array describing the state of each signal: an element contains *
       
    46  * 0 for the default action or some ZSIG_* flags ored together.   */
       
    47 
       
    48 /**/
       
    49 mod_export int sigtrapped[VSIGCOUNT];
       
    50 
       
    51 /* trap functions for each signal */
       
    52 
       
    53 /**/
       
    54 mod_export Eprog sigfuncs[VSIGCOUNT];
       
    55 
       
    56 /* Total count of trapped signals */
       
    57 
       
    58 /**/
       
    59 mod_export int nsigtrapped;
       
    60 
       
    61 /* Variables used by signal queueing */
       
    62 
       
    63 /**/
       
    64 mod_export int queueing_enabled, queue_front, queue_rear;
       
    65 /**/
       
    66 mod_export int signal_queue[MAX_QUEUE_SIZE];
       
    67 /**/
       
    68 mod_export sigset_t signal_mask_queue[MAX_QUEUE_SIZE];
       
    69 
       
    70 /* Variables used by trap queueing */
       
    71 
       
    72 /**/
       
    73 mod_export int trap_queueing_enabled, trap_queue_front, trap_queue_rear;
       
    74 /**/
       
    75 mod_export int trap_queue[MAX_QUEUE_SIZE];
       
    76 
       
    77 /* This is only used on machines that don't understand signal sets.  *
       
    78  * On SYSV machines this will represent the signals that are blocked *
       
    79  * (held) using sighold.  On machines which can't block signals at   *
       
    80  * all, we will simulate this by ignoring them and remembering them  *
       
    81  * in this variable.                                                 */
       
    82 #if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS)
       
    83 static sigset_t blocked_set;
       
    84 #endif
       
    85 
       
    86 #ifdef POSIX_SIGNALS
       
    87 # define signal_jmp_buf       sigjmp_buf
       
    88 # define signal_setjmp(b)     sigsetjmp((b),1)
       
    89 # define signal_longjmp(b,n)  siglongjmp((b),(n))
       
    90 #else
       
    91 # define signal_jmp_buf       jmp_buf
       
    92 # define signal_setjmp(b)     setjmp(b)
       
    93 # define signal_longjmp(b,n)  longjmp((b),(n))
       
    94 #endif
       
    95  
       
    96 #ifdef NO_SIGNAL_BLOCKING
       
    97 # define signal_process(sig)  signal_ignore(sig)
       
    98 # define signal_reset(sig)    install_handler(sig)
       
    99 #else
       
   100 # define signal_process(sig)  ;
       
   101 # define signal_reset(sig)    ;
       
   102 #endif
       
   103 
       
   104 /* Install signal handler for given signal.           *
       
   105  * If possible, we want to make sure that interrupted *
       
   106  * system calls are not restarted.                    */
       
   107 
       
   108 /**/
       
   109 mod_export void
       
   110 install_handler(int sig)
       
   111 {
       
   112 #ifdef POSIX_SIGNALS
       
   113     struct sigaction act;
       
   114  
       
   115     act.sa_handler = (SIGNAL_HANDTYPE) zhandler;
       
   116     sigemptyset(&act.sa_mask);        /* only block sig while in handler */
       
   117     act.sa_flags = 0;
       
   118 # ifdef SA_INTERRUPT                  /* SunOS 4.x */
       
   119     if (interact)
       
   120         act.sa_flags |= SA_INTERRUPT; /* make sure system calls are not restarted */
       
   121 # endif
       
   122 #ifndef __SYMBIAN32__
       
   123     sigaction(sig, &act, (struct sigaction *)NULL);
       
   124 #endif    
       
   125 #else
       
   126 # ifdef BSD_SIGNALS
       
   127     struct sigvec vec;
       
   128  
       
   129     vec.sv_handler = (SIGNAL_HANDTYPE) zhandler;
       
   130     vec.sv_mask = sigmask(sig);    /* mask out this signal while in handler    */
       
   131 #  ifdef SV_INTERRUPT
       
   132     vec.sv_flags = SV_INTERRUPT;   /* make sure system calls are not restarted */
       
   133 #  endif
       
   134     sigvec(sig, &vec, (struct sigvec *)NULL);
       
   135 # else
       
   136 #  ifdef SYSV_SIGNALS
       
   137     /* we want sigset rather than signal because it will   *
       
   138      * block sig while in handler.  signal usually doesn't */
       
   139     sigset(sig, zhandler);
       
   140 #  else  /* NO_SIGNAL_BLOCKING (bummer) */
       
   141 #ifndef __SYMBIAN32__
       
   142     signal(sig, zhandler); 
       
   143 #endif
       
   144 
       
   145 #  endif /* SYSV_SIGNALS  */
       
   146 # endif  /* BSD_SIGNALS   */
       
   147 #endif   /* POSIX_SIGNALS */
       
   148 }
       
   149 
       
   150 /* enable ^C interrupts */
       
   151  
       
   152 /**/
       
   153 mod_export void
       
   154 intr(void)
       
   155 {
       
   156     if (interact)
       
   157         install_handler(SIGINT);
       
   158 }
       
   159 
       
   160 /* disable ^C interrupts */
       
   161  
       
   162 #if 0 /**/
       
   163 void
       
   164 nointr(void)
       
   165 {
       
   166     if (interact)
       
   167         signal_ignore(SIGINT);
       
   168 }
       
   169 #endif
       
   170  
       
   171 /* temporarily block ^C interrupts */
       
   172  
       
   173 /**/
       
   174 mod_export void
       
   175 holdintr(void)
       
   176 {
       
   177     if (interact)
       
   178         signal_block(signal_mask(SIGINT));
       
   179 }
       
   180 
       
   181 /* release ^C interrupts */
       
   182  
       
   183 /**/
       
   184 mod_export void
       
   185 noholdintr(void)
       
   186 {
       
   187     if (interact)
       
   188         signal_unblock(signal_mask(SIGINT));
       
   189 }
       
   190  
       
   191 /* create a signal mask containing *
       
   192  * only the given signal           */
       
   193  
       
   194 /**/
       
   195 sigset_t
       
   196 signal_mask(int sig)
       
   197 {
       
   198     sigset_t set;
       
   199  
       
   200     sigemptyset(&set);
       
   201     if (sig)
       
   202         sigaddset(&set, sig);
       
   203     return set;
       
   204 }
       
   205 
       
   206 /* Block the signals in the given signal *
       
   207  * set. Return the old signal set.       */
       
   208 
       
   209 /**/
       
   210 #ifdef POSIX_SIGNALS
       
   211 
       
   212 /**/
       
   213 mod_export sigset_t dummy_sigset1, dummy_sigset2;
       
   214 
       
   215 /**/
       
   216 #else
       
   217 
       
   218 /**/
       
   219 #ifndef BSD_SIGNALS
       
   220 
       
   221 sigset_t
       
   222 signal_block(sigset_t set)
       
   223 {
       
   224     sigset_t oset;
       
   225  
       
   226 #ifdef SYSV_SIGNALS
       
   227     int i;
       
   228  
       
   229     oset = blocked_set;
       
   230     for (i = 1; i <= NSIG; ++i) {
       
   231         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
       
   232             sigaddset(&blocked_set, i);
       
   233             sighold(i);
       
   234         }
       
   235     }
       
   236 #else  /* NO_SIGNAL_BLOCKING */
       
   237 /* We will just ignore signals if the system doesn't have *
       
   238  * the ability to block them.                             */
       
   239     int i;
       
   240 
       
   241     oset = blocked_set;
       
   242     for (i = 1; i <= NSIG; ++i) {
       
   243         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
       
   244             sigaddset(&blocked_set, i);
       
   245             signal_ignore(i);
       
   246         }
       
   247    }
       
   248 #endif /* SYSV_SIGNALS  */
       
   249  
       
   250     return oset;
       
   251 }
       
   252 
       
   253 /**/
       
   254 #endif /* BSD_SIGNALS */
       
   255 
       
   256 /**/
       
   257 #endif /* POSIX_SIGNALS */
       
   258 
       
   259 /* Unblock the signals in the given signal *
       
   260  * set. Return the old signal set.         */
       
   261 
       
   262 #ifndef POSIX_SIGNALS
       
   263 
       
   264 sigset_t
       
   265 signal_unblock(sigset_t set)
       
   266 {
       
   267 
       
   268     sigset_t oset;
       
   269     
       
   270 #ifndef __SYMBIAN32__
       
   271 # ifdef BSD_SIGNALS
       
   272     sigfillset(&oset);
       
   273     oset = sigsetmask(oset);
       
   274     sigsetmask(oset & ~set);
       
   275 # else
       
   276 #  ifdef SYSV_SIGNALS
       
   277     int i;
       
   278  
       
   279     oset = blocked_set;
       
   280     for (i = 1; i <= NSIG; ++i) {
       
   281         if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
       
   282             sigdelset(&blocked_set, i);
       
   283             sigrelse(i);
       
   284         }
       
   285     }
       
   286 #  else  /* NO_SIGNAL_BLOCKING */
       
   287 /* On systems that can't block signals, we are just ignoring them.  So *
       
   288  * to unblock signals, we just reenable the signal handler for them.   */
       
   289     int i;
       
   290 
       
   291     oset = blocked_set;
       
   292     for (i = 1; i <= NSIG; ++i) {
       
   293         if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
       
   294             sigdelset(&blocked_set, i);
       
   295             install_handler(i);
       
   296         }
       
   297    }
       
   298 #  endif /* SYSV_SIGNALS  */
       
   299 # endif  /* BSD_SIGNALS   */
       
   300  
       
   301 #endif //__SYMBIAN32__
       
   302     return oset;
       
   303 }
       
   304 
       
   305 #endif   /* POSIX_SIGNALS */
       
   306 
       
   307 /* set the process signal mask to *
       
   308  * be the given signal mask       */
       
   309 
       
   310 /**/
       
   311 mod_export sigset_t
       
   312 signal_setmask(sigset_t set)
       
   313 {
       
   314     sigset_t oset;
       
   315  
       
   316 #ifdef POSIX_SIGNALS
       
   317     sigprocmask(35, &set, &oset);
       
   318 #else
       
   319 # ifdef BSD_SIGNALS
       
   320     oset = sigsetmask(set);
       
   321 # else
       
   322 #  ifdef SYSV_SIGNALS
       
   323     int i;
       
   324  
       
   325     oset = blocked_set;
       
   326     for (i = 1; i <= NSIG; ++i) {
       
   327         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
       
   328             sigaddset(&blocked_set, i);
       
   329             sighold(i);
       
   330         } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
       
   331             sigdelset(&blocked_set, i);
       
   332             sigrelse(i);
       
   333         }
       
   334     }
       
   335 #  else  /* NO_SIGNAL_BLOCKING */
       
   336     int i;
       
   337 
       
   338     oset = blocked_set;
       
   339     for (i = 1; i < NSIG; ++i) {
       
   340         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
       
   341             sigaddset(&blocked_set, i);
       
   342             signal_ignore(i);
       
   343         } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
       
   344             sigdelset(&blocked_set, i);
       
   345             install_handler(i);
       
   346         }
       
   347     }
       
   348 #  endif /* SYSV_SIGNALS  */
       
   349 # endif  /* BSD_SIGNALS   */
       
   350 #endif   /* POSIX_SIGNALS */
       
   351  
       
   352     return oset;
       
   353 }
       
   354 
       
   355 #if defined(NO_SIGNAL_BLOCKING)
       
   356 static int suspend_longjmp = 0;
       
   357 static signal_jmp_buf suspend_jmp_buf;
       
   358 #endif
       
   359  
       
   360 /**/
       
   361 int
       
   362 signal_suspend(int sig, int sig2)
       
   363 {
       
   364     int ret;
       
   365  
       
   366 #ifdef POSIX_SIGNALS
       
   367     sigset_t set;
       
   368 #ifdef BROKEN_POSIX_SIGSUSPEND
       
   369     sigset_t oset;
       
   370 #endif /* BROKEN_POSIX_SIGSUSPEND */
       
   371 
       
   372     if (isset(TRAPSASYNC)) {
       
   373 	sigemptyset(&set);
       
   374     } else {
       
   375 	sigfillset(&set);
       
   376 	sigdelset(&set, sig);
       
   377 	sigdelset(&set, SIGHUP);  /* still don't know why we add this? */
       
   378 	if (sig2)
       
   379 	    sigdelset(&set, sig2);
       
   380     }
       
   381 #ifdef BROKEN_POSIX_SIGSUSPEND
       
   382     sigprocmask(SIG_SETMASK, &set, &oset);
       
   383     pause();
       
   384     sigprocmask(SIG_SETMASK, &oset, NULL);
       
   385 #else /* not BROKEN_POSIX_SIGSUSPEND */
       
   386     ret = sigsuspend(&set);
       
   387 #endif /* BROKEN_POSIX_SIGSUSPEND */
       
   388 #else /* not POSIX_SIGNALS */
       
   389 # ifdef BSD_SIGNALS
       
   390     sigset_t set;
       
   391 
       
   392     if (isset(TRAPSASYNC)) {
       
   393 	sigemptyset(&set);
       
   394     } else {
       
   395 	sigfillset(&set);
       
   396 	sigdelset(&set, sig);
       
   397 	if (sig2)
       
   398 	    sigdelset(&set, sig2);
       
   399 	ret = sigpause(set);
       
   400     }
       
   401 # else
       
   402 #  ifdef SYSV_SIGNALS
       
   403     ret = sigpause(sig);
       
   404 
       
   405 #  else  /* NO_SIGNAL_BLOCKING */
       
   406     /* need to use signal_longjmp to make this race-free *
       
   407      * between the child_unblock() and pause()           */
       
   408     if (signal_setjmp(suspend_jmp_buf) == 0) {
       
   409         suspend_longjmp = 1;   /* we want to signal_longjmp after catching signal */
       
   410         child_unblock();       /* do we need to unblock sig2 as well?             */
       
   411         ret = pause();
       
   412     }
       
   413     suspend_longjmp = 0;       /* turn off using signal_longjmp since we are past *
       
   414                                 * the pause() function.                           */
       
   415 #  endif /* SYSV_SIGNALS  */
       
   416 # endif  /* BSD_SIGNALS   */
       
   417 #endif   /* POSIX_SIGNALS */
       
   418  
       
   419     return ret;
       
   420 }
       
   421 
       
   422 /* the signal handler */
       
   423  
       
   424 /**/
       
   425 mod_export RETSIGTYPE
       
   426 zhandler(int sig)
       
   427 {
       
   428     sigset_t newmask, oldmask;
       
   429 
       
   430 #if defined(NO_SIGNAL_BLOCKING)
       
   431     int do_jump;
       
   432     signal_jmp_buf jump_to;
       
   433 #endif
       
   434  
       
   435     signal_process(sig);
       
   436  
       
   437     sigfillset(&newmask);
       
   438     oldmask = signal_block(newmask);        /* Block all signals temporarily           */
       
   439  
       
   440 #if defined(NO_SIGNAL_BLOCKING)
       
   441     do_jump = suspend_longjmp;              /* do we need to longjmp to signal_suspend */
       
   442     suspend_longjmp = 0;                    /* In case a SIGCHLD somehow arrives       */
       
   443 
       
   444     if (sig == SIGCHLD) {                   /* Traps can cause nested signal_suspend()  */
       
   445         if (do_jump)
       
   446             jump_to = suspend_jmp_buf;      /* Copy suspend_jmp_buf                    */
       
   447     }
       
   448 #endif
       
   449 
       
   450     /* Are we queueing signals now?      */
       
   451     if (queueing_enabled) {
       
   452         int temp_rear = ++queue_rear % MAX_QUEUE_SIZE;
       
   453 
       
   454 	DPUTS(temp_rear == queue_front, "BUG: signal queue full");
       
   455         if (temp_rear != queue_front) { /* Make sure it's not full (extremely unlikely) */
       
   456             queue_rear = temp_rear;                  /* ok, not full, so add to queue   */
       
   457             signal_queue[queue_rear] = sig;          /* save signal caught              */
       
   458             signal_mask_queue[queue_rear] = oldmask; /* save current signal mask        */
       
   459         }
       
   460         signal_reset(sig);
       
   461         return;
       
   462     }
       
   463  
       
   464     signal_setmask(oldmask);          /* Reset signal mask, signal traps ok now */
       
   465  
       
   466     switch (sig) {
       
   467     case SIGCHLD:
       
   468 
       
   469 	/* keep WAITING until no more child processes to reap */
       
   470 	for (;;)
       
   471 	  cont: {
       
   472             int old_errno = errno; /* save the errno, since WAIT may change it */
       
   473 	    int status;
       
   474 	    Job jn;
       
   475 	    Process pn;
       
   476             pid_t pid;
       
   477 	    pid_t *procsubpid = &cmdoutpid;
       
   478 	    int *procsubval = &cmdoutval;
       
   479 	    struct execstack *es = exstack;
       
   480 
       
   481 	    /*
       
   482 	     * Reap the child process.
       
   483 	     * If we want usage information, we need to use wait3.
       
   484 	     */
       
   485 #ifdef HAVE_WAIT3
       
   486 # ifdef HAVE_GETRUSAGE
       
   487 	    struct rusage ru;
       
   488 
       
   489 	    pid = wait3((void *)&status, WNOHANG|WUNTRACED, &ru); 
       
   490 # else
       
   491 	    pid = wait3((void *)&status, WNOHANG|WUNTRACED, NULL);
       
   492 # endif
       
   493 #else
       
   494 # ifdef HAVE_WAITPID
       
   495 	    pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
       
   496 # else
       
   497 	    pid = wait(&status);
       
   498 # endif
       
   499 #endif
       
   500 
       
   501             if (!pid)  /* no more children to reap */
       
   502                 break;
       
   503 
       
   504 	    /* check if child returned was from process substitution */
       
   505 	    for (;;) {
       
   506 		if (pid == *procsubpid) {
       
   507 		    *procsubpid = 0;
       
   508 		    if (WIFSIGNALED(status))
       
   509 			*procsubval = (0200 | WTERMSIG(status));
       
   510 		    else
       
   511 			*procsubval = WEXITSTATUS(status);
       
   512 		    get_usage();
       
   513 		    goto cont;
       
   514 		}
       
   515 		if (!es)
       
   516 		    break;
       
   517 		procsubpid = &es->cmdoutpid;
       
   518 		procsubval = &es->cmdoutval;
       
   519 		es = es->next;
       
   520 	    }
       
   521 
       
   522 	    /* check for WAIT error */
       
   523             if (pid == -1) {
       
   524                 if (errno != ECHILD)
       
   525                     zerr("wait failed: %e", NULL, errno);
       
   526                 errno = old_errno;    /* WAIT changed errno, so restore the original */
       
   527                 break;
       
   528             }
       
   529 
       
   530 	    /* Find the process and job containing this pid and update it. */
       
   531 	    if (findproc(pid, &jn, &pn, 0)) {
       
   532 #if defined(HAVE_WAIT3) && defined(HAVE_GETRUSAGE) 
       
   533 		struct timezone dummy_tz;
       
   534 		gettimeofday(&pn->endtime, &dummy_tz);
       
   535 		pn->status = status;
       
   536 		pn->ti = ru;
       
   537 #elif !defined(HAVE_GETRUSAGE)
       
   538 		update_process(pn, status);
       
   539 #endif
       
   540 		update_job(jn);
       
   541 	    } else if (findproc(pid, &jn, &pn, 1)) {
       
   542 		pn->status = status;
       
   543 		update_job(jn);
       
   544 	    } else {
       
   545 		/* If not found, update the shell record of time spent by
       
   546 		 * children in sub processes anyway:  otherwise, this
       
   547 		 * will get added on to the next found process that terminates.
       
   548 		 */
       
   549 		get_usage();
       
   550 	    }
       
   551         }
       
   552         break;
       
   553  
       
   554     case SIGHUP:
       
   555         if (sigtrapped[SIGHUP])
       
   556             dotrap(SIGHUP);
       
   557         else {
       
   558             stopmsg = 1;
       
   559             zexit(SIGHUP, 1);
       
   560         }
       
   561         break;
       
   562  
       
   563     case SIGINT:
       
   564         if (sigtrapped[SIGINT])
       
   565             dotrap(SIGINT);
       
   566         else {
       
   567 	    if ((isset(PRIVILEGED) || isset(RESTRICTED)) &&
       
   568 		isset(INTERACTIVE) && noerrexit < 0)
       
   569 		zexit(SIGINT, 1);
       
   570             if (list_pipe || chline || simple_pline) {
       
   571                 breaks = loops;
       
   572                 errflag = 1;
       
   573 		inerrflush();
       
   574             }
       
   575         }
       
   576         break;
       
   577 
       
   578 #ifdef SIGWINCH
       
   579     case SIGWINCH:
       
   580         adjustwinsize(1);  /* check window size and adjust */
       
   581 	if (sigtrapped[SIGWINCH])
       
   582 	    dotrap(SIGWINCH);
       
   583         break;
       
   584 #endif
       
   585 
       
   586     case SIGALRM:
       
   587         if (sigtrapped[SIGALRM]) {
       
   588 	    int tmout;
       
   589             dotrap(SIGALRM);
       
   590 
       
   591 	    if ((tmout = getiparam("TMOUT")))
       
   592 		alarm(tmout);           /* reset the alarm */
       
   593         } else {
       
   594 	    int idle = ttyidlegetfn(NULL);
       
   595 	    int tmout = getiparam("TMOUT");
       
   596 	    if (idle >= 0 && idle < tmout)
       
   597 		alarm(tmout - idle);
       
   598 	    else {
       
   599 		errflag = noerrs = 0;
       
   600 		zwarn("timeout", NULL, 0);
       
   601 		stopmsg = 1;
       
   602 		zexit(SIGALRM, 1);
       
   603 	    }
       
   604         }
       
   605         break;
       
   606  
       
   607     default:
       
   608         dotrap(sig);
       
   609         break;
       
   610     }   /* end of switch(sig) */
       
   611  
       
   612     signal_reset(sig);
       
   613 
       
   614 /* This is used to make signal_suspend() race-free */
       
   615 #if defined(NO_SIGNAL_BLOCKING)
       
   616     if (do_jump)
       
   617         signal_longjmp(jump_to, 1);
       
   618 #endif
       
   619 
       
   620 } /* handler */
       
   621 
       
   622  
       
   623 /* SIGHUP any jobs left running */
       
   624  
       
   625 /**/
       
   626 void
       
   627 killrunjobs(int from_signal)
       
   628 {
       
   629     int i, killed = 0;
       
   630  
       
   631     if (unset(HUP))
       
   632         return;
       
   633     for (i = 1; i <= maxjob; i++)
       
   634         if ((from_signal || i != thisjob) && (jobtab[i].stat & STAT_LOCKED) &&
       
   635             !(jobtab[i].stat & STAT_NOPRINT) &&
       
   636             !(jobtab[i].stat & STAT_STOPPED)) {
       
   637             if (jobtab[i].gleader != getpid() &&
       
   638 		killpg(jobtab[i].gleader, SIGHUP) != -1)
       
   639                 killed++;
       
   640         }
       
   641     if (killed)
       
   642         zwarn("warning: %d jobs SIGHUPed", NULL, killed);
       
   643 }
       
   644 
       
   645 
       
   646 /* send a signal to a job (simply involves kill if monitoring is on) */
       
   647  
       
   648 /**/
       
   649 int
       
   650 killjb(Job jn, int sig)
       
   651 {
       
   652     Process pn;
       
   653     int err = 0;
       
   654  
       
   655     if (jobbing) {
       
   656         if (jn->stat & STAT_SUPERJOB) {
       
   657             if (sig == SIGCONT) {
       
   658                 for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
       
   659                     if (killpg(pn->pid, sig) == -1)
       
   660 			if (kill(pn->pid, sig) == -1 && errno != ESRCH)
       
   661 			    err = -1;
       
   662  
       
   663                 for (pn = jn->procs; pn->next; pn = pn->next)
       
   664                     if (kill(pn->pid, sig) == -1 && errno != ESRCH)
       
   665 			err = -1;
       
   666 
       
   667 		if (!jobtab[jn->other].procs && pn)
       
   668 		    if (kill(pn->pid, sig) == -1 && errno != ESRCH)
       
   669 			err = -1;
       
   670 
       
   671                 return err;
       
   672             }
       
   673             if (killpg(jobtab[jn->other].gleader, sig) == -1 && errno != ESRCH)
       
   674 		err = -1;
       
   675 		
       
   676 	    if (killpg(jn->gleader, sig) == -1 && errno != ESRCH)
       
   677 		err = -1;
       
   678 
       
   679 	    return err;
       
   680         }
       
   681         else
       
   682 	    return killpg(jn->gleader, sig);
       
   683     }
       
   684     for (pn = jn->procs; pn; pn = pn->next)
       
   685         if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH && sig != 0)
       
   686             return -1;
       
   687     return err;
       
   688 }
       
   689 
       
   690 /*
       
   691  * List for saving traps.  We don't usually have that many traps
       
   692  * at once, so just use a linked list.
       
   693  */
       
   694 struct savetrap {
       
   695     int sig, flags, local;
       
   696     void *list;
       
   697 };
       
   698 
       
   699 static LinkList savetraps;
       
   700 static int dontsavetrap;
       
   701 
       
   702 /*
       
   703  * Save the current trap by copying it.  This does nothing to
       
   704  * the existing value of sigtrapped or sigfuncs.
       
   705  */
       
   706 
       
   707 static void
       
   708 dosavetrap(int sig, int level)
       
   709 {
       
   710     struct savetrap *st;
       
   711     st = (struct savetrap *)zalloc(sizeof(*st));
       
   712     st->sig = sig;
       
   713     st->local = level;
       
   714     if ((st->flags = sigtrapped[sig]) & ZSIG_FUNC) {
       
   715 	/*
       
   716 	 * Get the old function: this assumes we haven't added
       
   717 	 * the new one yet.
       
   718 	 */
       
   719 	Shfunc shf, newshf = NULL;
       
   720 	if ((shf = (Shfunc)gettrapnode(sig, 1))) {
       
   721 	    /* Copy the node for saving */
       
   722 	    newshf = (Shfunc) zalloc(sizeof(*newshf));
       
   723 	    newshf->nam = ztrdup(shf->nam);
       
   724 	    newshf->flags = shf->flags;
       
   725 	    newshf->funcdef = dupeprog(shf->funcdef, 0);
       
   726 	    if (shf->flags & PM_UNDEFINED)
       
   727 		newshf->funcdef->shf = newshf;
       
   728 	}
       
   729 #ifdef DEBUG
       
   730 	else dputs("BUG: no function present with function trap flag set.");
       
   731 #endif
       
   732 	st->list = newshf;
       
   733     } else if (sigtrapped[sig]) {
       
   734 	st->list = sigfuncs[sig] ? dupeprog(sigfuncs[sig], 0) : NULL;
       
   735     } else {
       
   736 	DPUTS(sigfuncs[sig], "BUG: sigfuncs not null for untrapped signal");
       
   737 	st->list = NULL;
       
   738     }
       
   739     if (!savetraps)
       
   740 	savetraps = znewlinklist();
       
   741     /*
       
   742      * Put this at the front of the list
       
   743      */
       
   744     zinsertlinknode(savetraps, (LinkNode)savetraps, st);
       
   745 }
       
   746 
       
   747 /**/
       
   748 mod_export int
       
   749 settrap(int sig, Eprog l)
       
   750 {
       
   751     if (sig == -1)
       
   752         return 1;
       
   753     if (jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN)) {
       
   754         zerr("can't trap SIG%s in interactive shells", sigs[sig], 0);
       
   755         return 1;
       
   756     }
       
   757 
       
   758     /*
       
   759      * Call unsettrap() unconditionally, to make sure trap is saved
       
   760      * if necessary.
       
   761      */
       
   762     queue_signals();
       
   763     unsettrap(sig);
       
   764 
       
   765     sigfuncs[sig] = l;
       
   766     if (empty_eprog(l)) {
       
   767 	sigtrapped[sig] = ZSIG_IGNORED;
       
   768         if (sig && sig <= SIGCOUNT &&
       
   769 #ifdef SIGWINCH
       
   770             sig != SIGWINCH &&
       
   771 #endif
       
   772             sig != SIGCHLD)
       
   773             signal_ignore(sig);
       
   774     } else {
       
   775 	nsigtrapped++;
       
   776         sigtrapped[sig] = ZSIG_TRAPPED;
       
   777         if (sig && sig <= SIGCOUNT &&
       
   778 #ifdef SIGWINCH
       
   779             sig != SIGWINCH &&
       
   780 #endif
       
   781             sig != SIGCHLD)
       
   782             install_handler(sig);
       
   783     }
       
   784     /*
       
   785      * Note that introducing the locallevel does not affect whether
       
   786      * sigtrapped[sig] is zero or not, i.e. a test without a mask
       
   787      * works just the same.
       
   788      */
       
   789     sigtrapped[sig] |= (locallevel << ZSIG_SHIFT);
       
   790     unqueue_signals();
       
   791     return 0;
       
   792 }
       
   793 
       
   794 /**/
       
   795 void
       
   796 unsettrap(int sig)
       
   797 {
       
   798     HashNode hn;
       
   799 
       
   800     queue_signals();
       
   801     hn = removetrap(sig);
       
   802     if (hn)
       
   803 	shfunctab->freenode(hn);
       
   804     unqueue_signals();
       
   805 }
       
   806 
       
   807 /**/
       
   808 HashNode
       
   809 removetrap(int sig)
       
   810 {
       
   811     int trapped;
       
   812 
       
   813     if (sig == -1 ||
       
   814 	(jobbing && (sig == SIGTTOU || sig == SIGTSTP || sig == SIGTTIN)))
       
   815 	return NULL;
       
   816 
       
   817     queue_signals();
       
   818     trapped = sigtrapped[sig];
       
   819     /*
       
   820      * Note that we save the trap here even if there isn't an existing
       
   821      * one, to aid in removing this one.  However, if there's
       
   822      * already one at the current locallevel we just overwrite it.
       
   823      */
       
   824     if (!dontsavetrap && (isset(LOCALTRAPS) || sig == SIGEXIT) &&
       
   825 	locallevel &&
       
   826 	(!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT)))
       
   827 	dosavetrap(sig, locallevel);
       
   828 
       
   829     if (!trapped) {
       
   830 	unqueue_signals();
       
   831         return NULL;
       
   832     }
       
   833     if (sigtrapped[sig] & ZSIG_TRAPPED)
       
   834 	nsigtrapped--;
       
   835     sigtrapped[sig] = 0;
       
   836     if (sig == SIGINT && interact) {
       
   837 	/* PWS 1995/05/16:  added test for interactive, also noholdintr() *
       
   838 	 * as subshells ignoring SIGINT have it blocked from delivery     */
       
   839         intr();
       
   840 	noholdintr();
       
   841     } else if (sig == SIGHUP)
       
   842         install_handler(sig);
       
   843     else if (sig && sig <= SIGCOUNT &&
       
   844 #ifdef SIGWINCH
       
   845              sig != SIGWINCH &&
       
   846 #endif
       
   847              sig != SIGCHLD)
       
   848         signal_default(sig);
       
   849 
       
   850     /*
       
   851      * At this point we free the appropriate structs.  If we don't
       
   852      * want that to happen then either the function should already have been
       
   853      * removed from shfunctab, or the entry in sigfuncs should have been set
       
   854      * to NULL.  This is no longer necessary for saving traps as that
       
   855      * copies the structures, so here we are remove the originals.
       
   856      * That causes a little inefficiency, but a good deal more reliability.
       
   857      */
       
   858     if (trapped & ZSIG_FUNC) {
       
   859 	HashNode node = gettrapnode(sig, 1);
       
   860 
       
   861 	/*
       
   862 	 * As in dosavetrap(), don't call removeshfuncnode() because
       
   863 	 * that calls back into unsettrap();
       
   864 	 */
       
   865 	sigfuncs[sig] = NULL;
       
   866 	if (node)
       
   867 	    removehashnode(shfunctab, node->nam);
       
   868 	unqueue_signals();
       
   869 
       
   870 	return node;
       
   871     } else if (sigfuncs[sig]) {
       
   872 	freeeprog(sigfuncs[sig]);
       
   873 	sigfuncs[sig] = NULL;
       
   874     }
       
   875     unqueue_signals();
       
   876 
       
   877     return NULL;
       
   878 }
       
   879 
       
   880 /**/
       
   881 void
       
   882 starttrapscope(void)
       
   883 {
       
   884     /* No special SIGEXIT behaviour inside another trap. */
       
   885     if (intrap)
       
   886 	return;
       
   887 
       
   888     /*
       
   889      * SIGEXIT needs to be restored at the current locallevel,
       
   890      * so give it the next higher one. dosavetrap() is called
       
   891      * automatically where necessary.
       
   892      */
       
   893     if (sigtrapped[SIGEXIT]) {
       
   894 	locallevel++;
       
   895 	unsettrap(SIGEXIT);
       
   896 	locallevel--;
       
   897     }
       
   898 }
       
   899 
       
   900 /*
       
   901  * Reset traps after the end of a function: must be called after
       
   902  * endparamscope() so that the locallevel has been decremented.
       
   903  */
       
   904 
       
   905 /**/
       
   906 void
       
   907 endtrapscope(void)
       
   908 {
       
   909     LinkNode ln;
       
   910     struct savetrap *st;
       
   911     int exittr;
       
   912     void *exitfn = NULL;
       
   913 
       
   914     /*
       
   915      * Remember the exit trap, but don't run it until
       
   916      * after all the other traps have been put back.
       
   917      * Don't do this inside another trap.
       
   918      */
       
   919     if (intrap)
       
   920 	exittr = 0;
       
   921     else if ((exittr = sigtrapped[SIGEXIT])) {
       
   922 	if (exittr & ZSIG_FUNC) {
       
   923 	    exitfn = removehashnode(shfunctab, "TRAPEXIT");
       
   924 	} else {
       
   925 	    exitfn = sigfuncs[SIGEXIT];
       
   926 	}
       
   927 	sigfuncs[SIGEXIT] = NULL;
       
   928 	if (sigtrapped[SIGEXIT] & ZSIG_TRAPPED)
       
   929 	    nsigtrapped--;
       
   930 	sigtrapped[SIGEXIT] = 0;
       
   931     }
       
   932 
       
   933     if (savetraps) {
       
   934 	while ((ln = firstnode(savetraps)) &&
       
   935 	       (st = (struct savetrap *) ln->dat) &&
       
   936 	       st->local > locallevel) {
       
   937 	    int sig = st->sig;
       
   938 
       
   939 	    remnode(savetraps, ln);
       
   940 
       
   941 	    if (st->flags && (st->list != NULL)) {
       
   942 		Eprog prog = (st->flags & ZSIG_FUNC) ?
       
   943 		    ((Shfunc) st->list)->funcdef : (Eprog) st->list;
       
   944 		/* prevent settrap from saving this */
       
   945 		dontsavetrap++;
       
   946 		settrap(sig, prog);
       
   947 		dontsavetrap--;
       
   948 		/*
       
   949 		 * counting of nsigtrapped should presumably be handled
       
   950 		 * in settrap...
       
   951 		 */
       
   952 		DPUTS((sigtrapped[sig] ^ st->flags) & ZSIG_TRAPPED,
       
   953 		      "BUG: settrap didn't restore correct ZSIG_TRAPPED");
       
   954 		if ((sigtrapped[sig] = st->flags) & ZSIG_FUNC)
       
   955 		    shfunctab->addnode(shfunctab, ((Shfunc)st->list)->nam,
       
   956 				       (Shfunc) st->list);
       
   957 	    } else if (sigtrapped[sig])
       
   958 		unsettrap(sig);
       
   959 
       
   960 	    zfree(st, sizeof(*st));
       
   961 	}
       
   962     }
       
   963 
       
   964     if (exittr) {
       
   965 	dotrapargs(SIGEXIT, &exittr, (exittr & ZSIG_FUNC) ?
       
   966 		   ((Shfunc)exitfn)->funcdef : (Eprog) exitfn);
       
   967 	if (exittr & ZSIG_FUNC)
       
   968 	    shfunctab->freenode((HashNode)exitfn);
       
   969 	else
       
   970 	    freeeprog(exitfn);
       
   971     }
       
   972     DPUTS(!locallevel && savetraps && firstnode(savetraps),
       
   973 	  "BUG: still saved traps outside all function scope");
       
   974 }
       
   975 
       
   976 /* Execute a trap function for a given signal, possibly
       
   977  * with non-standard sigtrapped & sigfuncs values
       
   978  */
       
   979 
       
   980 /* Are we already executing a trap? */
       
   981 /**/
       
   982 int intrap;
       
   983 
       
   984 /* Is the current trap a function? */
       
   985 
       
   986 /**/
       
   987 int trapisfunc;
       
   988 
       
   989 /**/
       
   990 void
       
   991 dotrapargs(int sig, int *sigtr, void *sigfn)
       
   992 {
       
   993     LinkList args;
       
   994     char *name, num[4];
       
   995     int trapret = 0;
       
   996     int obreaks = breaks;
       
   997     int isfunc;
       
   998 
       
   999     /* if signal is being ignored or the trap function		      *
       
  1000      * is NULL, then return					      *
       
  1001      *								      *
       
  1002      * Also return if errflag is set.  In fact, the code in the       *
       
  1003      * function will test for this, but this way we keep status flags *
       
  1004      * intact without working too hard.  Special cases (e.g. calling  *
       
  1005      * a trap for SIGINT after the error flag was set) are handled    *
       
  1006      * by the calling code.  (PWS 1995/06/08).			      *
       
  1007      *                                                                *
       
  1008      * This test is now replicated in dotrap().                       */
       
  1009     if ((*sigtr & ZSIG_IGNORED) || !sigfn || errflag)
       
  1010         return;
       
  1011 
       
  1012     /*
       
  1013      * Never execute special (synchronous) traps inside other traps.
       
  1014      * This can cause unexpected code execution when more than one
       
  1015      * of these is set.
       
  1016      *
       
  1017      * The down side is that it's harder to debug traps.  I don't think
       
  1018      * that's a big issue.
       
  1019      */
       
  1020     if (intrap) {
       
  1021 	switch (sig) {
       
  1022 	case SIGEXIT:
       
  1023 	case SIGDEBUG:
       
  1024 	case SIGZERR:
       
  1025 	    return;
       
  1026 	}
       
  1027     }
       
  1028 
       
  1029     intrap++;
       
  1030     *sigtr |= ZSIG_IGNORED;
       
  1031 
       
  1032     lexsave();
       
  1033     execsave();
       
  1034     breaks = 0;
       
  1035     runhookdef(BEFORETRAPHOOK, NULL);
       
  1036     if (*sigtr & ZSIG_FUNC) {
       
  1037 	int osc = sfcontext;
       
  1038 	HashNode hn = gettrapnode(sig, 0);
       
  1039 
       
  1040 	args = znewlinklist();
       
  1041 	/*
       
  1042 	 * In case of multiple names, try to get
       
  1043 	 * a hint of the name in use from the function table.
       
  1044 	 * In special cases, e.g. EXIT traps, the function
       
  1045 	 * has already been removed.  Then it's OK to
       
  1046 	 * use the standard name.
       
  1047 	 */
       
  1048 	if (hn) {
       
  1049 	    name = ztrdup(hn->nam);
       
  1050 	} else {
       
  1051 	    name = (char *) zalloc(5 + strlen(sigs[sig]));
       
  1052 	    sprintf(name, "TRAP%s", sigs[sig]);
       
  1053 	}
       
  1054 	zaddlinknode(args, name);
       
  1055 	sprintf(num, "%d", sig);
       
  1056 	zaddlinknode(args, num);
       
  1057 
       
  1058 	trapreturn = -1;	/* incremented by doshfunc */
       
  1059 	trapisfunc = isfunc = 1;
       
  1060 
       
  1061 	sfcontext = SFC_SIGNAL;
       
  1062 	doshfunc(name, sigfn, args, 0, 1);
       
  1063 	sfcontext = osc;
       
  1064 	freelinklist(args, (FreeFunc) NULL);
       
  1065 	zsfree(name);
       
  1066 
       
  1067     } else {
       
  1068 	trapreturn = -2;	/* not incremented, used at current level */
       
  1069 	trapisfunc = isfunc = 0;
       
  1070 
       
  1071 	execode(sigfn, 1, 0);
       
  1072     }
       
  1073     runhookdef(AFTERTRAPHOOK, NULL);
       
  1074 
       
  1075     if (trapreturn > 0 && isfunc) {
       
  1076 	/*
       
  1077 	 * Context was its own function.  We propagate the return
       
  1078 	 * value specially.  Return value zero means don't do
       
  1079 	 * anything special, so don't handle it.
       
  1080 	 */
       
  1081 	trapret = trapreturn;
       
  1082     } else if (trapreturn >= 0 && !isfunc) {
       
  1083 	/*
       
  1084 	 * Context was an inline trap.  If an explicit return value
       
  1085 	 * was used, we need to set `lastval'.  Otherwise we use the
       
  1086 	 * value restored by execrestore.  In this case, all return
       
  1087 	 * values indicate an explicit return from the current function,
       
  1088 	 * so always handle specially.  trapreturn is always restored by
       
  1089 	 * execrestore.
       
  1090 	 */
       
  1091 	trapret = trapreturn + 1;
       
  1092     } else if (errflag)
       
  1093 	trapret = 1;
       
  1094     execrestore();
       
  1095     lexrestore();
       
  1096 
       
  1097     if (trapret > 0) {
       
  1098 	if (isfunc) {
       
  1099 	    breaks = loops;
       
  1100 	    errflag = 1;
       
  1101 	} else {
       
  1102 	    lastval = trapret-1;
       
  1103 	}
       
  1104     } else {
       
  1105 	breaks += obreaks;
       
  1106 	if (breaks > loops)
       
  1107 	    breaks = loops;
       
  1108     }
       
  1109 
       
  1110     /*
       
  1111      * If zle was running while the trap was executed, see if we
       
  1112      * need to restore the display.
       
  1113      */
       
  1114     if (zleactive && resetneeded)
       
  1115 	zrefresh();
       
  1116 
       
  1117     if (*sigtr != ZSIG_IGNORED)
       
  1118 	*sigtr &= ~ZSIG_IGNORED;
       
  1119     intrap--;
       
  1120 }
       
  1121 
       
  1122 /* Standard call to execute a trap for a given signal. */
       
  1123 
       
  1124 /**/
       
  1125 void
       
  1126 dotrap(int sig)
       
  1127 {
       
  1128     /* Copied from dotrapargs(). */
       
  1129     if ((sigtrapped[sig] & ZSIG_IGNORED) || !sigfuncs[sig] || errflag)
       
  1130 	return;
       
  1131 
       
  1132     dotrapargs(sig, sigtrapped+sig, sigfuncs[sig]);
       
  1133 }