"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/signal.c" (8 Aug 2018, 15025 Bytes) of package /linux/misc/s-nail-14.9.11.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "signal.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.10_vs_14.9.11.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Signal related stuff as well as NotYetDead functions.
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  * SPDX-License-Identifier: BSD-3-Clause TODO ISC (better: drop)
    7  */
    8 /*
    9  * Copyright (c) 1980, 1993
   10  *      The Regents of the University of California.  All rights reserved.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. 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 #undef n_FILE
   37 #define n_FILE signal
   38 
   39 #ifndef HAVE_AMALGAMATION
   40 # include "nail.h"
   41 #endif
   42 
   43 /*
   44  * TODO At the beginning of November 2015 -- for v14.9 -- i've tried for one
   45  * TODO and a half week to convert this codebase to SysV style signal handling,
   46  * TODO meaning no SA_RESTART and EINTR in a lot of places and error reporting
   47  * TODO up the chain.   I failed miserably, not only because S/MIME / SSL but
   48  * TODO also because of general frustration.  Directly after v14.9 i will strip
   49  * TODO ANYTHING off the codebase (socket stuff etc.) and keep only the very
   50  * TODO core, doing namespace and type cleanup and convert this core to a clean
   51  * TODO approach, from which i plan to start this thing anew.
   52  * TODO For now i introduced the n_sigman, yet another hack, to be used in a
   53  * TODO few places.
   54  * TODO The real solution:
   55  * TODO - No SA_RESTART.  Just like for my C++ library: encapsulate EINTR in
   56  * TODO   userspace at the systemcall (I/O rewrite: drop stdio), normal
   57  * TODO   interface auto-restarts, special _intr() series return EINTR.
   58  * TODO   Do n_sigman_poll()/peek()/whatever whenever desired for the former,
   59  * TODO   report errors up the call chain, have places where operations can be
   60  * TODO   "properly" aborted.
   61  * TODO - We save the initial signal settings upon program startup.
   62  * TODO - We register our sigman handlers once, at program startup.
   63  * TODO   Maximally, and most likely only due to lack of atomic CAS, ignore
   64  * TODO   or block some signals temporarily.  Best if not.
   65  * TODO   The signal handlers only set a flag.  Block all signals for handler
   66  * TODO   execution, like this we are safe to "set the first signal was x".
   67  * TODO - In interactive context, ignore SIGTERM.
   68  * TODO   I.e., see the POSIX standard for what a shell does.
   69  * TODO - In non-interactive context, don't know anything about job control!?!
   70  * TODO - Place child processes in their own process group.  Restore the signal
   71  * TODO   mask back to the saved original one for them, before exec.
   72  * TODO - Except for job control related (<-> interactive) ignore any signals
   73  * TODO   while we are "behind" a child that occupies the terminal.  For those,
   74  * TODO   perform proper terminal attribute handling.  For childs that don't
   75  * TODO   occupy the terminal we "are the shell" and should therefore manage
   76  * TODO   them accordingly, including termination request as necessary.
   77  * TODO   And if we have a worker in a pipeline, we need to manage it and deal
   78  * TODO   with it properly, WITHOUT temporary signal overwrites.
   79  * TODO - No more jumps.
   80  * TODO - (When sockets will be reintroduced, non-blocking.)
   81  * TODO - (When SSL is reintroduced, memory BIO.  It MAY be necessary to
   82  * TODO   temporarily block signals during a few SSL functions?  Read SSL docu!
   83  * TODO   But i prefer blocking since it's a single syscall, not temporary
   84  * TODO   SA_RESTART setting, since that has to be done for every signal.)
   85  */
   86 
   87 #ifdef HAVE_NYD
   88 struct nyd_info {
   89    char const  *ni_file;
   90    char const  *ni_fun;
   91    ui32_t      ni_chirp_line;
   92    ui32_t      ni_level;
   93 };
   94 #endif
   95 
   96 /* {hold,rele}_all_sigs() */
   97 static size_t           _alls_depth;
   98 static sigset_t         _alls_nset, _alls_oset;
   99 
  100 /* {hold,rele}_sigs() */
  101 static size_t           _hold_sigdepth;
  102 static sigset_t         _hold_nset, _hold_oset;
  103 
  104 /* NYD, memory pool debug */
  105 #ifdef HAVE_NYD
  106 static ui32_t           _nyd_curr, _nyd_level;
  107 static struct nyd_info  _nyd_infos[NYD_CALLS_MAX];
  108 #endif
  109 
  110 /* */
  111 #ifdef HAVE_NYD
  112 static void    _nyd_print(int fd, struct nyd_info *nip);
  113 #endif
  114 
  115 #ifdef HAVE_NYD
  116 static void
  117 _nyd_print(int fd, struct nyd_info *nip)
  118 {
  119    char buf[80];
  120    union {int i; size_t z;} u;
  121 
  122    u.i = snprintf(buf, sizeof buf,
  123          "%c [%2" PRIu32 "] %.25s (%.40s:%" PRIu32 ")\n",
  124          "=><"[(nip->ni_chirp_line >> 29) & 0x3], nip->ni_level, nip->ni_fun,
  125          nip->ni_file, (nip->ni_chirp_line & 0x1FFFFFFFu));
  126    if (u.i > 0) {
  127       u.z = u.i;
  128       if (u.z > sizeof buf)
  129          u.z = sizeof buf - 1; /* (Skip \0) */
  130       write(fd, buf, u.z);
  131    }
  132 }
  133 #endif
  134 
  135 #ifdef HAVE_DEVEL
  136 FL int
  137 c_sigstate(void *vp){ /* TODO remove again */
  138    struct{
  139       int val;
  140       char const name[12];
  141    } const *hdlp, hdla[] = {
  142       {SIGINT, "SIGINT"}, {SIGHUP, "SIGHUP"}, {SIGQUIT, "SIGQUIT"},
  143       {SIGTSTP, "SIGTSTP"}, {SIGTTIN, "SIGTTIN"}, {SIGTTOU, "SIGTTOU"},
  144       {SIGCHLD, "SIGCHLD"}, {SIGPIPE, "SIGPIPE"}
  145    };
  146    char const *cp;
  147    NYD2_ENTER;
  148 
  149    if((cp = vp) != NULL && cp[0] != '\0'){
  150       if(!asccasecmp(&cp[1], "all")){
  151          if(cp[0] == '+')
  152             hold_all_sigs();
  153          else
  154             rele_all_sigs();
  155       }else if(!asccasecmp(&cp[1], "hold")){
  156          if(cp[0] == '+')
  157             hold_sigs();
  158          else
  159             rele_sigs();
  160       }
  161    }
  162 
  163    fprintf(n_stdout, "alls_depth %zu, hold_sigdepth %zu\nHandlers:\n",
  164       _alls_depth, _hold_sigdepth);
  165    for(hdlp = hdla; hdlp < &hdla[n_NELEM(hdla)]; ++hdlp){
  166       sighandler_type shp;
  167 
  168       shp = safe_signal(hdlp->val, SIG_IGN);
  169       safe_signal(hdlp->val, shp);
  170       fprintf(n_stdout, "  %s: %p (%s)\n", hdlp->name, shp,
  171          (shp == SIG_ERR ? "ERR" : (shp == SIG_DFL ? "DFL"
  172             : (shp == SIG_IGN ? "IGN" : "ptf?"))));
  173    }
  174    NYD2_LEAVE;
  175    return OKAY;
  176 }
  177 #endif /* HAVE_DEVEL */
  178 
  179 FL void
  180 n_raise(int signo)
  181 {
  182    NYD2_ENTER;
  183    if(n_pid == 0)
  184       n_pid = getpid();
  185    kill(n_pid, signo);
  186    NYD2_LEAVE;
  187 }
  188 
  189 FL sighandler_type
  190 safe_signal(int signum, sighandler_type handler)
  191 {
  192    struct sigaction nact, oact;
  193    sighandler_type rv;
  194    NYD2_ENTER;
  195 
  196    nact.sa_handler = handler;
  197    sigfillset(&nact.sa_mask);
  198    nact.sa_flags = SA_RESTART;
  199    rv = (sigaction(signum, &nact, &oact) != 0) ? SIG_ERR : oact.sa_handler;
  200    NYD2_LEAVE;
  201    return rv;
  202 }
  203 
  204 FL n_sighdl_t
  205 n_signal(int signo, n_sighdl_t hdl){
  206    struct sigaction nact, oact;
  207    NYD2_ENTER;
  208 
  209    nact.sa_handler = hdl;
  210    sigfillset(&nact.sa_mask);
  211    nact.sa_flags = 0;
  212    hdl = (sigaction(signo, &nact, &oact) != 0) ? SIG_ERR : oact.sa_handler;
  213    NYD2_LEAVE;
  214    return hdl;
  215 }
  216 
  217 FL void
  218 hold_all_sigs(void)
  219 {
  220    NYD2_ENTER;
  221    if (_alls_depth++ == 0) {
  222       sigfillset(&_alls_nset);
  223       sigdelset(&_alls_nset, SIGABRT);
  224 #ifdef SIGBUS
  225       sigdelset(&_alls_nset, SIGBUS);
  226 #endif
  227       sigdelset(&_alls_nset, SIGFPE);
  228       sigdelset(&_alls_nset, SIGILL);
  229       sigdelset(&_alls_nset, SIGKILL);
  230       sigdelset(&_alls_nset, SIGSEGV);
  231       sigdelset(&_alls_nset, SIGSTOP);
  232 
  233       sigdelset(&_alls_nset, SIGCHLD);
  234       sigprocmask(SIG_BLOCK, &_alls_nset, &_alls_oset);
  235    }
  236    NYD2_LEAVE;
  237 }
  238 
  239 FL void
  240 rele_all_sigs(void)
  241 {
  242    NYD2_ENTER;
  243    if (--_alls_depth == 0)
  244       sigprocmask(SIG_SETMASK, &_alls_oset, (sigset_t*)NULL);
  245    NYD2_LEAVE;
  246 }
  247 
  248 FL void
  249 hold_sigs(void)
  250 {
  251    NYD2_ENTER;
  252    if (_hold_sigdepth++ == 0) {
  253       sigemptyset(&_hold_nset);
  254       sigaddset(&_hold_nset, SIGHUP);
  255       sigaddset(&_hold_nset, SIGINT);
  256       sigaddset(&_hold_nset, SIGQUIT);
  257       sigprocmask(SIG_BLOCK, &_hold_nset, &_hold_oset);
  258    }
  259    NYD2_LEAVE;
  260 }
  261 
  262 FL void
  263 rele_sigs(void)
  264 {
  265    NYD2_ENTER;
  266    if (--_hold_sigdepth == 0)
  267       sigprocmask(SIG_SETMASK, &_hold_oset, NULL);
  268    NYD2_LEAVE;
  269 }
  270 
  271 /* TODO This is temporary gracyness */
  272 static struct n_sigman *n__sigman;
  273 static void n__sigman_hdl(int signo);
  274 static void
  275 n__sigman_hdl(int signo){
  276    NYD_X; /* Signal handler */
  277    n__sigman->sm_signo = signo;
  278    siglongjmp(n__sigman->sm_jump, 1);
  279 }
  280 
  281 FL int
  282 n__sigman_enter(struct n_sigman *self, int flags){
  283    /* TODO no error checking when installing sighdls */
  284    int rv;
  285    NYD2_ENTER;
  286 
  287    if((int)flags >= 0){
  288       self->sm_flags = (enum n_sigman_flags)flags;
  289       self->sm_signo = 0;
  290       self->sm_outer = n__sigman;
  291       if(flags & n_SIGMAN_HUP)
  292          self->sm_ohup = safe_signal(SIGHUP, &n__sigman_hdl);
  293       if(flags & n_SIGMAN_INT)
  294          self->sm_oint = safe_signal(SIGINT, &n__sigman_hdl);
  295       if(flags & n_SIGMAN_QUIT)
  296          self->sm_oquit = safe_signal(SIGQUIT, &n__sigman_hdl);
  297       if(flags & n_SIGMAN_PIPE)
  298          self->sm_opipe = safe_signal(SIGPIPE, &n__sigman_hdl);
  299       n__sigman = self;
  300       rv = 0;
  301    }else{
  302       flags = self->sm_flags;
  303 
  304       /* Just in case of a race (signal while holding and ignoring? really?) */
  305       if(!(flags & n__SIGMAN_PING)){
  306          if(flags & n_SIGMAN_HUP)
  307             safe_signal(SIGHUP, SIG_IGN);
  308          if(flags & n_SIGMAN_INT)
  309             safe_signal(SIGINT, SIG_IGN);
  310          if(flags & n_SIGMAN_QUIT)
  311             safe_signal(SIGQUIT, SIG_IGN);
  312          if(flags & n_SIGMAN_PIPE)
  313             safe_signal(SIGPIPE, SIG_IGN);
  314       }
  315       rv = self->sm_signo;
  316       /* The signal mask has been restored, but of course rele_sigs() has
  317        * already been called: account for restoration due to jump */
  318       ++_hold_sigdepth;
  319    }
  320    rele_sigs();
  321    NYD2_LEAVE;
  322    return rv;
  323 }
  324 
  325 FL void
  326 n_sigman_cleanup_ping(struct n_sigman *self){
  327    ui32_t f;
  328    NYD2_ENTER;
  329 
  330    hold_sigs();
  331 
  332    f = self->sm_flags;
  333    f |= n__SIGMAN_PING;
  334    self->sm_flags = f;
  335 
  336    if(f & n_SIGMAN_HUP)
  337       safe_signal(SIGHUP, SIG_IGN);
  338    if(f & n_SIGMAN_INT)
  339       safe_signal(SIGINT, SIG_IGN);
  340    if(f & n_SIGMAN_QUIT)
  341       safe_signal(SIGQUIT, SIG_IGN);
  342    if(f & n_SIGMAN_PIPE)
  343       safe_signal(SIGPIPE, SIG_IGN);
  344 
  345    rele_sigs();
  346    NYD2_LEAVE;
  347 }
  348 
  349 FL void
  350 n_sigman_leave(struct n_sigman *self,
  351       enum n_sigman_flags reraise_flags){
  352    ui32_t f;
  353    int sig;
  354    NYD2_ENTER;
  355 
  356    hold_sigs();
  357    n__sigman = self->sm_outer;
  358 
  359    f = self->sm_flags;
  360    if(f & n_SIGMAN_HUP)
  361       safe_signal(SIGHUP, self->sm_ohup);
  362    if(f & n_SIGMAN_INT)
  363       safe_signal(SIGINT, self->sm_oint);
  364    if(f & n_SIGMAN_QUIT)
  365       safe_signal(SIGQUIT, self->sm_oquit);
  366    if(f & n_SIGMAN_PIPE)
  367       safe_signal(SIGPIPE, self->sm_opipe);
  368 
  369    rele_sigs();
  370 
  371    sig = 0;
  372    switch(self->sm_signo){
  373    case SIGPIPE:
  374       if((reraise_flags & n_SIGMAN_PIPE) ||
  375             ((reraise_flags & n_SIGMAN_NTTYOUT_PIPE) &&
  376              !(n_psonce & n_PSO_TTYOUT)))
  377          sig = SIGPIPE;
  378       break;
  379    case SIGHUP:
  380       if(reraise_flags & n_SIGMAN_HUP)
  381          sig = SIGHUP;
  382       break;
  383    case SIGINT:
  384       if(reraise_flags & n_SIGMAN_INT)
  385          sig = SIGINT;
  386       break;
  387    case SIGQUIT:
  388       if(reraise_flags & n_SIGMAN_QUIT)
  389          sig = SIGQUIT;
  390       break;
  391    default:
  392       break;
  393    }
  394 
  395    NYD2_LEAVE;
  396    if(sig != 0){
  397       sigset_t cset;
  398 
  399       sigemptyset(&cset);
  400       sigaddset(&cset, sig);
  401       sigprocmask(SIG_UNBLOCK, &cset, NULL);
  402       n_raise(sig);
  403    }
  404 }
  405 
  406 FL int
  407 n_sigman_peek(void){
  408    int rv;
  409    NYD2_ENTER;
  410    rv = 0;
  411    NYD2_LEAVE;
  412    return rv;
  413 }
  414 
  415 FL void
  416 n_sigman_consume(void){
  417    NYD2_ENTER;
  418    NYD2_LEAVE;
  419 }
  420 
  421 #ifdef HAVE_NYD
  422 FL void
  423 _nyd_chirp(ui8_t act, char const *file, ui32_t line, char const *fun)
  424 {
  425    struct nyd_info *nip = _nyd_infos;
  426 
  427    if (_nyd_curr != n_NELEM(_nyd_infos))
  428       nip += _nyd_curr++;
  429    else
  430       _nyd_curr = 1;
  431    nip->ni_file = file;
  432    nip->ni_fun = fun;
  433    nip->ni_chirp_line = ((ui32_t)(act & 0x3) << 29) | (line & 0x1FFFFFFFu);
  434    nip->ni_level = ((act == 0) ? _nyd_level
  435          : (act == 1) ? ++_nyd_level : _nyd_level--);
  436 }
  437 
  438 FL void
  439 _nyd_oncrash(int signo)
  440 {
  441    char pathbuf[PATH_MAX], s2ibuf[32], *cp;
  442    struct sigaction xact;
  443    sigset_t xset;
  444    struct nyd_info *nip;
  445    int fd;
  446    size_t i, fnl;
  447    char const *tmpdir;
  448 
  449    n_LCTA(sizeof("./") -1 + sizeof(VAL_UAGENT) -1 + sizeof(".dat") < PATH_MAX,
  450       "System limits too low for fixed-size buffer operation");
  451 
  452    xact.sa_handler = SIG_DFL;
  453    sigemptyset(&xact.sa_mask);
  454    xact.sa_flags = 0;
  455    sigaction(signo, &xact, NULL);
  456 
  457    i = strlen(tmpdir = ok_vlook(TMPDIR));
  458    fnl = sizeof(VAL_UAGENT) -1;
  459 
  460    if (i + 1 + fnl + 1 + sizeof(".dat") > sizeof(pathbuf)) {
  461       (cp = pathbuf)[0] = '.';
  462       i = 1;
  463    } else
  464       memcpy(cp = pathbuf, tmpdir, i);
  465    cp[i++] = '/'; /* xxx pathsep */
  466    memcpy(cp += i, VAL_UAGENT, fnl);
  467    i += fnl;
  468    memcpy(cp += fnl, ".dat", sizeof(".dat"));
  469    fnl = i + sizeof(".dat") -1;
  470 
  471    if ((fd = open(pathbuf, O_WRONLY | O_CREAT | O_EXCL, 0666)) == -1)
  472       fd = STDERR_FILENO;
  473 
  474 # undef _X
  475 # define _X(X) (X), sizeof(X) -1
  476    write(fd, _X("\n\nNYD: program dying due to signal "));
  477 
  478    cp = s2ibuf + sizeof(s2ibuf) -1;
  479    *cp = '\0';
  480    i = signo;
  481    do {
  482       *--cp = "0123456789"[i % 10];
  483       i /= 10;
  484    } while (i != 0);
  485    write(fd, cp, PTR2SIZE((s2ibuf + sizeof(s2ibuf) -1) - cp));
  486 
  487    write(fd, _X(":\n"));
  488 
  489    if (_nyd_infos[n_NELEM(_nyd_infos) - 1].ni_file != NULL)
  490       for (i = _nyd_curr, nip = _nyd_infos + i; i < n_NELEM(_nyd_infos); ++i)
  491          _nyd_print(fd, nip++);
  492    for (i = 0, nip = _nyd_infos; i < _nyd_curr; ++i)
  493       _nyd_print(fd, nip++);
  494 
  495    write(fd, _X("----------\nCome up to the lab and see what's on the slab\n"));
  496 
  497    if (fd != STDERR_FILENO) {
  498       write(STDERR_FILENO, _X("Crash NYD listing written to "));
  499       write(STDERR_FILENO, pathbuf, fnl);
  500       write(STDERR_FILENO, _X("\n"));
  501 # undef _X
  502 
  503       close(fd);
  504    }
  505 
  506    sigemptyset(&xset);
  507    sigaddset(&xset, signo);
  508    sigprocmask(SIG_UNBLOCK, &xset, NULL);
  509    n_raise(signo);
  510    for (;;)
  511       _exit(n_EXIT_ERR);
  512 }
  513 #endif /* HAVE_NYD */
  514 
  515 /* s-it-mode */