os161-1.99
 All Data Structures
hostcompat.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 #include <unistd.h>
00031 #include <termios.h>
00032 #include <signal.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 
00036 #include "hostcompat.h"
00037 
00038 /*
00039  * The program name.
00040  * This is used in err.c.
00041  */
00042 const char *hostcompat_progname = NULL;
00043 
00044 /*
00045  * Unix tty state, for when we're running and to put it back the way it was,
00046  * respectively.
00047  */
00048 static struct termios hostcompat_runtios;
00049 static struct termios hostcompat_savetios;
00050 
00051 /*
00052  * Put the tty state back the way it was.
00053  */
00054 static
00055 void
00056 hostcompat_ttyreset(void)
00057 {
00058         tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_savetios);
00059 }
00060 
00061 /*
00062  * Set the tty state back to the way we want it for running.
00063  */
00064 static
00065 void
00066 hostcompat_ttyresume(void)
00067 {
00068         tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_runtios);
00069 }
00070 
00071 /*
00072  * Set up the tty state stuff.
00073  */
00074 static
00075 int
00076 hostcompat_ttysetup(void)
00077 {
00078         struct termios tios;
00079 
00080         /* Get the current tty state. */
00081         if (tcgetattr(STDIN_FILENO, &tios) < 0) {
00082                 /* stdin is not a tty */
00083                 return -1;
00084         }
00085 
00086         hostcompat_savetios = tios;
00087 
00088         /* Turn off canonical ("cooked") input. */
00089         tios.c_lflag &= ~ICANON;
00090 
00091         /*
00092          * With canonical input off, this says how many characters must be
00093          * typed before read() will return.
00094          */
00095         tios.c_cc[VMIN] = 1;
00096 
00097         /* This can be used to set up read timeouts, but we don't need that. */
00098         tios.c_cc[VTIME] = 0;
00099 
00100         /* Turn off echoing of keypresses. */
00101         tios.c_lflag &= ~(ECHO|ECHONL|ECHOCTL);
00102 
00103         /* Do not support XON/XOFF flow control. */
00104         tios.c_iflag &= ~(IXON|IXOFF);
00105 
00106         /* On input, we want no CR/LF translation. */
00107         tios.c_iflag &= ~(INLCR|IGNCR|ICRNL);
00108 
00109         /* However, on output we want LF ('\n') mapped to CRLF. */
00110 #ifdef OCRNL    /* missing on OS X */
00111         tios.c_oflag &= ~(OCRNL);
00112 #endif
00113         tios.c_oflag |= OPOST|ONLCR;
00114 
00115         /* Enable keyboard signals (^C, ^Z, etc.) because they're useful. */
00116         tios.c_lflag |= ISIG;
00117 
00118         /* Set the new tty state. */
00119         hostcompat_runtios = tios;
00120         tcsetattr(STDIN_FILENO, TCSADRAIN, &tios);
00121 
00122         return 0;
00123 }
00124 
00125 /*
00126  * Signal handler for all the fatal signals (SIGSEGV, SIGTERM, etc.)
00127  */
00128 static
00129 void
00130 hostcompat_die(int sig)
00131 {
00132         /* Set the tty back to the way we found it */
00133         hostcompat_ttyreset();
00134 
00135         /* Make sure the default action will occur when we get another signal*/
00136         signal(sig, SIG_DFL);
00137 
00138         /* Post the signal back to ourselves, to cause the right exit status.*/
00139         kill(getpid(), sig);
00140 
00141         /* Just in case. */
00142         _exit(255);
00143 }
00144 
00145 /*
00146  * Signal handler for the stop signals (SIGTSTP, SIGTTIN, etc.)
00147  */
00148 static
00149 void
00150 hostcompat_stop(int sig)
00151 {
00152         /* Set the tty back to the way we found it */
00153         hostcompat_ttyreset();
00154 
00155         /* Make sure the default action will occur when we get another signal*/
00156         signal(sig, SIG_DFL);
00157 
00158         /* Post the signal back to ourselves. */
00159         kill(getpid(), sig);
00160 }
00161 
00162 /*
00163  * Signal handler for SIGCONT.
00164  */
00165 static
00166 void
00167 hostcompat_cont(int sig)
00168 {
00169         (void)sig;
00170 
00171         /* Set the tty to the way we want it for running. */
00172         hostcompat_ttyresume();
00173 
00174         /*
00175          * Reload the signal handlers for stop/continue signals, in case
00176          * they were set up with one-shot signals.
00177          */
00178         signal(SIGTTIN, hostcompat_stop);
00179         signal(SIGTTOU, hostcompat_stop);
00180         signal(SIGTSTP, hostcompat_stop);
00181         signal(SIGCONT, hostcompat_cont);
00182 }
00183 
00184 /*
00185  * Initialize the hostcompat library.
00186  */
00187 void
00188 hostcompat_init(int argc, char *argv[])
00189 {
00190         /* Set the program name */
00191         if (argc > 0 && argv[0] != NULL) {
00192                 hostcompat_progname = argv[0];
00193         }
00194 
00195         /* Set the tty modes */
00196         if (hostcompat_ttysetup() < 0) {
00197                 return;
00198         }
00199 
00200         /* When exit() is called, clean up */
00201         atexit(hostcompat_ttyreset);
00202 
00203         /* stdout/stderr should be unbuffered */
00204         setvbuf(stdout, NULL, _IONBF, 0);
00205         setvbuf(stderr, NULL, _IONBF, 0);
00206 
00207         /* Catch all the fatal signals, so we can clean up */
00208         signal(SIGHUP, hostcompat_die);
00209         signal(SIGINT, hostcompat_die);
00210         signal(SIGQUIT, hostcompat_die);
00211         signal(SIGILL, hostcompat_die);
00212         signal(SIGTRAP, hostcompat_die);
00213         signal(SIGABRT, hostcompat_die);
00214 #ifdef SIGEMT
00215         signal(SIGEMT, hostcompat_die);
00216 #endif
00217         signal(SIGFPE, hostcompat_die);
00218         signal(SIGBUS, hostcompat_die);
00219         signal(SIGSEGV, hostcompat_die);
00220         signal(SIGSYS, hostcompat_die);
00221         signal(SIGPIPE, hostcompat_die);
00222         signal(SIGALRM, hostcompat_die);
00223         signal(SIGTERM, hostcompat_die);
00224         signal(SIGXCPU, hostcompat_die);
00225         signal(SIGXFSZ, hostcompat_die);
00226         signal(SIGVTALRM, hostcompat_die);
00227         signal(SIGPROF, hostcompat_die);
00228         signal(SIGUSR1, hostcompat_die);
00229         signal(SIGUSR2, hostcompat_die);
00230 
00231         /* Catch the stop signals, so we can adjust the tty */
00232         signal(SIGTTIN, hostcompat_stop);
00233         signal(SIGTTOU, hostcompat_stop);
00234         signal(SIGTSTP, hostcompat_stop);
00235 
00236         /* Catch the continue signal, so we can adjust the tty */
00237         signal(SIGCONT, hostcompat_cont);
00238 }
 All Data Structures