1/* 2 * Copyright (c) 2009-2011 Todd C. Miller <Todd.Miller@courtesan.com> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include <config.h> 18 19#include <sys/errno.h> 20#include <sys/types.h> 21#include <sys/param.h> 22#include <stdio.h> 23#ifdef STDC_HEADERS 24# include <stdlib.h> 25# include <stddef.h> 26#else 27# ifdef HAVE_STDLIB_H 28# include <stdlib.h> 29# endif 30#endif /* STDC_HEADERS */ 31#ifdef HAVE_STRING_H 32# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) 33# include <memory.h> 34# endif 35# include <string.h> 36#endif /* HAVE_STRING_H */ 37#ifdef HAVE_STRINGS_H 38# include <strings.h> 39#endif /* HAVE_STRINGS_H */ 40#ifdef HAVE_TERMIOS_H 41# include <termios.h> 42#else 43# ifdef HAVE_TERMIO_H 44# include <termio.h> 45# else 46# include <sgtty.h> 47# include <sys/ioctl.h> 48# endif /* HAVE_TERMIO_H */ 49#endif /* HAVE_TERMIOS_H */ 50 51#include "sudo.h" 52 53#ifndef TCSASOFT 54# define TCSASOFT 0 55#endif 56#ifndef ECHONL 57# define ECHONL 0 58#endif 59#ifndef IEXTEN 60# define IEXTEN 0 61#endif 62#ifndef IUCLC 63# define IUCLC 0 64#endif 65 66#ifndef _POSIX_VDISABLE 67# ifdef VDISABLE 68# define _POSIX_VDISABLE VDISABLE 69# else 70# define _POSIX_VDISABLE 0 71# endif 72#endif 73 74/* 75 * Compat macros for non-termios systems. 76 */ 77#ifndef HAVE_TERMIOS_H 78# ifdef HAVE_TERMIO_H 79# undef termios 80# define termios termio 81# define tcgetattr(f, t) ioctl(f, TCGETA, t) 82# define tcsetattr(f, a, t) ioctl(f, a, t) 83# undef TCSAFLUSH 84# define TCSAFLUSH TCSETAF 85# undef TCSADRAIN 86# define TCSADRAIN TCSETAW 87# else /* SGTTY */ 88# undef termios 89# define termios sgttyb 90# define c_lflag sg_flags 91# define tcgetattr(f, t) ioctl(f, TIOCGETP, t) 92# define tcsetattr(f, a, t) ioctl(f, a, t) 93# undef TCSAFLUSH 94# define TCSAFLUSH TIOCSETP 95# undef TCSADRAIN 96# define TCSADRAIN TIOCSETN 97# endif /* HAVE_TERMIO_H */ 98#endif /* HAVE_TERMIOS_H */ 99 100typedef struct termios sudo_term_t; 101 102static sudo_term_t term, oterm; 103static int changed; 104int term_erase; 105int term_kill; 106 107int 108term_restore(fd, flush) 109 int fd; 110 int flush; 111{ 112 if (changed) { 113 int flags = TCSASOFT; 114 flags |= flush ? TCSAFLUSH : TCSADRAIN; 115 for (;;) { 116 if (tcsetattr(fd, flags, &oterm) == 0) 117 break; 118 if (errno == EINTR) 119 continue; 120 return 0; 121 } 122 changed = 0; 123 } 124 return 1; 125} 126 127int 128term_noecho(fd) 129 int fd; 130{ 131 if (!changed && tcgetattr(fd, &oterm) != 0) 132 return 0; 133 (void) memcpy(&term, &oterm, sizeof(term)); 134 CLR(term.c_lflag, ECHO|ECHONL); 135#ifdef VSTATUS 136 term.c_cc[VSTATUS] = _POSIX_VDISABLE; 137#endif 138 for (;;) { 139 if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { 140 changed = 1; 141 return 1; 142 } 143 if (errno != EINTR) 144 break; 145 } 146 return 0; 147} 148 149#if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H) 150 151int 152term_raw(fd, isig) 153 int fd; 154 int isig; 155{ 156 struct termios term; 157 158 if (!changed && tcgetattr(fd, &oterm) != 0) 159 return 0; 160 (void) memcpy(&term, &oterm, sizeof(term)); 161 /* Set terminal to raw mode */ 162 term.c_cc[VMIN] = 1; 163 term.c_cc[VTIME] = 0; 164 CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON); 165 CLR(term.c_oflag, OPOST); 166 CLR(term.c_lflag, ECHO | ICANON | ISIG | IEXTEN); 167 if (isig) 168 SET(term.c_lflag, ISIG); 169 if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { 170 changed = 1; 171 return 1; 172 } 173 return 0; 174} 175 176int 177term_cbreak(fd) 178 int fd; 179{ 180 if (!changed && tcgetattr(fd, &oterm) != 0) 181 return 0; 182 (void) memcpy(&term, &oterm, sizeof(term)); 183 /* Set terminal to half-cooked mode */ 184 term.c_cc[VMIN] = 1; 185 term.c_cc[VTIME] = 0; 186 CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN); 187 SET(term.c_lflag, ISIG); 188#ifdef VSTATUS 189 term.c_cc[VSTATUS] = _POSIX_VDISABLE; 190#endif 191 if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { 192 term_erase = term.c_cc[VERASE]; 193 term_kill = term.c_cc[VKILL]; 194 changed = 1; 195 return 1; 196 } 197 return 0; 198} 199 200int 201term_copy(src, dst) 202 int src; 203 int dst; 204{ 205 struct termios tt; 206 207 if (tcgetattr(src, &tt) != 0) 208 return 0; 209 /* XXX - add TCSANOW compat define */ 210 if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0) 211 return 0; 212 return 1; 213} 214 215#else /* SGTTY */ 216 217int 218term_raw(fd, isig) 219 int fd; 220 int isig; 221{ 222 if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0) 223 return 0; 224 (void) memcpy(&term, &oterm, sizeof(term)); 225 /* Set terminal to raw mode */ 226 /* XXX - how to support isig? */ 227 CLR(term.c_lflag, ECHO); 228 SET(term.sg_flags, RAW); 229 if (ioctl(fd, TIOCSETP, &term) == 0) { 230 changed = 1; 231 return 1; 232 } 233 return 0; 234} 235 236int 237term_cbreak(fd) 238 int fd; 239{ 240 if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0) 241 return 0; 242 (void) memcpy(&term, &oterm, sizeof(term)); 243 /* Set terminal to half-cooked mode */ 244 CLR(term.c_lflag, ECHO); 245 SET(term.sg_flags, CBREAK); 246 if (ioctl(fd, TIOCSETP, &term) == 0) { 247 term_erase = term.sg_erase; 248 term_kill = term.sg_kill; 249 changed = 1; 250 return 1; 251 } 252 return 0; 253} 254 255int 256term_copy(src, dst) 257 int src; 258 int dst; 259{ 260 struct sgttyb b; 261 struct tchars tc; 262 struct ltchars lc; 263 int l, lb; 264 265 if (ioctl(src, TIOCGETP, &b) != 0 || ioctl(src, TIOCGETC, &tc) != 0 || 266 ioctl(src, TIOCGETD, &l) != 0 || ioctl(src, TIOCGLTC, &lc) != 0 || 267 ioctl(src, TIOCLGET, &lb)) { 268 return 0; 269 } 270 if (ioctl(dst, TIOCSETP, &b) != 0 || ioctl(dst, TIOCSETC, &tc) != 0 || 271 ioctl(dst, TIOCSLTC, &lc) != 0 || ioctl(dst, TIOCLSET, &lb) != 0 || 272 ioctl(dst, TIOCSETD, &l) != 0) { 273 return 0; 274 } 275 return 1; 276} 277 278#endif 279