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