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 #define STREQ(a, b) (strcmp ((a), (b)) == 0)
29 #ifndef _POSIX_VDISABLE
30 # define _POSIX_VDISABLE ((unsigned char) 0)
33 #define Control(c) ((c) & 0x1f)
34 /* Canonical values for control characters. */
36 # define CINTR Control ('c')
45 # define CKILL Control ('u')
48 # define CEOF Control ('d')
51 # define CEOL _POSIX_VDISABLE
54 # define CSTART Control ('q')
57 # define CSTOP Control ('s')
60 # define CSUSP Control ('z')
62 #if defined(VEOL2) && !defined(CEOL2)
63 # define CEOL2 _POSIX_VDISABLE
65 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
66 #if defined(VSUSP) && !defined(VSWTCH)
70 #if defined(VSWTCH) && !defined(CSWTCH)
71 # define CSWTCH _POSIX_VDISABLE
74 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
75 So the default is to disable `swtch.' */
76 #if defined (__sparc__) && defined (__svr4__)
78 # define CSWTCH _POSIX_VDISABLE
81 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
82 # define VWERASE VWERSE
84 #if defined(VDSUSP) && !defined (CDSUSP)
85 # define CDSUSP Control ('y')
87 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
88 # define VREPRINT VRPRNT
90 #if defined(VREPRINT) && !defined(CRPRNT)
91 # define CRPRNT Control ('r')
93 #if defined(VWERASE) && !defined(CWERASE)
94 # define CWERASE Control ('w')
96 #if defined(VLNEXT) && !defined(CLNEXT)
97 # define CLNEXT Control ('v')
99 #if defined(VDISCARD) && !defined(VFLUSHO)
100 # define VFLUSHO VDISCARD
102 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
103 # define VFLUSHO VFLUSH
105 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
106 # define ECHOCTL CTLECH
108 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
109 # define ECHOCTL TCTLECH
111 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
112 # define ECHOKE CRTKIL
114 #if defined(VFLUSHO) && !defined(CFLUSHO)
115 # define CFLUSHO Control ('o')
117 #if defined(VSTATUS) && !defined(CSTATUS)
118 # define CSTATUS Control ('t')
121 /* Which speeds to set. */
123 input_speed, output_speed, both_speeds
126 /* Which member(s) of `struct termios' a mode uses. */
128 /* Do NOT change the order or values, as mode_type_flag()
129 * depends on them. */
130 control, input, output, local, combination
134 static const char evenp [] = "evenp";
135 static const char raw [] = "raw";
136 static const char stty_min [] = "min";
137 static const char stty_time [] = "time";
138 static const char stty_swtch[] = "swtch";
139 static const char stty_eol [] = "eol";
140 static const char stty_eof [] = "eof";
141 static const char parity [] = "parity";
142 static const char stty_oddp [] = "oddp";
143 static const char stty_nl [] = "nl";
144 static const char stty_ek [] = "ek";
145 static const char stty_sane [] = "sane";
146 static const char cbreak [] = "cbreak";
147 static const char stty_pass8[] = "pass8";
148 static const char litout [] = "litout";
149 static const char cooked [] = "cooked";
150 static const char decctlq [] = "decctlq";
151 static const char stty_tabs [] = "tabs";
152 static const char stty_lcase[] = "lcase";
153 static const char stty_LCASE[] = "LCASE";
154 static const char stty_crt [] = "crt";
155 static const char stty_dec [] = "dec";
158 /* Flags for `struct mode_info'. */
159 #define SANE_SET 1 /* Set in `sane' mode. */
160 #define SANE_UNSET 2 /* Unset in `sane' mode. */
161 #define REV 4 /* Can be turned off by prepending `-'. */
162 #define OMIT 8 /* Don't display value. */
166 const char *name; /* Name given on command line. */
167 /* enum mode_type type; */
168 char type; /* Which structure element to change. */
169 char flags; /* Setting and display options. */
170 unsigned short mask; /* Other bits to turn off for this mode. */
171 unsigned long bits; /* Bits to set for this mode. */
174 #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
176 static const struct mode_info mode_info[] = {
177 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
178 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
179 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
180 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
181 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
182 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
183 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
184 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
185 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
186 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
187 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
189 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
191 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
192 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
193 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
194 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
195 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
196 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
197 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
198 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
199 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
200 MI_ENTRY("ixon", input, REV, IXON, 0 ),
201 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
202 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
204 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
207 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
210 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
212 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
214 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
217 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
220 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
223 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
226 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
229 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
232 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
235 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
236 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
239 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
240 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
241 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
242 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
246 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
247 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
248 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
249 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
252 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
257 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
258 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
261 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
262 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
265 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
266 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
268 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
269 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
271 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
273 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
274 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
275 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
276 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
277 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
278 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
280 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
283 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
286 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
287 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
290 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
291 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
294 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
295 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
297 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
298 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
299 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
300 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
301 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
302 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
303 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
304 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
305 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
306 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
307 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
309 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
311 #if defined (TABDLY) || defined (OXTABS)
312 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
314 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
315 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
316 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
318 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
319 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
324 (sizeof(mode_info) / sizeof(struct mode_info))
327 /* Control character settings. */
328 struct control_info {
329 const char *name; /* Name given on command line. */
330 unsigned char saneval; /* Value to set for `stty sane'. */
331 unsigned char offset; /* Offset in c_cc. */
334 /* Control characters. */
336 static const struct control_info control_info[] = {
337 {"intr", CINTR, VINTR},
338 {"quit", CQUIT, VQUIT},
339 {"erase", CERASE, VERASE},
340 {"kill", CKILL, VKILL},
341 {stty_eof, CEOF, VEOF},
342 {stty_eol, CEOL, VEOL},
344 {"eol2", CEOL2, VEOL2},
347 {stty_swtch, CSWTCH, VSWTCH},
349 {"start", CSTART, VSTART},
350 {"stop", CSTOP, VSTOP},
351 {"susp", CSUSP, VSUSP},
353 {"dsusp", CDSUSP, VDSUSP},
356 {"rprnt", CRPRNT, VREPRINT},
359 {"werase", CWERASE, VWERASE},
362 {"lnext", CLNEXT, VLNEXT},
365 {"flush", CFLUSHO, VFLUSHO},
368 {"status", CSTATUS, VSTATUS},
370 /* These must be last because of the display routines. */
372 {stty_time, 0, VTIME},
377 (sizeof(control_info) / sizeof(struct control_info))
380 #define EMT(t) ((enum mode_type)(t))
382 static const char * visible(unsigned int ch);
383 static int recover_mode(char *arg, struct termios *mode);
384 static int screen_columns(void);
385 static int set_mode(const struct mode_info *info,
386 int reversed, struct termios *mode);
387 static speed_t string_to_baud(const char *arg);
388 static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
389 static void display_all(struct termios *mode);
390 static void display_changed(struct termios *mode);
391 static void display_recoverable(struct termios *mode);
392 static void display_speed(struct termios *mode, int fancy);
393 static void display_window_size(int fancy);
394 static void sane_mode(struct termios *mode);
395 static void set_control_char(const struct control_info *info,
396 const char *arg, struct termios *mode);
397 static void set_speed(enum speed_setting type,
398 const char *arg, struct termios *mode);
399 static void set_window_size(int rows, int cols);
401 static const char *device_name;
403 static ATTRIBUTE_NORETURN void perror_on_device(const char *fmt)
405 bb_perror_msg_and_die(fmt, device_name);
409 /* The width of the screen, for output wrapping. */
412 /* Current position, to know when to wrap. */
413 static int current_col;
415 /* Print format string MESSAGE and optional args.
416 Wrap to next line first if it won't fit.
417 Print a space first unless MESSAGE will start a new line. */
419 static void wrapf(const char *message, ...)
422 char buf[1024]; /* Plenty long for our needs. */
425 va_start(args, message);
426 vsprintf(buf, message, args);
428 buflen = strlen(buf);
429 if (current_col + (current_col > 0) + buflen >= max_col) {
433 if (current_col > 0) {
438 current_col += buflen;
441 static const struct suffix_mult stty_suffixes[] = {
448 int stty_main(int argc, char **argv)
451 void (*output_func)(struct termios *);
453 int require_set_attr;
456 int recoverable_output;
459 char * file_name = NULL;
461 output_func = display_changed;
463 recoverable_output = 0;
465 /* Don't print error messages for unrecognized options. */
468 while ((optc = getopt(argc, argv, "agF:")) != -1) {
472 output_func = display_all;
476 recoverable_output = 1;
477 output_func = display_recoverable;
482 bb_error_msg_and_die("only one device may be specified");
486 default: /* unrecognized option */
498 /* Specifying both -a and -g gets an error. */
499 if (verbose_output & recoverable_output)
500 bb_error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
502 /* Specifying any other arguments with -a or -g gets an error. */
503 if (~noargs & (verbose_output | recoverable_output))
504 bb_error_msg_and_die ("modes may not be set when specifying an output style");
506 /* FIXME: it'd be better not to open the file until we've verified
507 that all arguments are valid. Otherwise, we could end up doing
508 only some of the requested operations and then failing, probably
509 leaving things in an undesirable state. */
514 device_name = file_name;
516 xopen(device_name, O_RDONLY | O_NONBLOCK);
517 fdflags = fcntl(STDIN_FILENO, F_GETFL);
518 if (fdflags == -1 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
519 perror_on_device("%s: couldn't reset non-blocking mode");
521 device_name = bb_msg_standard_input;
524 /* Initialize to all zeroes so there is no risk memcmp will report a
525 spurious difference in an uninitialized portion of the structure. */
526 memset(&mode, 0, sizeof(mode));
527 if (tcgetattr(STDIN_FILENO, &mode))
528 perror_on_device("%s");
530 if (verbose_output | recoverable_output | noargs) {
531 max_col = screen_columns();
538 require_set_attr = 0;
545 if (argv[k][0] == '-') {
550 /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
551 Find the options that have been parsed. This is really
552 gross, but it's needed because stty SETTINGS look like options to
553 getopt(), so we need to work around things in a really horrible
554 way. If any new options are ever added to stty, the short option
555 MUST NOT be a letter which is the first letter of one of the
556 possible stty settings.
558 find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
560 if(find_dev_opt[1]==0) /* -*F /dev/foo */
561 k++; /* skip /dev/foo */
562 continue; /* else -*F/dev/foo - no skip */
564 if(argv[k][0]=='a' || argv[k][0]=='g')
566 /* Is not options - is reverse params */
569 for (i = 0; i < NUM_mode_info; ++i)
570 if (STREQ(argv[k], mode_info[i].name)) {
571 match_found = set_mode(&mode_info[i], reversed, &mode);
572 require_set_attr = 1;
576 if (match_found == 0 && reversed)
577 bb_error_msg_and_die("invalid argument `%s'", --argv[k]);
579 if (match_found == 0)
580 for (i = 0; i < NUM_control_info; ++i)
581 if (STREQ(argv[k], control_info[i].name)) {
583 bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
586 set_control_char(&control_info[i], argv[k], &mode);
587 require_set_attr = 1;
591 if (match_found == 0) {
592 if (STREQ(argv[k], "ispeed")) {
594 bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
596 set_speed(input_speed, argv[k], &mode);
598 require_set_attr = 1;
599 } else if (STREQ(argv[k], "ospeed")) {
601 bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
603 set_speed(output_speed, argv[k], &mode);
605 require_set_attr = 1;
608 else if (STREQ(argv[k], "rows")) {
610 bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
612 set_window_size((int) bb_xparse_number(argv[k], stty_suffixes),
614 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
616 bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
619 (int) bb_xparse_number(argv[k], stty_suffixes));
620 } else if (STREQ(argv[k], "size")) {
621 max_col = screen_columns();
623 display_window_size(0);
627 else if (STREQ(argv[k], "line")) {
629 bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
631 mode.c_line = bb_xparse_number(argv[k], stty_suffixes);
632 require_set_attr = 1;
635 else if (STREQ(argv[k], "speed")) {
636 max_col = screen_columns();
637 display_speed(&mode, 0);
638 } else if (recover_mode(argv[k], &mode) == 1)
639 require_set_attr = 1;
640 else if (string_to_baud(argv[k]) != (speed_t) - 1) {
641 set_speed(both_speeds, argv[k], &mode);
643 require_set_attr = 1;
645 bb_error_msg_and_die("invalid argument `%s'", argv[k]);
649 if (require_set_attr) {
650 struct termios new_mode;
652 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
653 perror_on_device("%s");
655 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
656 it performs *any* of the requested operations. This means it
657 can report `success' when it has actually failed to perform
658 some proper subset of the requested operations. To detect
659 this partial failure, get the current terminal attributes and
660 compare them to the requested ones. */
662 /* Initialize to all zeroes so there is no risk memcmp will report a
663 spurious difference in an uninitialized portion of the structure. */
664 memset(&new_mode, 0, sizeof(new_mode));
665 if (tcgetattr(STDIN_FILENO, &new_mode))
666 perror_on_device("%s");
668 /* Normally, one shouldn't use memcmp to compare structures that
669 may have `holes' containing uninitialized data, but we have been
670 careful to initialize the storage of these two variables to all
671 zeroes. One might think it more efficient simply to compare the
672 modified fields, but that would require enumerating those fields --
673 and not all systems have the same fields in this structure. */
675 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
677 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
678 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
679 sometimes (m1 != m2). The only difference is in the four bits
680 of the c_cflag field corresponding to the baud rate. To save
681 Sun users a little confusion, don't report an error if this
682 happens. But suppress the error only if we haven't tried to
683 set the baud rate explicitly -- otherwise we'd never give an
684 error for a true failure to set the baud rate. */
686 new_mode.c_cflag &= (~CIBAUD);
687 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
689 perror_on_device ("%s: unable to perform all requested operations");
696 /* Return 0 if not applied because not reversible; otherwise return 1. */
699 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
703 if (reversed && (info->flags & REV) == 0)
706 bitsp = mode_type_flag(EMT(info->type), mode);
709 /* Combination mode. */
710 if (info->name == evenp || info->name == parity) {
712 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
715 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
716 } else if (info->name == stty_oddp) {
718 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
721 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
722 } else if (info->name == stty_nl) {
724 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
725 mode->c_oflag = (mode->c_oflag
738 mode->c_iflag = mode->c_iflag & ~ICRNL;
740 mode->c_oflag = mode->c_oflag & ~ONLCR;
743 } else if (info->name == stty_ek) {
744 mode->c_cc[VERASE] = CERASE;
745 mode->c_cc[VKILL] = CKILL;
746 } else if (info->name == stty_sane)
748 else if (info->name == cbreak) {
750 mode->c_lflag |= ICANON;
752 mode->c_lflag &= ~ICANON;
753 } else if (info->name == stty_pass8) {
755 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
756 mode->c_iflag |= ISTRIP;
758 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
759 mode->c_iflag &= ~ISTRIP;
761 } else if (info->name == litout) {
763 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
764 mode->c_iflag |= ISTRIP;
765 mode->c_oflag |= OPOST;
767 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
768 mode->c_iflag &= ~ISTRIP;
769 mode->c_oflag &= ~OPOST;
771 } else if (info->name == raw || info->name == cooked) {
772 if ((info->name[0] == 'r' && reversed)
773 || (info->name[0] == 'c' && !reversed)) {
775 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
776 mode->c_oflag |= OPOST;
777 mode->c_lflag |= ISIG | ICANON;
779 mode->c_cc[VEOF] = CEOF;
782 mode->c_cc[VEOL] = CEOL;
787 mode->c_oflag &= ~OPOST;
788 mode->c_lflag &= ~(ISIG | ICANON
793 mode->c_cc[VMIN] = 1;
794 mode->c_cc[VTIME] = 0;
798 else if (info->name == decctlq) {
800 mode->c_iflag |= IXANY;
802 mode->c_iflag &= ~IXANY;
806 else if (info->name == stty_tabs) {
808 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
810 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
814 else if (info->name == stty_tabs) {
816 mode->c_oflag = mode->c_oflag | OXTABS;
818 mode->c_oflag = mode->c_oflag & ~OXTABS;
822 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
823 else if (info->name == stty_lcase || info->name == stty_LCASE) {
825 mode->c_lflag &= ~XCASE;
826 mode->c_iflag &= ~IUCLC;
827 mode->c_oflag &= ~OLCUC;
829 mode->c_lflag |= XCASE;
830 mode->c_iflag |= IUCLC;
831 mode->c_oflag |= OLCUC;
835 else if (info->name == stty_crt)
836 mode->c_lflag |= ECHOE
844 else if (info->name == stty_dec) {
845 mode->c_cc[VINTR] = 3; /* ^C */
846 mode->c_cc[VERASE] = 127; /* DEL */
847 mode->c_cc[VKILL] = 21; /* ^U */
848 mode->c_lflag |= ECHOE
857 mode->c_iflag &= ~IXANY;
861 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
863 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
869 set_control_char(const struct control_info *info, const char *arg,
870 struct termios *mode)
874 if (info->name == stty_min || info->name == stty_time)
875 value = bb_xparse_number(arg, stty_suffixes);
876 else if (arg[0] == '\0' || arg[1] == '\0')
878 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
879 value = _POSIX_VDISABLE;
880 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
884 value = arg[1] & ~0140; /* Non-letters get weird results. */
886 value = bb_xparse_number(arg, stty_suffixes);
887 mode->c_cc[info->offset] = value;
891 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
895 baud = string_to_baud(arg);
897 if (type != output_speed) { /* either input or both */
898 cfsetispeed(mode, baud);
900 if (type != input_speed) { /* either output or both */
901 cfsetospeed(mode, baud);
907 static int get_win_size(int fd, struct winsize *win)
909 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
915 set_window_size(int rows, int cols)
919 if (get_win_size(STDIN_FILENO, &win)) {
921 perror_on_device("%s");
922 memset(&win, 0, sizeof(win));
931 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
932 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
933 This comment from sys/ttold.h describes Sun's twisted logic - a better
934 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
935 At any rate, the problem is gone in Solaris 2.x. */
937 if (win.ws_row == 0 || win.ws_col == 0) {
938 struct ttysize ttysz;
940 ttysz.ts_lines = win.ws_row;
941 ttysz.ts_cols = win.ws_col;
943 win.ws_row = win.ws_col = 1;
945 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
946 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
947 perror_on_device("%s");
953 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
954 perror_on_device("%s");
957 static void display_window_size(int fancy)
959 const char *fmt_str = "%s" "\0" "%s: no size information for this device";
962 if (get_win_size(STDIN_FILENO, &win)) {
963 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
964 perror_on_device(fmt_str);
967 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
968 win.ws_row, win.ws_col);
975 static int screen_columns(void)
983 /* With Solaris 2.[123], this ioctl fails and errno is set to
984 EINVAL for telnet (but not rlogin) sessions.
985 On ISC 3.0, it fails for the console and the serial port
986 (but it works for ptys).
987 It can also fail on any system when stdout isn't a tty.
988 In case of any failure, just use the default. */
989 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
994 if ((s = getenv("COLUMNS"))) {
1000 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1002 static const unsigned char tcflag_offsets[] = {
1003 offsetof(struct termios, c_cflag), /* control */
1004 offsetof(struct termios, c_iflag), /* input */
1005 offsetof(struct termios, c_oflag), /* output */
1006 offsetof(struct termios, c_lflag) /* local */
1009 if (((unsigned int) type) <= local) {
1010 return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
1015 static void display_changed(struct termios *mode)
1021 enum mode_type prev_type = control;
1023 display_speed(mode, 1);
1025 wrapf("line = %d;", mode->c_line);
1031 for (i = 0; control_info[i].name != stty_min; ++i) {
1032 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1034 /* If swtch is the same as susp, don't print both. */
1036 if (control_info[i].name == stty_swtch)
1039 /* If eof uses the same slot as min, only print whichever applies. */
1041 if ((mode->c_lflag & ICANON) == 0
1042 && (control_info[i].name == stty_eof
1043 || control_info[i].name == stty_eol)) continue;
1047 wrapf("%s = %s;", control_info[i].name,
1048 visible(mode->c_cc[control_info[i].offset]));
1050 if ((mode->c_lflag & ICANON) == 0) {
1051 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1052 (int) mode->c_cc[VTIME]);
1053 } else if (empty_line == 0)
1058 for (i = 0; i < NUM_mode_info; ++i) {
1059 if (mode_info[i].flags & OMIT)
1061 if (EMT(mode_info[i].type) != prev_type) {
1062 if (empty_line == 0) {
1067 prev_type = EMT(mode_info[i].type);
1070 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1071 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1072 if ((*bitsp & mask) == mode_info[i].bits) {
1073 if (mode_info[i].flags & SANE_UNSET) {
1074 wrapf("%s", mode_info[i].name);
1078 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1080 wrapf("-%s", mode_info[i].name);
1084 if (empty_line == 0)
1090 display_all(struct termios *mode)
1095 enum mode_type prev_type = control;
1097 display_speed(mode, 1);
1099 display_window_size(1);
1102 wrapf("line = %d;", mode->c_line);
1107 for (i = 0; control_info[i].name != stty_min; ++i) {
1108 /* If swtch is the same as susp, don't print both. */
1110 if (control_info[i].name == stty_swtch)
1113 /* If eof uses the same slot as min, only print whichever applies. */
1115 if ((mode->c_lflag & ICANON) == 0
1116 && (control_info[i].name == stty_eof
1117 || control_info[i].name == stty_eol)) continue;
1119 wrapf("%s = %s;", control_info[i].name,
1120 visible(mode->c_cc[control_info[i].offset]));
1123 if ((mode->c_lflag & ICANON) == 0)
1125 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1126 if (current_col != 0)
1130 for (i = 0; i < NUM_mode_info; ++i) {
1131 if (mode_info[i].flags & OMIT)
1133 if (EMT(mode_info[i].type) != prev_type) {
1136 prev_type = EMT(mode_info[i].type);
1139 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1140 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1141 if ((*bitsp & mask) == mode_info[i].bits)
1142 wrapf("%s", mode_info[i].name);
1143 else if (mode_info[i].flags & REV)
1144 wrapf("-%s", mode_info[i].name);
1150 static void display_speed(struct termios *mode, int fancy)
1152 unsigned long ispeed, ospeed;
1153 const char *fmt_str =
1154 "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
1155 "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
1157 ospeed = ispeed = cfgetispeed(mode);
1158 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1159 ispeed = ospeed; /* in case ispeed was 0 */
1165 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1170 static void display_recoverable(struct termios *mode)
1174 printf("%lx:%lx:%lx:%lx",
1175 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1176 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1177 for (i = 0; i < NCCS; ++i)
1178 printf(":%x", (unsigned int) mode->c_cc[i]);
1182 static int recover_mode(char *arg, struct termios *mode)
1186 unsigned long iflag, oflag, cflag, lflag;
1188 /* Scan into temporaries since it is too much trouble to figure out
1189 the right format for `tcflag_t'. */
1190 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1191 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1193 mode->c_iflag = iflag;
1194 mode->c_oflag = oflag;
1195 mode->c_cflag = cflag;
1196 mode->c_lflag = lflag;
1198 for (i = 0; i < NCCS; ++i) {
1199 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1201 mode->c_cc[i] = chr;
1205 /* Fail if there are too many fields. */
1212 static speed_t string_to_baud(const char *arg)
1214 return tty_value_to_baud(bb_xparse_number(arg, 0));
1217 static void sane_mode(struct termios *mode)
1222 for (i = 0; i < NUM_control_info; ++i) {
1224 if (control_info[i].name == stty_min)
1227 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1230 for (i = 0; i < NUM_mode_info; ++i) {
1231 if (mode_info[i].flags & SANE_SET) {
1232 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1233 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1234 | mode_info[i].bits;
1235 } else if (mode_info[i].flags & SANE_UNSET) {
1236 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1237 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1238 & ~mode_info[i].bits;
1243 /* Return a string that is the printable representation of character CH. */
1244 /* Adapted from `cat' by Torbjorn Granlund. */
1246 static const char *visible(unsigned int ch)
1248 static char buf[10];
1251 if (ch == _POSIX_VDISABLE) {
1264 } else if (ch < 127) {
1272 return (const char *) buf;