1 /* vi: set sw=4 ts=4: */
2 /* stty -- change and print terminal line settings
3 Copyright (C) 1990-1999 Free Software Foundation, Inc.
5 Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
7 /* Usage: stty [-ag] [-F device] [setting...]
10 -a Write all current settings to stdout in human-readable form.
11 -g Write all current settings to stdout in stty-readable form.
12 -F Open and use the specified device instead of stdin
14 If no args are given, write to stdout the baud rate and settings that
15 have been changed from their defaults. Mode reading and changes
16 are done on the specified device, or stdin if none was specified.
18 David MacKenzie <djm@gnu.ai.mit.edu>
20 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
26 #ifndef _POSIX_VDISABLE
27 # define _POSIX_VDISABLE ((unsigned char) 0)
30 #define Control(c) ((c) & 0x1f)
31 /* Canonical values for control characters */
33 # define CINTR Control('c')
42 # define CKILL Control('u')
45 # define CEOF Control('d')
48 # define CEOL _POSIX_VDISABLE
51 # define CSTART Control('q')
54 # define CSTOP Control('s')
57 # define CSUSP Control('z')
59 #if defined(VEOL2) && !defined(CEOL2)
60 # define CEOL2 _POSIX_VDISABLE
62 /* ISC renamed swtch to susp for termios, but we'll accept either name */
63 #if defined(VSUSP) && !defined(VSWTCH)
67 #if defined(VSWTCH) && !defined(CSWTCH)
68 # define CSWTCH _POSIX_VDISABLE
71 /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
72 So the default is to disable 'swtch.' */
73 #if defined (__sparc__) && defined (__svr4__)
75 # define CSWTCH _POSIX_VDISABLE
78 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
79 # define VWERASE VWERSE
81 #if defined(VDSUSP) && !defined (CDSUSP)
82 # define CDSUSP Control('y')
84 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
85 # define VREPRINT VRPRNT
87 #if defined(VREPRINT) && !defined(CRPRNT)
88 # define CRPRNT Control('r')
90 #if defined(VWERASE) && !defined(CWERASE)
91 # define CWERASE Control('w')
93 #if defined(VLNEXT) && !defined(CLNEXT)
94 # define CLNEXT Control('v')
96 #if defined(VDISCARD) && !defined(VFLUSHO)
97 # define VFLUSHO VDISCARD
99 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
100 # define VFLUSHO VFLUSH
102 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
103 # define ECHOCTL CTLECH
105 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
106 # define ECHOCTL TCTLECH
108 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
109 # define ECHOKE CRTKIL
111 #if defined(VFLUSHO) && !defined(CFLUSHO)
112 # define CFLUSHO Control('o')
114 #if defined(VSTATUS) && !defined(CSTATUS)
115 # define CSTATUS Control('t')
118 /* Which speeds to set */
120 input_speed, output_speed, both_speeds
123 /* Which member(s) of 'struct termios' a mode uses */
125 /* Do NOT change the order or values, as mode_type_flag()
127 control, input, output, local, combination
130 static const char evenp [] = "evenp";
131 static const char raw [] = "raw";
132 static const char stty_min [] = "min";
133 static const char stty_time [] = "time";
134 static const char stty_swtch[] = "swtch";
135 static const char stty_eol [] = "eol";
136 static const char stty_eof [] = "eof";
137 static const char parity [] = "parity";
138 static const char stty_oddp [] = "oddp";
139 static const char stty_nl [] = "nl";
140 static const char stty_ek [] = "ek";
141 static const char stty_sane [] = "sane";
142 static const char cbreak [] = "cbreak";
143 static const char stty_pass8[] = "pass8";
144 static const char litout [] = "litout";
145 static const char cooked [] = "cooked";
146 static const char decctlq [] = "decctlq";
147 static const char stty_tabs [] = "tabs";
148 static const char stty_lcase[] = "lcase";
149 static const char stty_LCASE[] = "LCASE";
150 static const char stty_crt [] = "crt";
151 static const char stty_dec [] = "dec";
153 /* Flags for 'struct mode_info' */
154 #define SANE_SET 1 /* Set in 'sane' mode */
155 #define SANE_UNSET 2 /* Unset in 'sane' mode */
156 #define REV 4 /* Can be turned off by prepending '-' */
157 #define OMIT 8 /* Don't display value */
161 const char *name; /* Name given on command line */
162 char type; /* Which structure element to change */
163 char flags; /* Setting and display options */
164 unsigned short mask; /* Other bits to turn off for this mode */
165 unsigned long bits; /* Bits to set for this mode */
168 #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
170 static const struct mode_info mode_info[] = {
171 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
172 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
173 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
174 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
175 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
176 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
177 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
178 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
179 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
180 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
181 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
183 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
185 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
186 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
187 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
188 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
189 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
190 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
191 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
192 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
193 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
194 MI_ENTRY("ixon", input, REV, IXON, 0 ),
195 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
196 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
198 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
201 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
204 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
206 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
208 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
211 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
214 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
217 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
220 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
223 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
226 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
229 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
230 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
233 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
234 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
235 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
236 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
240 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
241 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
242 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
243 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
246 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
251 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
252 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
255 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
256 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
259 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
260 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
262 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
263 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
265 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
267 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
268 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
269 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
270 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
271 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
272 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
274 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
277 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
280 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
281 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
284 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
285 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
288 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
289 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
291 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
292 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
293 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
294 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
295 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
296 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
297 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
298 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
299 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
300 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
301 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
303 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
305 #if defined(TABDLY) || defined(OXTABS)
306 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
308 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
309 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
310 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
312 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
313 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
317 NUM_mode_info = (sizeof(mode_info) / sizeof(mode_info[0]))
320 /* Control character settings */
321 struct control_info {
322 const char *name; /* Name given on command line */
323 unsigned char saneval; /* Value to set for 'stty sane' */
324 unsigned char offset; /* Offset in c_cc */
327 /* Control characters */
329 static const struct control_info control_info[] = {
330 {"intr", CINTR, VINTR},
331 {"quit", CQUIT, VQUIT},
332 {"erase", CERASE, VERASE},
333 {"kill", CKILL, VKILL},
334 {stty_eof, CEOF, VEOF},
335 {stty_eol, CEOL, VEOL},
337 {"eol2", CEOL2, VEOL2},
340 {stty_swtch, CSWTCH, VSWTCH},
342 {"start", CSTART, VSTART},
343 {"stop", CSTOP, VSTOP},
344 {"susp", CSUSP, VSUSP},
346 {"dsusp", CDSUSP, VDSUSP},
349 {"rprnt", CRPRNT, VREPRINT},
352 {"werase", CWERASE, VWERASE},
355 {"lnext", CLNEXT, VLNEXT},
358 {"flush", CFLUSHO, VFLUSHO},
361 {"status", CSTATUS, VSTATUS},
363 /* These must be last because of the display routines */
365 {stty_time, 0, VTIME},
369 NUM_control_info = (sizeof(control_info) / sizeof(control_info[0]))
372 /* The width of the screen, for output wrapping */
373 static unsigned max_col = 80; /* default */
374 /* Current position, to know when to wrap */
375 static unsigned current_col;
376 static const char *device_name = bb_msg_standard_input;
378 /* Return a string that is the printable representation of character CH */
379 /* Adapted from 'cat' by Torbjorn Granlund */
380 static const char *visible(unsigned int ch)
385 if (ch == _POSIX_VDISABLE)
397 } else if (ch < 127) {
408 static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
410 static const unsigned char tcflag_offsets[] = {
411 offsetof(struct termios, c_cflag), /* control */
412 offsetof(struct termios, c_iflag), /* input */
413 offsetof(struct termios, c_oflag), /* output */
414 offsetof(struct termios, c_lflag), /* local */
418 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
423 static speed_t string_to_baud_or_die(const char *arg)
425 return tty_value_to_baud(xatou(arg));
428 static void set_speed_or_die(enum speed_setting type, const char *arg,
429 struct termios *mode)
433 baud = string_to_baud_or_die(arg);
435 if (type != output_speed) { /* either input or both */
436 cfsetispeed(mode, baud);
438 if (type != input_speed) { /* either output or both */
439 cfsetospeed(mode, baud);
443 static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt)
445 bb_perror_msg_and_die(fmt, device_name);
448 static void perror_on_device(const char *fmt)
450 bb_perror_msg(fmt, device_name);
453 /* No, inline won't be as efficient (gcc 3.4.3) */
454 #define streq(a,b) (!strcmp((a),(b)))
456 /* Print format string MESSAGE and optional args.
457 Wrap to next line first if it won't fit.
458 Print a space first unless MESSAGE will start a new line */
459 static void wrapf(const char *message, ...)
465 va_start(args, message);
466 vsnprintf(buf, sizeof(buf), message, args);
468 buflen = strlen(buf);
471 if (current_col > 0) {
473 if (buf[0] != '\n') {
474 if (current_col + buflen >= max_col) {
482 current_col += buflen;
483 if (buf[buflen-1] == '\n')
489 static int get_win_size(int fd, struct winsize *win)
491 return ioctl(fd, TIOCGWINSZ, (char *) win);
494 static void set_window_size(int rows, int cols)
498 if (get_win_size(STDIN_FILENO, &win)) {
499 if (errno != EINVAL) {
500 perror_on_device("%s");
503 memset(&win, 0, sizeof(win));
512 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
513 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
514 This comment from sys/ttold.h describes Sun's twisted logic - a better
515 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
516 At any rate, the problem is gone in Solaris 2.x */
518 if (win.ws_row == 0 || win.ws_col == 0) {
519 struct ttysize ttysz;
521 ttysz.ts_lines = win.ws_row;
522 ttysz.ts_cols = win.ws_col;
524 win.ws_row = win.ws_col = 1;
526 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
527 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
528 perror_on_device("%s");
534 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
535 perror_on_device("%s");
538 static void display_window_size(int fancy)
540 const char *fmt_str = "%s\0%s: no size information for this device";
543 if (get_win_size(STDIN_FILENO, &win)) {
544 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
545 perror_on_device(fmt_str);
548 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
549 win.ws_row, win.ws_col);
553 #else /* !TIOCGWINSZ */
555 static inline void display_window_size(int fancy) {}
557 #endif /* !TIOCGWINSZ */
559 static int screen_columns_or_die(void)
566 /* With Solaris 2.[123], this ioctl fails and errno is set to
567 EINVAL for telnet (but not rlogin) sessions.
568 On ISC 3.0, it fails for the console and the serial port
569 (but it works for ptys).
570 It can also fail on any system when stdout isn't a tty.
571 In case of any failure, just use the default */
572 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
576 s = getenv("COLUMNS");
582 static const struct suffix_mult stty_suffixes[] = {
589 static const struct mode_info *find_mode(const char *name)
592 for (i = 0; i < NUM_mode_info; ++i)
593 if (streq(name, mode_info[i].name))
594 return &mode_info[i];
598 static const struct control_info *find_control(const char *name)
601 for (i = 0; i < NUM_control_info; ++i)
602 if (streq(name, control_info[i].name))
603 return &control_info[i];
608 param_need_arg = 0x80,
609 param_line = 1 | 0x80,
610 param_rows = 2 | 0x80,
611 param_cols = 3 | 0x80,
614 param_ispeed = 6 | 0x80,
615 param_ospeed = 7 | 0x80,
618 static int find_param(const char *name)
621 if (streq(name, "line")) return param_line;
624 if (streq(name, "rows")) return param_rows;
625 if (streq(name, "cols")) return param_cols;
626 if (streq(name, "columns")) return param_cols;
627 if (streq(name, "size")) return param_size;
629 if (streq(name, "speed")) return param_speed;
630 if (streq(name, "ispeed")) return param_ispeed;
631 if (streq(name, "ospeed")) return param_ospeed;
636 static int recover_mode(const char *arg, struct termios *mode);
637 static void set_mode(const struct mode_info *info,
638 int reversed, struct termios *mode);
639 static void display_all(const struct termios *mode);
640 static void display_changed(const struct termios *mode);
641 static void display_recoverable(const struct termios *mode);
642 static void display_speed(const struct termios *mode, int fancy);
643 static void sane_mode(struct termios *mode);
644 static void set_control_char_or_die(const struct control_info *info,
645 const char *arg, struct termios *mode);
647 int stty_main(int argc, char **argv)
650 void (*output_func)(const struct termios *);
651 const char *file_name = NULL;
652 int require_set_attr;
655 int recoverable_output;
659 output_func = display_changed;
662 require_set_attr = 0;
664 recoverable_output = 0;
666 /* First pass: only parse/verify command line params */
669 const struct mode_info *mp;
670 const struct control_info *cp;
671 const char *arg = argv[k];
672 const char *argnext = argv[k+1];
677 mp = find_mode(arg+1);
679 if (!(mp->flags & REV))
680 bb_error_msg_and_die("invalid argument '%s'", arg);
684 /* It is an option - parse it */
690 output_func = display_all;
693 recoverable_output = 1;
694 output_func = display_recoverable;
698 bb_error_msg_and_die("only one device may be specified");
699 file_name = &arg[i+1]; /* "-Fdevice" ? */
700 if (!file_name[0]) { /* nope, "-F device" */
701 int p = k+1; /* argv[p] is argnext */
704 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
705 /* remove -F param from arg[vc] */
707 while (argv[p]) { argv[p] = argv[p+1]; ++p; }
711 bb_error_msg_and_die("invalid argument '%s'", arg);
724 cp = find_control(arg);
727 bb_error_msg_and_die(bb_msg_requires_arg, arg);
728 /* called for the side effect of xfunc death only */
729 set_control_char_or_die(cp, argnext, &mode);
735 param = find_param(arg);
736 if (param & param_need_arg) {
738 bb_error_msg_and_die(bb_msg_requires_arg, arg);
746 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
748 # endif /* else fall-through */
753 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
760 /* called for the side effect of xfunc death only */
761 set_speed_or_die(input_speed, argnext, &mode);
764 /* called for the side effect of xfunc death only */
765 set_speed_or_die(output_speed, argnext, &mode);
768 if (recover_mode(arg, &mode) == 1) break;
769 if (string_to_baud_or_die(arg) != (speed_t) -1) break;
770 bb_error_msg_and_die("invalid argument '%s'", arg);
775 /* Specifying both -a and -g is an error */
776 if (verbose_output && recoverable_output)
777 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
778 /* Specifying -a or -g with non-options is an error */
779 if (!noargs && (verbose_output || recoverable_output))
780 bb_error_msg_and_die("modes may not be set when specifying an output style");
782 /* Now it is safe to start doing things */
785 device_name = file_name;
786 fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
787 if (fd != STDIN_FILENO) {
788 dup2(fd, STDIN_FILENO);
791 fdflags = fcntl(STDIN_FILENO, F_GETFL);
792 if (fdflags == -1 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
793 perror_on_device_and_die("%s: cannot reset non-blocking mode");
796 /* Initialize to all zeroes so there is no risk memcmp will report a
797 spurious difference in an uninitialized portion of the structure */
798 memset(&mode, 0, sizeof(mode));
799 if (tcgetattr(STDIN_FILENO, &mode))
800 perror_on_device_and_die("%s");
802 if (verbose_output || recoverable_output || noargs) {
803 max_col = screen_columns_or_die();
808 /* Second pass: perform actions */
811 const struct mode_info *mp;
812 const struct control_info *cp;
813 const char *arg = argv[k];
814 const char *argnext = argv[k+1];
818 mp = find_mode(arg+1);
820 set_mode(mp, 1 /* reversed */, &mode);
822 /* It is an option - already parsed. Skip it */
828 set_mode(mp, 0 /* non-reversed */, &mode);
832 cp = find_control(arg);
835 set_control_char_or_die(cp, argnext, &mode);
839 param = find_param(arg);
840 if (param & param_need_arg) {
847 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
848 require_set_attr = 1;
853 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
856 display_window_size(0);
859 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
863 display_speed(&mode, 0);
866 set_speed_or_die(input_speed, argnext, &mode);
868 require_set_attr = 1;
871 set_speed_or_die(output_speed, argnext, &mode);
873 require_set_attr = 1;
876 if (recover_mode(arg, &mode) == 1)
877 require_set_attr = 1;
878 else /* true: if (string_to_baud_or_die(arg) != (speed_t) -1) */ {
879 set_speed_or_die(both_speeds, arg, &mode);
881 require_set_attr = 1;
882 } /* else - impossible (caught in the first pass):
883 bb_error_msg_and_die("invalid argument '%s'", arg); */
887 if (require_set_attr) {
888 struct termios new_mode;
890 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
891 perror_on_device_and_die("%s");
893 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
894 it performs *any* of the requested operations. This means it
895 can report 'success' when it has actually failed to perform
896 some proper subset of the requested operations. To detect
897 this partial failure, get the current terminal attributes and
898 compare them to the requested ones */
900 /* Initialize to all zeroes so there is no risk memcmp will report a
901 spurious difference in an uninitialized portion of the structure */
902 memset(&new_mode, 0, sizeof(new_mode));
903 if (tcgetattr(STDIN_FILENO, &new_mode))
904 perror_on_device_and_die("%s");
906 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
908 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
909 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
910 sometimes (m1 != m2). The only difference is in the four bits
911 of the c_cflag field corresponding to the baud rate. To save
912 Sun users a little confusion, don't report an error if this
913 happens. But suppress the error only if we haven't tried to
914 set the baud rate explicitly -- otherwise we'd never give an
915 error for a true failure to set the baud rate */
917 new_mode.c_cflag &= (~CIBAUD);
918 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
920 perror_on_device_and_die ("%s: unable to perform all requested operations");
927 /* Save set_mode from #ifdef forest plague */
962 static void set_mode(const struct mode_info *info, int reversed,
963 struct termios *mode)
967 bitsp = mode_type_flag(info->type, mode);
971 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
973 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
977 /* Combination mode */
978 if (info->name == evenp || info->name == parity) {
980 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
982 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
983 } else if (info->name == stty_oddp) {
985 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
987 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
988 } else if (info->name == stty_nl) {
990 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
991 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
993 mode->c_iflag = mode->c_iflag & ~ICRNL;
994 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
996 } else if (info->name == stty_ek) {
997 mode->c_cc[VERASE] = CERASE;
998 mode->c_cc[VKILL] = CKILL;
999 } else if (info->name == stty_sane) {
1002 else if (info->name == cbreak) {
1004 mode->c_lflag |= ICANON;
1006 mode->c_lflag &= ~ICANON;
1007 } else if (info->name == stty_pass8) {
1009 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1010 mode->c_iflag |= ISTRIP;
1012 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1013 mode->c_iflag &= ~ISTRIP;
1015 } else if (info->name == litout) {
1017 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1018 mode->c_iflag |= ISTRIP;
1019 mode->c_oflag |= OPOST;
1021 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1022 mode->c_iflag &= ~ISTRIP;
1023 mode->c_oflag &= ~OPOST;
1025 } else if (info->name == raw || info->name == cooked) {
1026 if ((info->name[0] == 'r' && reversed)
1027 || (info->name[0] == 'c' && !reversed)) {
1029 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1030 mode->c_oflag |= OPOST;
1031 mode->c_lflag |= ISIG | ICANON;
1033 mode->c_cc[VEOF] = CEOF;
1036 mode->c_cc[VEOL] = CEOL;
1041 mode->c_oflag &= ~OPOST;
1042 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1043 mode->c_cc[VMIN] = 1;
1044 mode->c_cc[VTIME] = 0;
1047 else if (IXANY && info->name == decctlq) {
1049 mode->c_iflag |= IXANY;
1051 mode->c_iflag &= ~IXANY;
1053 else if (TABDLY && info->name == stty_tabs) {
1055 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1057 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1059 else if (OXTABS && info->name == stty_tabs) {
1061 mode->c_oflag |= OXTABS;
1063 mode->c_oflag &= ~OXTABS;
1065 else if (XCASE && IUCLC && OLCUC
1066 && (info->name == stty_lcase || info->name == stty_LCASE)) {
1068 mode->c_lflag &= ~XCASE;
1069 mode->c_iflag &= ~IUCLC;
1070 mode->c_oflag &= ~OLCUC;
1072 mode->c_lflag |= XCASE;
1073 mode->c_iflag |= IUCLC;
1074 mode->c_oflag |= OLCUC;
1077 else if (info->name == stty_crt) {
1078 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1080 else if (info->name == stty_dec) {
1081 mode->c_cc[VINTR] = 3; /* ^C */
1082 mode->c_cc[VERASE] = 127; /* DEL */
1083 mode->c_cc[VKILL] = 21; /* ^U */
1084 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1085 if (IXANY) mode->c_iflag &= ~IXANY;
1089 static void set_control_char_or_die(const struct control_info *info,
1090 const char *arg, struct termios *mode)
1092 unsigned char value;
1094 if (info->name == stty_min || info->name == stty_time)
1095 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1096 else if (arg[0] == '\0' || arg[1] == '\0')
1098 else if (streq(arg, "^-") || streq(arg, "undef"))
1099 value = _POSIX_VDISABLE;
1100 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1101 value = arg[1] & 0x1f; /* Non-letters get weird results */
1105 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1106 mode->c_cc[info->offset] = value;
1109 static void display_changed(const struct termios *mode)
1114 int prev_type = control;
1116 display_speed(mode, 1);
1118 wrapf("line = %d;\n", mode->c_line);
1123 for (i = 0; control_info[i].name != stty_min; ++i) {
1124 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1126 /* If swtch is the same as susp, don't print both */
1128 if (control_info[i].name == stty_swtch)
1131 /* If eof uses the same slot as min, only print whichever applies */
1133 if ((mode->c_lflag & ICANON) == 0
1134 && (control_info[i].name == stty_eof
1135 || control_info[i].name == stty_eol)) continue;
1137 wrapf("%s = %s;", control_info[i].name,
1138 visible(mode->c_cc[control_info[i].offset]));
1140 if ((mode->c_lflag & ICANON) == 0) {
1141 wrapf("min = %d; time = %d;", (int) mode->c_cc[VMIN],
1142 (int) mode->c_cc[VTIME]);
1144 if (current_col) wrapf("\n");
1146 for (i = 0; i < NUM_mode_info; ++i) {
1147 if (mode_info[i].flags & OMIT)
1149 if (mode_info[i].type != prev_type) {
1150 if (current_col) wrapf("\n");
1151 prev_type = mode_info[i].type;
1154 bitsp = mode_type_flag(mode_info[i].type, mode);
1155 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1156 if ((*bitsp & mask) == mode_info[i].bits) {
1157 if (mode_info[i].flags & SANE_UNSET) {
1158 wrapf("%s", mode_info[i].name);
1160 } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) {
1161 wrapf("-%s", mode_info[i].name);
1164 if (current_col) wrapf("\n");
1167 static void display_all(const struct termios *mode)
1172 int prev_type = control;
1174 display_speed(mode, 1);
1175 display_window_size(1);
1177 wrapf("line = %d;\n", mode->c_line);
1182 for (i = 0; control_info[i].name != stty_min; ++i) {
1183 /* If swtch is the same as susp, don't print both */
1185 if (control_info[i].name == stty_swtch)
1188 /* If eof uses the same slot as min, only print whichever applies */
1190 if ((mode->c_lflag & ICANON) == 0
1191 && (control_info[i].name == stty_eof
1192 || control_info[i].name == stty_eol)) continue;
1194 wrapf("%s = %s;", control_info[i].name,
1195 visible(mode->c_cc[control_info[i].offset]));
1198 if ((mode->c_lflag & ICANON) == 0)
1200 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1201 if (current_col) wrapf("\n");
1203 for (i = 0; i < NUM_mode_info; ++i) {
1204 if (mode_info[i].flags & OMIT)
1206 if (mode_info[i].type != prev_type) {
1208 prev_type = mode_info[i].type;
1211 bitsp = mode_type_flag(mode_info[i].type, mode);
1212 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1213 if ((*bitsp & mask) == mode_info[i].bits)
1214 wrapf("%s", mode_info[i].name);
1215 else if (mode_info[i].flags & REV)
1216 wrapf("-%s", mode_info[i].name);
1218 if (current_col) wrapf("\n");
1221 static void display_speed(const struct termios *mode, int fancy)
1224 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
1225 unsigned long ispeed, ospeed;
1227 ospeed = ispeed = cfgetispeed(mode);
1228 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1229 ispeed = ospeed; /* in case ispeed was 0 */
1231 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
1233 if (fancy) fmt_str += 9;
1234 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1237 static void display_recoverable(const struct termios *mode)
1240 printf("%lx:%lx:%lx:%lx",
1241 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1242 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1243 for (i = 0; i < NCCS; ++i)
1244 printf(":%x", (unsigned int) mode->c_cc[i]);
1248 static int recover_mode(const char *arg, struct termios *mode)
1252 unsigned long iflag, oflag, cflag, lflag;
1254 /* Scan into temporaries since it is too much trouble to figure out
1255 the right format for 'tcflag_t' */
1256 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1257 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1259 mode->c_iflag = iflag;
1260 mode->c_oflag = oflag;
1261 mode->c_cflag = cflag;
1262 mode->c_lflag = lflag;
1264 for (i = 0; i < NCCS; ++i) {
1265 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1267 mode->c_cc[i] = chr;
1271 /* Fail if there are too many fields */
1278 static void sane_mode(struct termios *mode)
1283 for (i = 0; i < NUM_control_info; ++i) {
1285 if (control_info[i].name == stty_min)
1288 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1291 for (i = 0; i < NUM_mode_info; ++i) {
1292 if (mode_info[i].flags & SANE_SET) {
1293 bitsp = mode_type_flag(mode_info[i].type, mode);
1294 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1295 | mode_info[i].bits;
1296 } else if (mode_info[i].flags & SANE_UNSET) {
1297 bitsp = mode_type_flag(mode_info[i].type, mode);
1298 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1299 & ~mode_info[i].bits;