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
u_interrupt(int type)42 u_interrupt(int type)
43 {
44 signal_intr = 1;
45 }
46
47 /*
48 * "Stop" (^Z) signal handler.
49 */
50 static void
stop(int type)51 stop(int type)
52 {
53 signal_stop = 1;
54 }
55
56 /*
57 * "Window" change handler
58 */
59 void
sigwinch(int type)60 sigwinch(int type)
61 {
62 signal_winch = 1;
63 }
64
65 /*
66 * Set up the signal handlers.
67 */
68 void
init_signals(int on)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
psignals(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 *
lsignal(int s,void (* a)(int))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
any_sigs(void)162 any_sigs(void)
163 {
164 return (signal_intr || signal_stop || signal_winch);
165 }
166
167 int
abort_sigs(void)168 abort_sigs(void)
169 {
170 return (signal_intr || signal_stop);
171 }
172
173