/src/libssh/src/ttyopts.c
Line | Count | Source |
1 | | /* |
2 | | * ttyopts.c - encoding of TTY modes. |
3 | | * |
4 | | * This file is part of the SSH Library |
5 | | * |
6 | | * Copyright (c) 2023 by Utimaco TS GmbH <oss_committee@utimaco.com> |
7 | | * Author: Daniel Evers <daniel.evers@utimaco.com> |
8 | | * |
9 | | * The SSH Library is free software; you can redistribute it and/or modify |
10 | | * it under the terms of the GNU Lesser General Public License as published by |
11 | | * the Free Software Foundation; either version 2.1 of the License, or (at your |
12 | | * option) any later version. |
13 | | * |
14 | | * The SSH Library is distributed in the hope that it will be useful, but |
15 | | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
16 | | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
17 | | * License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public License |
20 | | * along with the SSH Library; see the file COPYING. If not, write to |
21 | | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
22 | | * MA 02111-1307, USA. |
23 | | */ |
24 | | |
25 | | #include "config.h" |
26 | | |
27 | | #include <stdint.h> |
28 | | #include <stdio.h> |
29 | | |
30 | | #include <libssh/priv.h> |
31 | | #include <string.h> |
32 | | |
33 | | #ifdef HAVE_TERMIOS_H |
34 | | #include <termios.h> |
35 | | #endif |
36 | | |
37 | | /** Terminal mode opcodes */ |
38 | | enum { |
39 | | TTY_OP_END = 0, |
40 | | TTY_OP_VINTR = 1, |
41 | | TTY_OP_VQUIT = 2, |
42 | | TTY_OP_VERASE = 3, |
43 | | TTY_OP_VKILL = 4, |
44 | | TTY_OP_VEOF = 5, |
45 | | TTY_OP_VEOL = 6, |
46 | | TTY_OP_VEOL2 = 7, |
47 | | TTY_OP_VSTART = 8, |
48 | | TTY_OP_VSTOP = 9, |
49 | | TTY_OP_VSUSP = 10, |
50 | | TTY_OP_VDSUSP = 11, |
51 | | TTY_OP_VREPRINT = 12, |
52 | | TTY_OP_VWERASE = 13, |
53 | | TTY_OP_VLNEXT = 14, |
54 | | TTY_OP_VFLUSH = 15, |
55 | | TTY_OP_VSWTC = 16, |
56 | | TTY_OP_VSTATUS = 17, |
57 | | TTY_OP_VDISCARD = 18, |
58 | | TTY_OP_IGNPAR = 30, |
59 | | TTY_OP_PARMRK = 31, |
60 | | TTY_OP_INPCK = 32, |
61 | | TTY_OP_ISTRIP = 33, |
62 | | TTY_OP_INLCR = 34, |
63 | | TTY_OP_IGNCR = 35, |
64 | | TTY_OP_ICRNL = 36, |
65 | | TTY_OP_IUCLC = 37, |
66 | | TTY_OP_IXON = 38, |
67 | | TTY_OP_IXANY = 39, |
68 | | TTY_OP_IXOFF = 40, |
69 | | TTY_OP_IMAXBEL = 41, |
70 | | TTY_OP_IUTF8 = 42, |
71 | | TTY_OP_ISIG = 50, |
72 | | TTY_OP_ICANON = 51, |
73 | | TTY_OP_XCASE = 52, |
74 | | TTY_OP_ECHO = 53, |
75 | | TTY_OP_ECHOE = 54, |
76 | | TTY_OP_ECHOK = 55, |
77 | | TTY_OP_ECHONL = 56, |
78 | | TTY_OP_NOFLSH = 57, |
79 | | TTY_OP_TOSTOP = 58, |
80 | | TTY_OP_IEXTEN = 59, |
81 | | TTY_OP_ECHOCTL = 60, |
82 | | TTY_OP_ECHOKE = 61, |
83 | | TTY_OP_PENDIN = 62, |
84 | | TTY_OP_OPOST = 70, |
85 | | TTY_OP_OLCUC = 71, |
86 | | TTY_OP_ONLCR = 72, |
87 | | TTY_OP_OCRNL = 73, |
88 | | TTY_OP_ONOCR = 74, |
89 | | TTY_OP_ONLRET = 75, |
90 | | TTY_OP_CS7 = 90, |
91 | | TTY_OP_CS8 = 91, |
92 | | TTY_OP_PARENB = 92, |
93 | | TTY_OP_PARODD = 93, |
94 | | TTY_OP_ISPEED = 128, |
95 | | TTY_OP_OSPEED = 129, |
96 | | }; |
97 | | |
98 | | /** |
99 | | * Encodes a single SSH terminal mode option into the buffer. |
100 | | * |
101 | | * @param[in] attr The mode's opcode value. |
102 | | * |
103 | | * @param[in] value The mode's value. |
104 | | * |
105 | | * @param[out] buf Destination buffer to encode into. |
106 | | * |
107 | | * @param[in] buflen The length of the buffer. |
108 | | * |
109 | | * @return number of bytes written to the buffer on success, -1 on |
110 | | * error. |
111 | | */ |
112 | | static int |
113 | | encode_termios_opt(unsigned char opcode, |
114 | | uint32_t value, |
115 | | unsigned char *buf, |
116 | | size_t buflen) |
117 | 0 | { |
118 | 0 | int offset = 0; |
119 | | |
120 | | /* always need 5 bytes */ |
121 | 0 | if (buflen < 5) { |
122 | 0 | return -1; |
123 | 0 | } |
124 | | |
125 | | /* 1 byte opcode */ |
126 | 0 | buf[offset++] = opcode; |
127 | | |
128 | | /* 4 bytes value (big endian) */ |
129 | 0 | value = htonl(value); |
130 | 0 | memcpy(buf + offset, &value, sizeof(value)); |
131 | 0 | offset += sizeof(value); |
132 | |
|
133 | 0 | return offset; |
134 | 0 | } |
135 | | |
136 | | #ifdef HAVE_TERMIOS_H |
137 | | /** Converts a baudrate constant (Bxxxx) to a numeric value. */ |
138 | | static int |
139 | | baud2speed(int baudrate) |
140 | 0 | { |
141 | 0 | switch (baudrate) { |
142 | 0 | default: |
143 | 0 | case B0: |
144 | 0 | return 0; |
145 | 0 | case B50: |
146 | 0 | return 50; |
147 | 0 | case B75: |
148 | 0 | return 75; |
149 | 0 | case B110: |
150 | 0 | return 110; |
151 | 0 | case B134: |
152 | 0 | return 134; |
153 | 0 | case B150: |
154 | 0 | return 150; |
155 | 0 | case B200: |
156 | 0 | return 200; |
157 | 0 | case B300: |
158 | 0 | return 300; |
159 | 0 | case B600: |
160 | 0 | return 600; |
161 | 0 | case B1200: |
162 | 0 | return 1200; |
163 | 0 | case B1800: |
164 | 0 | return 1800; |
165 | 0 | case B2400: |
166 | 0 | return 2400; |
167 | 0 | case B4800: |
168 | 0 | return 4800; |
169 | 0 | case B9600: |
170 | 0 | return 9600; |
171 | 0 | case B19200: |
172 | 0 | return 19200; |
173 | 0 | case B38400: |
174 | 0 | return 38400; |
175 | 0 | #ifdef B57600 |
176 | 0 | case B57600: |
177 | 0 | return 57600; |
178 | 0 | #endif |
179 | 0 | #ifdef B115200 |
180 | 0 | case B115200: |
181 | 0 | return 115200; |
182 | 0 | #endif |
183 | 0 | #ifdef B230400 |
184 | 0 | case B230400: |
185 | 0 | return 230400; |
186 | 0 | #endif |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | | /** |
191 | | * Encodes all terminal options from the given \c termios structure |
192 | | * into the buffer. |
193 | | * |
194 | | * @param[in] attr The terminal options to encode. |
195 | | * |
196 | | * @param[out] buf Modes will be encoded into this buffer. |
197 | | * |
198 | | * @param[in] buflen The length of the buffer. |
199 | | * |
200 | | * @return number of bytes in the buffer on success, -1 on error. |
201 | | */ |
202 | | static int |
203 | | encode_termios_opts(struct termios *attr, unsigned char *buf, size_t buflen) |
204 | 0 | { |
205 | 0 | unsigned int offset = 0; |
206 | 0 | int rc; |
207 | |
|
208 | 0 | #define SSH_ENCODE_OPT(code, value) \ |
209 | 0 | rc = encode_termios_opt(code, value, buf + offset, buflen - offset); \ |
210 | 0 | if (rc < 0) { \ |
211 | 0 | return rc; \ |
212 | 0 | } else { \ |
213 | 0 | offset += rc; \ |
214 | 0 | } |
215 | |
|
216 | 0 | #define SSH_ENCODE_INPUT_OPT(opt) \ |
217 | 0 | SSH_ENCODE_OPT(TTY_OP_##opt, (attr->c_iflag & opt) ? 1 : 0) |
218 | 0 | SSH_ENCODE_INPUT_OPT(IGNPAR) |
219 | 0 | SSH_ENCODE_INPUT_OPT(PARMRK) |
220 | 0 | SSH_ENCODE_INPUT_OPT(INPCK) |
221 | 0 | SSH_ENCODE_INPUT_OPT(ISTRIP) |
222 | 0 | SSH_ENCODE_INPUT_OPT(INLCR) |
223 | 0 | SSH_ENCODE_INPUT_OPT(IGNCR) |
224 | 0 | SSH_ENCODE_INPUT_OPT(ICRNL) |
225 | 0 | #ifdef IUCLC |
226 | 0 | SSH_ENCODE_INPUT_OPT(IUCLC) |
227 | 0 | #endif |
228 | 0 | SSH_ENCODE_INPUT_OPT(IXON) |
229 | 0 | SSH_ENCODE_INPUT_OPT(IXANY) |
230 | 0 | SSH_ENCODE_INPUT_OPT(IXOFF) |
231 | 0 | #ifdef IMAXBEL |
232 | 0 | SSH_ENCODE_INPUT_OPT(IMAXBEL) |
233 | 0 | #endif |
234 | 0 | #ifdef IUTF8 |
235 | 0 | SSH_ENCODE_INPUT_OPT(IUTF8) |
236 | 0 | #endif |
237 | 0 | #undef SSH_ENCODE_INPUT_OPT |
238 | | |
239 | 0 | #define SSH_ENCODE_OUTPUT_OPT(opt) \ |
240 | 0 | SSH_ENCODE_OPT(TTY_OP_##opt, (attr->c_oflag & opt) ? 1 : 0) |
241 | 0 | SSH_ENCODE_OUTPUT_OPT(OPOST) |
242 | 0 | #ifdef OLCUC |
243 | 0 | SSH_ENCODE_OUTPUT_OPT(OLCUC) |
244 | 0 | #endif |
245 | 0 | SSH_ENCODE_OUTPUT_OPT(ONLCR) |
246 | 0 | SSH_ENCODE_OUTPUT_OPT(OCRNL) |
247 | 0 | SSH_ENCODE_OUTPUT_OPT(ONOCR) |
248 | 0 | SSH_ENCODE_OUTPUT_OPT(ONLRET) |
249 | 0 | #undef SSH_ENCODE_OUTPUT_OPT |
250 | | |
251 | 0 | #define SSH_ENCODE_CONTROL_OPT(opt) \ |
252 | 0 | SSH_ENCODE_OPT(TTY_OP_##opt, (attr->c_cflag & opt) ? 1 : 0) |
253 | 0 | SSH_ENCODE_CONTROL_OPT(CS7) |
254 | 0 | SSH_ENCODE_CONTROL_OPT(CS8) |
255 | 0 | SSH_ENCODE_CONTROL_OPT(PARENB) |
256 | 0 | SSH_ENCODE_CONTROL_OPT(PARODD) |
257 | 0 | #undef SSH_ENCODE_CONTROL_OPT |
258 | | |
259 | 0 | #define SSH_ENCODE_LOCAL_OPT(opt) \ |
260 | 0 | SSH_ENCODE_OPT(TTY_OP_##opt, (attr->c_lflag & opt) ? 1 : 0) |
261 | 0 | SSH_ENCODE_LOCAL_OPT(ISIG) |
262 | 0 | SSH_ENCODE_LOCAL_OPT(ICANON) |
263 | 0 | #ifdef XCASE |
264 | 0 | SSH_ENCODE_LOCAL_OPT(XCASE) |
265 | 0 | #endif |
266 | 0 | SSH_ENCODE_LOCAL_OPT(ECHO) |
267 | 0 | SSH_ENCODE_LOCAL_OPT(ECHOE) |
268 | 0 | SSH_ENCODE_LOCAL_OPT(ECHOK) |
269 | 0 | SSH_ENCODE_LOCAL_OPT(ECHONL) |
270 | 0 | SSH_ENCODE_LOCAL_OPT(NOFLSH) |
271 | 0 | SSH_ENCODE_LOCAL_OPT(TOSTOP) |
272 | 0 | SSH_ENCODE_LOCAL_OPT(IEXTEN) |
273 | 0 | #ifdef ECHOCTL |
274 | 0 | SSH_ENCODE_LOCAL_OPT(ECHOCTL) |
275 | 0 | #endif |
276 | 0 | #ifdef ECHOKE |
277 | 0 | SSH_ENCODE_LOCAL_OPT(ECHOKE) |
278 | 0 | #endif |
279 | 0 | #ifdef PENDIN |
280 | 0 | SSH_ENCODE_LOCAL_OPT(PENDIN) |
281 | 0 | #endif |
282 | 0 | #undef SSH_ENCODE_LOCAL_OPT |
283 | | |
284 | 0 | #define SSH_ENCODE_CC_OPT(opt) SSH_ENCODE_OPT(TTY_OP_##opt, attr->c_cc[opt]) |
285 | 0 | SSH_ENCODE_CC_OPT(VINTR) |
286 | 0 | SSH_ENCODE_CC_OPT(VQUIT) |
287 | 0 | SSH_ENCODE_CC_OPT(VERASE) |
288 | 0 | SSH_ENCODE_CC_OPT(VKILL) |
289 | 0 | SSH_ENCODE_CC_OPT(VEOF) |
290 | 0 | SSH_ENCODE_CC_OPT(VEOL) |
291 | 0 | #ifdef VEOL2 |
292 | 0 | SSH_ENCODE_CC_OPT(VEOL2) |
293 | 0 | #endif |
294 | 0 | SSH_ENCODE_CC_OPT(VSTART) |
295 | 0 | SSH_ENCODE_CC_OPT(VSTOP) |
296 | 0 | SSH_ENCODE_CC_OPT(VSUSP) |
297 | | #ifdef VDSUSP |
298 | | SSH_ENCODE_CC_OPT(VDSUSP) |
299 | | #endif |
300 | 0 | #ifdef VREPRINT |
301 | 0 | SSH_ENCODE_CC_OPT(VREPRINT) |
302 | 0 | #endif |
303 | 0 | #ifdef VWERASE |
304 | 0 | SSH_ENCODE_CC_OPT(VWERASE) |
305 | 0 | #endif |
306 | 0 | #ifdef VLNEXT |
307 | 0 | SSH_ENCODE_CC_OPT(VLNEXT) |
308 | 0 | #endif |
309 | | #ifdef VFLUSH |
310 | | SSH_ENCODE_CC_OPT(VFLUSH) |
311 | | #endif |
312 | 0 | #ifdef VSWTC |
313 | 0 | SSH_ENCODE_CC_OPT(VSWTC) |
314 | 0 | #endif |
315 | | #ifdef VSTATUS |
316 | | SSH_ENCODE_CC_OPT(VSTATUS) |
317 | | #endif |
318 | 0 | #ifdef VDISCARD |
319 | 0 | SSH_ENCODE_CC_OPT(VDISCARD) |
320 | 0 | #endif |
321 | 0 | #undef SSH_ENCODE_CC_OPT |
322 | | |
323 | 0 | SSH_ENCODE_OPT(TTY_OP_ISPEED, baud2speed(cfgetispeed(attr))) |
324 | 0 | SSH_ENCODE_OPT(TTY_OP_OSPEED, baud2speed(cfgetospeed(attr))) |
325 | 0 | #undef SSH_ENCODE_OPT |
326 | | |
327 | | /* end of options */ |
328 | 0 | if (buflen > offset) { |
329 | 0 | buf[offset++] = TTY_OP_END; |
330 | 0 | } else { |
331 | 0 | return -1; |
332 | 0 | } |
333 | | |
334 | 0 | return (int)offset; |
335 | 0 | } |
336 | | #endif |
337 | | |
338 | | /** |
339 | | * Encodes a set of default options to ensure "sane" PTY behavior. |
340 | | * This function intentionally doesn't use the \c termios structure |
341 | | * to allow it to work on Windows as well. |
342 | | * |
343 | | * The "sane" default set is derived from the `stty sane`, but iutf8 support is |
344 | | * added on top of that. |
345 | | * |
346 | | * @param[out] buf Modes will be encoded into this buffer. |
347 | | * |
348 | | * @param[in] buflen The length of the buffer. |
349 | | * |
350 | | * @return number of bytes in the buffer on success, -1 on error. |
351 | | */ |
352 | | static int |
353 | | encode_default_opts(unsigned char *buf, size_t buflen) |
354 | 0 | { |
355 | 0 | unsigned int offset = 0; |
356 | 0 | int rc; |
357 | |
|
358 | 0 | #define SSH_ENCODE_OPT(code, value) \ |
359 | 0 | rc = encode_termios_opt(code, value, buf + offset, buflen - offset); \ |
360 | 0 | if (rc < 0) { \ |
361 | 0 | return rc; \ |
362 | 0 | } else { \ |
363 | 0 | offset += rc; \ |
364 | 0 | } |
365 | |
|
366 | 0 | SSH_ENCODE_OPT(TTY_OP_VINTR, 003) |
367 | 0 | SSH_ENCODE_OPT(TTY_OP_VQUIT, 034) |
368 | 0 | SSH_ENCODE_OPT(TTY_OP_VERASE, 0177) |
369 | 0 | SSH_ENCODE_OPT(TTY_OP_VKILL, 025) |
370 | 0 | SSH_ENCODE_OPT(TTY_OP_VEOF, 004) |
371 | 0 | SSH_ENCODE_OPT(TTY_OP_VEOL, 0) |
372 | 0 | SSH_ENCODE_OPT(TTY_OP_VEOL2, 0) |
373 | 0 | SSH_ENCODE_OPT(TTY_OP_VSTART, 021) |
374 | 0 | SSH_ENCODE_OPT(TTY_OP_VSTOP, 023) |
375 | 0 | SSH_ENCODE_OPT(TTY_OP_VSUSP, 032) |
376 | 0 | SSH_ENCODE_OPT(TTY_OP_VDSUSP, 031) |
377 | 0 | SSH_ENCODE_OPT(TTY_OP_VREPRINT, 022) |
378 | 0 | SSH_ENCODE_OPT(TTY_OP_VWERASE, 027) |
379 | 0 | SSH_ENCODE_OPT(TTY_OP_VLNEXT, 026) |
380 | 0 | SSH_ENCODE_OPT(TTY_OP_VDISCARD, 017) |
381 | 0 | SSH_ENCODE_OPT(TTY_OP_IGNPAR, 0) |
382 | 0 | SSH_ENCODE_OPT(TTY_OP_PARMRK, 0) |
383 | 0 | SSH_ENCODE_OPT(TTY_OP_INPCK, 0) |
384 | 0 | SSH_ENCODE_OPT(TTY_OP_ISTRIP, 0) |
385 | 0 | SSH_ENCODE_OPT(TTY_OP_INLCR, 0) |
386 | 0 | SSH_ENCODE_OPT(TTY_OP_IGNCR, 0) |
387 | 0 | SSH_ENCODE_OPT(TTY_OP_ICRNL, 1) |
388 | 0 | SSH_ENCODE_OPT(TTY_OP_IUCLC, 0) |
389 | 0 | SSH_ENCODE_OPT(TTY_OP_IXON, 1) |
390 | 0 | SSH_ENCODE_OPT(TTY_OP_IXANY, 0) |
391 | 0 | SSH_ENCODE_OPT(TTY_OP_IXOFF, 0) |
392 | 0 | SSH_ENCODE_OPT(TTY_OP_IMAXBEL, 0) |
393 | 0 | SSH_ENCODE_OPT(TTY_OP_IUTF8, 1) |
394 | 0 | SSH_ENCODE_OPT(TTY_OP_ISIG, 1) |
395 | 0 | SSH_ENCODE_OPT(TTY_OP_ICANON, 1) |
396 | 0 | SSH_ENCODE_OPT(TTY_OP_XCASE, 0) |
397 | 0 | SSH_ENCODE_OPT(TTY_OP_ECHO, 1) |
398 | 0 | SSH_ENCODE_OPT(TTY_OP_ECHOE, 1) |
399 | 0 | SSH_ENCODE_OPT(TTY_OP_ECHOK, 1) |
400 | 0 | SSH_ENCODE_OPT(TTY_OP_ECHONL, 0) |
401 | 0 | SSH_ENCODE_OPT(TTY_OP_NOFLSH, 0) |
402 | 0 | SSH_ENCODE_OPT(TTY_OP_TOSTOP, 0) |
403 | 0 | SSH_ENCODE_OPT(TTY_OP_IEXTEN, 1) |
404 | 0 | SSH_ENCODE_OPT(TTY_OP_ECHOCTL, 1) |
405 | 0 | SSH_ENCODE_OPT(TTY_OP_ECHOKE, 1) |
406 | 0 | SSH_ENCODE_OPT(TTY_OP_PENDIN, 0) |
407 | 0 | SSH_ENCODE_OPT(TTY_OP_OPOST, 1) |
408 | 0 | SSH_ENCODE_OPT(TTY_OP_OLCUC, 0) |
409 | 0 | SSH_ENCODE_OPT(TTY_OP_ONLCR, 1) |
410 | 0 | SSH_ENCODE_OPT(TTY_OP_OCRNL, 0) |
411 | 0 | SSH_ENCODE_OPT(TTY_OP_ONOCR, 0) |
412 | 0 | SSH_ENCODE_OPT(TTY_OP_ONLRET, 0) |
413 | 0 | SSH_ENCODE_OPT(TTY_OP_CS7, 1) |
414 | 0 | SSH_ENCODE_OPT(TTY_OP_CS8, 1) |
415 | 0 | SSH_ENCODE_OPT(TTY_OP_PARENB, 0) |
416 | 0 | SSH_ENCODE_OPT(TTY_OP_PARODD, 0) |
417 | 0 | SSH_ENCODE_OPT(TTY_OP_ISPEED, 38400); |
418 | 0 | SSH_ENCODE_OPT(TTY_OP_OSPEED, 38400); |
419 | |
|
420 | 0 | #undef SSH_ENCODE_OPT |
421 | | |
422 | | /* end of options */ |
423 | 0 | if (buflen > offset) { |
424 | 0 | buf[offset++] = TTY_OP_END; |
425 | 0 | } else { |
426 | 0 | return -1; |
427 | 0 | } |
428 | | |
429 | 0 | return (int)offset; |
430 | 0 | } |
431 | | |
432 | | /** |
433 | | * @ingroup libssh_misc |
434 | | * |
435 | | * @brief Encode the current TTY options as SSH modes. |
436 | | * |
437 | | * Call this function to determine the settings of the process' TTY and |
438 | | * encode them as SSH Terminal Modes according to RFC 4254 section 8. |
439 | | * |
440 | | * If STDIN isn't connected to a TTY, this function fills the buffer with |
441 | | * "sane" default modes. |
442 | | * |
443 | | * The encoded modes can be passed to \c ssh_channel_request_pty_size_modes . |
444 | | * |
445 | | * @code |
446 | | * unsigned char modes_buf[SSH_TTY_MODES_MAX_BUFSIZE]; |
447 | | * encode_current_tty_opts(modes_buf, sizeof(modes_buf)); |
448 | | * @endcode |
449 | | * |
450 | | * |
451 | | * @param[out] buf Modes will be encoded into this buffer. |
452 | | * |
453 | | * @param[in] buflen The length of the buffer. |
454 | | * |
455 | | * @return number of bytes in the buffer on success, -1 on error. |
456 | | */ |
457 | | int |
458 | | encode_current_tty_opts(unsigned char *buf, size_t buflen) |
459 | 0 | { |
460 | 0 | #ifdef HAVE_TERMIOS_H |
461 | 0 | struct termios attr; |
462 | 0 | ZERO_STRUCT(attr); |
463 | |
|
464 | 0 | if (isatty(STDIN_FILENO)) { |
465 | | /* get local terminal attributes */ |
466 | 0 | if (tcgetattr(STDIN_FILENO, &attr) < 0) { |
467 | 0 | perror("tcgetattr"); |
468 | 0 | return -1; |
469 | 0 | } |
470 | 0 | return encode_termios_opts(&attr, buf, buflen); |
471 | 0 | } |
472 | 0 | #endif |
473 | | |
474 | | /* use "sane" default attributes */ |
475 | 0 | return encode_default_opts(buf, buflen); |
476 | 0 | } |