"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.7/signal.c" (16 Feb 2018, 14960 Bytes) of package /linux/misc/s-nail-14.9.7.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.6_vs_14.9.7.

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