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 */
374 /* Current position, to know when to wrap */
375 static int 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(bb_xparse_number(arg, 0));
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 (current_col + buflen >= max_col) {
477 if (buf[0] != '\n') putchar(' ');
480 current_col += buflen;
481 if (buf[buflen-1] == '\n')
487 static int get_win_size(struct winsize *win)
489 return ioctl(STDIN_FILENO, TIOCGWINSZ, (char *) win);
492 static void set_window_size(int rows, int cols)
496 if (get_win_size(&win)) {
497 if (errno != EINVAL) {
498 perror_on_device("%s");
501 memset(&win, 0, sizeof(win));
510 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
511 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
512 This comment from sys/ttold.h describes Sun's twisted logic - a better
513 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
514 At any rate, the problem is gone in Solaris 2.x */
516 if (win.ws_row == 0 || win.ws_col == 0) {
517 struct ttysize ttysz;
519 ttysz.ts_lines = win.ws_row;
520 ttysz.ts_cols = win.ws_col;
522 win.ws_row = win.ws_col = 1;
524 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
525 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
526 perror_on_device("%s");
532 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
533 perror_on_device("%s");
536 static void display_window_size(int fancy)
538 const char *fmt_str = "%s\0%s: no size information for this device";
541 if (get_win_size(&win)) {
542 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
543 perror_on_device(fmt_str);
546 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
547 win.ws_row, win.ws_col);
551 #else /* !TIOCGWINSZ */
553 static inline void display_window_size(int fancy) {}
555 #endif /* !TIOCGWINSZ */
557 static int screen_columns(void)
565 /* With Solaris 2.[123], this ioctl fails and errno is set to
566 EINVAL for telnet (but not rlogin) sessions.
567 On ISC 3.0, it fails for the console and the serial port
568 (but it works for ptys).
569 It can also fail on any system when stdout isn't a tty.
570 In case of any failure, just use the default */
571 if (get_win_size(&win) == 0 && win.ws_col > 0)
576 if ((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+1]) { 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 bb_xparse_number(argnext, stty_suffixes);
748 # endif /* else fall-through */
753 bb_xparse_number(argnext, 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);
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: couldn't 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();
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 = bb_xparse_number(argnext, stty_suffixes);
848 require_set_attr = 1;
853 set_window_size(-1, (int) bb_xparse_number(argnext, stty_suffixes));
856 max_col = screen_columns();
857 display_window_size(0);
860 set_window_size((int) bb_xparse_number(argnext, stty_suffixes), -1);
864 max_col = screen_columns();
865 display_speed(&mode, 0);
868 set_speed_or_die(input_speed, argnext, &mode);
870 require_set_attr = 1;
873 set_speed_or_die(output_speed, argnext, &mode);
875 require_set_attr = 1;
878 if (recover_mode(arg, &mode) == 1)
879 require_set_attr = 1;
880 else /* true: if (string_to_baud_or_die(arg) != (speed_t) -1) */ {
881 set_speed_or_die(both_speeds, arg, &mode);
883 require_set_attr = 1;
884 } /* else - impossible (caught in the first pass):
885 bb_error_msg_and_die("invalid argument '%s'", arg); */
889 if (require_set_attr) {
890 struct termios new_mode;
892 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
893 perror_on_device_and_die("%s");
895 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
896 it performs *any* of the requested operations. This means it
897 can report `success' when it has actually failed to perform
898 some proper subset of the requested operations. To detect
899 this partial failure, get the current terminal attributes and
900 compare them to the requested ones */
902 /* Initialize to all zeroes so there is no risk memcmp will report a
903 spurious difference in an uninitialized portion of the structure */
904 memset(&new_mode, 0, sizeof(new_mode));
905 if (tcgetattr(STDIN_FILENO, &new_mode))
906 perror_on_device_and_die("%s");
908 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
910 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
911 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
912 sometimes (m1 != m2). The only difference is in the four bits
913 of the c_cflag field corresponding to the baud rate. To save
914 Sun users a little confusion, don't report an error if this
915 happens. But suppress the error only if we haven't tried to
916 set the baud rate explicitly -- otherwise we'd never give an
917 error for a true failure to set the baud rate */
919 new_mode.c_cflag &= (~CIBAUD);
920 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
922 perror_on_device_and_die ("%s: unable to perform all requested operations");
929 /* Save set_mode from #ifdef forest plague */
964 static void set_mode(const struct mode_info *info, int reversed,
965 struct termios *mode)
969 bitsp = mode_type_flag(info->type, mode);
973 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
975 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
979 /* Combination mode */
980 if (info->name == evenp || info->name == parity) {
982 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
984 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
985 } else if (info->name == stty_oddp) {
987 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
989 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
990 } else if (info->name == stty_nl) {
992 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
993 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
995 mode->c_iflag = mode->c_iflag & ~ICRNL;
996 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
998 } else if (info->name == stty_ek) {
999 mode->c_cc[VERASE] = CERASE;
1000 mode->c_cc[VKILL] = CKILL;
1001 } else if (info->name == stty_sane) {
1004 else if (info->name == cbreak) {
1006 mode->c_lflag |= ICANON;
1008 mode->c_lflag &= ~ICANON;
1009 } else if (info->name == stty_pass8) {
1011 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1012 mode->c_iflag |= ISTRIP;
1014 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1015 mode->c_iflag &= ~ISTRIP;
1017 } else if (info->name == litout) {
1019 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1020 mode->c_iflag |= ISTRIP;
1021 mode->c_oflag |= OPOST;
1023 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1024 mode->c_iflag &= ~ISTRIP;
1025 mode->c_oflag &= ~OPOST;
1027 } else if (info->name == raw || info->name == cooked) {
1028 if ((info->name[0] == 'r' && reversed)
1029 || (info->name[0] == 'c' && !reversed)) {
1031 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1032 mode->c_oflag |= OPOST;
1033 mode->c_lflag |= ISIG | ICANON;
1035 mode->c_cc[VEOF] = CEOF;
1038 mode->c_cc[VEOL] = CEOL;
1043 mode->c_oflag &= ~OPOST;
1044 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1045 mode->c_cc[VMIN] = 1;
1046 mode->c_cc[VTIME] = 0;
1049 else if (IXANY && info->name == decctlq) {
1051 mode->c_iflag |= IXANY;
1053 mode->c_iflag &= ~IXANY;
1055 else if (TABDLY && info->name == stty_tabs) {
1057 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1059 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1061 else if (OXTABS && info->name == stty_tabs) {
1063 mode->c_oflag |= OXTABS;
1065 mode->c_oflag &= ~OXTABS;
1067 else if (XCASE && IUCLC && OLCUC
1068 && (info->name == stty_lcase || info->name == stty_LCASE)) {
1070 mode->c_lflag &= ~XCASE;
1071 mode->c_iflag &= ~IUCLC;
1072 mode->c_oflag &= ~OLCUC;
1074 mode->c_lflag |= XCASE;
1075 mode->c_iflag |= IUCLC;
1076 mode->c_oflag |= OLCUC;
1079 else if (info->name == stty_crt) {
1080 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1082 else if (info->name == stty_dec) {
1083 mode->c_cc[VINTR] = 3; /* ^C */
1084 mode->c_cc[VERASE] = 127; /* DEL */
1085 mode->c_cc[VKILL] = 21; /* ^U */
1086 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1087 if (IXANY) mode->c_iflag &= ~IXANY;
1091 static void set_control_char_or_die(const struct control_info *info,
1092 const char *arg, struct termios *mode)
1094 unsigned char value;
1096 if (info->name == stty_min || info->name == stty_time)
1097 value = bb_xparse_number(arg, stty_suffixes);
1098 else if (arg[0] == '\0' || arg[1] == '\0')
1100 else if (streq(arg, "^-") || streq(arg, "undef"))
1101 value = _POSIX_VDISABLE;
1102 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1103 value = arg[1] & 0x1f; /* Non-letters get weird results */
1107 value = bb_xparse_number(arg, stty_suffixes);
1108 mode->c_cc[info->offset] = value;
1111 static void display_changed(const struct termios *mode)
1116 int prev_type = control;
1118 display_speed(mode, 1);
1120 wrapf("line = %d;\n", mode->c_line);
1125 for (i = 0; control_info[i].name != stty_min; ++i) {
1126 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1128 /* If swtch is the same as susp, don't print both */
1130 if (control_info[i].name == stty_swtch)
1133 /* If eof uses the same slot as min, only print whichever applies */
1135 if ((mode->c_lflag & ICANON) == 0
1136 && (control_info[i].name == stty_eof
1137 || control_info[i].name == stty_eol)) continue;
1139 wrapf("%s = %s;", control_info[i].name,
1140 visible(mode->c_cc[control_info[i].offset]));
1142 if ((mode->c_lflag & ICANON) == 0) {
1143 wrapf("min = %d; time = %d;", (int) mode->c_cc[VMIN],
1144 (int) mode->c_cc[VTIME]);
1146 if (current_col) wrapf("\n");
1148 for (i = 0; i < NUM_mode_info; ++i) {
1149 if (mode_info[i].flags & OMIT)
1151 if (mode_info[i].type != prev_type) {
1152 if (current_col) wrapf("\n");
1153 prev_type = mode_info[i].type;
1156 bitsp = mode_type_flag(mode_info[i].type, mode);
1157 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1158 if ((*bitsp & mask) == mode_info[i].bits) {
1159 if (mode_info[i].flags & SANE_UNSET) {
1160 wrapf("%s", mode_info[i].name);
1162 } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) {
1163 wrapf("-%s", mode_info[i].name);
1166 if (current_col) wrapf("\n");
1169 static void display_all(const struct termios *mode)
1174 int prev_type = control;
1176 display_speed(mode, 1);
1177 display_window_size(1);
1179 wrapf("line = %d;\n", mode->c_line);
1184 for (i = 0; control_info[i].name != stty_min; ++i) {
1185 /* If swtch is the same as susp, don't print both */
1187 if (control_info[i].name == stty_swtch)
1190 /* If eof uses the same slot as min, only print whichever applies */
1192 if ((mode->c_lflag & ICANON) == 0
1193 && (control_info[i].name == stty_eof
1194 || control_info[i].name == stty_eol)) continue;
1196 wrapf("%s = %s;", control_info[i].name,
1197 visible(mode->c_cc[control_info[i].offset]));
1200 if ((mode->c_lflag & ICANON) == 0)
1202 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1203 if (current_col) wrapf("\n");
1205 for (i = 0; i < NUM_mode_info; ++i) {
1206 if (mode_info[i].flags & OMIT)
1208 if (mode_info[i].type != prev_type) {
1210 prev_type = mode_info[i].type;
1213 bitsp = mode_type_flag(mode_info[i].type, mode);
1214 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1215 if ((*bitsp & mask) == mode_info[i].bits)
1216 wrapf("%s", mode_info[i].name);
1217 else if (mode_info[i].flags & REV)
1218 wrapf("-%s", mode_info[i].name);
1220 if (current_col) wrapf("\n");
1223 static void display_speed(const struct termios *mode, int fancy)
1226 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
1227 unsigned long ispeed, ospeed;
1229 ospeed = ispeed = cfgetispeed(mode);
1230 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1231 ispeed = ospeed; /* in case ispeed was 0 */
1233 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
1235 if (fancy) fmt_str += 9;
1236 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1239 static void display_recoverable(const struct termios *mode)
1242 printf("%lx:%lx:%lx:%lx",
1243 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1244 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1245 for (i = 0; i < NCCS; ++i)
1246 printf(":%x", (unsigned int) mode->c_cc[i]);
1250 static int recover_mode(const char *arg, struct termios *mode)
1254 unsigned long iflag, oflag, cflag, lflag;
1256 /* Scan into temporaries since it is too much trouble to figure out
1257 the right format for `tcflag_t' */
1258 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1259 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1261 mode->c_iflag = iflag;
1262 mode->c_oflag = oflag;
1263 mode->c_cflag = cflag;
1264 mode->c_lflag = lflag;
1266 for (i = 0; i < NCCS; ++i) {
1267 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1269 mode->c_cc[i] = chr;
1273 /* Fail if there are too many fields */
1280 static void sane_mode(struct termios *mode)
1285 for (i = 0; i < NUM_control_info; ++i) {
1287 if (control_info[i].name == stty_min)
1290 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1293 for (i = 0; i < NUM_mode_info; ++i) {
1294 if (mode_info[i].flags & SANE_SET) {
1295 bitsp = mode_type_flag(mode_info[i].type, mode);
1296 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1297 | mode_info[i].bits;
1298 } else if (mode_info[i].flags & SANE_UNSET) {
1299 bitsp = mode_type_flag(mode_info[i].type, mode);
1300 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1301 & ~mode_info[i].bits;