"Fossies" - the Fresh Open Source Software Archive

Member "tin-2.4.1/src/signal.c" (12 Oct 2016, 14332 Bytes) of archive /linux/misc/tin-2.4.1.tar.gz:


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.0_vs_2.4.1.

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