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
28 #include <sys/ioctl.h>
30 #include <sys/param.h>
34 # define STDIN_FILENO 0
38 # define STDOUT_FILENO 1
50 #define STREQ(a, b) (strcmp ((a), (b)) == 0)
53 #ifndef _POSIX_VDISABLE
54 # define _POSIX_VDISABLE ((unsigned char) 0)
57 #define Control(c) ((c) & 0x1f)
58 /* Canonical values for control characters. */
60 # define CINTR Control ('c')
69 # define CKILL Control ('u')
72 # define CEOF Control ('d')
75 # define CEOL _POSIX_VDISABLE
78 # define CSTART Control ('q')
81 # define CSTOP Control ('s')
84 # define CSUSP Control ('z')
86 #if defined(VEOL2) && !defined(CEOL2)
87 # define CEOL2 _POSIX_VDISABLE
89 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
90 #if defined(VSUSP) && !defined(VSWTCH)
94 #if defined(VSWTCH) && !defined(CSWTCH)
95 # define CSWTCH _POSIX_VDISABLE
98 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
99 So the default is to disable `swtch.' */
100 #if defined (__sparc__) && defined (__svr4__)
102 # define CSWTCH _POSIX_VDISABLE
105 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
106 # define VWERASE VWERSE
108 #if defined(VDSUSP) && !defined (CDSUSP)
109 # define CDSUSP Control ('y')
111 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
112 # define VREPRINT VRPRNT
114 #if defined(VREPRINT) && !defined(CRPRNT)
115 # define CRPRNT Control ('r')
117 #if defined(VWERASE) && !defined(CWERASE)
118 # define CWERASE Control ('w')
120 #if defined(VLNEXT) && !defined(CLNEXT)
121 # define CLNEXT Control ('v')
123 #if defined(VDISCARD) && !defined(VFLUSHO)
124 # define VFLUSHO VDISCARD
126 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
127 # define VFLUSHO VFLUSH
129 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
130 # define ECHOCTL CTLECH
132 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
133 # define ECHOCTL TCTLECH
135 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
136 # define ECHOKE CRTKIL
138 #if defined(VFLUSHO) && !defined(CFLUSHO)
139 # define CFLUSHO Control ('o')
141 #if defined(VSTATUS) && !defined(CSTATUS)
142 # define CSTATUS Control ('t')
145 /* Which speeds to set. */
147 input_speed, output_speed, both_speeds
150 /* Which member(s) of `struct termios' a mode uses. */
152 /* Do NOT change the order or values, as mode_type_flag()
153 * depends on them. */
154 control, input, output, local, combination
158 static const char evenp [] = "evenp";
159 static const char raw [] = "raw";
160 static const char stty_min [] = "min";
161 static const char stty_time [] = "time";
162 static const char stty_swtch[] = "swtch";
163 static const char stty_eol [] = "eol";
164 static const char stty_eof [] = "eof";
165 static const char parity [] = "parity";
166 static const char stty_oddp [] = "oddp";
167 static const char stty_nl [] = "nl";
168 static const char stty_ek [] = "ek";
169 static const char stty_sane [] = "sane";
170 static const char cbreak [] = "cbreak";
171 static const char stty_pass8[] = "pass8";
172 static const char litout [] = "litout";
173 static const char cooked [] = "cooked";
174 static const char decctlq [] = "decctlq";
175 static const char stty_tabs [] = "tabs";
176 static const char stty_lcase[] = "lcase";
177 static const char stty_LCASE[] = "LCASE";
178 static const char stty_crt [] = "crt";
179 static const char stty_dec [] = "dec";
182 /* Flags for `struct mode_info'. */
183 #define SANE_SET 1 /* Set in `sane' mode. */
184 #define SANE_UNSET 2 /* Unset in `sane' mode. */
185 #define REV 4 /* Can be turned off by prepending `-'. */
186 #define OMIT 8 /* Don't display value. */
190 const char *name; /* Name given on command line. */
191 /* enum mode_type type; */
192 char type; /* Which structure element to change. */
193 char flags; /* Setting and display options. */
194 unsigned short mask; /* Other bits to turn off for this mode. */
195 unsigned long bits; /* Bits to set for this mode. */
198 #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
200 static const struct mode_info mode_info[] = {
201 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
202 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
203 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
204 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
205 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
206 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
207 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
208 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
209 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
210 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
211 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
213 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
215 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
216 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
217 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
218 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
219 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
220 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
221 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
222 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
223 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
224 MI_ENTRY("ixon", input, REV, IXON, 0 ),
225 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
226 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
228 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
231 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
234 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
236 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
238 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
241 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
244 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
247 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
250 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
253 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
256 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
259 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
260 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
263 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
264 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
265 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
266 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
270 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
271 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
272 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
273 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
276 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
281 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
282 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
285 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
286 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
289 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
290 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
292 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
293 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
295 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
297 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
298 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
299 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
300 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
301 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
302 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
304 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
307 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
310 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
311 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
314 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
315 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
318 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
319 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
321 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
322 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
323 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
324 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
325 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
326 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
327 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
328 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
329 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
330 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
331 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
333 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
335 #if defined (TABDLY) || defined (OXTABS)
336 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
338 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
339 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
340 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
342 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
343 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
348 (sizeof(mode_info) / sizeof(struct mode_info))
351 /* Control character settings. */
352 struct control_info {
353 const char *name; /* Name given on command line. */
354 unsigned char saneval; /* Value to set for `stty sane'. */
355 unsigned char offset; /* Offset in c_cc. */
358 /* Control characters. */
360 static const struct control_info control_info[] = {
361 {"intr", CINTR, VINTR},
362 {"quit", CQUIT, VQUIT},
363 {"erase", CERASE, VERASE},
364 {"kill", CKILL, VKILL},
365 {stty_eof, CEOF, VEOF},
366 {stty_eol, CEOL, VEOL},
368 {"eol2", CEOL2, VEOL2},
371 {stty_swtch, CSWTCH, VSWTCH},
373 {"start", CSTART, VSTART},
374 {"stop", CSTOP, VSTOP},
375 {"susp", CSUSP, VSUSP},
377 {"dsusp", CDSUSP, VDSUSP},
380 {"rprnt", CRPRNT, VREPRINT},
383 {"werase", CWERASE, VWERASE},
386 {"lnext", CLNEXT, VLNEXT},
389 {"flush", CFLUSHO, VFLUSHO},
392 {"status", CSTATUS, VSTATUS},
394 /* These must be last because of the display routines. */
396 {stty_time, 0, VTIME},
401 (sizeof(control_info) / sizeof(struct control_info))
404 #define EMT(t) ((enum mode_type)(t))
406 static const char * visible(unsigned int ch);
407 static int recover_mode(char *arg, struct termios *mode);
408 static int screen_columns(void);
409 static int set_mode(const struct mode_info *info,
410 int reversed, struct termios *mode);
411 static speed_t string_to_baud(const char *arg);
412 static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
413 static void display_all(struct termios *mode);
414 static void display_changed(struct termios *mode);
415 static void display_recoverable(struct termios *mode);
416 static void display_speed(struct termios *mode, int fancy);
417 static void display_window_size(int fancy);
418 static void sane_mode(struct termios *mode);
419 static void set_control_char(const struct control_info *info,
420 const char *arg, struct termios *mode);
421 static void set_speed(enum speed_setting type,
422 const char *arg, struct termios *mode);
423 static void set_window_size(int rows, int cols);
425 static const char *device_name;
427 static ATTRIBUTE_NORETURN void perror_on_device(const char *fmt)
429 bb_perror_msg_and_die(fmt, device_name);
433 /* The width of the screen, for output wrapping. */
436 /* Current position, to know when to wrap. */
437 static int current_col;
439 /* Print format string MESSAGE and optional args.
440 Wrap to next line first if it won't fit.
441 Print a space first unless MESSAGE will start a new line. */
443 static void wrapf(const char *message, ...)
446 char buf[1024]; /* Plenty long for our needs. */
449 va_start(args, message);
450 vsprintf(buf, message, args);
452 buflen = strlen(buf);
453 if (current_col + (current_col > 0) + buflen >= max_col) {
457 if (current_col > 0) {
462 current_col += buflen;
465 static const struct suffix_mult stty_suffixes[] = {
473 int stty_main(int argc, char **argv)
475 int main(int argc, char **argv)
479 void (*output_func)(struct termios *);
481 int require_set_attr;
484 int recoverable_output;
487 char * file_name = NULL;
489 output_func = display_changed;
491 recoverable_output = 0;
493 /* Don't print error messages for unrecognized options. */
496 while ((optc = getopt(argc, argv, "agF:")) != -1) {
500 output_func = display_all;
504 recoverable_output = 1;
505 output_func = display_recoverable;
510 bb_error_msg_and_die("only one device may be specified");
514 default: /* unrecognized option */
526 /* Specifying both -a and -g gets an error. */
527 if (verbose_output & recoverable_output)
528 bb_error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
530 /* Specifying any other arguments with -a or -g gets an error. */
531 if (~noargs & (verbose_output | recoverable_output))
532 bb_error_msg_and_die ("modes may not be set when specifying an output style");
534 /* FIXME: it'd be better not to open the file until we've verified
535 that all arguments are valid. Otherwise, we could end up doing
536 only some of the requested operations and then failing, probably
537 leaving things in an undesirable state. */
542 device_name = file_name;
544 bb_xopen(device_name, O_RDONLY | O_NONBLOCK);
545 if ((fdflags = fcntl(STDIN_FILENO, F_GETFL)) == -1
546 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
547 perror_on_device("%s: couldn't reset non-blocking mode");
549 device_name = bb_msg_standard_input;
552 /* Initialize to all zeroes so there is no risk memcmp will report a
553 spurious difference in an uninitialized portion of the structure. */
554 memset(&mode, 0, sizeof(mode));
555 if (tcgetattr(STDIN_FILENO, &mode))
556 perror_on_device("%s");
558 if (verbose_output | recoverable_output | noargs) {
559 max_col = screen_columns();
566 require_set_attr = 0;
573 if (argv[k][0] == '-') {
578 /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
579 Find the options that have been parsed. This is really
580 gross, but it's needed because stty SETTINGS look like options to
581 getopt(), so we need to work around things in a really horrible
582 way. If any new options are ever added to stty, the short option
583 MUST NOT be a letter which is the first letter of one of the
584 possible stty settings.
586 find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
588 if(find_dev_opt[1]==0) /* -*F /dev/foo */
589 k++; /* skip /dev/foo */
590 continue; /* else -*F/dev/foo - no skip */
592 if(argv[k][0]=='a' || argv[k][0]=='g')
594 /* Is not options - is reverse params */
597 for (i = 0; i < NUM_mode_info; ++i)
598 if (STREQ(argv[k], mode_info[i].name)) {
599 match_found = set_mode(&mode_info[i], reversed, &mode);
600 require_set_attr = 1;
604 if (match_found == 0 && reversed)
605 bb_error_msg_and_die("invalid argument `%s'", --argv[k]);
607 if (match_found == 0)
608 for (i = 0; i < NUM_control_info; ++i)
609 if (STREQ(argv[k], control_info[i].name)) {
611 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
614 set_control_char(&control_info[i], argv[k], &mode);
615 require_set_attr = 1;
619 if (match_found == 0) {
620 if (STREQ(argv[k], "ispeed")) {
622 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
624 set_speed(input_speed, argv[k], &mode);
626 require_set_attr = 1;
627 } else if (STREQ(argv[k], "ospeed")) {
629 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
631 set_speed(output_speed, argv[k], &mode);
633 require_set_attr = 1;
636 else if (STREQ(argv[k], "rows")) {
638 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
640 set_window_size((int) bb_xparse_number(argv[k], stty_suffixes),
642 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
644 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
647 (int) bb_xparse_number(argv[k], stty_suffixes));
648 } else if (STREQ(argv[k], "size")) {
649 max_col = screen_columns();
651 display_window_size(0);
655 else if (STREQ(argv[k], "line")) {
657 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
659 mode.c_line = bb_xparse_number(argv[k], stty_suffixes);
660 require_set_attr = 1;
663 else if (STREQ(argv[k], "speed")) {
664 max_col = screen_columns();
665 display_speed(&mode, 0);
666 } else if (recover_mode(argv[k], &mode) == 1)
667 require_set_attr = 1;
668 else if (string_to_baud(argv[k]) != (speed_t) - 1) {
669 set_speed(both_speeds, argv[k], &mode);
671 require_set_attr = 1;
673 bb_error_msg_and_die("invalid argument `%s'", argv[k]);
677 if (require_set_attr) {
678 struct termios new_mode;
680 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
681 perror_on_device("%s");
683 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
684 it performs *any* of the requested operations. This means it
685 can report `success' when it has actually failed to perform
686 some proper subset of the requested operations. To detect
687 this partial failure, get the current terminal attributes and
688 compare them to the requested ones. */
690 /* Initialize to all zeroes so there is no risk memcmp will report a
691 spurious difference in an uninitialized portion of the structure. */
692 memset(&new_mode, 0, sizeof(new_mode));
693 if (tcgetattr(STDIN_FILENO, &new_mode))
694 perror_on_device("%s");
696 /* Normally, one shouldn't use memcmp to compare structures that
697 may have `holes' containing uninitialized data, but we have been
698 careful to initialize the storage of these two variables to all
699 zeroes. One might think it more efficient simply to compare the
700 modified fields, but that would require enumerating those fields --
701 and not all systems have the same fields in this structure. */
703 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
705 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
706 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
707 sometimes (m1 != m2). The only difference is in the four bits
708 of the c_cflag field corresponding to the baud rate. To save
709 Sun users a little confusion, don't report an error if this
710 happens. But suppress the error only if we haven't tried to
711 set the baud rate explicitly -- otherwise we'd never give an
712 error for a true failure to set the baud rate. */
714 new_mode.c_cflag &= (~CIBAUD);
715 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
717 perror_on_device ("%s: unable to perform all requested operations");
724 /* Return 0 if not applied because not reversible; otherwise return 1. */
727 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
731 if (reversed && (info->flags & REV) == 0)
734 bitsp = mode_type_flag(EMT(info->type), mode);
737 /* Combination mode. */
738 if (info->name == evenp || info->name == parity) {
740 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
743 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
744 } else if (info->name == stty_oddp) {
746 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
749 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
750 } else if (info->name == stty_nl) {
752 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
753 mode->c_oflag = (mode->c_oflag
766 mode->c_iflag = mode->c_iflag & ~ICRNL;
768 mode->c_oflag = mode->c_oflag & ~ONLCR;
771 } else if (info->name == stty_ek) {
772 mode->c_cc[VERASE] = CERASE;
773 mode->c_cc[VKILL] = CKILL;
774 } else if (info->name == stty_sane)
776 else if (info->name == cbreak) {
778 mode->c_lflag |= ICANON;
780 mode->c_lflag &= ~ICANON;
781 } else if (info->name == stty_pass8) {
783 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
784 mode->c_iflag |= ISTRIP;
786 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
787 mode->c_iflag &= ~ISTRIP;
789 } else if (info->name == litout) {
791 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
792 mode->c_iflag |= ISTRIP;
793 mode->c_oflag |= OPOST;
795 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
796 mode->c_iflag &= ~ISTRIP;
797 mode->c_oflag &= ~OPOST;
799 } else if (info->name == raw || info->name == cooked) {
800 if ((info->name[0] == 'r' && reversed)
801 || (info->name[0] == 'c' && !reversed)) {
803 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
804 mode->c_oflag |= OPOST;
805 mode->c_lflag |= ISIG | ICANON;
807 mode->c_cc[VEOF] = CEOF;
810 mode->c_cc[VEOL] = CEOL;
815 mode->c_oflag &= ~OPOST;
816 mode->c_lflag &= ~(ISIG | ICANON
821 mode->c_cc[VMIN] = 1;
822 mode->c_cc[VTIME] = 0;
826 else if (info->name == decctlq) {
828 mode->c_iflag |= IXANY;
830 mode->c_iflag &= ~IXANY;
834 else if (info->name == stty_tabs) {
836 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
838 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
842 else if (info->name == stty_tabs) {
844 mode->c_oflag = mode->c_oflag | OXTABS;
846 mode->c_oflag = mode->c_oflag & ~OXTABS;
850 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
851 else if (info->name == stty_lcase || info->name == stty_LCASE) {
853 mode->c_lflag &= ~XCASE;
854 mode->c_iflag &= ~IUCLC;
855 mode->c_oflag &= ~OLCUC;
857 mode->c_lflag |= XCASE;
858 mode->c_iflag |= IUCLC;
859 mode->c_oflag |= OLCUC;
863 else if (info->name == stty_crt)
864 mode->c_lflag |= ECHOE
872 else if (info->name == stty_dec) {
873 mode->c_cc[VINTR] = 3; /* ^C */
874 mode->c_cc[VERASE] = 127; /* DEL */
875 mode->c_cc[VKILL] = 21; /* ^U */
876 mode->c_lflag |= ECHOE
885 mode->c_iflag &= ~IXANY;
889 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
891 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
897 set_control_char(const struct control_info *info, const char *arg,
898 struct termios *mode)
902 if (info->name == stty_min || info->name == stty_time)
903 value = bb_xparse_number(arg, stty_suffixes);
904 else if (arg[0] == '\0' || arg[1] == '\0')
906 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
907 value = _POSIX_VDISABLE;
908 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
912 value = arg[1] & ~0140; /* Non-letters get weird results. */
914 value = bb_xparse_number(arg, stty_suffixes);
915 mode->c_cc[info->offset] = value;
919 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
923 baud = string_to_baud(arg);
925 if (type != output_speed) { /* either input or both */
926 cfsetispeed(mode, baud);
928 if (type != input_speed) { /* either output or both */
929 cfsetospeed(mode, baud);
935 static int get_win_size(int fd, struct winsize *win)
937 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
943 set_window_size(int rows, int cols)
947 if (get_win_size(STDIN_FILENO, &win)) {
949 perror_on_device("%s");
950 memset(&win, 0, sizeof(win));
959 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
960 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
961 This comment from sys/ttold.h describes Sun's twisted logic - a better
962 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
963 At any rate, the problem is gone in Solaris 2.x. */
965 if (win.ws_row == 0 || win.ws_col == 0) {
966 struct ttysize ttysz;
968 ttysz.ts_lines = win.ws_row;
969 ttysz.ts_cols = win.ws_col;
971 win.ws_row = win.ws_col = 1;
973 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
974 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
975 perror_on_device("%s");
981 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
982 perror_on_device("%s");
985 static void display_window_size(int fancy)
987 const char *fmt_str = "%s" "\0" "%s: no size information for this device";
990 if (get_win_size(STDIN_FILENO, &win)) {
991 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
992 perror_on_device(fmt_str);
995 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
996 win.ws_row, win.ws_col);
1003 static int screen_columns(void)
1011 /* With Solaris 2.[123], this ioctl fails and errno is set to
1012 EINVAL for telnet (but not rlogin) sessions.
1013 On ISC 3.0, it fails for the console and the serial port
1014 (but it works for ptys).
1015 It can also fail on any system when stdout isn't a tty.
1016 In case of any failure, just use the default. */
1017 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1022 if ((s = getenv("COLUMNS"))) {
1028 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1030 static const unsigned char tcflag_offsets[] = {
1031 offsetof(struct termios, c_cflag), /* control */
1032 offsetof(struct termios, c_iflag), /* input */
1033 offsetof(struct termios, c_oflag), /* output */
1034 offsetof(struct termios, c_lflag) /* local */
1037 if (((unsigned int) type) <= local) {
1038 return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
1043 static void display_changed(struct termios *mode)
1049 enum mode_type prev_type = control;
1051 display_speed(mode, 1);
1053 wrapf("line = %d;", mode->c_line);
1059 for (i = 0; control_info[i].name != stty_min; ++i) {
1060 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1062 /* If swtch is the same as susp, don't print both. */
1064 if (control_info[i].name == stty_swtch)
1067 /* If eof uses the same slot as min, only print whichever applies. */
1069 if ((mode->c_lflag & ICANON) == 0
1070 && (control_info[i].name == stty_eof
1071 || control_info[i].name == stty_eol)) continue;
1075 wrapf("%s = %s;", control_info[i].name,
1076 visible(mode->c_cc[control_info[i].offset]));
1078 if ((mode->c_lflag & ICANON) == 0) {
1079 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1080 (int) mode->c_cc[VTIME]);
1081 } else if (empty_line == 0)
1086 for (i = 0; i < NUM_mode_info; ++i) {
1087 if (mode_info[i].flags & OMIT)
1089 if (EMT(mode_info[i].type) != prev_type) {
1090 if (empty_line == 0) {
1095 prev_type = EMT(mode_info[i].type);
1098 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1099 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1100 if ((*bitsp & mask) == mode_info[i].bits) {
1101 if (mode_info[i].flags & SANE_UNSET) {
1102 wrapf("%s", mode_info[i].name);
1106 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1108 wrapf("-%s", mode_info[i].name);
1112 if (empty_line == 0)
1118 display_all(struct termios *mode)
1123 enum mode_type prev_type = control;
1125 display_speed(mode, 1);
1127 display_window_size(1);
1130 wrapf("line = %d;", mode->c_line);
1135 for (i = 0; control_info[i].name != stty_min; ++i) {
1136 /* If swtch is the same as susp, don't print both. */
1138 if (control_info[i].name == stty_swtch)
1141 /* If eof uses the same slot as min, only print whichever applies. */
1143 if ((mode->c_lflag & ICANON) == 0
1144 && (control_info[i].name == stty_eof
1145 || control_info[i].name == stty_eol)) continue;
1147 wrapf("%s = %s;", control_info[i].name,
1148 visible(mode->c_cc[control_info[i].offset]));
1151 if ((mode->c_lflag & ICANON) == 0)
1153 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1154 if (current_col != 0)
1158 for (i = 0; i < NUM_mode_info; ++i) {
1159 if (mode_info[i].flags & OMIT)
1161 if (EMT(mode_info[i].type) != prev_type) {
1164 prev_type = EMT(mode_info[i].type);
1167 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1168 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1169 if ((*bitsp & mask) == mode_info[i].bits)
1170 wrapf("%s", mode_info[i].name);
1171 else if (mode_info[i].flags & REV)
1172 wrapf("-%s", mode_info[i].name);
1178 static void display_speed(struct termios *mode, int fancy)
1180 unsigned long ispeed, ospeed;
1181 const char *fmt_str =
1182 "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
1183 "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
1185 ospeed = ispeed = cfgetispeed(mode);
1186 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1187 ispeed = ospeed; /* in case ispeed was 0 */
1193 wrapf(fmt_str, bb_baud_to_value(ispeed), bb_baud_to_value(ospeed));
1198 static void display_recoverable(struct termios *mode)
1202 printf("%lx:%lx:%lx:%lx",
1203 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1204 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1205 for (i = 0; i < NCCS; ++i)
1206 printf(":%x", (unsigned int) mode->c_cc[i]);
1210 static int recover_mode(char *arg, struct termios *mode)
1214 unsigned long iflag, oflag, cflag, lflag;
1216 /* Scan into temporaries since it is too much trouble to figure out
1217 the right format for `tcflag_t'. */
1218 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1219 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1221 mode->c_iflag = iflag;
1222 mode->c_oflag = oflag;
1223 mode->c_cflag = cflag;
1224 mode->c_lflag = lflag;
1226 for (i = 0; i < NCCS; ++i) {
1227 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1229 mode->c_cc[i] = chr;
1233 /* Fail if there are too many fields. */
1240 static speed_t string_to_baud(const char *arg)
1242 return bb_value_to_baud(bb_xparse_number(arg, 0));
1245 static void sane_mode(struct termios *mode)
1250 for (i = 0; i < NUM_control_info; ++i) {
1252 if (control_info[i].name == stty_min)
1255 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1258 for (i = 0; i < NUM_mode_info; ++i) {
1259 if (mode_info[i].flags & SANE_SET) {
1260 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1261 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1262 | mode_info[i].bits;
1263 } else if (mode_info[i].flags & SANE_UNSET) {
1264 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1265 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1266 & ~mode_info[i].bits;
1271 /* Return a string that is the printable representation of character CH. */
1272 /* Adapted from `cat' by Torbjorn Granlund. */
1274 static const char *visible(unsigned int ch)
1276 static char buf[10];
1279 if (ch == _POSIX_VDISABLE) {
1292 } else if (ch < 127) {
1300 return (const char *) buf;
1305 const char *bb_applet_name = "stty";