hostcompat.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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. #include <unistd.h>
  30. #include <termios.h>
  31. #include <signal.h>
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include "hostcompat.h"
  35. /*
  36. * The program name.
  37. * This is used in err.c.
  38. */
  39. const char *hostcompat_progname = NULL;
  40. /*
  41. * Unix tty state, for when we're running and to put it back the way it was,
  42. * respectively.
  43. */
  44. static struct termios hostcompat_runtios;
  45. static struct termios hostcompat_savetios;
  46. /*
  47. * Put the tty state back the way it was.
  48. */
  49. static
  50. void
  51. hostcompat_ttyreset(void)
  52. {
  53. tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_savetios);
  54. }
  55. /*
  56. * Set the tty state back to the way we want it for running.
  57. */
  58. static
  59. void
  60. hostcompat_ttyresume(void)
  61. {
  62. tcsetattr(STDIN_FILENO, TCSADRAIN, &hostcompat_runtios);
  63. }
  64. /*
  65. * Set up the tty state stuff.
  66. */
  67. static
  68. int
  69. hostcompat_ttysetup(void)
  70. {
  71. struct termios tios;
  72. /* Get the current tty state. */
  73. if (tcgetattr(STDIN_FILENO, &tios) < 0) {
  74. /* stdin is not a tty */
  75. return -1;
  76. }
  77. hostcompat_savetios = tios;
  78. /* Turn off canonical ("cooked") input. */
  79. tios.c_lflag &= ~ICANON;
  80. /*
  81. * With canonical input off, this says how many characters must be
  82. * typed before read() will return.
  83. */
  84. tios.c_cc[VMIN] = 1;
  85. /* This can be used to set up read timeouts, but we don't need that. */
  86. tios.c_cc[VTIME] = 0;
  87. /* Turn off echoing of keypresses. */
  88. tios.c_lflag &= ~(ECHO|ECHONL|ECHOCTL);
  89. /* Do not support XON/XOFF flow control. */
  90. tios.c_iflag &= ~(IXON|IXOFF);
  91. /* On input, we want no CR/LF translation. */
  92. tios.c_iflag &= ~(INLCR|IGNCR|ICRNL);
  93. /* However, on output we want LF ('\n') mapped to CRLF. */
  94. #ifdef OCRNL /* missing on OS X */
  95. tios.c_oflag &= ~(OCRNL);
  96. #endif
  97. tios.c_oflag |= OPOST|ONLCR;
  98. /* Enable keyboard signals (^C, ^Z, etc.) because they're useful. */
  99. tios.c_lflag |= ISIG;
  100. /* Set the new tty state. */
  101. hostcompat_runtios = tios;
  102. tcsetattr(STDIN_FILENO, TCSADRAIN, &tios);
  103. return 0;
  104. }
  105. /*
  106. * Signal handler for all the fatal signals (SIGSEGV, SIGTERM, etc.)
  107. */
  108. static
  109. void
  110. hostcompat_die(int sig)
  111. {
  112. /* Set the tty back to the way we found it */
  113. hostcompat_ttyreset();
  114. /* Make sure the default action will occur when we get another signal*/
  115. signal(sig, SIG_DFL);
  116. /* Post the signal back to ourselves, to cause the right exit status.*/
  117. kill(getpid(), sig);
  118. /* Just in case. */
  119. _exit(255);
  120. }
  121. /*
  122. * Signal handler for the stop signals (SIGTSTP, SIGTTIN, etc.)
  123. */
  124. static
  125. void
  126. hostcompat_stop(int sig)
  127. {
  128. /* Set the tty back to the way we found it */
  129. hostcompat_ttyreset();
  130. /* Make sure the default action will occur when we get another signal*/
  131. signal(sig, SIG_DFL);
  132. /* Post the signal back to ourselves. */
  133. kill(getpid(), sig);
  134. }
  135. /*
  136. * Signal handler for SIGCONT.
  137. */
  138. static
  139. void
  140. hostcompat_cont(int sig)
  141. {
  142. (void)sig;
  143. /* Set the tty to the way we want it for running. */
  144. hostcompat_ttyresume();
  145. /*
  146. * Reload the signal handlers for stop/continue signals, in case
  147. * they were set up with one-shot signals.
  148. */
  149. signal(SIGTTIN, hostcompat_stop);
  150. signal(SIGTTOU, hostcompat_stop);
  151. signal(SIGTSTP, hostcompat_stop);
  152. signal(SIGCONT, hostcompat_cont);
  153. }
  154. /*
  155. * Initialize the hostcompat library.
  156. */
  157. void
  158. hostcompat_init(int argc, char *argv[])
  159. {
  160. /* Set the program name */
  161. if (argc > 0 && argv[0] != NULL) {
  162. hostcompat_progname = argv[0];
  163. }
  164. /* Set the tty modes */
  165. if (hostcompat_ttysetup() < 0) {
  166. return;
  167. }
  168. /* When exit() is called, clean up */
  169. atexit(hostcompat_ttyreset);
  170. /* stdout/stderr should be unbuffered */
  171. setvbuf(stdout, NULL, _IONBF, 0);
  172. setvbuf(stderr, NULL, _IONBF, 0);
  173. /* Catch all the fatal signals, so we can clean up */
  174. signal(SIGHUP, hostcompat_die);
  175. signal(SIGINT, hostcompat_die);
  176. signal(SIGQUIT, hostcompat_die);
  177. signal(SIGILL, hostcompat_die);
  178. signal(SIGTRAP, hostcompat_die);
  179. signal(SIGABRT, hostcompat_die);
  180. #ifdef SIGEMT
  181. signal(SIGEMT, hostcompat_die);
  182. #endif
  183. signal(SIGFPE, hostcompat_die);
  184. signal(SIGBUS, hostcompat_die);
  185. signal(SIGSEGV, hostcompat_die);
  186. signal(SIGSYS, hostcompat_die);
  187. signal(SIGPIPE, hostcompat_die);
  188. signal(SIGALRM, hostcompat_die);
  189. signal(SIGTERM, hostcompat_die);
  190. signal(SIGXCPU, hostcompat_die);
  191. signal(SIGXFSZ, hostcompat_die);
  192. signal(SIGVTALRM, hostcompat_die);
  193. signal(SIGPROF, hostcompat_die);
  194. signal(SIGUSR1, hostcompat_die);
  195. signal(SIGUSR2, hostcompat_die);
  196. /* Catch the stop signals, so we can adjust the tty */
  197. signal(SIGTTIN, hostcompat_stop);
  198. signal(SIGTTOU, hostcompat_stop);
  199. signal(SIGTSTP, hostcompat_stop);
  200. /* Catch the continue signal, so we can adjust the tty */
  201. signal(SIGCONT, hostcompat_cont);
  202. }