1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2023 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16
17 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
18
19 Options:
20 -a, --all Write all current settings to stdout in human-readable form.
21 -g, --save Write all current settings to stdout in stty-readable form.
22 -F, --file Open and use the specified device instead of stdin
23
24 If no args are given, write to stdout the baud rate and settings that
25 have been changed from their defaults. Mode reading and changes
26 are done on the specified device, or stdin if none was specified.
27
28 David MacKenzie <djm@gnu.ai.mit.edu> */
29
30 #include <config.h>
31
32 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
33 # define _XOPEN_SOURCE
34 #endif
35
36 #include <stdio.h>
37 #include <sys/types.h>
38
39 #include <termios.h>
40 #if HAVE_STROPTS_H
41 # include <stropts.h>
42 #endif
43 #include <sys/ioctl.h>
44
45 #ifdef WINSIZE_IN_PTEM
46 # include <sys/stream.h>
47 # include <sys/ptem.h>
48 #endif
49 #ifdef GWINSZ_IN_SYS_PTY
50 # include <sys/tty.h>
51 # include <sys/pty.h>
52 #endif
53 #include <getopt.h>
54 #include <stdarg.h>
55
56 #include "system.h"
57 #include "assure.h"
58 #include "fd-reopen.h"
59 #include "quote.h"
60 #include "xdectoint.h"
61 #include "xstrtol.h"
62
63 /* The official name of this program (e.g., no 'g' prefix). */
64 #define PROGRAM_NAME "stty"
65
66 #define AUTHORS proper_name ("David MacKenzie")
67
68 #ifndef _POSIX_VDISABLE
69 # define _POSIX_VDISABLE 0
70 #endif
71
72 #define Control(c) ((c) & 0x1f)
73 /* Canonical values for control characters. */
74 #ifndef CINTR
75 # define CINTR Control ('c')
76 #endif
77 #ifndef CQUIT
78 # define CQUIT 28
79 #endif
80 #ifndef CERASE
81 # define CERASE 127
82 #endif
83 #ifndef CKILL
84 # define CKILL Control ('u')
85 #endif
86 #ifndef CEOF
87 # define CEOF Control ('d')
88 #endif
89 #ifndef CEOL
90 # define CEOL _POSIX_VDISABLE
91 #endif
92 #ifndef CSTART
93 # define CSTART Control ('q')
94 #endif
95 #ifndef CSTOP
96 # define CSTOP Control ('s')
97 #endif
98 #ifndef CSUSP
99 # define CSUSP Control ('z')
100 #endif
101 #if defined VEOL2 && !defined CEOL2
102 # define CEOL2 _POSIX_VDISABLE
103 #endif
104 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
105 character is initialized by CSWTCH, if present. */
106 #if defined VSWTC && !defined VSWTCH
107 # define VSWTCH VSWTC
108 #endif
109 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
110 #if defined VSUSP && !defined VSWTCH
111 # define VSWTCH VSUSP
112 # if defined CSUSP && !defined CSWTCH
113 # define CSWTCH CSUSP
114 # endif
115 #endif
116 #if defined VSWTCH && !defined CSWTCH
117 # define CSWTCH _POSIX_VDISABLE
118 #endif
119
120 /* SunOS >= 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
121 So the default is to disable 'swtch.' */
122 #if defined __sun
123 # undef CSWTCH
124 # define CSWTCH _POSIX_VDISABLE
125 #endif
126
127 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
128 # define VWERASE VWERSE
129 #endif
130 #if defined VDSUSP && !defined CDSUSP
131 # define CDSUSP Control ('y')
132 #endif
133 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
134 # define VREPRINT VRPRNT
135 #endif
136 #if defined VREPRINT && !defined CRPRNT
137 # define CRPRNT Control ('r')
138 #endif
139 #if defined CREPRINT && !defined CRPRNT
140 # define CRPRNT Control ('r')
141 #endif
142 #if defined VWERASE && !defined CWERASE
143 # define CWERASE Control ('w')
144 #endif
145 #if defined VLNEXT && !defined CLNEXT
146 # define CLNEXT Control ('v')
147 #endif
148 #if defined VDISCARD && !defined VFLUSHO
149 # define VFLUSHO VDISCARD
150 #endif
151 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
152 # define VFLUSHO VFLUSH
153 #endif
154 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
155 # define ECHOCTL CTLECH
156 #endif
157 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
158 # define ECHOCTL TCTLECH
159 #endif
160 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
161 # define ECHOKE CRTKIL
162 #endif
163 #if defined VFLUSHO && !defined CFLUSHO
164 # define CFLUSHO Control ('o')
165 #endif
166 #if defined VSTATUS && !defined CSTATUS
167 # define CSTATUS Control ('t')
168 #endif
169
170 /* Which speeds to set. */
171 enum speed_setting
172 {
173 input_speed, output_speed, both_speeds
174 };
175
176 /* What to output and how. */
177 enum output_type
178 {
179 changed, all, recoverable /* Default, -a, -g. */
180 };
181
182 /* Which member(s) of 'struct termios' a mode uses. */
183 enum mode_type
184 {
185 control, input, output, local, combination
186 };
187
188 /* Flags for 'struct mode_info'. */
189 #define SANE_SET 1 /* Set in 'sane' mode. */
190 #define SANE_UNSET 2 /* Unset in 'sane' mode. */
191 #define REV 4 /* Can be turned off by prepending '-'. */
192 #define OMIT 8 /* Don't display value. */
193 #define NO_SETATTR 16 /* tcsetattr not used to set mode bits. */
194
195 /* Each mode. */
196 struct mode_info
197 {
198 char const *name; /* Name given on command line. */
199 enum mode_type type; /* Which structure element to change. */
200 char flags; /* Setting and display options. */
201 unsigned long bits; /* Bits to set for this mode. */
202 unsigned long mask; /* Other bits to turn off for this mode. */
203 };
204
205 static struct mode_info const mode_info[] =
206 {
207 {"parenb", control, REV, PARENB, 0},
208 {"parodd", control, REV, PARODD, 0},
209 #ifdef CMSPAR
210 {"cmspar", control, REV, CMSPAR, 0},
211 #endif
212 {"cs5", control, 0, CS5, CSIZE},
213 {"cs6", control, 0, CS6, CSIZE},
214 {"cs7", control, 0, CS7, CSIZE},
215 {"cs8", control, 0, CS8, CSIZE},
216 {"hupcl", control, REV, HUPCL, 0},
217 {"hup", control, REV | OMIT, HUPCL, 0},
218 {"cstopb", control, REV, CSTOPB, 0},
219 {"cread", control, SANE_SET | REV, CREAD, 0},
220 {"clocal", control, REV, CLOCAL, 0},
221 #ifdef CRTSCTS
222 {"crtscts", control, REV, CRTSCTS, 0},
223 #endif
224 #ifdef CDTRDSR
225 {"cdtrdsr", control, REV, CDTRDSR, 0},
226 #endif
227
228 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
229 {"brkint", input, SANE_SET | REV, BRKINT, 0},
230 {"ignpar", input, REV, IGNPAR, 0},
231 {"parmrk", input, REV, PARMRK, 0},
232 {"inpck", input, REV, INPCK, 0},
233 {"istrip", input, REV, ISTRIP, 0},
234 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
235 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
236 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
237 {"ixon", input, REV, IXON, 0},
238 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
239 {"tandem", input, REV | OMIT, IXOFF, 0},
240 #ifdef IUCLC
241 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
242 #endif
243 #ifdef IXANY
244 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
245 #endif
246 #ifdef IMAXBEL
247 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
248 #endif
249 #ifdef IUTF8
250 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
251 #endif
252
253 {"opost", output, SANE_SET | REV, OPOST, 0},
254 #ifdef OLCUC
255 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
256 #endif
257 #ifdef OCRNL
258 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
259 #endif
260 #ifdef ONLCR
261 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
262 #endif
263 #ifdef ONOCR
264 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
265 #endif
266 #ifdef ONLRET
267 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
268 #endif
269 #ifdef OFILL
270 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
271 #endif
272 #ifdef OFDEL
273 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
274 #endif
275 #ifdef NLDLY
276 {"nl1", output, SANE_UNSET, NL1, NLDLY},
277 {"nl0", output, SANE_SET, NL0, NLDLY},
278 #endif
279 #ifdef CRDLY
280 {"cr3", output, SANE_UNSET, CR3, CRDLY},
281 {"cr2", output, SANE_UNSET, CR2, CRDLY},
282 {"cr1", output, SANE_UNSET, CR1, CRDLY},
283 {"cr0", output, SANE_SET, CR0, CRDLY},
284 #endif
285 #ifdef TABDLY
286 # ifdef TAB3
287 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
288 # endif
289 # ifdef TAB2
290 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
291 # endif
292 # ifdef TAB1
293 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
294 # endif
295 # ifdef TAB0
296 {"tab0", output, SANE_SET, TAB0, TABDLY},
297 # endif
298 #else
299 # ifdef OXTABS
300 {"tab3", output, SANE_UNSET, OXTABS, 0},
301 # endif
302 #endif
303 #ifdef BSDLY
304 {"bs1", output, SANE_UNSET, BS1, BSDLY},
305 {"bs0", output, SANE_SET, BS0, BSDLY},
306 #endif
307 #ifdef VTDLY
308 {"vt1", output, SANE_UNSET, VT1, VTDLY},
309 {"vt0", output, SANE_SET, VT0, VTDLY},
310 #endif
311 #ifdef FFDLY
312 {"ff1", output, SANE_UNSET, FF1, FFDLY},
313 {"ff0", output, SANE_SET, FF0, FFDLY},
314 #endif
315
316 {"isig", local, SANE_SET | REV, ISIG, 0},
317 {"icanon", local, SANE_SET | REV, ICANON, 0},
318 #ifdef IEXTEN
319 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
320 #endif
321 {"echo", local, SANE_SET | REV, ECHO, 0},
322 {"echoe", local, SANE_SET | REV, ECHOE, 0},
323 {"crterase", local, REV | OMIT, ECHOE, 0},
324 {"echok", local, SANE_SET | REV, ECHOK, 0},
325 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
326 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
327 #ifdef XCASE
328 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
329 #endif
330 #ifdef TOSTOP
331 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
332 #endif
333 #ifdef ECHOPRT
334 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
335 {"prterase", local, REV | OMIT, ECHOPRT, 0},
336 #endif
337 #ifdef ECHOCTL
338 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
339 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
340 #endif
341 #ifdef ECHOKE
342 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
343 {"crtkill", local, REV | OMIT, ECHOKE, 0},
344 #endif
345 #ifdef FLUSHO
346 {"flusho", local, SANE_UNSET | REV, FLUSHO, 0},
347 #endif
348 #if defined TIOCEXT
349 {"extproc", local, SANE_UNSET | REV | NO_SETATTR, EXTPROC, 0},
350 #elif defined EXTPROC
351 {"extproc", local, SANE_UNSET | REV, EXTPROC, 0},
352 #endif
353
354 {"evenp", combination, REV | OMIT, 0, 0},
355 {"parity", combination, REV | OMIT, 0, 0},
356 {"oddp", combination, REV | OMIT, 0, 0},
357 {"nl", combination, REV | OMIT, 0, 0},
358 {"ek", combination, OMIT, 0, 0},
359 {"sane", combination, OMIT, 0, 0},
360 {"cooked", combination, REV | OMIT, 0, 0},
361 {"raw", combination, REV | OMIT, 0, 0},
362 {"pass8", combination, REV | OMIT, 0, 0},
363 {"litout", combination, REV | OMIT, 0, 0},
364 {"cbreak", combination, REV | OMIT, 0, 0},
365 #ifdef IXANY
366 {"decctlq", combination, REV | OMIT, 0, 0},
367 #endif
368 #if defined TABDLY || defined OXTABS
369 {"tabs", combination, REV | OMIT, 0, 0},
370 #endif
371 #if defined XCASE && defined IUCLC && defined OLCUC
372 {"lcase", combination, REV | OMIT, 0, 0},
373 {"LCASE", combination, REV | OMIT, 0, 0},
374 #endif
375 {"crt", combination, OMIT, 0, 0},
376 {"dec", combination, OMIT, 0, 0},
377
378 {nullptr, control, 0, 0, 0}
379 };
380
381 /* Control character settings. */
382 struct control_info
383 {
384 char const *name; /* Name given on command line. */
385 cc_t saneval; /* Value to set for 'stty sane'. */
386 size_t offset; /* Offset in c_cc. */
387 };
388
389 /* Control characters. */
390
391 static struct control_info const control_info[] =
392 {
393 {"intr", CINTR, VINTR},
394 {"quit", CQUIT, VQUIT},
395 {"erase", CERASE, VERASE},
396 {"kill", CKILL, VKILL},
397 {"eof", CEOF, VEOF},
398 {"eol", CEOL, VEOL},
399 #ifdef VEOL2
400 {"eol2", CEOL2, VEOL2},
401 #endif
402 #ifdef VSWTCH
403 {"swtch", CSWTCH, VSWTCH},
404 #endif
405 {"start", CSTART, VSTART},
406 {"stop", CSTOP, VSTOP},
407 {"susp", CSUSP, VSUSP},
408 #ifdef VDSUSP
409 {"dsusp", CDSUSP, VDSUSP},
410 #endif
411 #ifdef VREPRINT
412 {"rprnt", CRPRNT, VREPRINT},
413 #else
414 # ifdef CREPRINT /* HPUX 10.20 needs this */
415 {"rprnt", CRPRNT, CREPRINT},
416 # endif
417 #endif
418 #ifdef VWERASE
419 {"werase", CWERASE, VWERASE},
420 #endif
421 #ifdef VLNEXT
422 {"lnext", CLNEXT, VLNEXT},
423 #endif
424 #ifdef VFLUSHO
425 {"flush", CFLUSHO, VFLUSHO}, /* deprecated compat option. */
426 {"discard", CFLUSHO, VFLUSHO},
427 #endif
428 #ifdef VSTATUS
429 {"status", CSTATUS, VSTATUS},
430 #endif
431
432 /* These must be last because of the display routines. */
433 {"min", 1, VMIN},
434 {"time", 0, VTIME},
435 {nullptr, 0, 0}
436 };
437
438 static char const *visible (cc_t ch);
439 static unsigned long int baud_to_value (speed_t speed);
440 static bool recover_mode (char const *arg, struct termios *mode);
441 static int screen_columns (void);
442 static bool set_mode (struct mode_info const *info, bool reversed,
443 struct termios *mode);
444 static bool eq_mode (struct termios *mode1, struct termios *mode2);
445 static unsigned long int integer_arg (char const *s, unsigned long int max);
446 static speed_t string_to_baud (char const *arg);
447 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
448 static void display_all (struct termios *mode, char const *device_name);
449 static void display_changed (struct termios *mode);
450 static void display_recoverable (struct termios *mode);
451 static void display_settings (enum output_type output_type,
452 struct termios *mode,
453 char const *device_name);
454 static void check_speed (struct termios *mode);
455 static void display_speed (struct termios *mode, bool fancy);
456 static void display_window_size (bool fancy, char const *device_name);
457 static void sane_mode (struct termios *mode);
458 static void set_control_char (struct control_info const *info,
459 char const *arg,
460 struct termios *mode);
461 static void set_speed (enum speed_setting type, char const *arg,
462 struct termios *mode);
463 static void set_window_size (int rows, int cols, char const *device_name);
464
465 /* The width of the screen, for output wrapping. */
466 static int max_col;
467
468 /* Current position, to know when to wrap. */
469 static int current_col;
470
471 /* Default "drain" mode for tcsetattr. */
472 static int tcsetattr_options = TCSADRAIN;
473
474 /* Extra info to aid stty development. */
475 static bool dev_debug;
476
477 /* Record last speed set for correlation. */
478 static speed_t last_ibaud = (speed_t) -1;
479 static speed_t last_obaud = (speed_t) -1;
480
481 /* For long options that have no equivalent short option, use a
482 non-character as a pseudo short option, starting with CHAR_MAX + 1. */
483 enum
484 {
485 DEV_DEBUG_OPTION = CHAR_MAX + 1,
486 };
487
488 static struct option const longopts[] =
489 {
490 {"all", no_argument, nullptr, 'a'},
491 {"save", no_argument, nullptr, 'g'},
492 {"file", required_argument, nullptr, 'F'},
493 {"-debug", no_argument, nullptr, DEV_DEBUG_OPTION},
494 {GETOPT_HELP_OPTION_DECL},
495 {GETOPT_VERSION_OPTION_DECL},
496 {nullptr, 0, nullptr, 0}
497 };
498
499 /* Print format string MESSAGE and optional args.
500 Wrap to next line first if it won't fit.
501 Print a space first unless MESSAGE will start a new line. */
502
503 ATTRIBUTE_FORMAT ((printf, 1, 2))
504 static void
wrapf(char const * message,...)505 wrapf (char const *message,...)
506 {
507 va_list args;
508 char *buf;
509 int buflen;
510
511 va_start (args, message);
512 buflen = vasprintf (&buf, message, args);
513 va_end (args);
514
515 if (buflen < 0)
516 xalloc_die ();
517
518 if (0 < current_col)
519 {
520 if (max_col - current_col <= buflen)
521 {
522 putchar ('\n');
523 current_col = 0;
524 }
525 else
526 {
527 putchar (' ');
528 current_col++;
529 }
530 }
531
532 fputs (buf, stdout);
533 free (buf);
534 current_col += buflen;
535 }
536
537 void
usage(int status)538 usage (int status)
539 {
540 if (status != EXIT_SUCCESS)
541 emit_try_help ();
542 else
543 {
544 printf (_("\
545 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
546 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
547 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
548 "),
549 program_name, program_name, program_name);
550 fputs (_("\
551 Print or change terminal characteristics.\n\
552 "), stdout);
553
554 emit_mandatory_arg_note ();
555
556 fputs (_("\
557 -a, --all print all current settings in human-readable form\n\
558 -g, --save print all current settings in a stty-readable form\n\
559 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
560 "), stdout);
561 fputs (HELP_OPTION_DESCRIPTION, stdout);
562 fputs (VERSION_OPTION_DESCRIPTION, stdout);
563 fputs (_("\
564 \n\
565 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
566 settings. The underlying system defines which settings are available.\n\
567 "), stdout);
568 fputs (_("\
569 \n\
570 Special characters:\n"), stdout);
571 #ifdef VFLUSHO
572 fputs (_("\
573 * discard CHAR CHAR will toggle discarding of output\n\
574 "), stdout);
575 #endif
576 #ifdef VDSUSP
577 fputs (_("\
578 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
579 "), stdout);
580 #endif
581 fputs (_("\
582 eof CHAR CHAR will send an end of file (terminate the input)\n\
583 eol CHAR CHAR will end the line\n\
584 "), stdout);
585 #ifdef VEOL2
586 fputs (_("\
587 * eol2 CHAR alternate CHAR for ending the line\n\
588 "), stdout);
589 #endif
590 fputs (_("\
591 erase CHAR CHAR will erase the last character typed\n\
592 intr CHAR CHAR will send an interrupt signal\n\
593 kill CHAR CHAR will erase the current line\n\
594 "), stdout);
595 #ifdef VLNEXT
596 fputs (_("\
597 * lnext CHAR CHAR will enter the next character quoted\n\
598 "), stdout);
599 #endif
600 #ifdef VSTATUS
601 fputs (_("\
602 * status CHAR CHAR will send an info signal\n\
603 "), stdout);
604 #endif
605 fputs (_("\
606 quit CHAR CHAR will send a quit signal\n\
607 "), stdout);
608 #if defined CREPRINT || defined VREPRINT
609 fputs (_("\
610 * rprnt CHAR CHAR will redraw the current line\n\
611 "), stdout);
612 #endif
613 fputs (_("\
614 start CHAR CHAR will restart the output after stopping it\n\
615 stop CHAR CHAR will stop the output\n\
616 susp CHAR CHAR will send a terminal stop signal\n\
617 "), stdout);
618 #ifdef VSWTCH
619 fputs (_("\
620 * swtch CHAR CHAR will switch to a different shell layer\n\
621 "), stdout);
622 #endif
623 #ifdef VWERASE
624 fputs (_("\
625 * werase CHAR CHAR will erase the last word typed\n\
626 "), stdout);
627 #endif
628 fputs (_("\
629 \n\
630 Special settings:\n\
631 N set the input and output speeds to N bauds\n\
632 "), stdout);
633 #ifdef TIOCGWINSZ
634 fputs (_("\
635 * cols N tell the kernel that the terminal has N columns\n\
636 * columns N same as cols N\n\
637 "), stdout);
638 #endif
639 printf (_("\
640 * [-]drain wait for transmission before applying settings (%s by default)\
641 \n"), tcsetattr_options == TCSADRAIN ? _("on") : _("off"));
642 fputs (_("\
643 ispeed N set the input speed to N\n\
644 "), stdout);
645 #ifdef HAVE_C_LINE
646 fputs (_("\
647 * line N use line discipline N\n\
648 "), stdout);
649 #endif
650 fputs (_("\
651 min N with -icanon, set N characters minimum for a completed read\n\
652 ospeed N set the output speed to N\n\
653 "), stdout);
654 #ifdef TIOCGWINSZ
655 fputs (_("\
656 * rows N tell the kernel that the terminal has N rows\n\
657 * size print the number of rows and columns according to the kernel\n\
658 "), stdout);
659 #endif
660 fputs (_("\
661 speed print the terminal speed\n\
662 time N with -icanon, set read timeout of N tenths of a second\n\
663 "), stdout);
664 fputs (_("\
665 \n\
666 Control settings:\n\
667 [-]clocal disable modem control signals\n\
668 [-]cread allow input to be received\n\
669 "), stdout);
670 #ifdef CRTSCTS
671 fputs (_("\
672 * [-]crtscts enable RTS/CTS handshaking\n\
673 "), stdout);
674 #endif
675 #ifdef CDTRDSR
676 fputs (_("\
677 * [-]cdtrdsr enable DTR/DSR handshaking\n\
678 "), stdout);
679 #endif
680 fputs (_("\
681 csN set character size to N bits, N in [5..8]\n\
682 "), stdout);
683 fputs (_("\
684 [-]cstopb use two stop bits per character (one with '-')\n\
685 [-]hup send a hangup signal when the last process closes the tty\n\
686 [-]hupcl same as [-]hup\n\
687 [-]parenb generate parity bit in output and expect parity bit in input\n\
688 [-]parodd set odd parity (or even parity with '-')\n\
689 "), stdout);
690 #ifdef CMSPAR
691 fputs (_("\
692 * [-]cmspar use \"stick\" (mark/space) parity\n\
693 "), stdout);
694 #endif
695 fputs (_("\
696 \n\
697 Input settings:\n\
698 [-]brkint breaks cause an interrupt signal\n\
699 [-]icrnl translate carriage return to newline\n\
700 [-]ignbrk ignore break characters\n\
701 [-]igncr ignore carriage return\n\
702 [-]ignpar ignore characters with parity errors\n\
703 "), stdout);
704 #ifdef IMAXBEL
705 fputs (_("\
706 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
707 "), stdout);
708 #endif
709 fputs (_("\
710 [-]inlcr translate newline to carriage return\n\
711 [-]inpck enable input parity checking\n\
712 [-]istrip clear high (8th) bit of input characters\n\
713 "), stdout);
714 #ifdef IUTF8
715 fputs (_("\
716 * [-]iutf8 assume input characters are UTF-8 encoded\n\
717 "), stdout);
718 #endif
719 #ifdef IUCLC
720 fputs (_("\
721 * [-]iuclc translate uppercase characters to lowercase\n\
722 "), stdout);
723 #endif
724 #ifdef IXANY
725 fputs (_("\
726 * [-]ixany let any character restart output, not only start character\n\
727 "), stdout);
728 #endif
729 fputs (_("\
730 [-]ixoff enable sending of start/stop characters\n\
731 [-]ixon enable XON/XOFF flow control\n\
732 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
733 [-]tandem same as [-]ixoff\n\
734 "), stdout);
735 fputs (_("\
736 \n\
737 Output settings:\n\
738 "), stdout);
739 #ifdef BSDLY
740 fputs (_("\
741 * bsN backspace delay style, N in [0..1]\n\
742 "), stdout);
743 #endif
744 #ifdef CRDLY
745 fputs (_("\
746 * crN carriage return delay style, N in [0..3]\n\
747 "), stdout);
748 #endif
749 #ifdef FFDLY
750 fputs (_("\
751 * ffN form feed delay style, N in [0..1]\n\
752 "), stdout);
753 #endif
754 #ifdef NLDLY
755 fputs (_("\
756 * nlN newline delay style, N in [0..1]\n\
757 "), stdout);
758 #endif
759 #ifdef OCRNL
760 fputs (_("\
761 * [-]ocrnl translate carriage return to newline\n\
762 "), stdout);
763 #endif
764 #ifdef OFDEL
765 fputs (_("\
766 * [-]ofdel use delete characters for fill instead of NUL characters\n\
767 "), stdout);
768 #endif
769 #ifdef OFILL
770 fputs (_("\
771 * [-]ofill use fill (padding) characters instead of timing for delays\n\
772 "), stdout);
773 #endif
774 #ifdef OLCUC
775 fputs (_("\
776 * [-]olcuc translate lowercase characters to uppercase\n\
777 "), stdout);
778 #endif
779 #ifdef ONLCR
780 fputs (_("\
781 * [-]onlcr translate newline to carriage return-newline\n\
782 "), stdout);
783 #endif
784 #ifdef ONLRET
785 fputs (_("\
786 * [-]onlret newline performs a carriage return\n\
787 "), stdout);
788 #endif
789 #ifdef ONOCR
790 fputs (_("\
791 * [-]onocr do not print carriage returns in the first column\n\
792 "), stdout);
793 #endif
794 fputs (_("\
795 [-]opost postprocess output\n\
796 "), stdout);
797 #if defined TABDLY || defined OXTABS
798 fputs (_("\
799 * tabN horizontal tab delay style, N in [0..3]\n\
800 * tabs same as tab0\n\
801 * -tabs same as tab3\n\
802 "), stdout);
803 #endif
804 #ifdef VTDLY
805 fputs (_("\
806 * vtN vertical tab delay style, N in [0..1]\n\
807 "), stdout);
808 #endif
809 fputs (_("\
810 \n\
811 Local settings:\n\
812 [-]crterase echo erase characters as backspace-space-backspace\n\
813 "), stdout);
814 #ifdef ECHOKE
815 fputs (_("\
816 * crtkill kill all line by obeying the echoprt and echoe settings\n\
817 * -crtkill kill all line by obeying the echoctl and echok settings\n\
818 "), stdout);
819 #endif
820 #ifdef ECHOCTL
821 fputs (_("\
822 * [-]ctlecho echo control characters in hat notation ('^c')\n\
823 "), stdout);
824 #endif
825 fputs (_("\
826 [-]echo echo input characters\n\
827 "), stdout);
828 #ifdef ECHOCTL
829 fputs (_("\
830 * [-]echoctl same as [-]ctlecho\n\
831 "), stdout);
832 #endif
833 fputs (_("\
834 [-]echoe same as [-]crterase\n\
835 [-]echok echo a newline after a kill character\n\
836 "), stdout);
837 #ifdef ECHOKE
838 fputs (_("\
839 * [-]echoke same as [-]crtkill\n\
840 "), stdout);
841 #endif
842 fputs (_("\
843 [-]echonl echo newline even if not echoing other characters\n\
844 "), stdout);
845 #ifdef ECHOPRT
846 fputs (_("\
847 * [-]echoprt echo erased characters backward, between '\\' and '/'\n\
848 "), stdout);
849 #endif
850 #if defined EXTPROC || defined TIOCEXT
851 fputs (_("\
852 * [-]extproc enable \"LINEMODE\"; useful with high latency links\n\
853 "), stdout);
854 #endif
855 #if defined FLUSHO
856 fputs (_("\
857 * [-]flusho discard output\n\
858 "), stdout);
859 #endif
860 printf (_("\
861 [-]icanon enable special characters: %s\n\
862 [-]iexten enable non-POSIX special characters\n\
863 "), "erase, kill"
864 #ifdef VWERASE
865 ", werase"
866 #endif
867 #if defined CREPRINT || defined VREPRINT
868 ", rprnt"
869 #endif
870 );
871 fputs (_("\
872 [-]isig enable interrupt, quit, and suspend special characters\n\
873 [-]noflsh disable flushing after interrupt and quit special characters\n\
874 "), stdout);
875 #ifdef ECHOPRT
876 fputs (_("\
877 * [-]prterase same as [-]echoprt\n\
878 "), stdout);
879 #endif
880 #ifdef TOSTOP
881 fputs (_("\
882 * [-]tostop stop background jobs that try to write to the terminal\n\
883 "), stdout);
884 #endif
885 #ifdef XCASE
886 fputs (_("\
887 * [-]xcase with icanon, escape with '\\' for uppercase characters\n\
888 "), stdout);
889 #endif
890 fputs (_("\
891 \n\
892 Combination settings:\n\
893 "), stdout);
894 #if defined XCASE && defined IUCLC && defined OLCUC
895 fputs (_("\
896 * [-]LCASE same as [-]lcase\n\
897 "), stdout);
898 #endif
899 fputs (_("\
900 cbreak same as -icanon\n\
901 -cbreak same as icanon\n\
902 "), stdout);
903 fputs (_("\
904 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
905 icanon, eof and eol characters to their default values\n\
906 -cooked same as raw\n\
907 "), stdout);
908 printf (_("\
909 crt same as %s\n\
910 "), "echoe"
911 #ifdef ECHOCTL
912 " echoctl"
913 #endif
914 #ifdef ECHOKE
915 " echoke"
916 #endif
917 );
918 printf (_("\
919 dec same as %s intr ^c erase 0177\n\
920 kill ^u\n\
921 "), "echoe"
922 #ifdef ECHOCTL
923 " echoctl"
924 #endif
925 #ifdef ECHOKE
926 " echoke"
927 #endif
928 #ifdef IXANY
929 " -ixany"
930 #endif
931 );
932 #ifdef IXANY
933 fputs (_("\
934 * [-]decctlq same as [-]ixany\n\
935 "), stdout);
936 #endif
937 fputs (_("\
938 ek erase and kill characters to their default values\n\
939 evenp same as parenb -parodd cs7\n\
940 -evenp same as -parenb cs8\n\
941 "), stdout);
942 #if defined XCASE && defined IUCLC && defined OLCUC
943 fputs (_("\
944 * [-]lcase same as xcase iuclc olcuc\n\
945 "), stdout);
946 #endif
947 fputs (_("\
948 litout same as -parenb -istrip -opost cs8\n\
949 -litout same as parenb istrip opost cs7\n\
950 "), stdout);
951 printf (_("\
952 nl same as %s\n\
953 -nl same as %s\n\
954 "), "-icrnl"
955 #ifdef ONLCR
956 " -onlcr"
957 #endif
958 , "icrnl -inlcr -igncr"
959 #ifdef ONLCR
960 " onlcr"
961 #endif
962 #ifdef OCRNL
963 " -ocrnl"
964 #endif
965 #ifdef ONLRET
966 " -onlret"
967 #endif
968 );
969 fputs (_("\
970 oddp same as parenb parodd cs7\n\
971 -oddp same as -parenb cs8\n\
972 [-]parity same as [-]evenp\n\
973 pass8 same as -parenb -istrip cs8\n\
974 -pass8 same as parenb istrip cs7\n\
975 "), stdout);
976 printf (_("\
977 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
978 -inlcr -igncr -icrnl -ixon -ixoff -icanon -opost\n\
979 -isig%s min 1 time 0\n\
980 -raw same as cooked\n\
981 "),
982 #ifdef IUCLC
983 " -iuclc"
984 #endif
985 #ifdef IXANY
986 " -ixany"
987 #endif
988 #ifdef IMAXBEL
989 " -imaxbel"
990 #endif
991 #ifdef XCASE
992 " -xcase"
993 #endif
994 );
995 printf (_("\
996 sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\
997 icanon iexten echo echoe echok -echonl -noflsh\n\
998 %s\n\
999 %s\n\
1000 %s,\n\
1001 all special characters to their default values\n\
1002 "),
1003 "-ixoff"
1004 #ifdef IUTF8
1005 " -iutf8"
1006 #endif
1007 #ifdef IUCLC
1008 " -iuclc"
1009 #endif
1010 #ifdef IXANY
1011 " -ixany"
1012 #endif
1013 #ifdef IMAXBEL
1014 " imaxbel"
1015 #endif
1016 #ifdef XCASE
1017 " -xcase"
1018 #endif
1019 #ifdef OLCUC
1020 " -olcuc"
1021 #endif
1022 #ifdef OCRNL
1023 " -ocrnl"
1024 #endif
1025
1026 , "opost"
1027 #ifdef OFILL
1028 " -ofill"
1029 #endif
1030 #ifdef ONLCR
1031 " onlcr"
1032 #endif
1033 #ifdef ONOCR
1034 " -onocr"
1035 #endif
1036 #ifdef ONLRET
1037 " -onlret"
1038 #endif
1039 #ifdef NLDLY
1040 " nl0"
1041 #endif
1042 #ifdef CRDLY
1043 " cr0"
1044 #endif
1045 #ifdef TAB0
1046 " tab0"
1047 #endif
1048 #ifdef BSDLY
1049 " bs0"
1050 #endif
1051 #ifdef VTDLY
1052 " vt0"
1053 #endif
1054 #ifdef FFDLY
1055 " ff0"
1056 #endif
1057
1058 , "isig"
1059 #ifdef TOSTOP
1060 " -tostop"
1061 #endif
1062 #ifdef OFDEL
1063 " -ofdel"
1064 #endif
1065 #ifdef ECHOPRT
1066 " -echoprt"
1067 #endif
1068 #ifdef ECHOCTL
1069 " echoctl"
1070 #endif
1071 #ifdef ECHOKE
1072 " echoke"
1073 #endif
1074 #ifdef EXTPROC
1075 " -extproc"
1076 #endif
1077 #ifdef FLUSHO
1078 " -flusho"
1079 #endif
1080 );
1081 fputs (_("\
1082 \n\
1083 Handle the tty line connected to standard input. Without arguments,\n\
1084 prints baud rate, line discipline, and deviations from stty sane. In\n\
1085 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
1086 127; special values ^- or undef used to disable special characters.\n\
1087 "), stdout);
1088 emit_ancillary_info (PROGRAM_NAME);
1089 }
1090 exit (status);
1091 }
1092
1093
1094 /* Apply specified settings to MODE and REQUIRE_SET_ATTR as required.
1095 If CHECKING is true, this function doesn't interact
1096 with a device, and only validates specified settings. */
1097
1098 static void
apply_settings(bool checking,char const * device_name,char * const * settings,int n_settings,struct termios * mode,bool * require_set_attr)1099 apply_settings (bool checking, char const *device_name,
1100 char * const *settings, int n_settings,
1101 struct termios *mode, bool *require_set_attr)
1102 {
1103 #define check_argument(arg) \
1104 do \
1105 { \
1106 if (k == n_settings - 1 || ! settings[k + 1]) \
1107 { \
1108 error (0, 0, _("missing argument to %s"), quote (arg)); \
1109 usage (EXIT_FAILURE); \
1110 } \
1111 } \
1112 while (0)
1113
1114 for (int k = 1; k < n_settings; k++)
1115 {
1116 char const *arg = settings[k];
1117 bool match_found = false;
1118 bool not_set_attr = false;
1119 bool reversed = false;
1120 int i;
1121
1122 if (! arg)
1123 continue;
1124
1125 if (arg[0] == '-')
1126 {
1127 ++arg;
1128 reversed = true;
1129 }
1130 if (STREQ (arg, "drain"))
1131 {
1132 tcsetattr_options = reversed ? TCSANOW : TCSADRAIN;
1133 continue;
1134 }
1135 for (i = 0; mode_info[i].name != nullptr; ++i)
1136 {
1137 if (STREQ (arg, mode_info[i].name))
1138 {
1139 if ((mode_info[i].flags & NO_SETATTR) == 0)
1140 {
1141 match_found = set_mode (&mode_info[i], reversed, mode);
1142 *require_set_attr = true;
1143 }
1144 else
1145 match_found = not_set_attr = true;
1146 break;
1147 }
1148 }
1149 if (!match_found && reversed)
1150 {
1151 error (0, 0, _("invalid argument %s"), quote (arg - 1));
1152 usage (EXIT_FAILURE);
1153 }
1154 if (!match_found)
1155 {
1156 for (i = 0; control_info[i].name != nullptr; ++i)
1157 {
1158 if (STREQ (arg, control_info[i].name))
1159 {
1160 check_argument (arg);
1161 match_found = true;
1162 ++k;
1163 set_control_char (&control_info[i], settings[k], mode);
1164 *require_set_attr = true;
1165 break;
1166 }
1167 }
1168 }
1169 if (!match_found || not_set_attr)
1170 {
1171 if (STREQ (arg, "ispeed"))
1172 {
1173 check_argument (arg);
1174 ++k;
1175 if (string_to_baud (settings[k]) == (speed_t) -1)
1176 {
1177 error (0, 0, _("invalid ispeed %s"), quote (settings[k]));
1178 usage (EXIT_FAILURE);
1179 }
1180 set_speed (input_speed, settings[k], mode);
1181 if (checking)
1182 continue;
1183 *require_set_attr = true;
1184 }
1185 else if (STREQ (arg, "ospeed"))
1186 {
1187 check_argument (arg);
1188 ++k;
1189 if (string_to_baud (settings[k]) == (speed_t) -1)
1190 {
1191 error (0, 0, _("invalid ospeed %s"), quote (settings[k]));
1192 usage (EXIT_FAILURE);
1193 }
1194 set_speed (output_speed, settings[k], mode);
1195 if (checking)
1196 continue;
1197 *require_set_attr = true;
1198 }
1199 #ifdef TIOCEXT
1200 /* This is the BSD interface to "extproc".
1201 Even though it's an lflag, an ioctl is used to set it. */
1202 else if (STREQ (arg, "extproc"))
1203 {
1204 int val = ! reversed;
1205
1206 if (checking)
1207 continue;
1208
1209 if (ioctl (STDIN_FILENO, TIOCEXT, &val) != 0)
1210 error (EXIT_FAILURE, errno, _("%s: error setting %s"),
1211 quotef_n (0, device_name), quote_n (1, arg));
1212 }
1213 #endif
1214 #ifdef TIOCGWINSZ
1215 else if (STREQ (arg, "rows"))
1216 {
1217 check_argument (arg);
1218 ++k;
1219 if (checking)
1220 continue;
1221 set_window_size (integer_arg (settings[k], INT_MAX), -1,
1222 device_name);
1223 }
1224 else if (STREQ (arg, "cols")
1225 || STREQ (arg, "columns"))
1226 {
1227 check_argument (arg);
1228 ++k;
1229 if (checking)
1230 continue;
1231 set_window_size (-1, integer_arg (settings[k], INT_MAX),
1232 device_name);
1233 }
1234 else if (STREQ (arg, "size"))
1235 {
1236 if (checking)
1237 continue;
1238 max_col = screen_columns ();
1239 current_col = 0;
1240 display_window_size (false, device_name);
1241 }
1242 #endif
1243 #ifdef HAVE_C_LINE
1244 else if (STREQ (arg, "line"))
1245 {
1246 unsigned long int value;
1247 check_argument (arg);
1248 ++k;
1249 mode->c_line = value = integer_arg (settings[k], ULONG_MAX);
1250 if (mode->c_line != value)
1251 error (0, 0, _("invalid line discipline %s"),
1252 quote (settings[k]));
1253 *require_set_attr = true;
1254 }
1255 #endif
1256 else if (STREQ (arg, "speed"))
1257 {
1258 if (checking)
1259 continue;
1260 max_col = screen_columns ();
1261 display_speed (mode, false);
1262 }
1263 else if (string_to_baud (arg) != (speed_t) -1)
1264 {
1265 set_speed (both_speeds, arg, mode);
1266 if (checking)
1267 continue;
1268 *require_set_attr = true;
1269 }
1270 else
1271 {
1272 if (! recover_mode (arg, mode))
1273 {
1274 error (0, 0, _("invalid argument %s"), quote (arg));
1275 usage (EXIT_FAILURE);
1276 }
1277 *require_set_attr = true;
1278 }
1279 }
1280 }
1281
1282 if (checking)
1283 check_speed (mode);
1284 }
1285
1286 int
main(int argc,char ** argv)1287 main (int argc, char **argv)
1288 {
1289 /* Initialize to all zeroes so there is no risk memcmp will report a
1290 spurious difference in an uninitialized portion of the structure. */
1291 static struct termios mode;
1292
1293 enum output_type output_type;
1294 int optc;
1295 int argi = 0;
1296 int opti = 1;
1297 bool require_set_attr;
1298 bool verbose_output;
1299 bool recoverable_output;
1300 bool noargs = true;
1301 char *file_name = nullptr;
1302 char const *device_name;
1303
1304 initialize_main (&argc, &argv);
1305 set_program_name (argv[0]);
1306 setlocale (LC_ALL, "");
1307 bindtextdomain (PACKAGE, LOCALEDIR);
1308 textdomain (PACKAGE);
1309
1310 atexit (close_stdout);
1311
1312 output_type = changed;
1313 verbose_output = false;
1314 recoverable_output = false;
1315
1316 /* Don't print error messages for unrecognized options. */
1317 opterr = 0;
1318
1319 /* If any new options are ever added to stty, the short options MUST
1320 NOT allow any ambiguity with the stty settings. For example, the
1321 stty setting "-gagFork" would not be feasible, since it will be
1322 parsed as "-g -a -g -F ork". If you change anything about how
1323 stty parses options, be sure it still works with combinations of
1324 short and long options, --, POSIXLY_CORRECT, etc. */
1325
1326 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
1327 longopts, nullptr))
1328 != -1)
1329 {
1330 switch (optc)
1331 {
1332 case 'a':
1333 verbose_output = true;
1334 output_type = all;
1335 break;
1336
1337 case 'g':
1338 recoverable_output = true;
1339 output_type = recoverable;
1340 break;
1341
1342 case 'F':
1343 if (file_name)
1344 error (EXIT_FAILURE, 0, _("only one device may be specified"));
1345 file_name = optarg;
1346 break;
1347
1348 case DEV_DEBUG_OPTION:
1349 dev_debug = true;
1350 break;
1351
1352 case_GETOPT_HELP_CHAR;
1353
1354 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
1355
1356 default:
1357 /* Consider "drain" as an option rather than a setting,
1358 to support: alias stty='stty -drain' etc. */
1359 if (! STREQ (argv[argi + opti], "-drain")
1360 && ! STREQ (argv[argi + opti], "drain"))
1361 noargs = false;
1362
1363 /* Skip the argument containing this unrecognized option;
1364 the 2nd pass will analyze it. */
1365 argi += opti;
1366
1367 /* Restart getopt_long from the first unskipped argument. */
1368 opti = 1;
1369 optind = 0;
1370
1371 break;
1372 }
1373
1374 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
1375 while (opti < optind)
1376 argv[argi + opti++] = nullptr;
1377 }
1378
1379 /* Specifying both -a and -g gets an error. */
1380 if (verbose_output && recoverable_output)
1381 error (EXIT_FAILURE, 0,
1382 _("the options for verbose and stty-readable output styles are\n"
1383 "mutually exclusive"));
1384
1385 /* Specifying any other arguments with -a or -g gets an error. */
1386 if (!noargs && (verbose_output || recoverable_output))
1387 error (EXIT_FAILURE, 0,
1388 _("when specifying an output style, modes may not be set"));
1389
1390 device_name = file_name ? file_name : _("standard input");
1391
1392 if (!noargs && !verbose_output && !recoverable_output)
1393 {
1394 static struct termios check_mode;
1395 apply_settings (/* checking= */ true, device_name, argv, argc,
1396 &check_mode, &require_set_attr);
1397 }
1398
1399 if (file_name)
1400 {
1401 int fdflags;
1402 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
1403 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1404 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
1405 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
1406 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
1407 quotef (device_name));
1408 }
1409
1410 if (tcgetattr (STDIN_FILENO, &mode))
1411 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1412
1413 if (verbose_output || recoverable_output || noargs)
1414 {
1415 max_col = screen_columns ();
1416 current_col = 0;
1417 display_settings (output_type, &mode, device_name);
1418 return EXIT_SUCCESS;
1419 }
1420
1421 require_set_attr = false;
1422 apply_settings (/* checking= */ false, device_name, argv, argc,
1423 &mode, &require_set_attr);
1424
1425 if (require_set_attr)
1426 {
1427 /* Initialize to all zeroes so there is no risk memcmp will report a
1428 spurious difference in an uninitialized portion of the structure. */
1429 static struct termios new_mode;
1430
1431 if (tcsetattr (STDIN_FILENO, tcsetattr_options, &mode))
1432 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1433
1434 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1435 it performs *any* of the requested operations. This means it
1436 can report 'success' when it has actually failed to perform
1437 some proper subset of the requested operations. To detect
1438 this partial failure, get the current terminal attributes and
1439 compare them to the requested ones. */
1440
1441 if (tcgetattr (STDIN_FILENO, &new_mode))
1442 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1443
1444 if (! eq_mode (&mode, &new_mode))
1445 {
1446 if (dev_debug)
1447 {
1448 error (0, 0, _("indx: mode: actual mode"));
1449 for (unsigned int i = 0; i < sizeof (new_mode); i++)
1450 {
1451 unsigned int newc = *(((unsigned char *) &new_mode) + i);
1452 unsigned int oldc = *(((unsigned char *) &mode) + i);
1453 error (0, 0, "0x%02x, 0x%02x: 0x%02x%s", i, oldc, newc,
1454 newc == oldc ? "" : " *");
1455 }
1456 }
1457
1458 error (EXIT_FAILURE, 0,
1459 _("%s: unable to perform all requested operations"),
1460 quotef (device_name));
1461 }
1462 }
1463
1464 return EXIT_SUCCESS;
1465 }
1466
1467 /* Return true if modes are equivalent. */
1468
1469 static bool
eq_mode(struct termios * mode1,struct termios * mode2)1470 eq_mode (struct termios *mode1, struct termios *mode2)
1471 {
1472 return mode1->c_iflag == mode2->c_iflag
1473 && mode1->c_oflag == mode2->c_oflag
1474 && mode1->c_cflag == mode2->c_cflag
1475 && mode1->c_lflag == mode2->c_lflag
1476 #ifdef HAVE_C_LINE
1477 && mode1->c_line == mode2->c_line
1478 #endif
1479 && memcmp (mode1->c_cc, mode2->c_cc, sizeof (mode1->c_cc)) == 0
1480 && cfgetispeed (mode1) == cfgetispeed (mode2)
1481 && cfgetospeed (mode1) == cfgetospeed (mode2);
1482 }
1483
1484 /* Return false if not applied because not reversible; otherwise
1485 return true. */
1486
1487 static bool
set_mode(struct mode_info const * info,bool reversed,struct termios * mode)1488 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1489 {
1490 tcflag_t *bitsp;
1491
1492 if (reversed && (info->flags & REV) == 0)
1493 return false;
1494
1495 bitsp = mode_type_flag (info->type, mode);
1496
1497 if (bitsp == nullptr)
1498 {
1499 /* Combination mode. */
1500 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1501 {
1502 if (reversed)
1503 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1504 else
1505 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1506 }
1507 else if (STREQ (info->name, "oddp"))
1508 {
1509 if (reversed)
1510 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1511 else
1512 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1513 }
1514 else if (STREQ (info->name, "nl"))
1515 {
1516 if (reversed)
1517 {
1518 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1519 mode->c_oflag = (mode->c_oflag
1520 #ifdef ONLCR
1521 | ONLCR
1522 #endif
1523 )
1524 #ifdef OCRNL
1525 & ~OCRNL
1526 #endif
1527 #ifdef ONLRET
1528 & ~ONLRET
1529 #endif
1530 ;
1531 }
1532 else
1533 {
1534 mode->c_iflag = mode->c_iflag & ~ICRNL;
1535 #ifdef ONLCR
1536 mode->c_oflag = mode->c_oflag & ~ONLCR;
1537 #endif
1538 }
1539 }
1540 else if (STREQ (info->name, "ek"))
1541 {
1542 mode->c_cc[VERASE] = CERASE;
1543 mode->c_cc[VKILL] = CKILL;
1544 }
1545 else if (STREQ (info->name, "sane"))
1546 sane_mode (mode);
1547 else if (STREQ (info->name, "cbreak"))
1548 {
1549 if (reversed)
1550 mode->c_lflag |= ICANON;
1551 else
1552 mode->c_lflag &= ~ICANON;
1553 }
1554 else if (STREQ (info->name, "pass8"))
1555 {
1556 if (reversed)
1557 {
1558 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1559 mode->c_iflag |= ISTRIP;
1560 }
1561 else
1562 {
1563 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1564 mode->c_iflag &= ~ISTRIP;
1565 }
1566 }
1567 else if (STREQ (info->name, "litout"))
1568 {
1569 if (reversed)
1570 {
1571 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1572 mode->c_iflag |= ISTRIP;
1573 mode->c_oflag |= OPOST;
1574 }
1575 else
1576 {
1577 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1578 mode->c_iflag &= ~ISTRIP;
1579 mode->c_oflag &= ~OPOST;
1580 }
1581 }
1582 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1583 {
1584 if ((info->name[0] == 'r' && reversed)
1585 || (info->name[0] == 'c' && !reversed))
1586 {
1587 /* Cooked mode. */
1588 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1589 mode->c_oflag |= OPOST;
1590 mode->c_lflag |= ISIG | ICANON;
1591 #if VMIN == VEOF
1592 mode->c_cc[VEOF] = CEOF;
1593 #endif
1594 #if VTIME == VEOL
1595 mode->c_cc[VEOL] = CEOL;
1596 #endif
1597 }
1598 else
1599 {
1600 /* Raw mode. */
1601 mode->c_iflag = 0;
1602 mode->c_oflag &= ~OPOST;
1603 mode->c_lflag &= ~(ISIG | ICANON
1604 #ifdef XCASE
1605 | XCASE
1606 #endif
1607 );
1608 mode->c_cc[VMIN] = 1;
1609 mode->c_cc[VTIME] = 0;
1610 }
1611 }
1612 #ifdef IXANY
1613 else if (STREQ (info->name, "decctlq"))
1614 {
1615 if (reversed)
1616 mode->c_iflag |= IXANY;
1617 else
1618 mode->c_iflag &= ~IXANY;
1619 }
1620 #endif
1621 #ifdef TABDLY
1622 else if (STREQ (info->name, "tabs"))
1623 {
1624 if (reversed)
1625 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1626 else
1627 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1628 }
1629 #else
1630 # ifdef OXTABS
1631 else if (STREQ (info->name, "tabs"))
1632 {
1633 if (reversed)
1634 mode->c_oflag = mode->c_oflag | OXTABS;
1635 else
1636 mode->c_oflag = mode->c_oflag & ~OXTABS;
1637 }
1638 # endif
1639 #endif
1640 #if defined XCASE && defined IUCLC && defined OLCUC
1641 else if (STREQ (info->name, "lcase")
1642 || STREQ (info->name, "LCASE"))
1643 {
1644 if (reversed)
1645 {
1646 mode->c_lflag &= ~XCASE;
1647 mode->c_iflag &= ~IUCLC;
1648 mode->c_oflag &= ~OLCUC;
1649 }
1650 else
1651 {
1652 mode->c_lflag |= XCASE;
1653 mode->c_iflag |= IUCLC;
1654 mode->c_oflag |= OLCUC;
1655 }
1656 }
1657 #endif
1658 else if (STREQ (info->name, "crt"))
1659 mode->c_lflag |= ECHOE
1660 #ifdef ECHOCTL
1661 | ECHOCTL
1662 #endif
1663 #ifdef ECHOKE
1664 | ECHOKE
1665 #endif
1666 ;
1667 else if (STREQ (info->name, "dec"))
1668 {
1669 mode->c_cc[VINTR] = 3; /* ^C */
1670 mode->c_cc[VERASE] = 127; /* DEL */
1671 mode->c_cc[VKILL] = 21; /* ^U */
1672 mode->c_lflag |= ECHOE
1673 #ifdef ECHOCTL
1674 | ECHOCTL
1675 #endif
1676 #ifdef ECHOKE
1677 | ECHOKE
1678 #endif
1679 ;
1680 #ifdef IXANY
1681 mode->c_iflag &= ~IXANY;
1682 #endif
1683 }
1684 }
1685 else if (reversed)
1686 *bitsp = *bitsp & ~info->mask & ~info->bits;
1687 else
1688 *bitsp = (*bitsp & ~info->mask) | info->bits;
1689
1690 return true;
1691 }
1692
1693 static void
set_control_char(struct control_info const * info,char const * arg,struct termios * mode)1694 set_control_char (struct control_info const *info, char const *arg,
1695 struct termios *mode)
1696 {
1697 unsigned long int value;
1698
1699 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1700 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1701 else if (arg[0] == '\0' || arg[1] == '\0')
1702 value = to_uchar (arg[0]);
1703 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1704 value = _POSIX_VDISABLE;
1705 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1706 {
1707 if (arg[1] == '?')
1708 value = 127;
1709 else
1710 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1711 }
1712 else
1713 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1714 mode->c_cc[info->offset] = value;
1715 }
1716
1717 static void
set_speed(enum speed_setting type,char const * arg,struct termios * mode)1718 set_speed (enum speed_setting type, char const *arg, struct termios *mode)
1719 {
1720 /* Note cfset[io]speed(), do not check with the device,
1721 and only check whether the system logic supports the specified speed.
1722 Therefore we don't report the device name in any errors. */
1723
1724 speed_t baud = string_to_baud (arg);
1725 affirm (baud != (speed_t) -1);
1726
1727 if (type == input_speed || type == both_speeds)
1728 {
1729 last_ibaud = baud;
1730 if (cfsetispeed (mode, baud))
1731 error (EXIT_FAILURE, 0, _("unsupported ispeed %s"), quoteaf (arg));
1732 }
1733 if (type == output_speed || type == both_speeds)
1734 {
1735 last_obaud = baud;
1736 if (cfsetospeed (mode, baud))
1737 error (EXIT_FAILURE, 0, _("unsupported ospeed %s"), quoteaf (arg));
1738 }
1739 }
1740
1741 #ifdef TIOCGWINSZ
1742
1743 static int
get_win_size(int fd,struct winsize * win)1744 get_win_size (int fd, struct winsize *win)
1745 {
1746 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1747 return err;
1748 }
1749
1750 static void
set_window_size(int rows,int cols,char const * device_name)1751 set_window_size (int rows, int cols, char const *device_name)
1752 {
1753 struct winsize win;
1754
1755 if (get_win_size (STDIN_FILENO, &win))
1756 {
1757 if (errno != EINVAL)
1758 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1759 memset (&win, 0, sizeof (win));
1760 }
1761
1762 if (rows >= 0)
1763 win.ws_row = rows;
1764 if (cols >= 0)
1765 win.ws_col = cols;
1766
1767 # ifdef TIOCSSIZE
1768 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1769 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1770 This comment from sys/ttold.h describes Sun's twisted logic - a better
1771 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1772 At any rate, the problem is gone in Solaris 2.x.
1773
1774 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1775 but they can be disambiguated by checking whether a "struct ttysize"
1776 structure's "ts_lines" field is greater than 64K or not. If so,
1777 it's almost certainly a "struct winsize" instead.
1778
1779 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1780 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16)
1781 + ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1782 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1783 "stty cols 0 rows 0" would do the right thing. On a little-endian
1784 machine like the sun386i, the problem is the same, but for ws_col == 0.
1785
1786 The workaround is to do the ioctl once with row and col = 1 to set the
1787 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1788
1789 if (win.ws_row == 0 || win.ws_col == 0)
1790 {
1791 struct ttysize ttysz;
1792
1793 ttysz.ts_lines = win.ws_row;
1794 ttysz.ts_cols = win.ws_col;
1795
1796 win.ws_row = 1;
1797 win.ws_col = 1;
1798
1799 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1800 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1801
1802 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1803 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1804 return;
1805 }
1806 # endif
1807
1808 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1809 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1810 }
1811
1812 static void
display_window_size(bool fancy,char const * device_name)1813 display_window_size (bool fancy, char const *device_name)
1814 {
1815 struct winsize win;
1816
1817 if (get_win_size (STDIN_FILENO, &win))
1818 {
1819 if (errno != EINVAL)
1820 error (EXIT_FAILURE, errno, "%s", quotef (device_name));
1821 if (!fancy)
1822 error (EXIT_FAILURE, 0,
1823 _("%s: no size information for this device"),
1824 quotef (device_name));
1825 }
1826 else
1827 {
1828 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1829 win.ws_row, win.ws_col);
1830 if (!fancy)
1831 current_col = 0;
1832 }
1833 }
1834 #endif
1835
1836 static int
screen_columns(void)1837 screen_columns (void)
1838 {
1839 #ifdef TIOCGWINSZ
1840 struct winsize win;
1841
1842 /* With Solaris 2.[123], this ioctl fails and errno is set to
1843 EINVAL for telnet (but not rlogin) sessions.
1844 On ISC 3.0, it fails for the console and the serial port
1845 (but it works for ptys).
1846 It can also fail on any system when stdout isn't a tty.
1847 In case of any failure, just use the default. */
1848 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1849 return win.ws_col;
1850 #endif
1851 {
1852 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1853 char *col_string = getenv ("COLUMNS");
1854 long int n_columns;
1855 if (!(col_string != nullptr
1856 && xstrtol (col_string, nullptr, 0, &n_columns, "") == LONGINT_OK
1857 && 0 < n_columns
1858 && n_columns <= INT_MAX))
1859 n_columns = 80;
1860 return n_columns;
1861 }
1862 }
1863
1864 ATTRIBUTE_PURE
1865 static tcflag_t *
mode_type_flag(enum mode_type type,struct termios * mode)1866 mode_type_flag (enum mode_type type, struct termios *mode)
1867 {
1868 switch (type)
1869 {
1870 case control:
1871 return &mode->c_cflag;
1872
1873 case input:
1874 return &mode->c_iflag;
1875
1876 case output:
1877 return &mode->c_oflag;
1878
1879 case local:
1880 return &mode->c_lflag;
1881
1882 case combination:
1883 return nullptr;
1884
1885 default:
1886 unreachable ();
1887 }
1888 }
1889
1890 static void
display_settings(enum output_type output_type,struct termios * mode,char const * device_name)1891 display_settings (enum output_type output_type, struct termios *mode,
1892 char const *device_name)
1893 {
1894 switch (output_type)
1895 {
1896 case changed:
1897 display_changed (mode);
1898 break;
1899
1900 case all:
1901 display_all (mode, device_name);
1902 break;
1903
1904 case recoverable:
1905 display_recoverable (mode);
1906 break;
1907 }
1908 }
1909
1910 static void
display_changed(struct termios * mode)1911 display_changed (struct termios *mode)
1912 {
1913 int i;
1914 bool empty_line;
1915 tcflag_t *bitsp;
1916 unsigned long mask;
1917 enum mode_type prev_type = control;
1918
1919 display_speed (mode, true);
1920 #ifdef HAVE_C_LINE
1921 wrapf ("line = %d;", mode->c_line);
1922 #endif
1923 putchar ('\n');
1924 current_col = 0;
1925
1926 empty_line = true;
1927 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1928 {
1929 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1930 continue;
1931
1932 #ifdef VFLUSHO
1933 /* 'flush' is the deprecated equivalent of 'discard'. */
1934 if (STREQ (control_info[i].name, "flush"))
1935 continue;
1936 #endif
1937 /* If swtch is the same as susp, don't print both. */
1938 #if VSWTCH == VSUSP
1939 if (STREQ (control_info[i].name, "swtch"))
1940 continue;
1941 #endif
1942 /* If eof uses the same slot as min, only print whichever applies. */
1943 #if VEOF == VMIN
1944 if ((mode->c_lflag & ICANON) == 0
1945 && (STREQ (control_info[i].name, "eof")
1946 || STREQ (control_info[i].name, "eol")))
1947 continue;
1948 #endif
1949
1950 empty_line = false;
1951 wrapf ("%s = %s;", control_info[i].name,
1952 visible (mode->c_cc[control_info[i].offset]));
1953 }
1954 if ((mode->c_lflag & ICANON) == 0)
1955 {
1956 wrapf ("min = %lu; time = %lu;\n",
1957 (unsigned long int) mode->c_cc[VMIN],
1958 (unsigned long int) mode->c_cc[VTIME]);
1959 }
1960 else if (!empty_line)
1961 putchar ('\n');
1962 current_col = 0;
1963
1964 empty_line = true;
1965 for (i = 0; mode_info[i].name != nullptr; ++i)
1966 {
1967 if (mode_info[i].flags & OMIT)
1968 continue;
1969 if (mode_info[i].type != prev_type)
1970 {
1971 if (!empty_line)
1972 {
1973 putchar ('\n');
1974 current_col = 0;
1975 empty_line = true;
1976 }
1977 prev_type = mode_info[i].type;
1978 }
1979
1980 bitsp = mode_type_flag (mode_info[i].type, mode);
1981 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1982 if ((*bitsp & mask) == mode_info[i].bits)
1983 {
1984 if (mode_info[i].flags & SANE_UNSET)
1985 {
1986 wrapf ("%s", mode_info[i].name);
1987 empty_line = false;
1988 }
1989 }
1990 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1991 {
1992 wrapf ("-%s", mode_info[i].name);
1993 empty_line = false;
1994 }
1995 }
1996 if (!empty_line)
1997 putchar ('\n');
1998 current_col = 0;
1999 }
2000
2001 static void
display_all(struct termios * mode,char const * device_name)2002 display_all (struct termios *mode, char const *device_name)
2003 {
2004 int i;
2005 tcflag_t *bitsp;
2006 unsigned long mask;
2007 enum mode_type prev_type = control;
2008
2009 display_speed (mode, true);
2010 #ifdef TIOCGWINSZ
2011 display_window_size (true, device_name);
2012 #endif
2013 #ifdef HAVE_C_LINE
2014 wrapf ("line = %d;", mode->c_line);
2015 #endif
2016 putchar ('\n');
2017 current_col = 0;
2018
2019 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
2020 {
2021 #ifdef VFLUSHO
2022 /* 'flush' is the deprecated equivalent of 'discard'. */
2023 if (STREQ (control_info[i].name, "flush"))
2024 continue;
2025 #endif
2026 /* If swtch is the same as susp, don't print both. */
2027 #if VSWTCH == VSUSP
2028 if (STREQ (control_info[i].name, "swtch"))
2029 continue;
2030 #endif
2031 /* If eof uses the same slot as min, only print whichever applies. */
2032 #if VEOF == VMIN
2033 if ((mode->c_lflag & ICANON) == 0
2034 && (STREQ (control_info[i].name, "eof")
2035 || STREQ (control_info[i].name, "eol")))
2036 continue;
2037 #endif
2038 wrapf ("%s = %s;", control_info[i].name,
2039 visible (mode->c_cc[control_info[i].offset]));
2040 }
2041 #if VEOF == VMIN
2042 if ((mode->c_lflag & ICANON) == 0)
2043 #endif
2044 wrapf ("min = %lu; time = %lu;",
2045 (unsigned long int) mode->c_cc[VMIN],
2046 (unsigned long int) mode->c_cc[VTIME]);
2047 if (current_col != 0)
2048 putchar ('\n');
2049 current_col = 0;
2050
2051 for (i = 0; mode_info[i].name != nullptr; ++i)
2052 {
2053 if (mode_info[i].flags & OMIT)
2054 continue;
2055 if (mode_info[i].type != prev_type)
2056 {
2057 putchar ('\n');
2058 current_col = 0;
2059 prev_type = mode_info[i].type;
2060 }
2061
2062 bitsp = mode_type_flag (mode_info[i].type, mode);
2063 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
2064 if ((*bitsp & mask) == mode_info[i].bits)
2065 wrapf ("%s", mode_info[i].name);
2066 else if (mode_info[i].flags & REV)
2067 wrapf ("-%s", mode_info[i].name);
2068 }
2069 putchar ('\n');
2070 current_col = 0;
2071 }
2072
2073 /* Verify requested asymmetric speeds are supported.
2074 Note we don't flag the case where only ispeed or
2075 ospeed is set, when that would set both. */
2076
2077 static void
check_speed(struct termios * mode)2078 check_speed (struct termios *mode)
2079 {
2080 if (last_ibaud != -1 && last_obaud != -1)
2081 {
2082 if (cfgetispeed (mode) != last_ibaud
2083 || cfgetospeed (mode) != last_obaud)
2084 error (EXIT_FAILURE, 0,
2085 _("asymmetric input (%lu), output (%lu) speeds not supported"),
2086 baud_to_value (last_ibaud), baud_to_value (last_obaud));
2087 }
2088 }
2089
2090 static void
display_speed(struct termios * mode,bool fancy)2091 display_speed (struct termios *mode, bool fancy)
2092 {
2093 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
2094 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
2095 baud_to_value (cfgetospeed (mode)));
2096 else
2097 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
2098 baud_to_value (cfgetispeed (mode)),
2099 baud_to_value (cfgetospeed (mode)));
2100 if (!fancy)
2101 current_col = 0;
2102 }
2103
2104 static void
display_recoverable(struct termios * mode)2105 display_recoverable (struct termios *mode)
2106 {
2107 printf ("%lx:%lx:%lx:%lx",
2108 (unsigned long int) mode->c_iflag,
2109 (unsigned long int) mode->c_oflag,
2110 (unsigned long int) mode->c_cflag,
2111 (unsigned long int) mode->c_lflag);
2112 for (size_t i = 0; i < NCCS; ++i)
2113 printf (":%lx", (unsigned long int) mode->c_cc[i]);
2114 putchar ('\n');
2115 }
2116
2117 /* NOTE: identical to below, modulo use of tcflag_t */
2118 static int
strtoul_tcflag_t(char const * s,int base,char ** p,tcflag_t * result,char delim)2119 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
2120 char delim)
2121 {
2122 unsigned long ul;
2123 errno = 0;
2124 ul = strtoul (s, p, base);
2125 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
2126 return -1;
2127 *result = ul;
2128 return 0;
2129 }
2130
2131 /* NOTE: identical to above, modulo use of cc_t */
2132 static int
strtoul_cc_t(char const * s,int base,char ** p,cc_t * result,char delim)2133 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
2134 {
2135 unsigned long ul;
2136 errno = 0;
2137 ul = strtoul (s, p, base);
2138 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
2139 return -1;
2140 *result = ul;
2141 return 0;
2142 }
2143
2144 /* Parse the output of display_recoverable.
2145 Return false if any part of it is invalid. */
2146 static bool
recover_mode(char const * arg,struct termios * mode)2147 recover_mode (char const *arg, struct termios *mode)
2148 {
2149 tcflag_t flag[4];
2150 char const *s = arg;
2151 size_t i;
2152 for (i = 0; i < 4; i++)
2153 {
2154 char *p;
2155 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
2156 return false;
2157 s = p + 1;
2158 }
2159 mode->c_iflag = flag[0];
2160 mode->c_oflag = flag[1];
2161 mode->c_cflag = flag[2];
2162 mode->c_lflag = flag[3];
2163
2164 for (i = 0; i < NCCS; ++i)
2165 {
2166 char *p;
2167 char delim = i < NCCS - 1 ? ':' : '\0';
2168 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
2169 return false;
2170 s = p + 1;
2171 }
2172
2173 return true;
2174 }
2175
2176 struct speed_map
2177 {
2178 char const *string; /* ASCII representation. */
2179 speed_t speed; /* Internal form. */
2180 unsigned long int value; /* Numeric value. */
2181 };
2182
2183 static struct speed_map const speeds[] =
2184 {
2185 {"0", B0, 0},
2186 {"50", B50, 50},
2187 {"75", B75, 75},
2188 {"110", B110, 110},
2189 {"134", B134, 134},
2190 {"134.5", B134, 134},
2191 {"150", B150, 150},
2192 {"200", B200, 200},
2193 {"300", B300, 300},
2194 {"600", B600, 600},
2195 {"1200", B1200, 1200},
2196 {"1800", B1800, 1800},
2197 {"2400", B2400, 2400},
2198 {"4800", B4800, 4800},
2199 {"9600", B9600, 9600},
2200 {"19200", B19200, 19200},
2201 {"38400", B38400, 38400},
2202 {"exta", B19200, 19200},
2203 {"extb", B38400, 38400},
2204 #ifdef B57600
2205 {"57600", B57600, 57600},
2206 #endif
2207 #ifdef B115200
2208 {"115200", B115200, 115200},
2209 #endif
2210 #ifdef B230400
2211 {"230400", B230400, 230400},
2212 #endif
2213 #ifdef B460800
2214 {"460800", B460800, 460800},
2215 #endif
2216 #ifdef B500000
2217 {"500000", B500000, 500000},
2218 #endif
2219 #ifdef B576000
2220 {"576000", B576000, 576000},
2221 #endif
2222 #ifdef B921600
2223 {"921600", B921600, 921600},
2224 #endif
2225 #ifdef B1000000
2226 {"1000000", B1000000, 1000000},
2227 #endif
2228 #ifdef B1152000
2229 {"1152000", B1152000, 1152000},
2230 #endif
2231 #ifdef B1500000
2232 {"1500000", B1500000, 1500000},
2233 #endif
2234 #ifdef B2000000
2235 {"2000000", B2000000, 2000000},
2236 #endif
2237 #ifdef B2500000
2238 {"2500000", B2500000, 2500000},
2239 #endif
2240 #ifdef B3000000
2241 {"3000000", B3000000, 3000000},
2242 #endif
2243 #ifdef B3500000
2244 {"3500000", B3500000, 3500000},
2245 #endif
2246 #ifdef B4000000
2247 {"4000000", B4000000, 4000000},
2248 #endif
2249 {nullptr, 0, 0}
2250 };
2251
2252 ATTRIBUTE_PURE
2253 static speed_t
string_to_baud(char const * arg)2254 string_to_baud (char const *arg)
2255 {
2256 for (int i = 0; speeds[i].string != nullptr; ++i)
2257 if (STREQ (arg, speeds[i].string))
2258 return speeds[i].speed;
2259 return (speed_t) -1;
2260 }
2261
2262 ATTRIBUTE_PURE
2263 static unsigned long int
baud_to_value(speed_t speed)2264 baud_to_value (speed_t speed)
2265 {
2266 for (int i = 0; speeds[i].string != nullptr; ++i)
2267 if (speed == speeds[i].speed)
2268 return speeds[i].value;
2269 return 0;
2270 }
2271
2272 static void
sane_mode(struct termios * mode)2273 sane_mode (struct termios *mode)
2274 {
2275 int i;
2276 tcflag_t *bitsp;
2277
2278 for (i = 0; control_info[i].name; ++i)
2279 {
2280 #if VMIN == VEOF
2281 if (STREQ (control_info[i].name, "min"))
2282 break;
2283 #endif
2284 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
2285 }
2286
2287 for (i = 0; mode_info[i].name != nullptr; ++i)
2288 {
2289 if (mode_info[i].flags & NO_SETATTR)
2290 continue;
2291
2292 if (mode_info[i].flags & SANE_SET)
2293 {
2294 bitsp = mode_type_flag (mode_info[i].type, mode);
2295 assume (bitsp); /* combination modes will not have SANE_SET. */
2296 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
2297 }
2298 else if (mode_info[i].flags & SANE_UNSET)
2299 {
2300 bitsp = mode_type_flag (mode_info[i].type, mode);
2301 assume (bitsp); /* combination modes will not have SANE_UNSET. */
2302 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
2303 }
2304 }
2305 }
2306
2307 /* Return a string that is the printable representation of character CH. */
2308 /* Adapted from 'cat' by Torbjörn Granlund. */
2309
2310 static char const *
visible(cc_t ch)2311 visible (cc_t ch)
2312 {
2313 static char buf[10];
2314 char *bpout = buf;
2315
2316 if (ch == _POSIX_VDISABLE)
2317 return "<undef>";
2318
2319 if (ch >= 32)
2320 {
2321 if (ch < 127)
2322 *bpout++ = ch;
2323 else if (ch == 127)
2324 {
2325 *bpout++ = '^';
2326 *bpout++ = '?';
2327 }
2328 else
2329 {
2330 *bpout++ = 'M';
2331 *bpout++ = '-';
2332 if (ch >= 128 + 32)
2333 {
2334 if (ch < 128 + 127)
2335 *bpout++ = ch - 128;
2336 else
2337 {
2338 *bpout++ = '^';
2339 *bpout++ = '?';
2340 }
2341 }
2342 else
2343 {
2344 *bpout++ = '^';
2345 *bpout++ = ch - 128 + 64;
2346 }
2347 }
2348 }
2349 else
2350 {
2351 *bpout++ = '^';
2352 *bpout++ = ch + 64;
2353 }
2354 *bpout = '\0';
2355 return (char const *) buf;
2356 }
2357
2358 /* Parse string S as an integer, using decimal radix by default,
2359 but allowing octal and hex numbers as in C. Reject values
2360 larger than MAXVAL. */
2361
2362 static unsigned long int
integer_arg(char const * s,unsigned long int maxval)2363 integer_arg (char const *s, unsigned long int maxval)
2364 {
2365 return xnumtoumax (s, 0, 0, maxval, "bB", _("invalid integer argument"), 0);
2366 }
2367