e9c4a499df1949be87bb2067fe411ab4acc53c50
[debian/sudo] / common / term.c
1 /*
2  * Copyright (c) 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/types.h>
20 #include <sys/param.h>
21 #include <stdio.h>
22 #ifdef STDC_HEADERS
23 # include <stdlib.h>
24 # include <stddef.h>
25 #else
26 # ifdef HAVE_STDLIB_H
27 #  include <stdlib.h>
28 # endif
29 #endif /* STDC_HEADERS */
30 #ifdef HAVE_STRING_H
31 # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
32 #  include <memory.h>
33 # endif
34 # include <string.h>
35 #endif /* HAVE_STRING_H */
36 #ifdef HAVE_STRINGS_H
37 # include <strings.h>
38 #endif /* HAVE_STRINGS_H */
39 #include <termios.h>
40
41 #include "missing.h"
42 #include "sudo_debug.h"
43
44 #ifndef TCSASOFT
45 # define TCSASOFT       0
46 #endif
47 #ifndef ECHONL
48 # define ECHONL         0
49 #endif
50 #ifndef IEXTEN
51 # define IEXTEN         0
52 #endif
53 #ifndef IUCLC
54 # define IUCLC          0
55 #endif
56
57 #ifndef _POSIX_VDISABLE
58 # ifdef VDISABLE
59 #  define _POSIX_VDISABLE       VDISABLE
60 # else
61 #  define _POSIX_VDISABLE       0
62 # endif
63 #endif
64
65 static struct termios term, oterm;
66 static int changed;
67 int term_erase;
68 int term_kill;
69
70 int
71 term_restore(int fd, int flush)
72 {
73     debug_decl(term_restore, SUDO_DEBUG_UTIL)
74
75     if (changed) {
76         int flags = TCSASOFT;
77         flags |= flush ? TCSAFLUSH : TCSADRAIN;
78         if (tcsetattr(fd, flags, &oterm) != 0)
79             debug_return_int(0);
80         changed = 0;
81     }
82     debug_return_int(1);
83 }
84
85 int
86 term_noecho(int fd)
87 {
88     debug_decl(term_noecho, SUDO_DEBUG_UTIL)
89
90     if (!changed && tcgetattr(fd, &oterm) != 0)
91         debug_return_int(0);
92     (void) memcpy(&term, &oterm, sizeof(term));
93     CLR(term.c_lflag, ECHO|ECHONL);
94 #ifdef VSTATUS
95     term.c_cc[VSTATUS] = _POSIX_VDISABLE;
96 #endif
97     if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
98         changed = 1;
99         debug_return_int(1);
100     }
101     debug_return_int(0);
102 }
103
104 int
105 term_raw(int fd, int isig)
106 {
107     struct termios term;
108     debug_decl(term_raw, SUDO_DEBUG_UTIL)
109
110     if (!changed && tcgetattr(fd, &oterm) != 0)
111         return 0;
112     (void) memcpy(&term, &oterm, sizeof(term));
113     /* Set terminal to raw mode */
114     term.c_cc[VMIN] = 1;
115     term.c_cc[VTIME] = 0;
116     CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON);
117     CLR(term.c_oflag, OPOST);
118     CLR(term.c_lflag, ECHO | ICANON | ISIG | IEXTEN);
119     if (isig)
120         SET(term.c_lflag, ISIG);
121     if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
122         changed = 1;
123         debug_return_int(1);
124     }
125     debug_return_int(0);
126 }
127
128 int
129 term_cbreak(int fd)
130 {
131     debug_decl(term_cbreak, SUDO_DEBUG_UTIL)
132
133     if (!changed && tcgetattr(fd, &oterm) != 0)
134         return 0;
135     (void) memcpy(&term, &oterm, sizeof(term));
136     /* Set terminal to half-cooked mode */
137     term.c_cc[VMIN] = 1;
138     term.c_cc[VTIME] = 0;
139     CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN);
140     SET(term.c_lflag, ISIG);
141 #ifdef VSTATUS
142     term.c_cc[VSTATUS] = _POSIX_VDISABLE;
143 #endif
144     if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) {
145         term_erase = term.c_cc[VERASE];
146         term_kill = term.c_cc[VKILL];
147         changed = 1;
148         debug_return_int(1);
149     }
150     debug_return_int(0);
151 }
152
153 int
154 term_copy(int src, int dst)
155 {
156     struct termios tt;
157     debug_decl(term_copy, SUDO_DEBUG_UTIL)
158
159     if (tcgetattr(src, &tt) != 0)
160         debug_return_int(0);
161     if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0)
162         debug_return_int(0);
163     debug_return_int(1);
164 }