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 /* enum mode_type type; */
163 char type; /* Which structure element to change */
164 char flags; /* Setting and display options */
165 unsigned short mask; /* Other bits to turn off for this mode */
166 unsigned long bits; /* Bits to set for this mode */
168 #define EMT(t) ((enum mode_type)(t))
170 #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
172 static const struct mode_info mode_info[] = {
173 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
174 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
175 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
176 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
177 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
178 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
179 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
180 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
181 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
182 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
183 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
185 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
187 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
188 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
189 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
190 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
191 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
192 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
193 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
194 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
195 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
196 MI_ENTRY("ixon", input, REV, IXON, 0 ),
197 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
198 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
200 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
203 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
206 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
208 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
210 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
213 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
216 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
219 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
222 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
225 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
228 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
231 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
232 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
235 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
236 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
237 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
238 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
242 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
243 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
244 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
245 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
248 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
253 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
254 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
257 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
258 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
261 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
262 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
264 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
265 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
267 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
269 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
270 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
271 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
272 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
273 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
274 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
276 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
279 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
282 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
283 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
286 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
287 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
290 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
291 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
293 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
294 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
295 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
296 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
297 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
298 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
299 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
300 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
301 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
302 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
303 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
305 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
307 #if defined(TABDLY) || defined(OXTABS)
308 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
310 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
311 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
312 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
314 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
315 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
319 NUM_mode_info = (sizeof(mode_info) / sizeof(mode_info[0]))
322 /* Control character settings */
323 struct control_info {
324 const char *name; /* Name given on command line */
325 unsigned char saneval; /* Value to set for `stty sane' */
326 unsigned char offset; /* Offset in c_cc */
329 /* Control characters */
331 static const struct control_info control_info[] = {
332 {"intr", CINTR, VINTR},
333 {"quit", CQUIT, VQUIT},
334 {"erase", CERASE, VERASE},
335 {"kill", CKILL, VKILL},
336 {stty_eof, CEOF, VEOF},
337 {stty_eol, CEOL, VEOL},
339 {"eol2", CEOL2, VEOL2},
342 {stty_swtch, CSWTCH, VSWTCH},
344 {"start", CSTART, VSTART},
345 {"stop", CSTOP, VSTOP},
346 {"susp", CSUSP, VSUSP},
348 {"dsusp", CDSUSP, VDSUSP},
351 {"rprnt", CRPRNT, VREPRINT},
354 {"werase", CWERASE, VWERASE},
357 {"lnext", CLNEXT, VLNEXT},
360 {"flush", CFLUSHO, VFLUSHO},
363 {"status", CSTATUS, VSTATUS},
365 /* These must be last because of the display routines */
367 {stty_time, 0, VTIME},
371 NUM_control_info = (sizeof(control_info) / sizeof(control_info[0]))
374 /* The width of the screen, for output wrapping */
377 /* Current position, to know when to wrap */
378 static int current_col;
380 static const char * visible(unsigned int ch);
381 static int recover_mode(const char *arg, struct termios *mode);
382 static int screen_columns(void);
383 static void set_mode(const struct mode_info *info,
384 int reversed, struct termios *mode);
385 static speed_t string_to_baud(const char *arg);
386 static tcflag_t* mode_type_flag(enum mode_type type, const struct termios *mode);
387 static void display_all(const struct termios *mode);
388 static void display_changed(const struct termios *mode);
389 static void display_recoverable(const struct termios *mode);
390 static void display_speed(const struct termios *mode, int fancy);
391 static void display_window_size(int fancy);
392 static void sane_mode(struct termios *mode);
393 static void set_control_char(const struct control_info *info,
394 const char *arg, struct termios *mode);
395 static void set_speed(enum speed_setting type,
396 const char *arg, struct termios *mode);
397 static void set_window_size(int rows, int cols);
399 static const char *device_name = bb_msg_standard_input;
401 static ATTRIBUTE_NORETURN void perror_on_device(const char *fmt)
403 bb_perror_msg_and_die(fmt, device_name);
406 static ATTRIBUTE_ALWAYS_INLINE int streq(const char *a, const char *b)
408 return strcmp(a, b) == 0;
411 /* Print format string MESSAGE and optional args.
412 Wrap to next line first if it won't fit.
413 Print a space first unless MESSAGE will start a new line */
415 static void wrapf(const char *message, ...)
418 char buf[1024]; /* Plenty long for our needs */
421 va_start(args, message);
422 vsprintf(buf, message, args);
424 buflen = strlen(buf);
425 if (current_col + (current_col > 0) + buflen >= max_col) {
429 if (current_col > 0) {
434 current_col += buflen;
437 static const struct suffix_mult stty_suffixes[] = {
444 static const struct mode_info *find_mode(const char *name)
447 for (i = 0; i < NUM_mode_info; ++i)
448 if (streq(name, mode_info[i].name))
449 return &mode_info[i];
453 static const struct control_info *find_control(const char *name)
456 for (i = 0; i < NUM_control_info; ++i)
457 if (streq(name, control_info[i].name))
458 return &control_info[i];
463 param_need_arg = 0x80,
464 param_line = 1 | 0x80,
465 param_rows = 2 | 0x80,
466 param_cols = 3 | 0x80,
468 param_ispeed = 5 | 0x80,
469 param_ospeed = 6 | 0x80,
473 static int find_param(const char *name)
476 if (streq(name, "line")) return param_line;
479 if (streq(name, "rows")) return param_rows;
480 if (streq(name, "cols")) return param_cols;
481 if (streq(name, "columns")) return param_cols;
482 if (streq(name, "size")) return param_size;
484 if (streq(name, "ispeed")) return param_ispeed;
485 if (streq(name, "ospeed")) return param_ospeed;
486 if (streq(name, "speed")) return param_speed;
491 int stty_main(int argc, char **argv)
494 void (*output_func)(const struct termios *);
495 const char *file_name = NULL;
496 int require_set_attr;
499 int recoverable_output;
503 output_func = display_changed;
506 require_set_attr = 0;
508 recoverable_output = 0;
510 /* First pass: only parse/verify command line params */
513 const struct mode_info *mp;
514 const struct control_info *cp;
515 const char *arg = argv[k];
516 const char *argnext = argv[k+1];
521 mp = find_mode(arg+1);
523 if (!(mp->flags & REV))
524 bb_error_msg_and_die("invalid argument '%s'", arg);
528 /* It is an option - parse it */
534 output_func = display_all;
537 recoverable_output = 1;
538 output_func = display_recoverable;
542 bb_error_msg_and_die("only one device may be specified");
543 file_name = &arg[i+1]; /* "-Fdevice" ? */
544 if (!file_name[0]) { /* nope, "-F device" */
545 int p = k+1; /* argv[p] is argnext */
548 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
549 /* remove -F param from arg[vc] */
551 while (argv[p+1]) { argv[p] = argv[p+1]; ++p; }
555 bb_error_msg_and_die("invalid argument '%s'", arg);
568 cp = find_control(arg);
571 bb_error_msg_and_die(bb_msg_requires_arg, arg);
577 param = find_param(arg);
578 if (param & param_need_arg) {
580 bb_error_msg_and_die(bb_msg_requires_arg, arg);
587 bb_xparse_number(argnext, stty_suffixes);
592 bb_xparse_number(argnext, stty_suffixes);
595 bb_xparse_number(argnext, stty_suffixes);
604 if (recover_mode(arg, &mode) == 1) break;
605 if (string_to_baud(arg) != (speed_t) -1) break;
606 bb_error_msg_and_die("invalid argument '%s'", arg);
611 /* Specifying both -a and -g is an error */
612 if (verbose_output && recoverable_output)
613 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
614 /* Specifying -a or -g with non-options is an error */
615 if (!noargs && (verbose_output || recoverable_output))
616 bb_error_msg_and_die("modes may not be set when specifying an output style");
618 /* Now it is safe to start doing things */
621 device_name = file_name;
622 fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
627 fdflags = fcntl(STDIN_FILENO, F_GETFL);
628 if (fdflags == -1 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
629 perror_on_device("%s: couldn't reset non-blocking mode");
632 /* Initialize to all zeroes so there is no risk memcmp will report a
633 spurious difference in an uninitialized portion of the structure */
634 memset(&mode, 0, sizeof(mode));
635 if (tcgetattr(STDIN_FILENO, &mode))
636 perror_on_device("%s");
638 if (verbose_output || recoverable_output || noargs) {
639 max_col = screen_columns();
645 /* Second pass: perform actions */
648 const struct mode_info *mp;
649 const struct control_info *cp;
650 const char *arg = argv[k];
651 const char *argnext = argv[k+1];
655 mp = find_mode(arg+1);
657 set_mode(mp, 1 /* reversed */, &mode);
659 /* It is an option - already parsed. Skip it */
665 set_mode(mp, 0 /* non-reversed */, &mode);
669 cp = find_control(arg);
672 set_control_char(cp, argnext, &mode);
676 param = find_param(arg);
677 if (param & param_need_arg) {
684 mode.c_line = bb_xparse_number(argnext, stty_suffixes);
685 require_set_attr = 1;
690 set_window_size(-1, (int) bb_xparse_number(argnext, stty_suffixes));
693 max_col = screen_columns();
695 display_window_size(0);
698 set_window_size((int) bb_xparse_number(argnext, stty_suffixes), -1);
702 set_speed(input_speed, argnext, &mode);
704 require_set_attr = 1;
707 set_speed(output_speed, argnext, &mode);
709 require_set_attr = 1;
712 max_col = screen_columns();
713 display_speed(&mode, 0);
716 if (recover_mode(arg, &mode) == 1)
717 require_set_attr = 1;
718 else /* true: if (string_to_baud(arg) != (speed_t) -1) */ {
719 set_speed(both_speeds, arg, &mode);
721 require_set_attr = 1;
722 } /* else - impossible (caught in the first pass):
723 bb_error_msg_and_die("invalid argument '%s'", arg); */
727 if (require_set_attr) {
728 struct termios new_mode;
730 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
731 perror_on_device("%s");
733 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
734 it performs *any* of the requested operations. This means it
735 can report `success' when it has actually failed to perform
736 some proper subset of the requested operations. To detect
737 this partial failure, get the current terminal attributes and
738 compare them to the requested ones */
740 /* Initialize to all zeroes so there is no risk memcmp will report a
741 spurious difference in an uninitialized portion of the structure */
742 memset(&new_mode, 0, sizeof(new_mode));
743 if (tcgetattr(STDIN_FILENO, &new_mode))
744 perror_on_device("%s");
746 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
748 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
749 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
750 sometimes (m1 != m2). The only difference is in the four bits
751 of the c_cflag field corresponding to the baud rate. To save
752 Sun users a little confusion, don't report an error if this
753 happens. But suppress the error only if we haven't tried to
754 set the baud rate explicitly -- otherwise we'd never give an
755 error for a true failure to set the baud rate */
757 new_mode.c_cflag &= (~CIBAUD);
758 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
760 perror_on_device ("%s: unable to perform all requested operations");
769 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
773 bitsp = mode_type_flag(EMT(info->type), mode);
776 /* Combination mode */
777 if (info->name == evenp || info->name == parity) {
779 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
782 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
783 } else if (info->name == stty_oddp) {
785 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
788 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
789 } else if (info->name == stty_nl) {
791 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
792 mode->c_oflag = (mode->c_oflag
805 mode->c_iflag = mode->c_iflag & ~ICRNL;
807 mode->c_oflag = mode->c_oflag & ~ONLCR;
810 } else if (info->name == stty_ek) {
811 mode->c_cc[VERASE] = CERASE;
812 mode->c_cc[VKILL] = CKILL;
813 } else if (info->name == stty_sane)
815 else if (info->name == cbreak) {
817 mode->c_lflag |= ICANON;
819 mode->c_lflag &= ~ICANON;
820 } else if (info->name == stty_pass8) {
822 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
823 mode->c_iflag |= ISTRIP;
825 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
826 mode->c_iflag &= ~ISTRIP;
828 } else if (info->name == litout) {
830 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
831 mode->c_iflag |= ISTRIP;
832 mode->c_oflag |= OPOST;
834 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
835 mode->c_iflag &= ~ISTRIP;
836 mode->c_oflag &= ~OPOST;
838 } else if (info->name == raw || info->name == cooked) {
839 if ((info->name[0] == 'r' && reversed)
840 || (info->name[0] == 'c' && !reversed)) {
842 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
843 mode->c_oflag |= OPOST;
844 mode->c_lflag |= ISIG | ICANON;
846 mode->c_cc[VEOF] = CEOF;
849 mode->c_cc[VEOL] = CEOL;
854 mode->c_oflag &= ~OPOST;
855 mode->c_lflag &= ~(ISIG | ICANON
860 mode->c_cc[VMIN] = 1;
861 mode->c_cc[VTIME] = 0;
865 else if (info->name == decctlq) {
867 mode->c_iflag |= IXANY;
869 mode->c_iflag &= ~IXANY;
873 else if (info->name == stty_tabs) {
875 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
877 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
881 else if (info->name == stty_tabs) {
883 mode->c_oflag = mode->c_oflag | OXTABS;
885 mode->c_oflag = mode->c_oflag & ~OXTABS;
889 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
890 else if (info->name == stty_lcase || info->name == stty_LCASE) {
892 mode->c_lflag &= ~XCASE;
893 mode->c_iflag &= ~IUCLC;
894 mode->c_oflag &= ~OLCUC;
896 mode->c_lflag |= XCASE;
897 mode->c_iflag |= IUCLC;
898 mode->c_oflag |= OLCUC;
902 else if (info->name == stty_crt)
903 mode->c_lflag |= ECHOE
911 else if (info->name == stty_dec) {
912 mode->c_cc[VINTR] = 3; /* ^C */
913 mode->c_cc[VERASE] = 127; /* DEL */
914 mode->c_cc[VKILL] = 21; /* ^U */
915 mode->c_lflag |= ECHOE
924 mode->c_iflag &= ~IXANY;
928 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
930 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
934 set_control_char(const struct control_info *info, const char *arg,
935 struct termios *mode)
939 if (info->name == stty_min || info->name == stty_time)
940 value = bb_xparse_number(arg, stty_suffixes);
941 else if (arg[0] == '\0' || arg[1] == '\0')
943 else if (streq(arg, "^-") || streq(arg, "undef"))
944 value = _POSIX_VDISABLE;
945 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk */
949 value = arg[1] & ~0140; /* Non-letters get weird results */
951 value = bb_xparse_number(arg, stty_suffixes);
952 mode->c_cc[info->offset] = value;
956 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
960 baud = string_to_baud(arg);
962 if (type != output_speed) { /* either input or both */
963 cfsetispeed(mode, baud);
965 if (type != input_speed) { /* either output or both */
966 cfsetospeed(mode, baud);
972 static int get_win_size(int fd, struct winsize *win)
974 return ioctl(fd, TIOCGWINSZ, (char *) win);
978 set_window_size(int rows, int cols)
982 if (get_win_size(STDIN_FILENO, &win)) {
984 perror_on_device("%s");
985 memset(&win, 0, sizeof(win));
994 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
995 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
996 This comment from sys/ttold.h describes Sun's twisted logic - a better
997 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
998 At any rate, the problem is gone in Solaris 2.x */
1000 if (win.ws_row == 0 || win.ws_col == 0) {
1001 struct ttysize ttysz;
1003 ttysz.ts_lines = win.ws_row;
1004 ttysz.ts_cols = win.ws_col;
1006 win.ws_row = win.ws_col = 1;
1008 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
1009 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
1010 perror_on_device("%s");
1016 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1017 perror_on_device("%s");
1020 static void display_window_size(int fancy)
1022 const char *fmt_str = "%s" "\0" "%s: no size information for this device";
1025 if (get_win_size(STDIN_FILENO, &win)) {
1026 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
1027 perror_on_device(fmt_str);
1030 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
1031 win.ws_row, win.ws_col);
1038 static int screen_columns(void)
1046 /* With Solaris 2.[123], this ioctl fails and errno is set to
1047 EINVAL for telnet (but not rlogin) sessions.
1048 On ISC 3.0, it fails for the console and the serial port
1049 (but it works for ptys).
1050 It can also fail on any system when stdout isn't a tty.
1051 In case of any failure, just use the default */
1052 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1057 if ((s = getenv("COLUMNS"))) {
1063 static tcflag_t *mode_type_flag(enum mode_type type, const struct termios *mode)
1065 static const unsigned char tcflag_offsets[] = {
1066 offsetof(struct termios, c_cflag), /* control */
1067 offsetof(struct termios, c_iflag), /* input */
1068 offsetof(struct termios, c_oflag), /* output */
1069 offsetof(struct termios, c_lflag) /* local */
1072 if (((unsigned int) type) <= local) {
1073 return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
1078 static void display_changed(const struct termios *mode)
1084 enum mode_type prev_type = control;
1086 display_speed(mode, 1);
1088 wrapf("line = %d;", mode->c_line);
1094 for (i = 0; control_info[i].name != stty_min; ++i) {
1095 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1097 /* If swtch is the same as susp, don't print both */
1099 if (control_info[i].name == stty_swtch)
1102 /* If eof uses the same slot as min, only print whichever applies */
1104 if ((mode->c_lflag & ICANON) == 0
1105 && (control_info[i].name == stty_eof
1106 || control_info[i].name == stty_eol)) continue;
1110 wrapf("%s = %s;", control_info[i].name,
1111 visible(mode->c_cc[control_info[i].offset]));
1113 if ((mode->c_lflag & ICANON) == 0) {
1114 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1115 (int) mode->c_cc[VTIME]);
1116 } else if (empty_line == 0)
1121 for (i = 0; i < NUM_mode_info; ++i) {
1122 if (mode_info[i].flags & OMIT)
1124 if (EMT(mode_info[i].type) != prev_type) {
1125 if (empty_line == 0) {
1130 prev_type = EMT(mode_info[i].type);
1133 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1134 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1135 if ((*bitsp & mask) == mode_info[i].bits) {
1136 if (mode_info[i].flags & SANE_UNSET) {
1137 wrapf("%s", mode_info[i].name);
1140 } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) {
1141 wrapf("-%s", mode_info[i].name);
1145 if (empty_line == 0)
1151 display_all(const struct termios *mode)
1156 enum mode_type prev_type = control;
1158 display_speed(mode, 1);
1160 display_window_size(1);
1163 wrapf("line = %d;", mode->c_line);
1168 for (i = 0; control_info[i].name != stty_min; ++i) {
1169 /* If swtch is the same as susp, don't print both */
1171 if (control_info[i].name == stty_swtch)
1174 /* If eof uses the same slot as min, only print whichever applies */
1176 if ((mode->c_lflag & ICANON) == 0
1177 && (control_info[i].name == stty_eof
1178 || control_info[i].name == stty_eol)) continue;
1180 wrapf("%s = %s;", control_info[i].name,
1181 visible(mode->c_cc[control_info[i].offset]));
1184 if ((mode->c_lflag & ICANON) == 0)
1186 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1187 if (current_col != 0)
1191 for (i = 0; i < NUM_mode_info; ++i) {
1192 if (mode_info[i].flags & OMIT)
1194 if (EMT(mode_info[i].type) != prev_type) {
1197 prev_type = EMT(mode_info[i].type);
1200 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1201 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1202 if ((*bitsp & mask) == mode_info[i].bits)
1203 wrapf("%s", mode_info[i].name);
1204 else if (mode_info[i].flags & REV)
1205 wrapf("-%s", mode_info[i].name);
1211 static void display_speed(const struct termios *mode, int fancy)
1213 unsigned long ispeed, ospeed;
1214 const char *fmt_str =
1215 "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
1216 "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
1218 ospeed = ispeed = cfgetispeed(mode);
1219 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1220 ispeed = ospeed; /* in case ispeed was 0 */
1226 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1231 static void display_recoverable(const struct termios *mode)
1235 printf("%lx:%lx:%lx:%lx",
1236 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1237 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1238 for (i = 0; i < NCCS; ++i)
1239 printf(":%x", (unsigned int) mode->c_cc[i]);
1243 static int recover_mode(const char *arg, struct termios *mode)
1247 unsigned long iflag, oflag, cflag, lflag;
1249 /* Scan into temporaries since it is too much trouble to figure out
1250 the right format for `tcflag_t' */
1251 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1252 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1254 mode->c_iflag = iflag;
1255 mode->c_oflag = oflag;
1256 mode->c_cflag = cflag;
1257 mode->c_lflag = lflag;
1259 for (i = 0; i < NCCS; ++i) {
1260 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1262 mode->c_cc[i] = chr;
1266 /* Fail if there are too many fields */
1273 static speed_t string_to_baud(const char *arg)
1275 return tty_value_to_baud(bb_xparse_number(arg, 0));
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(EMT(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(EMT(mode_info[i].type), mode);
1298 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1299 & ~mode_info[i].bits;
1304 /* Return a string that is the printable representation of character CH */
1305 /* Adapted from `cat' by Torbjorn Granlund */
1307 static const char *visible(unsigned int ch)
1309 static char buf[10];
1312 if (ch == _POSIX_VDISABLE) {
1325 } else if (ch < 127) {