1 /* 2 * Copyright (C) 1984-2012 Mark Nudelman 3 * Modified for use with illumos by Garrett D'Amore. 4 * Copyright 2015 Garrett D'Amore <garrett@damore.org> 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Less License, as specified in the README file. 8 * 9 * For more information, see the README file. 10 */ 11 12 /* 13 * Routines dealing with signals. 14 * 15 * A signal usually merely causes a bit to be set in the "signals" word. 16 * At some convenient time, the mainline code checks to see if any 17 * signals need processing by calling psignal(). 18 */ 19 20 #include <signal.h> 21 22 #include "less.h" 23 24 /* 25 * "sigs" contains bits indicating signals which need to be processed. 26 */ 27 volatile sig_atomic_t sigs; 28 29 extern int sc_width, sc_height; 30 extern int screen_trashed; 31 extern int linenums; 32 extern int wscroll; 33 extern int quit_on_intr; 34 extern long jump_sline_fraction; 35 36 /* 37 * Interrupt signal handler. 38 */ 39 static void 40 u_interrupt(int type) 41 { 42 sigs |= S_INTERRUPT; 43 } 44 45 /* 46 * "Stop" (^Z) signal handler. 47 */ 48 static void 49 stop(int type) 50 { 51 sigs |= S_STOP; 52 } 53 54 /* 55 * "Window" change handler 56 */ 57 void 58 sigwinch(int type) 59 { 60 sigs |= S_WINCH; 61 } 62 63 /* 64 * Set up the signal handlers. 65 */ 66 void 67 init_signals(int on) 68 { 69 if (on) { 70 /* 71 * Set signal handlers. 72 */ 73 (void) lsignal(SIGINT, u_interrupt); 74 (void) lsignal(SIGTSTP, stop); 75 (void) lsignal(SIGWINCH, sigwinch); 76 (void) lsignal(SIGQUIT, SIG_IGN); 77 } else { 78 /* 79 * Restore signals to defaults. 80 */ 81 (void) lsignal(SIGINT, SIG_DFL); 82 (void) lsignal(SIGTSTP, SIG_DFL); 83 (void) lsignal(SIGWINCH, SIG_IGN); 84 (void) lsignal(SIGQUIT, SIG_DFL); 85 } 86 } 87 88 /* 89 * Process any signals we have received. 90 * A received signal cause a bit to be set in "sigs". 91 */ 92 void 93 psignals(void) 94 { 95 int tsignals; 96 97 if ((tsignals = sigs) == 0) 98 return; 99 sigs = 0; 100 101 if (tsignals & S_STOP) { 102 /* 103 * Clean up the terminal. 104 */ 105 lsignal(SIGTTOU, SIG_IGN); 106 clear_bot(); 107 deinit(); 108 flush(0); 109 raw_mode(0); 110 lsignal(SIGTTOU, SIG_DFL); 111 lsignal(SIGTSTP, SIG_DFL); 112 kill(getpid(), SIGTSTP); 113 /* 114 * ... Bye bye. ... 115 * Hopefully we'll be back later and resume here... 116 * Reset the terminal and arrange to repaint the 117 * screen when we get back to the main command loop. 118 */ 119 lsignal(SIGTSTP, stop); 120 raw_mode(1); 121 init(); 122 screen_trashed = 1; 123 tsignals |= S_WINCH; 124 } 125 if (tsignals & S_WINCH) { 126 int old_width, old_height; 127 /* 128 * Re-execute scrsize() to read the new window size. 129 */ 130 old_width = sc_width; 131 old_height = sc_height; 132 get_term(); 133 if (sc_width != old_width || sc_height != old_height) { 134 wscroll = (sc_height + 1) / 2; 135 calc_jump_sline(); 136 calc_shift_count(); 137 screen_trashed = 1; 138 } 139 } 140 if (tsignals & S_INTERRUPT) { 141 ring_bell(); 142 if (quit_on_intr) 143 quit(QUIT_INTERRUPT); 144 } 145 } 146 147 /* 148 * Custom version of signal() that causes syscalls to be interrupted. 149 */ 150 void * 151 lsignal(int s, void (*a)(int)) 152 { 153 struct sigaction sa, osa; 154 155 sa.sa_handler = a; 156 sigemptyset(&sa.sa_mask); 157 sa.sa_flags = 0; /* don't restart system calls */ 158 if (sigaction(s, &sa, &osa) != 0) 159 return (SIG_ERR); 160 return (osa.sa_handler); 161 } 162