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 * signals which need to be processed. 26 */ 27 volatile sig_atomic_t signal_intr; 28 volatile sig_atomic_t signal_stop; 29 volatile sig_atomic_t signal_winch; 30 31 extern int sc_width, sc_height; 32 extern int screen_trashed; 33 extern int linenums; 34 extern int wscroll; 35 extern int quit_on_intr; 36 extern long jump_sline_fraction; 37 38 /* 39 * Interrupt signal handler. 40 */ 41 static void 42 u_interrupt(int type) 43 { 44 signal_intr = 1; 45 } 46 47 /* 48 * "Stop" (^Z) signal handler. 49 */ 50 static void 51 stop(int type) 52 { 53 signal_stop = 1; 54 } 55 56 /* 57 * "Window" change handler 58 */ 59 void 60 sigwinch(int type) 61 { 62 signal_winch = 1; 63 } 64 65 /* 66 * Set up the signal handlers. 67 */ 68 void 69 init_signals(int on) 70 { 71 if (on) { 72 /* 73 * Set signal handlers. 74 */ 75 (void) lsignal(SIGINT, u_interrupt); 76 (void) lsignal(SIGTSTP, stop); 77 (void) lsignal(SIGWINCH, sigwinch); 78 (void) lsignal(SIGQUIT, SIG_IGN); 79 } else { 80 /* 81 * Restore signals to defaults. 82 */ 83 (void) lsignal(SIGINT, SIG_DFL); 84 (void) lsignal(SIGTSTP, SIG_DFL); 85 (void) lsignal(SIGWINCH, SIG_IGN); 86 (void) lsignal(SIGQUIT, SIG_DFL); 87 } 88 } 89 90 /* 91 * Process any signals we have received. 92 */ 93 void 94 psignals(void) 95 { 96 if (signal_stop) { 97 signal_stop = 0; 98 /* 99 * Clean up the terminal. 100 */ 101 lsignal(SIGTTOU, SIG_IGN); 102 clear_bot(); 103 deinit(); 104 flush(0); 105 raw_mode(0); 106 lsignal(SIGTTOU, SIG_DFL); 107 lsignal(SIGTSTP, SIG_DFL); 108 kill(getpid(), SIGTSTP); 109 /* 110 * ... Bye bye. ... 111 * Hopefully we'll be back later and resume here... 112 * Reset the terminal and arrange to repaint the 113 * screen when we get back to the main command loop. 114 */ 115 lsignal(SIGTSTP, stop); 116 raw_mode(1); 117 init(); 118 screen_trashed = 1; 119 signal_winch = 1; 120 } 121 if (signal_winch) { 122 signal_winch = 0; 123 int old_width, old_height; 124 /* 125 * Re-execute scrsize() to read the new window size. 126 */ 127 old_width = sc_width; 128 old_height = sc_height; 129 get_term(); 130 if (sc_width != old_width || sc_height != old_height) { 131 wscroll = (sc_height + 1) / 2; 132 calc_jump_sline(); 133 calc_shift_count(); 134 screen_trashed = 1; 135 } 136 } 137 if (signal_intr) { 138 signal_intr = 0; 139 ring_bell(); 140 if (quit_on_intr) 141 quit(QUIT_INTERRUPT); 142 } 143 } 144 145 /* 146 * Custom version of signal() that causes syscalls to be interrupted. 147 */ 148 void * 149 lsignal(int s, void (*a)(int)) 150 { 151 struct sigaction sa, osa; 152 153 sa.sa_handler = a; 154 sigemptyset(&sa.sa_mask); 155 sa.sa_flags = 0; /* don't restart system calls */ 156 if (sigaction(s, &sa, &osa) != 0) 157 return (SIG_ERR); 158 return (osa.sa_handler); 159 } 160 161 int 162 any_sigs(void) 163 { 164 return (signal_intr || signal_stop || signal_winch); 165 } 166 167 int 168 abort_sigs(void) 169 { 170 return (signal_intr || signal_stop); 171 } 172 173