"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.4/src/signal.c" (20 Nov 2019, 14446 Bytes) of package /linux/misc/tin-2.4.4.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: 2.4.3_vs_2.4.4.

    1 /*
    2  *  Project   : tin - a Usenet reader
    3  *  Module    : signal.c
    4  *  Author    : I.Lea
    5  *  Created   : 1991-04-01
    6  *  Updated   : 2019-07-17
    7  *  Notes     : signal handlers for different modes and window resizing
    8  *
    9  * Copyright (c) 1991-2020 Iain Lea <iain@bricbrac.de>
   10  * 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  *
   16  * 1. Redistributions of source code must retain the above copyright notice,
   17  *    this list of conditions and the following disclaimer.
   18  *
   19  * 2. Redistributions in binary form must reproduce the above copyright
   20  *    notice, this list of conditions and the following disclaimer in the
   21  *    documentation and/or other materials provided with the distribution.
   22  *
   23  * 3. Neither the name of the copyright holder nor the names of its
   24  *    contributors may be used to endorse or promote products derived from
   25  *    this software without specific prior written permission.
   26  *
   27  * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   37  * POSSIBILITY OF SUCH DAMAGE.
   38  */
   39 
   40 
   41 #ifndef TIN_H
   42 #   include "tin.h"
   43 #endif /* !TIN_H */
   44 #ifndef TCURSES_H
   45 #   include "tcurses.h"
   46 #endif /* !TCURSES_H */
   47 #ifndef included_trace_h
   48 #   include "trace.h"
   49 #endif /* !included_trace_h */
   50 #ifndef VERSION_H
   51 #   include "version.h"
   52 #endif /* !VERSION_H */
   53 
   54 /*
   55  * Needed for resizing under an xterm
   56  */
   57 #ifdef HAVE_TERMIOS_H
   58 #   include <termios.h>
   59 #else
   60 #   ifdef HAVE_TERMIO_H
   61 #       include <termio.h>
   62 #   endif /* HAVE_TERMIO_H */
   63 #endif /* HAVE_TERMIOS_H */
   64 
   65 #ifdef NEED_PTEM_H
   66 #   include <sys/stream.h>
   67 #   include <sys/ptem.h>
   68 #endif /* NEED_PTEM_H */
   69 
   70 #if defined(SIGWINCH) && !defined(DONT_HAVE_SIGWINCH)
   71 #   if !defined(TIOCGWINSZ) && !defined(TIOCGSIZE)
   72 #       ifdef HAVE_SYS_STREAM_H
   73 #           include <sys/stream.h>
   74 #       endif /* HAVE_SYS_STREAM_H */
   75 #       ifdef HAVE_SYS_PTY_H
   76 #           if !defined(_h_BSDTYPES) && defined(HAVE_SYS_BSDTYPES_H)
   77 #               include <sys/bsdtypes.h>
   78 #           endif /* !_h_BSDTYPES && HAVE_SYS_BSDTYPES_H */
   79 #           include <sys/pty.h>
   80 #       endif /* HAVE_SYS_PTY_H */
   81 #   endif /* !TIOCGWINSZ && !TIOCGSIZE */
   82 #endif /* SIGWINCH && !DONT_HAVE_SIGWINCH */
   83 
   84 #ifdef MINIX
   85 #   undef SIGTSTP
   86 #endif /* MINIX */
   87 
   88 /*
   89  * local prototypes
   90  */
   91 static const char *signal_name(int code);
   92 #ifdef SIGTSTP
   93     static void handle_suspend(void);
   94 #endif /* SIGTSTP */
   95 static void _CDECL signal_handler(SIG_ARGS);
   96 
   97 
   98 #ifdef SIGTSTP
   99     static t_bool do_sigtstp = FALSE;
  100 #endif /* SIGTSTP */
  101 #if defined(SIGWINCH) || defined(SIGTSTP)
  102     static t_bool redraw_after_suspend;
  103 #endif /* SIGWINCH || SIGTSTP */
  104 
  105 int signal_context = cMain;
  106 int input_context = cNone;
  107 int need_resize = cNo;
  108 /*
  109  * # lines of non-static data available for display
  110  */
  111 int NOTESLINES;
  112 
  113 
  114 #ifndef __LCLINT__ /* lclint doesn't like it */
  115 static const struct {
  116     int code;
  117     const char *name;
  118 } signal_list[] = {
  119 #   ifdef SIGINT
  120     { SIGINT,   "SIGINT" }, /* ctrl-C */
  121 #   endif /* SIGINT */
  122 #   ifdef SIGQUIT
  123     { SIGQUIT,  "SIGQUIT" },    /* ctrl-\ */
  124 #   endif /* SIGQUIT */
  125 #   ifdef SIGILL
  126     { SIGILL,   "SIGILL" }, /* illegal instruction */
  127 #   endif /* SIGILL */
  128 #   ifdef SIGFPE
  129     { SIGFPE,   "SIGFPE" }, /* floating point exception */
  130 #   endif /* SIGFPE */
  131 #   ifdef SIGBUS
  132     { SIGBUS,   "SIGBUS" }, /* bus error */
  133 #   endif /* SIGBUS */
  134 #   ifdef SIGSEGV
  135     { SIGSEGV,  "SIGSEGV" },    /* segmentation violation */
  136 #   endif /* SIGSEGV */
  137 #   ifdef SIGPIPE
  138     { SIGPIPE,  "SIGPIPE" },    /* broken pipe */
  139 #   endif /* SIGPIPE */
  140 #   ifdef SIGALRM
  141     { SIGALRM,  "SIGALRM" },    /* real-time timer expired */
  142 #   endif /* SIGALRM */
  143 #   ifdef SIGCHLD
  144     { SIGCHLD,  "SIGCHLD" },    /* death of a child process */
  145 #   endif /* SIGCHLD */
  146 #   ifdef SIGPWR
  147     { SIGPWR,   "SIGPWR" }, /* powerfail */
  148 #   endif /* SIGPWR */
  149 #   ifdef SIGTSTP
  150     { SIGTSTP,  "SIGTSTP" },    /* terminal-stop */
  151 #   endif /* SIGTSTP */
  152 #   ifdef SIGHUP
  153     { SIGHUP,   "SIGHUP" }, /* hang up */
  154 #   endif /* SIGHUP */
  155 #   ifdef SIGUSR1
  156     { SIGUSR1,  "SIGUSR1" },    /* User-defined signal 1 */
  157 #   endif /* SIGUSR1 */
  158 #   ifdef SIGUSR2
  159     { SIGUSR2,  "SIGUSR2" },    /* User-defined signal 2 */
  160 #   endif /* SIGUSR2 */
  161 #   ifdef SIGTERM
  162     { SIGTERM,  "SIGTERM" },    /* termination */
  163 #   endif /* SIGTERM */
  164 #   if defined(SIGWINCH) && !(defined(USE_CURSES) && defined(KEY_RESIZE))
  165     { SIGWINCH, "SIGWINCH" },   /* window-size change */
  166 #   endif /* SIGWINCH && !(USE_CURSES && KEY_RESIZE) */
  167 };
  168 #endif /* !__LCLINT__ */
  169 
  170 
  171 #ifdef HAVE_NESTED_PARAMS
  172     RETSIGTYPE (*sigdisp(int signum, RETSIGTYPE (_CDECL *func)(SIG_ARGS)))(SIG_ARGS)
  173 #else
  174     RETSIGTYPE (*sigdisp(signum, func))(SIG_ARGS)
  175     int signum;
  176     RETSIGTYPE (_CDECL *func)(SIG_ARGS);
  177 #endif /* HAVE_NESTED_PARAMS */
  178 {
  179 #ifdef HAVE_POSIX_JC
  180 #   define RESTORE_HANDLER(x, y)
  181     struct sigaction sa, osa;
  182 
  183     sa.sa_handler = func;
  184     sigemptyset(&sa.sa_mask);
  185     sa.sa_flags = 0;
  186 #   ifdef SA_RESTART
  187         sa.sa_flags |= SA_RESTART;
  188 #   endif /* SA_RESTART */
  189     if (sigaction(signum, &sa, &osa) < 0)
  190         return SIG_ERR;
  191     return (osa.sa_handler);
  192 #else
  193 #   define RESTORE_HANDLER(x, y)    signal(x, y)
  194     return (signal(signum, func));
  195 #endif /* HAVE_POSIX_JC */
  196 }
  197 
  198 
  199 /*
  200  * Block/unblock SIGWINCH/SIGTSTP restarting syscalls
  201  */
  202 void
  203 allow_resize(
  204     t_bool allow)
  205 {
  206 #ifdef HAVE_POSIX_JC
  207     struct sigaction sa, osa;
  208 
  209     sa.sa_handler = signal_handler;
  210     sigemptyset(&sa.sa_mask);
  211     sa.sa_flags = 0;
  212 #   ifdef SA_RESTART
  213     if (!allow)
  214         sa.sa_flags |= SA_RESTART;
  215 #   endif /* SA_RESTART */
  216 #   if defined(SIGWINCH) && !(defined(USE_CURSES) && defined(KEY_RESIZE))
  217     sigaction(SIGWINCH, &sa, &osa);
  218 #   endif /* SIGWINCH && !(USE_CURSES && KEY_RESIZE) */
  219 #   ifdef SIGTSTP
  220     sigaction(SIGTSTP, &sa, &osa);
  221 #   endif /* SIGTSTP */
  222 #endif /* HAVE_POSIX_JC */
  223 }
  224 
  225 
  226 static const char *
  227 signal_name(
  228     int code)
  229 {
  230     size_t n;
  231     const char *name = "unknown";
  232 
  233     for (n = 0; n < ARRAY_SIZE(signal_list); n++) {
  234         if (signal_list[n].code == code) {
  235             name = signal_list[n].name;
  236             break;
  237         }
  238     }
  239     return name;
  240 }
  241 
  242 
  243 /*
  244  * Rescale the display buffer and redraw the contents according to
  245  * the current context
  246  * This should NOT be called from an interrupt context
  247  */
  248 void
  249 handle_resize(
  250     t_bool repaint)
  251 {
  252 #if defined(SIGWINCH) || defined(SIGTSTP)
  253 #   ifdef SIGWINCH
  254     repaint |= set_win_size(&cLINES, &cCOLS);
  255 #   endif /* SIGWINCH */
  256 
  257     if (cLINES < MIN_LINES_ON_TERMINAL || cCOLS < MIN_COLUMNS_ON_TERMINAL) {
  258         ring_bell();
  259         tin_done(EXIT_FAILURE, _(txt_screen_too_small_exiting), tin_progname);
  260     }
  261 
  262     TRACE(("handle_resize(%d:%d)", signal_context, repaint));
  263 
  264     if (!repaint)
  265         return;
  266 
  267 #   ifdef USE_CURSES
  268 #       ifdef HAVE_RESIZETERM
  269     resizeterm(cLINES + 1, cCOLS);
  270     my_retouch();                   /* seems necessary if win size unchanged */
  271 #       else
  272     my_retouch();
  273 #       endif /* HAVE_RESIZETERM */
  274 #   endif /* USE_CURSES */
  275 
  276     switch (signal_context) {
  277         case cArt:
  278             ClearScreen();
  279             show_art_msg(CURR_GROUP.name);
  280             break;
  281 
  282         case cAttrib:
  283         case cConfig:
  284             refresh_config_page(SIGNAL_HANDLER);
  285             break;
  286 
  287         case cFilter:
  288             refresh_filter_menu();
  289             break;
  290 
  291         case cInfopager:
  292             display_info_page(0);
  293             break;
  294 
  295         case cAttachment:
  296         case cGroup:
  297         case cScope:
  298         case cSelect:
  299         case cThread:
  300         case cURL:
  301             ClearScreen();
  302             currmenu->redraw();
  303             break;
  304 
  305         case cPage:
  306             resize_article(TRUE, &pgart);
  307             draw_page(curr_group->name, 0);
  308             break;
  309 
  310         case cPost:
  311         case cPostCancel:
  312             refresh_post_screen(signal_context);
  313             break;
  314 
  315         case cPostFup:
  316             resize_article(TRUE, &pgart);
  317             draw_page(curr_group->name, 0);
  318             /*
  319              * Reset signal_context because draw_page()
  320              * sets signal_context to cPage.
  321              */
  322             signal_context = cPostFup;
  323             refresh_post_screen(signal_context);
  324             break;
  325 
  326         case cReconnect:
  327             ClearScreen();
  328             show_title(tin_progname);
  329             break;
  330 
  331         case cMain:
  332             break;
  333     }
  334     switch (input_context) {
  335         case cGetline:
  336             gl_redraw();
  337             break;
  338 
  339         case cPromptCONT:
  340             if (redraw_after_suspend)
  341                 info_message(_(txt_return_key));
  342             break;
  343 
  344         case cPromptSLK:
  345             prompt_slk_redraw();
  346             break;
  347 
  348         case cPromptYN:
  349             prompt_yn_redraw();
  350             break;
  351 
  352         default:
  353             break;
  354     }
  355     my_fflush(stdout);
  356     redraw_after_suspend = FALSE;
  357 #endif /* SIGWINCH || SIGTSTP */
  358 }
  359 
  360 
  361 #ifdef SIGTSTP
  362 static void
  363 handle_suspend(
  364     void)
  365 {
  366     t_bool save_cmd_line = cmd_line;
  367     t_bool save_state = (!batch_mode || !cmd_line);
  368 
  369     TRACE(("handle_suspend(%d)", signal_context));
  370 
  371     set_keypad_off();
  372     if (!cmd_line)
  373         set_xclick_off();
  374 
  375     if (save_state) {
  376         EndWin();
  377         Raw(FALSE);
  378     }
  379 
  380     wait_message(0, _(txt_suspended_message), tin_progname);
  381 
  382     kill(0, SIGSTOP);               /* Put ourselves to sleep */
  383 
  384     RESTORE_HANDLER(SIGTSTP, signal_handler);
  385 
  386     if (save_state) {
  387         Raw(TRUE);
  388         InitWin();
  389         cmd_line = save_cmd_line;
  390         if (!cmd_line)
  391             my_retouch();
  392         need_resize = cRedraw;      /* Flag a redraw */
  393         redraw_after_suspend = TRUE;
  394     }
  395     set_keypad_on();
  396     if (!cmd_line)
  397         set_xclick_on();
  398 }
  399 #endif /* SIGTSTP */
  400 
  401 
  402 static void _CDECL
  403 signal_handler(
  404     int sig)
  405 {
  406 #ifdef SIGCHLD
  407 #   ifdef HAVE_TYPE_UNIONWAIT
  408     union wait wait_status;
  409 #   else
  410     int wait_status = 1;
  411 #   endif /* HAVE_TYPE_UNIONWAIT */
  412 #endif /* SIGCHLD */
  413 
  414     /* In this case statement, we handle only the non-fatal signals */
  415     switch (sig) {
  416 #ifdef SIGINT
  417         case SIGINT:
  418             RESTORE_HANDLER(sig, signal_handler);
  419             return;
  420 #endif /* SIGINT */
  421 
  422 /*
  423  * fatal error but we don't want the "signal handler caught signal"
  424  * message here
  425  */
  426 #if defined(HAVE_ALARM) && defined(SIGALRM)
  427         case SIGALRM:
  428 #   ifdef DEBUG
  429             if ((debug & DEBUG_NNTP) && verbose > 1)
  430                 debug_print_file("NNTP", "get_server() %d sec elapsed without response", tinrc.nntp_read_timeout_secs);
  431 #   endif /* DEBUG */
  432             tin_done(NNTP_ERROR_EXIT, _("NNTP connection error. Exiting..."));
  433             return;
  434 #endif /* HAVE_ALARM && SIGALRM */
  435 
  436 #ifdef SIGCHLD
  437         case SIGCHLD:
  438             wait(&wait_status);
  439             RESTORE_HANDLER(sig, signal_handler);   /* death of a child */
  440             system_status = WIFEXITED(wait_status) ? WEXITSTATUS(wait_status) : 0;
  441             return;
  442 #endif /* SIGCHLD */
  443 
  444 #ifdef SIGTSTP
  445         case SIGTSTP:
  446             handle_suspend();
  447             return;
  448 #endif /* SIGTSTP */
  449 
  450 #ifdef SIGWINCH
  451         case SIGWINCH:
  452             need_resize = cYes;
  453             RESTORE_HANDLER(sig, signal_handler);
  454             return;
  455 #endif /* SIGWINCH */
  456 
  457 #ifdef SIGUSR2
  458         case SIGUSR2:
  459             if (!no_write) /* TODO: add more config-files to be saved */
  460                 write_newsrc();
  461             RESTORE_HANDLER(sig, signal_handler);
  462             return;
  463 #endif /* SIGUSR2 */
  464 
  465         default:
  466             break;
  467     }
  468 
  469     fprintf(stderr, "\n%s: signal handler caught %s signal (%d).\n", tin_progname, signal_name(sig), sig);
  470 
  471     switch (sig) {
  472 #ifdef SIGHUP
  473         case SIGHUP:
  474 #endif /* SIGHUP */
  475 #ifdef SIGUSR1
  476         case SIGUSR1:
  477 #endif /* SIGUSR1 */
  478 #ifdef SIGTERM
  479         case SIGTERM:
  480 #endif /* SIGTERM */
  481 #if defined(SIGHUP) || defined(SIGUSR1) || defined(SIGTERM)
  482             dangerous_signal_exit = TRUE;
  483             tin_done(-sig, NULL);
  484             /* NOTREACHED */
  485             break;
  486 #endif /* SIGHUP || SIGUSR1 || SIGTERM */
  487 
  488 #ifdef SIGSEGV
  489         case SIGSEGV:
  490 #   if defined(SIGBUS) && (SIGSEGV != SIGBUS) /* on Haiku SIGSEGV == SIGBUS */
  491         case SIGBUS:
  492 #   endif /* SIGBUS && SIGSEGV != SIGBUS */
  493 #else
  494 #   ifdef SIGBUS
  495         case SIGBUS:
  496 #   endif /* SIGBUS */
  497 #endif /* SIGSEGV */
  498 
  499 #if defined(SIGBUS) || defined(SIGSEGV)
  500             my_fprintf(stderr, _(txt_send_bugreport), tin_progname, VERSION, RELEASEDATE, RELEASENAME, bug_addr);
  501             my_fflush(stderr);
  502             break;
  503 #endif /* SIGBUS || SIGSEGV */
  504 
  505         default:
  506             break;
  507     }
  508 
  509     cleanup_tmp_files();
  510 
  511 #if 1
  512 /* #if defined(apollo) || defined(HAVE_COREFILE) */
  513     /* do this so we can get a traceback (doesn't dump core) */
  514     abort();
  515 #else
  516     giveup();
  517 #endif /* 1 */ /* apollo || HAVE_COREFILE */
  518 }
  519 
  520 
  521 /*
  522  * Turn on (flag != FALSE) our signal handler for TSTP and WINCH
  523  * Otherwise revert to the default handler
  524  */
  525 void
  526 set_signal_catcher(
  527     int flag)
  528 {
  529 #ifdef SIGTSTP
  530     if (do_sigtstp)
  531         sigdisp(SIGTSTP, flag ? signal_handler : SIG_DFL);
  532 #endif /* SIGTSTP */
  533 
  534 #if defined(SIGWINCH) && !(defined(USE_CURSES) && defined(KEY_RESIZE))
  535     sigdisp(SIGWINCH, flag ? signal_handler : SIG_DFL);
  536 #endif /* SIGWINCH && !(USE_CURSES && KEY_RESIZE) */
  537 }
  538 
  539 
  540 void
  541 set_signal_handlers(
  542     void)
  543 {
  544     size_t n;
  545     int code;
  546 #ifdef SIGTSTP
  547     RETSIGTYPE (*ptr)(SIG_ARGS);
  548 #endif /* SIGTSTP */
  549 
  550     for (n = 0; n < ARRAY_SIZE(signal_list); n++) {
  551         switch ((code = signal_list[n].code)) {
  552 #ifdef SIGPIPE
  553         case SIGPIPE:
  554             sigdisp(code, SIG_IGN);
  555             break;
  556 #endif /* SIGPIPE */
  557 #ifdef SIGTSTP
  558         case SIGTSTP:
  559             ptr = sigdisp(code, SIG_DFL);
  560             sigdisp(code, ptr);
  561             if (ptr == SIG_IGN)
  562                 break;
  563             /*
  564              * SIGTSTP is ignored when starting from shells
  565              * without job-control
  566              */
  567             do_sigtstp = TRUE;
  568             /* FALLTHROUGH */
  569 #endif /* SIGTSTP */
  570 
  571         default:
  572             sigdisp(code, signal_handler);
  573         }
  574     }
  575 }
  576 
  577 
  578 /*
  579  * Size the display at startup or rescale following a SIGWINCH etc.
  580  */
  581 t_bool
  582 set_win_size(
  583     int *num_lines,
  584     int *num_cols)
  585 {
  586     int old_lines;
  587     int old_cols;
  588 #ifdef TIOCGSIZE
  589     struct ttysize win;
  590 #else
  591 #   ifdef TIOCGWINSZ
  592     struct winsize win;
  593 #   endif /* TIOCGWINSZ */
  594 #endif /* TIOCGSIZE */
  595 
  596     old_lines = *num_lines;
  597     old_cols = *num_cols;
  598 
  599 #ifdef HAVE_XCURSES
  600     *num_lines = LINES - 1;     /* FIXME */
  601     *num_cols = COLS;
  602 #else /* curses/ncurses */
  603 
  604 #   ifndef USE_CURSES
  605     init_screen_array(FALSE);       /* deallocate screen array */
  606 #   endif /* !USE_CURSES */
  607 
  608 #   ifdef TIOCGSIZE
  609     if (ioctl(0, TIOCGSIZE, &win) == 0) {
  610         if (win.ts_lines != 0)
  611             *num_lines = win.ts_lines - 1;
  612         if (win.ts_cols != 0)
  613             *num_cols = win.ts_cols;
  614     }
  615 #   else
  616 #       ifdef TIOCGWINSZ
  617     if (ioctl(0, TIOCGWINSZ, &win) == 0) {
  618         if (win.ws_row != 0)
  619             *num_lines = win.ws_row - 1;
  620         if (win.ws_col != 0)
  621             *num_cols = win.ws_col;
  622     }
  623 #       else
  624 #       endif /* TIOCGWINSZ */
  625 #   endif /* TIOCGSIZE */
  626 
  627 #   ifndef USE_CURSES
  628     init_screen_array(TRUE);        /* allocate screen array for resize */
  629 #   endif /* !USE_CURSES */
  630 
  631 #endif /* HAVE_XCURSES */
  632 
  633     set_noteslines(*num_lines);
  634     return (*num_lines != old_lines || *num_cols != old_cols);
  635 }
  636 
  637 
  638 void
  639 set_noteslines(
  640     int num_lines)
  641 {
  642     NOTESLINES = num_lines - INDEX_TOP - (tinrc.beginner_level ? MINI_HELP_LINES : 1);
  643     if (NOTESLINES <= 0)
  644         NOTESLINES = 1;
  645 }