/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- hostcompat_ttyreset
- hostcompat_ttyresume
- hostcompat_ttysetup
- hostcompat_die
- hostcompat_stop
- hostcompat_cont
- hostcompat_init
1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3 * The President and Fellows of Harvard College.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <unistd.h>
31 #include <termios.h>
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35
36 #include "hostcompat.h"
37
38 /*
39 * The program name.
40 * This is used in err.c.
41 */
42 const char *hostcompat_progname = NULL;
43
44 /*
45 * Unix tty state, for when we're running and to put it back the way it was,
46 * respectively.
47 */
48 static struct termios hostcompat_runtios;
49 static struct termios hostcompat_savetios;
50
51 /*
52 * Put the tty state back the way it was.
53 */
54 static
55 void
56 hostcompat_ttyreset(void)
57 {
58 tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_savetios);
59 }
60
61 /*
62 * Set the tty state back to the way we want it for running.
63 */
64 static
65 void
66 hostcompat_ttyresume(void)
67 {
68 tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_runtios);
69 }
70
71 /*
72 * Set up the tty state stuff.
73 */
74 static
75 int
76 hostcompat_ttysetup(void)
77 {
78 struct termios tios;
79
80 /* Get the current tty state. */
81 if (tcgetattr(STDIN_FILENO, &tios) < 0) {
82 /* stdin is not a tty */
83 return -1;
84 }
85
86 hostcompat_savetios = tios;
87
88 /* Turn off canonical ("cooked") input. */
89 tios.c_lflag &= ~ICANON;
90
91 /*
92 * With canonical input off, this says how many characters must be
93 * typed before read() will return.
94 */
95 tios.c_cc[VMIN] = 1;
96
97 /* This can be used to set up read timeouts, but we don't need that. */
98 tios.c_cc[VTIME] = 0;
99
100 /* Turn off echoing of keypresses. */
101 tios.c_lflag &= ~(ECHO|ECHONL|ECHOCTL);
102
103 /* Do not support XON/XOFF flow control. */
104 tios.c_iflag &= ~(IXON|IXOFF);
105
106 /* On input, we want no CR/LF translation. */
107 tios.c_iflag &= ~(INLCR|IGNCR|ICRNL);
108
109 /* However, on output we want LF ('\n') mapped to CRLF. */
110 #ifdef OCRNL /* missing on OS X */
111 tios.c_oflag &= ~(OCRNL);
112 #endif
113 tios.c_oflag |= OPOST|ONLCR;
114
115 /* Enable keyboard signals (^C, ^Z, etc.) because they're useful. */
116 tios.c_lflag |= ISIG;
117
118 /* Set the new tty state. */
119 hostcompat_runtios = tios;
120 tcsetattr(STDIN_FILENO, TCSADRAIN, &tios);
121
122 return 0;
123 }
124
125 /*
126 * Signal handler for all the fatal signals (SIGSEGV, SIGTERM, etc.)
127 */
128 static
129 void
130 hostcompat_die(int sig)
131 {
132 /* Set the tty back to the way we found it */
133 hostcompat_ttyreset();
134
135 /* Make sure the default action will occur when we get another signal*/
136 signal(sig, SIG_DFL);
137
138 /* Post the signal back to ourselves, to cause the right exit status.*/
139 kill(getpid(), sig);
140
141 /* Just in case. */
142 _exit(255);
143 }
144
145 /*
146 * Signal handler for the stop signals (SIGTSTP, SIGTTIN, etc.)
147 */
148 static
149 void
150 hostcompat_stop(int sig)
151 {
152 /* Set the tty back to the way we found it */
153 hostcompat_ttyreset();
154
155 /* Make sure the default action will occur when we get another signal*/
156 signal(sig, SIG_DFL);
157
158 /* Post the signal back to ourselves. */
159 kill(getpid(), sig);
160 }
161
162 /*
163 * Signal handler for SIGCONT.
164 */
165 static
166 void
167 hostcompat_cont(int sig)
168 {
169 (void)sig;
170
171 /* Set the tty to the way we want it for running. */
172 hostcompat_ttyresume();
173
174 /*
175 * Reload the signal handlers for stop/continue signals, in case
176 * they were set up with one-shot signals.
177 */
178 signal(SIGTTIN, hostcompat_stop);
179 signal(SIGTTOU, hostcompat_stop);
180 signal(SIGTSTP, hostcompat_stop);
181 signal(SIGCONT, hostcompat_cont);
182 }
183
184 /*
185 * Initialize the hostcompat library.
186 */
187 void
188 hostcompat_init(int argc, char *argv[])
189 {
190 /* Set the program name */
191 if (argc > 0 && argv[0] != NULL) {
192 hostcompat_progname = argv[0];
193 }
194
195 /* Set the tty modes */
196 if (hostcompat_ttysetup() < 0) {
197 return;
198 }
199
200 /* When exit() is called, clean up */
201 atexit(hostcompat_ttyreset);
202
203 /* stdout/stderr should be unbuffered */
204 setvbuf(stdout, NULL, _IONBF, 0);
205 setvbuf(stderr, NULL, _IONBF, 0);
206
207 /* Catch all the fatal signals, so we can clean up */
208 signal(SIGHUP, hostcompat_die);
209 signal(SIGINT, hostcompat_die);
210 signal(SIGQUIT, hostcompat_die);
211 signal(SIGILL, hostcompat_die);
212 signal(SIGTRAP, hostcompat_die);
213 signal(SIGABRT, hostcompat_die);
214 #ifdef SIGEMT
215 signal(SIGEMT, hostcompat_die);
216 #endif
217 signal(SIGFPE, hostcompat_die);
218 signal(SIGBUS, hostcompat_die);
219 signal(SIGSEGV, hostcompat_die);
220 signal(SIGSYS, hostcompat_die);
221 signal(SIGPIPE, hostcompat_die);
222 signal(SIGALRM, hostcompat_die);
223 signal(SIGTERM, hostcompat_die);
224 signal(SIGXCPU, hostcompat_die);
225 signal(SIGXFSZ, hostcompat_die);
226 signal(SIGVTALRM, hostcompat_die);
227 signal(SIGPROF, hostcompat_die);
228 signal(SIGUSR1, hostcompat_die);
229 signal(SIGUSR2, hostcompat_die);
230
231 /* Catch the stop signals, so we can adjust the tty */
232 signal(SIGTTIN, hostcompat_stop);
233 signal(SIGTTOU, hostcompat_stop);
234 signal(SIGTSTP, hostcompat_stop);
235
236 /* Catch the continue signal, so we can adjust the tty */
237 signal(SIGCONT, hostcompat_cont);
238 }