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
51 #define STREQ(a, b) (strcmp ((a), (b)) == 0)
54 #ifndef _POSIX_VDISABLE
55 # define _POSIX_VDISABLE ((unsigned char) 0)
58 #define Control(c) ((c) & 0x1f)
59 /* Canonical values for control characters. */
61 # define CINTR Control ('c')
70 # define CKILL Control ('u')
73 # define CEOF Control ('d')
76 # define CEOL _POSIX_VDISABLE
79 # define CSTART Control ('q')
82 # define CSTOP Control ('s')
85 # define CSUSP Control ('z')
87 #if defined(VEOL2) && !defined(CEOL2)
88 # define CEOL2 _POSIX_VDISABLE
90 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
91 #if defined(VSUSP) && !defined(VSWTCH)
95 #if defined(VSWTCH) && !defined(CSWTCH)
96 # define CSWTCH _POSIX_VDISABLE
99 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
100 So the default is to disable `swtch.' */
101 #if defined (__sparc__) && defined (__svr4__)
103 # define CSWTCH _POSIX_VDISABLE
106 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
107 # define VWERASE VWERSE
109 #if defined(VDSUSP) && !defined (CDSUSP)
110 # define CDSUSP Control ('y')
112 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
113 # define VREPRINT VRPRNT
115 #if defined(VREPRINT) && !defined(CRPRNT)
116 # define CRPRNT Control ('r')
118 #if defined(VWERASE) && !defined(CWERASE)
119 # define CWERASE Control ('w')
121 #if defined(VLNEXT) && !defined(CLNEXT)
122 # define CLNEXT Control ('v')
124 #if defined(VDISCARD) && !defined(VFLUSHO)
125 # define VFLUSHO VDISCARD
127 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
128 # define VFLUSHO VFLUSH
130 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
131 # define ECHOCTL CTLECH
133 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
134 # define ECHOCTL TCTLECH
136 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
137 # define ECHOKE CRTKIL
139 #if defined(VFLUSHO) && !defined(CFLUSHO)
140 # define CFLUSHO Control ('o')
142 #if defined(VSTATUS) && !defined(CSTATUS)
143 # define CSTATUS Control ('t')
146 /* Which speeds to set. */
148 input_speed, output_speed, both_speeds
151 /* Which member(s) of `struct termios' a mode uses. */
153 /* Do NOT change the order or values, as mode_type_flag()
154 * depends on them. */
155 control, input, output, local, combination
159 static const char evenp [] = "evenp";
160 static const char raw [] = "raw";
161 static const char stty_min [] = "min";
162 static const char stty_time [] = "time";
163 static const char stty_swtch[] = "swtch";
164 static const char stty_eol [] = "eol";
165 static const char stty_eof [] = "eof";
166 static const char parity [] = "parity";
167 static const char stty_oddp [] = "oddp";
168 static const char stty_nl [] = "nl";
169 static const char stty_ek [] = "ek";
170 static const char stty_sane [] = "sane";
171 static const char cbreak [] = "cbreak";
172 static const char stty_pass8[] = "pass8";
173 static const char litout [] = "litout";
174 static const char cooked [] = "cooked";
175 static const char decctlq [] = "decctlq";
176 static const char stty_tabs [] = "tabs";
177 static const char stty_lcase[] = "lcase";
178 static const char stty_LCASE[] = "LCASE";
179 static const char stty_crt [] = "crt";
180 static const char stty_dec [] = "dec";
183 /* Flags for `struct mode_info'. */
184 #define SANE_SET 1 /* Set in `sane' mode. */
185 #define SANE_UNSET 2 /* Unset in `sane' mode. */
186 #define REV 4 /* Can be turned off by prepending `-'. */
187 #define OMIT 8 /* Don't display value. */
191 const char *name; /* Name given on command line. */
192 /* enum mode_type type; */
193 char type; /* Which structure element to change. */
194 char flags; /* Setting and display options. */
195 unsigned short mask; /* Other bits to turn off for this mode. */
196 unsigned long bits; /* Bits to set for this mode. */
199 #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
201 static const struct mode_info mode_info[] = {
202 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
203 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
204 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
205 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
206 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
207 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
208 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
209 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
210 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
211 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
212 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
214 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
216 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
217 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
218 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
219 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
220 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
221 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
222 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
223 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
224 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
225 MI_ENTRY("ixon", input, REV, IXON, 0 ),
226 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
227 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
229 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
232 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
235 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
237 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
239 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
242 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
245 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
248 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
251 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
254 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
257 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
260 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
261 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
264 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
265 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
266 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
267 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
271 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
272 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
273 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
274 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
277 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
282 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
283 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
286 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
287 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
290 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
291 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
293 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
294 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
296 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
298 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
299 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
300 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
301 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
302 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
303 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
305 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
308 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
311 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
312 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
315 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
316 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
319 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
320 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
322 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
323 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
324 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
325 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
326 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
327 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
328 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
329 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
330 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
331 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
332 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
334 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
336 #if defined (TABDLY) || defined (OXTABS)
337 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
339 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
340 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
341 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
343 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
344 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
347 static const int NUM_mode_info =
349 (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},
399 static const int NUM_control_info =
400 (sizeof(control_info) / sizeof(struct control_info));
402 #define EMT(t) ((enum mode_type)(t))
404 static const char * visible(unsigned int ch);
405 static int recover_mode(char *arg, struct termios *mode);
406 static int screen_columns(void);
407 static int set_mode(const struct mode_info *info,
408 int reversed, struct termios *mode);
409 static speed_t string_to_baud(const char *arg);
410 static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
411 static void display_all(struct termios *mode);
412 static void display_changed(struct termios *mode);
413 static void display_recoverable(struct termios *mode);
414 static void display_speed(struct termios *mode, int fancy);
415 static void display_window_size(int fancy);
416 static void sane_mode(struct termios *mode);
417 static void set_control_char(const struct control_info *info,
418 const char *arg, struct termios *mode);
419 static void set_speed(enum speed_setting type,
420 const char *arg, struct termios *mode);
421 static void set_window_size(int rows, int cols);
423 static const char *device_name;
425 static ATTRIBUTE_NORETURN void perror_on_device(const char *fmt)
427 bb_perror_msg_and_die(fmt, device_name);
431 /* The width of the screen, for output wrapping. */
434 /* Current position, to know when to wrap. */
435 static int current_col;
437 /* Print format string MESSAGE and optional args.
438 Wrap to next line first if it won't fit.
439 Print a space first unless MESSAGE will start a new line. */
441 static void wrapf(const char *message, ...)
444 char buf[1024]; /* Plenty long for our needs. */
447 va_start(args, message);
448 vsprintf(buf, message, args);
450 buflen = strlen(buf);
451 if (current_col + (current_col > 0) + buflen >= max_col) {
455 if (current_col > 0) {
460 current_col += buflen;
463 static const struct suffix_mult stty_suffixes[] = {
471 extern int stty_main(int argc, char **argv)
473 extern int main(int argc, char **argv)
477 void (*output_func)(struct termios *);
479 int require_set_attr;
482 int recoverable_output;
485 char * file_name = NULL;
487 output_func = display_changed;
489 recoverable_output = 0;
491 /* Don't print error messages for unrecognized options. */
494 while ((optc = getopt(argc, argv, "agF:")) != -1) {
498 output_func = display_all;
502 recoverable_output = 1;
503 output_func = display_recoverable;
508 bb_error_msg_and_die("only one device may be specified");
512 default: /* unrecognized option */
524 /* Specifying both -a and -g gets an error. */
525 if (verbose_output & recoverable_output)
526 bb_error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
528 /* Specifying any other arguments with -a or -g gets an error. */
529 if (~noargs & (verbose_output | recoverable_output))
530 bb_error_msg_and_die ("modes may not be set when specifying an output style");
532 /* FIXME: it'd be better not to open the file until we've verified
533 that all arguments are valid. Otherwise, we could end up doing
534 only some of the requested operations and then failing, probably
535 leaving things in an undesirable state. */
540 device_name = file_name;
542 bb_xopen(device_name, O_RDONLY | O_NONBLOCK);
543 if ((fdflags = fcntl(STDIN_FILENO, F_GETFL)) == -1
544 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
545 perror_on_device("%s: couldn't reset non-blocking mode");
547 device_name = bb_msg_standard_input;
550 /* Initialize to all zeroes so there is no risk memcmp will report a
551 spurious difference in an uninitialized portion of the structure. */
552 memset(&mode, 0, sizeof(mode));
553 if (tcgetattr(STDIN_FILENO, &mode))
554 perror_on_device("%s");
556 if (verbose_output | recoverable_output | noargs) {
557 max_col = screen_columns();
564 require_set_attr = 0;
571 if (argv[k][0] == '-') {
576 /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
577 Find the options that have been parsed. This is really
578 gross, but it's needed because stty SETTINGS look like options to
579 getopt(), so we need to work around things in a really horrible
580 way. If any new options are ever added to stty, the short option
581 MUST NOT be a letter which is the first letter of one of the
582 possible stty settings.
584 find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
586 if(find_dev_opt[1]==0) /* -*F /dev/foo */
587 k++; /* skip /dev/foo */
588 continue; /* else -*F/dev/foo - no skip */
590 if(argv[k][0]=='a' || argv[k][0]=='g')
592 /* Is not options - is reverse params */
595 for (i = 0; i < NUM_mode_info; ++i)
596 if (STREQ(argv[k], mode_info[i].name)) {
597 match_found = set_mode(&mode_info[i], reversed, &mode);
598 require_set_attr = 1;
602 if (match_found == 0 && reversed)
603 bb_error_msg_and_die("invalid argument `%s'", --argv[k]);
605 if (match_found == 0)
606 for (i = 0; i < NUM_control_info; ++i)
607 if (STREQ(argv[k], control_info[i].name)) {
609 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
612 set_control_char(&control_info[i], argv[k], &mode);
613 require_set_attr = 1;
617 if (match_found == 0) {
618 if (STREQ(argv[k], "ispeed")) {
620 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
622 set_speed(input_speed, argv[k], &mode);
624 require_set_attr = 1;
625 } else if (STREQ(argv[k], "ospeed")) {
627 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
629 set_speed(output_speed, argv[k], &mode);
631 require_set_attr = 1;
634 else if (STREQ(argv[k], "rows")) {
636 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
638 set_window_size((int) bb_xparse_number(argv[k], stty_suffixes),
640 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
642 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
645 (int) bb_xparse_number(argv[k], stty_suffixes));
646 } else if (STREQ(argv[k], "size")) {
647 max_col = screen_columns();
649 display_window_size(0);
653 else if (STREQ(argv[k], "line")) {
655 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
657 mode.c_line = bb_xparse_number(argv[k], stty_suffixes);
658 require_set_attr = 1;
661 else if (STREQ(argv[k], "speed")) {
662 max_col = screen_columns();
663 display_speed(&mode, 0);
664 } else if (recover_mode(argv[k], &mode) == 1)
665 require_set_attr = 1;
666 else if (string_to_baud(argv[k]) != (speed_t) - 1) {
667 set_speed(both_speeds, argv[k], &mode);
669 require_set_attr = 1;
671 bb_error_msg_and_die("invalid argument `%s'", argv[k]);
675 if (require_set_attr) {
676 struct termios new_mode;
678 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
679 perror_on_device("%s");
681 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
682 it performs *any* of the requested operations. This means it
683 can report `success' when it has actually failed to perform
684 some proper subset of the requested operations. To detect
685 this partial failure, get the current terminal attributes and
686 compare them to the requested ones. */
688 /* Initialize to all zeroes so there is no risk memcmp will report a
689 spurious difference in an uninitialized portion of the structure. */
690 memset(&new_mode, 0, sizeof(new_mode));
691 if (tcgetattr(STDIN_FILENO, &new_mode))
692 perror_on_device("%s");
694 /* Normally, one shouldn't use memcmp to compare structures that
695 may have `holes' containing uninitialized data, but we have been
696 careful to initialize the storage of these two variables to all
697 zeroes. One might think it more efficient simply to compare the
698 modified fields, but that would require enumerating those fields --
699 and not all systems have the same fields in this structure. */
701 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
703 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
704 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
705 sometimes (m1 != m2). The only difference is in the four bits
706 of the c_cflag field corresponding to the baud rate. To save
707 Sun users a little confusion, don't report an error if this
708 happens. But suppress the error only if we haven't tried to
709 set the baud rate explicitly -- otherwise we'd never give an
710 error for a true failure to set the baud rate. */
712 new_mode.c_cflag &= (~CIBAUD);
713 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
715 perror_on_device ("%s: unable to perform all requested operations");
722 /* Return 0 if not applied because not reversible; otherwise return 1. */
725 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
729 if (reversed && (info->flags & REV) == 0)
732 bitsp = mode_type_flag(EMT(info->type), mode);
735 /* Combination mode. */
736 if (info->name == evenp || info->name == parity) {
738 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
741 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
742 } else if (info->name == stty_oddp) {
744 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
747 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
748 } else if (info->name == stty_nl) {
750 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
751 mode->c_oflag = (mode->c_oflag
764 mode->c_iflag = mode->c_iflag & ~ICRNL;
766 mode->c_oflag = mode->c_oflag & ~ONLCR;
769 } else if (info->name == stty_ek) {
770 mode->c_cc[VERASE] = CERASE;
771 mode->c_cc[VKILL] = CKILL;
772 } else if (info->name == stty_sane)
774 else if (info->name == cbreak) {
776 mode->c_lflag |= ICANON;
778 mode->c_lflag &= ~ICANON;
779 } else if (info->name == stty_pass8) {
781 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
782 mode->c_iflag |= ISTRIP;
784 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
785 mode->c_iflag &= ~ISTRIP;
787 } else if (info->name == litout) {
789 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
790 mode->c_iflag |= ISTRIP;
791 mode->c_oflag |= OPOST;
793 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
794 mode->c_iflag &= ~ISTRIP;
795 mode->c_oflag &= ~OPOST;
797 } else if (info->name == raw || info->name == cooked) {
798 if ((info->name[0] == 'r' && reversed)
799 || (info->name[0] == 'c' && !reversed)) {
801 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
802 mode->c_oflag |= OPOST;
803 mode->c_lflag |= ISIG | ICANON;
805 mode->c_cc[VEOF] = CEOF;
808 mode->c_cc[VEOL] = CEOL;
813 mode->c_oflag &= ~OPOST;
814 mode->c_lflag &= ~(ISIG | ICANON
819 mode->c_cc[VMIN] = 1;
820 mode->c_cc[VTIME] = 0;
824 else if (info->name == decctlq) {
826 mode->c_iflag |= IXANY;
828 mode->c_iflag &= ~IXANY;
832 else if (info->name == stty_tabs) {
834 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
836 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
840 else if (info->name == stty_tabs) {
842 mode->c_oflag = mode->c_oflag | OXTABS;
844 mode->c_oflag = mode->c_oflag & ~OXTABS;
848 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
849 else if (info->name == stty_lcase || info->name == stty_LCASE) {
851 mode->c_lflag &= ~XCASE;
852 mode->c_iflag &= ~IUCLC;
853 mode->c_oflag &= ~OLCUC;
855 mode->c_lflag |= XCASE;
856 mode->c_iflag |= IUCLC;
857 mode->c_oflag |= OLCUC;
861 else if (info->name == stty_crt)
862 mode->c_lflag |= ECHOE
870 else if (info->name == stty_dec) {
871 mode->c_cc[VINTR] = 3; /* ^C */
872 mode->c_cc[VERASE] = 127; /* DEL */
873 mode->c_cc[VKILL] = 21; /* ^U */
874 mode->c_lflag |= ECHOE
883 mode->c_iflag &= ~IXANY;
887 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
889 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
895 set_control_char(const struct control_info *info, const char *arg,
896 struct termios *mode)
900 if (info->name == stty_min || info->name == stty_time)
901 value = bb_xparse_number(arg, stty_suffixes);
902 else if (arg[0] == '\0' || arg[1] == '\0')
904 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
905 value = _POSIX_VDISABLE;
906 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
910 value = arg[1] & ~0140; /* Non-letters get weird results. */
912 value = bb_xparse_number(arg, stty_suffixes);
913 mode->c_cc[info->offset] = value;
917 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
921 baud = string_to_baud(arg);
923 if (type != output_speed) { /* either input or both */
924 cfsetispeed(mode, baud);
926 if (type != input_speed) { /* either output or both */
927 cfsetospeed(mode, baud);
933 static int get_win_size(int fd, struct winsize *win)
935 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
941 set_window_size(int rows, int cols)
945 if (get_win_size(STDIN_FILENO, &win)) {
947 perror_on_device("%s");
948 memset(&win, 0, sizeof(win));
957 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
958 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
959 This comment from sys/ttold.h describes Sun's twisted logic - a better
960 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
961 At any rate, the problem is gone in Solaris 2.x. */
963 if (win.ws_row == 0 || win.ws_col == 0) {
964 struct ttysize ttysz;
966 ttysz.ts_lines = win.ws_row;
967 ttysz.ts_cols = win.ws_col;
969 win.ws_row = win.ws_col = 1;
971 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
972 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
973 perror_on_device("%s");
979 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
980 perror_on_device("%s");
983 static void display_window_size(int fancy)
985 const char *fmt_str = "%s" "\0" "%s: no size information for this device";
988 if (get_win_size(STDIN_FILENO, &win)) {
989 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
990 perror_on_device(fmt_str);
993 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
994 win.ws_row, win.ws_col);
1001 static int screen_columns(void)
1009 /* With Solaris 2.[123], this ioctl fails and errno is set to
1010 EINVAL for telnet (but not rlogin) sessions.
1011 On ISC 3.0, it fails for the console and the serial port
1012 (but it works for ptys).
1013 It can also fail on any system when stdout isn't a tty.
1014 In case of any failure, just use the default. */
1015 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1020 if ((s = getenv("COLUMNS"))) {
1026 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1028 static const unsigned char tcflag_offsets[] = {
1029 offsetof(struct termios, c_cflag), /* control */
1030 offsetof(struct termios, c_iflag), /* input */
1031 offsetof(struct termios, c_oflag), /* output */
1032 offsetof(struct termios, c_lflag) /* local */
1035 if (((unsigned int) type) <= local) {
1036 return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
1041 static void display_changed(struct termios *mode)
1047 enum mode_type prev_type = control;
1049 display_speed(mode, 1);
1051 wrapf("line = %d;", mode->c_line);
1057 for (i = 0; control_info[i].name != stty_min; ++i) {
1058 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1060 /* If swtch is the same as susp, don't print both. */
1062 if (control_info[i].name == stty_swtch)
1065 /* If eof uses the same slot as min, only print whichever applies. */
1067 if ((mode->c_lflag & ICANON) == 0
1068 && (control_info[i].name == stty_eof
1069 || control_info[i].name == stty_eol)) continue;
1073 wrapf("%s = %s;", control_info[i].name,
1074 visible(mode->c_cc[control_info[i].offset]));
1076 if ((mode->c_lflag & ICANON) == 0) {
1077 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1078 (int) mode->c_cc[VTIME]);
1079 } else if (empty_line == 0)
1084 for (i = 0; i < NUM_mode_info; ++i) {
1085 if (mode_info[i].flags & OMIT)
1087 if (EMT(mode_info[i].type) != prev_type) {
1088 if (empty_line == 0) {
1093 prev_type = EMT(mode_info[i].type);
1096 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1097 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1098 if ((*bitsp & mask) == mode_info[i].bits) {
1099 if (mode_info[i].flags & SANE_UNSET) {
1100 wrapf("%s", mode_info[i].name);
1104 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1106 wrapf("-%s", mode_info[i].name);
1110 if (empty_line == 0)
1116 display_all(struct termios *mode)
1121 enum mode_type prev_type = control;
1123 display_speed(mode, 1);
1125 display_window_size(1);
1128 wrapf("line = %d;", mode->c_line);
1133 for (i = 0; control_info[i].name != stty_min; ++i) {
1134 /* If swtch is the same as susp, don't print both. */
1136 if (control_info[i].name == stty_swtch)
1139 /* If eof uses the same slot as min, only print whichever applies. */
1141 if ((mode->c_lflag & ICANON) == 0
1142 && (control_info[i].name == stty_eof
1143 || control_info[i].name == stty_eol)) continue;
1145 wrapf("%s = %s;", control_info[i].name,
1146 visible(mode->c_cc[control_info[i].offset]));
1149 if ((mode->c_lflag & ICANON) == 0)
1151 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1152 if (current_col != 0)
1156 for (i = 0; i < NUM_mode_info; ++i) {
1157 if (mode_info[i].flags & OMIT)
1159 if (EMT(mode_info[i].type) != prev_type) {
1162 prev_type = EMT(mode_info[i].type);
1165 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1166 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1167 if ((*bitsp & mask) == mode_info[i].bits)
1168 wrapf("%s", mode_info[i].name);
1169 else if (mode_info[i].flags & REV)
1170 wrapf("-%s", mode_info[i].name);
1176 static void display_speed(struct termios *mode, int fancy)
1178 unsigned long ispeed, ospeed;
1179 const char *fmt_str =
1180 "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
1181 "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
1183 ospeed = ispeed = cfgetispeed(mode);
1184 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1185 ispeed = ospeed; /* in case ispeed was 0 */
1191 wrapf(fmt_str, bb_baud_to_value(ispeed), bb_baud_to_value(ospeed));
1196 static void display_recoverable(struct termios *mode)
1200 printf("%lx:%lx:%lx:%lx",
1201 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1202 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1203 for (i = 0; i < NCCS; ++i)
1204 printf(":%x", (unsigned int) mode->c_cc[i]);
1208 static int recover_mode(char *arg, struct termios *mode)
1212 unsigned long iflag, oflag, cflag, lflag;
1214 /* Scan into temporaries since it is too much trouble to figure out
1215 the right format for `tcflag_t'. */
1216 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1217 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1219 mode->c_iflag = iflag;
1220 mode->c_oflag = oflag;
1221 mode->c_cflag = cflag;
1222 mode->c_lflag = lflag;
1224 for (i = 0; i < NCCS; ++i) {
1225 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1227 mode->c_cc[i] = chr;
1231 /* Fail if there are too many fields. */
1238 static speed_t string_to_baud(const char *arg)
1240 return bb_value_to_baud(bb_xparse_number(arg, 0));
1243 static void sane_mode(struct termios *mode)
1248 for (i = 0; i < NUM_control_info; ++i) {
1250 if (control_info[i].name == stty_min)
1253 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1256 for (i = 0; i < NUM_mode_info; ++i) {
1257 if (mode_info[i].flags & SANE_SET) {
1258 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1259 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1260 | mode_info[i].bits;
1261 } else if (mode_info[i].flags & SANE_UNSET) {
1262 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1263 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1264 & ~mode_info[i].bits;
1269 /* Return a string that is the printable representation of character CH. */
1270 /* Adapted from `cat' by Torbjorn Granlund. */
1272 static const char *visible(unsigned int ch)
1274 static char buf[10];
1277 if (ch == _POSIX_VDISABLE) {
1290 } else if (ch < 127) {
1298 return (const char *) buf;
1303 const char *bb_applet_name = "stty";