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 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 You should have received a copy of the GNU General Public License
11 along with this program; if not, write to the Free Software Foundation,
12 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
14 /* Usage: stty [-ag] [-F device] [setting...]
17 -a Write all current settings to stdout in human-readable form.
18 -g Write all current settings to stdout in stty-readable form.
19 -F Open and use the specified device instead of stdin
21 If no args are given, write to stdout the baud rate and settings that
22 have been changed from their defaults. Mode reading and changes
23 are done on the specified device, or stdin if none was specified.
25 David MacKenzie <djm@gnu.ai.mit.edu>
27 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
35 #include <sys/ioctl.h>
37 #include <sys/param.h>
41 # define STDIN_FILENO 0
45 # define STDOUT_FILENO 1
58 #define STREQ(a, b) (strcmp ((a), (b)) == 0)
61 #ifndef _POSIX_VDISABLE
62 # define _POSIX_VDISABLE ((unsigned char) 0)
65 #define Control(c) ((c) & 0x1f)
66 /* Canonical values for control characters. */
68 # define CINTR Control ('c')
77 # define CKILL Control ('u')
80 # define CEOF Control ('d')
83 # define CEOL _POSIX_VDISABLE
86 # define CSTART Control ('q')
89 # define CSTOP Control ('s')
92 # define CSUSP Control ('z')
94 #if defined(VEOL2) && !defined(CEOL2)
95 # define CEOL2 _POSIX_VDISABLE
97 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
98 #if defined(VSUSP) && !defined(VSWTCH)
100 # define CSWTCH CSUSP
102 #if defined(VSWTCH) && !defined(CSWTCH)
103 # define CSWTCH _POSIX_VDISABLE
106 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
107 So the default is to disable `swtch.' */
108 #if defined (__sparc__) && defined (__svr4__)
110 # define CSWTCH _POSIX_VDISABLE
113 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
114 # define VWERASE VWERSE
116 #if defined(VDSUSP) && !defined (CDSUSP)
117 # define CDSUSP Control ('y')
119 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
120 # define VREPRINT VRPRNT
122 #if defined(VREPRINT) && !defined(CRPRNT)
123 # define CRPRNT Control ('r')
125 #if defined(VWERASE) && !defined(CWERASE)
126 # define CWERASE Control ('w')
128 #if defined(VLNEXT) && !defined(CLNEXT)
129 # define CLNEXT Control ('v')
131 #if defined(VDISCARD) && !defined(VFLUSHO)
132 # define VFLUSHO VDISCARD
134 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
135 # define VFLUSHO VFLUSH
137 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
138 # define ECHOCTL CTLECH
140 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
141 # define ECHOCTL TCTLECH
143 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
144 # define ECHOKE CRTKIL
146 #if defined(VFLUSHO) && !defined(CFLUSHO)
147 # define CFLUSHO Control ('o')
149 #if defined(VSTATUS) && !defined(CSTATUS)
150 # define CSTATUS Control ('t')
153 /* Which speeds to set. */
155 input_speed, output_speed, both_speeds
158 /* Which member(s) of `struct termios' a mode uses. */
160 /* Do NOT change the order or values, as mode_type_flag()
161 * depends on them. */
162 control, input, output, local, combination
166 static const char evenp [] = "evenp";
167 static const char raw [] = "raw";
168 static const char stty_min [] = "min";
169 static const char stty_time [] = "time";
170 static const char stty_swtch[] = "swtch";
171 static const char stty_eol [] = "eol";
172 static const char stty_eof [] = "eof";
173 static const char parity [] = "parity";
174 static const char stty_oddp [] = "oddp";
175 static const char stty_nl [] = "nl";
176 static const char stty_ek [] = "ek";
177 static const char stty_sane [] = "sane";
178 static const char cbreak [] = "cbreak";
179 static const char stty_pass8[] = "pass8";
180 static const char litout [] = "litout";
181 static const char cooked [] = "cooked";
182 static const char decctlq [] = "decctlq";
183 static const char stty_tabs [] = "tabs";
184 static const char stty_lcase[] = "lcase";
185 static const char stty_LCASE[] = "LCASE";
186 static const char stty_crt [] = "crt";
187 static const char stty_dec [] = "dec";
190 /* Flags for `struct mode_info'. */
191 #define SANE_SET 1 /* Set in `sane' mode. */
192 #define SANE_UNSET 2 /* Unset in `sane' mode. */
193 #define REV 4 /* Can be turned off by prepending `-'. */
194 #define OMIT 8 /* Don't display value. */
198 const char *name; /* Name given on command line. */
199 /* enum mode_type type; */
200 char type; /* Which structure element to change. */
201 char flags; /* Setting and display options. */
202 unsigned short mask; /* Other bits to turn off for this mode. */
203 unsigned long bits; /* Bits to set for this mode. */
206 #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
208 static const struct mode_info mode_info[] = {
209 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
210 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
211 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
212 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
213 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
214 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
215 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
216 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
217 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
218 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
219 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
221 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
223 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
224 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
225 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
226 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
227 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
228 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
229 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
230 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
231 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
232 MI_ENTRY("ixon", input, REV, IXON, 0 ),
233 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
234 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
236 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
239 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
242 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
244 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
246 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
249 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
252 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
255 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
258 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
261 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
264 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
267 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
268 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
271 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
272 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
273 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
274 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
278 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
279 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
280 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
281 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
284 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
289 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
290 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
293 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
294 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
297 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
298 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
300 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
301 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
303 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
305 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
306 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
307 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
308 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
309 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
310 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
312 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
315 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
318 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
319 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
322 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
323 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
326 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
327 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
329 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
330 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
331 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
332 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
333 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
334 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
335 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
336 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
337 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
338 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
339 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
341 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
343 #if defined (TABDLY) || defined (OXTABS)
344 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
346 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
347 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
348 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
350 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
351 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
354 static const int NUM_mode_info =
356 (sizeof(mode_info) / sizeof(struct mode_info));
358 /* Control character settings. */
359 struct control_info {
360 const char *name; /* Name given on command line. */
361 unsigned char saneval; /* Value to set for `stty sane'. */
362 unsigned char offset; /* Offset in c_cc. */
365 /* Control characters. */
367 static const struct control_info control_info[] = {
368 {"intr", CINTR, VINTR},
369 {"quit", CQUIT, VQUIT},
370 {"erase", CERASE, VERASE},
371 {"kill", CKILL, VKILL},
372 {stty_eof, CEOF, VEOF},
373 {stty_eol, CEOL, VEOL},
375 {"eol2", CEOL2, VEOL2},
378 {stty_swtch, CSWTCH, VSWTCH},
380 {"start", CSTART, VSTART},
381 {"stop", CSTOP, VSTOP},
382 {"susp", CSUSP, VSUSP},
384 {"dsusp", CDSUSP, VDSUSP},
387 {"rprnt", CRPRNT, VREPRINT},
390 {"werase", CWERASE, VWERASE},
393 {"lnext", CLNEXT, VLNEXT},
396 {"flush", CFLUSHO, VFLUSHO},
399 {"status", CSTATUS, VSTATUS},
401 /* These must be last because of the display routines. */
403 {stty_time, 0, VTIME},
406 static const int NUM_control_info =
407 (sizeof(control_info) / sizeof(struct control_info));
410 static const char * visible(unsigned int ch);
411 static int recover_mode(char *arg, struct termios *mode);
412 static int screen_columns(void);
413 static int set_mode(const struct mode_info *info,
414 int reversed, struct termios *mode);
415 static speed_t string_to_baud(const char *arg);
416 static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode);
417 static void display_all(struct termios *mode, int fd);
418 static void display_changed(struct termios *mode, int fd);
419 static void display_recoverable(struct termios *mode, int fd);
420 static void display_speed(struct termios *mode, int fancy);
421 static void display_window_size(int fancy, int fd);
422 static void sane_mode(struct termios *mode);
423 static void set_control_char(const struct control_info *info,
424 const char *arg, struct termios *mode);
425 static void set_speed(enum speed_setting type,
426 const char *arg, struct termios *mode);
427 static void set_window_size(int rows, int cols, int fd);
429 static const char *device_name;
431 static __attribute__ ((noreturn)) void perror_on_device(const char *fmt)
433 bb_perror_msg_and_die(fmt, device_name);
437 /* The width of the screen, for output wrapping. */
440 /* Current position, to know when to wrap. */
441 static int current_col;
443 /* Print format string MESSAGE and optional args.
444 Wrap to next line first if it won't fit.
445 Print a space first unless MESSAGE will start a new line. */
447 static void wrapf(const char *message, ...)
450 char buf[1024]; /* Plenty long for our needs. */
453 va_start(args, message);
454 vsprintf(buf, message, args);
456 buflen = strlen(buf);
457 if (current_col + (current_col > 0) + buflen >= max_col) {
461 if (current_col > 0) {
466 current_col += buflen;
469 static const struct suffix_mult stty_suffixes[] = {
477 extern int stty_main(int argc, char **argv)
479 extern int main(int argc, char **argv)
483 void (*output_func)(struct termios *, int);
485 int require_set_attr;
488 int recoverable_output;
491 char * file_name = NULL;
495 output_func = display_changed;
497 recoverable_output = 0;
499 /* Don't print error messages for unrecognized options. */
502 while ((optc = getopt(argc, argv, "agF:")) != -1) {
506 output_func = display_all;
510 recoverable_output = 1;
511 output_func = display_recoverable;
516 bb_error_msg_and_die("only one device may be specified");
520 default: /* unrecognized option */
532 /* Specifying both -a and -g gets an error. */
533 if (verbose_output & recoverable_output)
534 bb_error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
536 /* Specifying any other arguments with -a or -g gets an error. */
537 if (~noargs & (verbose_output | recoverable_output))
538 bb_error_msg_and_die ("modes may not be set when specifying an output style");
540 /* FIXME: it'd be better not to open the file until we've verified
541 that all arguments are valid. Otherwise, we could end up doing
542 only some of the requested operations and then failing, probably
543 leaving things in an undesirable state. */
548 device_name = file_name;
549 fd = bb_xopen(device_name, O_RDONLY | O_NONBLOCK);
550 if ((fdflags = fcntl(fd, F_GETFL)) == -1
551 || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
552 perror_on_device("%s: couldn't reset non-blocking mode");
555 device_name = bb_msg_standard_input;
558 /* Initialize to all zeroes so there is no risk memcmp will report a
559 spurious difference in an uninitialized portion of the structure. */
560 memset(&mode, 0, sizeof(mode));
561 if (tcgetattr(fd, &mode))
562 perror_on_device("%s");
564 if (verbose_output | recoverable_output | noargs) {
565 max_col = screen_columns();
567 output_func(&mode, fd);
572 require_set_attr = 0;
579 if (argv[k][0] == '-') {
584 /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
585 Find the options that have been parsed. This is really
586 gross, but it's needed because stty SETTINGS look like options to
587 getopt(), so we need to work around things in a really horrible
588 way. If any new options are ever added to stty, the short option
589 MUST NOT be a letter which is the first letter of one of the
590 possible stty settings.
592 find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
594 if(find_dev_opt[1]==0) /* -*F /dev/foo */
595 k++; /* skip /dev/foo */
596 continue; /* else -*F/dev/foo - no skip */
598 if(argv[k][0]=='a' || argv[k][0]=='g')
600 /* Is not options - is reverse params */
603 for (i = 0; i < NUM_mode_info; ++i)
604 if (STREQ(argv[k], mode_info[i].name)) {
605 match_found = set_mode(&mode_info[i], reversed, &mode);
606 require_set_attr = 1;
610 if (match_found == 0 && reversed)
611 bb_error_msg_and_die("invalid argument `%s'", --argv[k]);
613 if (match_found == 0)
614 for (i = 0; i < NUM_control_info; ++i)
615 if (STREQ(argv[k], control_info[i].name)) {
617 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
620 set_control_char(&control_info[i], argv[k], &mode);
621 require_set_attr = 1;
625 if (match_found == 0) {
626 if (STREQ(argv[k], "ispeed")) {
628 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
630 set_speed(input_speed, argv[k], &mode);
632 require_set_attr = 1;
633 } else if (STREQ(argv[k], "ospeed")) {
635 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
637 set_speed(output_speed, argv[k], &mode);
639 require_set_attr = 1;
642 else if (STREQ(argv[k], "rows")) {
644 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
646 set_window_size((int) bb_xparse_number(argv[k], stty_suffixes),
648 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
650 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
653 (int) bb_xparse_number(argv[k], stty_suffixes),
655 } else if (STREQ(argv[k], "size")) {
656 max_col = screen_columns();
658 display_window_size(0, fd);
662 else if (STREQ(argv[k], "line")) {
664 bb_error_msg_and_die("missing argument to `%s'", argv[k]);
666 mode.c_line = bb_xparse_number(argv[k], stty_suffixes);
667 require_set_attr = 1;
670 else if (STREQ(argv[k], "speed")) {
671 max_col = screen_columns();
672 display_speed(&mode, 0);
673 } else if (recover_mode(argv[k], &mode) == 1)
674 require_set_attr = 1;
675 else if (string_to_baud(argv[k]) != (speed_t) - 1) {
676 set_speed(both_speeds, argv[k], &mode);
678 require_set_attr = 1;
680 bb_error_msg_and_die("invalid argument `%s'", argv[k]);
684 if (require_set_attr) {
685 struct termios new_mode;
687 if (tcsetattr(fd, TCSADRAIN, &mode))
688 perror_on_device("%s");
690 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
691 it performs *any* of the requested operations. This means it
692 can report `success' when it has actually failed to perform
693 some proper subset of the requested operations. To detect
694 this partial failure, get the current terminal attributes and
695 compare them to the requested ones. */
697 /* Initialize to all zeroes so there is no risk memcmp will report a
698 spurious difference in an uninitialized portion of the structure. */
699 memset(&new_mode, 0, sizeof(new_mode));
700 if (tcgetattr(fd, &new_mode))
701 perror_on_device("%s");
703 /* Normally, one shouldn't use memcmp to compare structures that
704 may have `holes' containing uninitialized data, but we have been
705 careful to initialize the storage of these two variables to all
706 zeroes. One might think it more efficient simply to compare the
707 modified fields, but that would require enumerating those fields --
708 and not all systems have the same fields in this structure. */
710 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
712 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
713 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
714 sometimes (m1 != m2). The only difference is in the four bits
715 of the c_cflag field corresponding to the baud rate. To save
716 Sun users a little confusion, don't report an error if this
717 happens. But suppress the error only if we haven't tried to
718 set the baud rate explicitly -- otherwise we'd never give an
719 error for a true failure to set the baud rate. */
721 new_mode.c_cflag &= (~CIBAUD);
722 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
724 perror_on_device ("%s: unable to perform all requested operations");
731 /* Return 0 if not applied because not reversible; otherwise return 1. */
734 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
738 if (reversed && (info->flags & REV) == 0)
741 bitsp = mode_type_flag(info->type, mode);
744 /* Combination mode. */
745 if (info->name == evenp || info->name == parity) {
747 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
750 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
751 } else if (info->name == stty_oddp) {
753 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
756 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
757 } else if (info->name == stty_nl) {
759 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
760 mode->c_oflag = (mode->c_oflag
773 mode->c_iflag = mode->c_iflag & ~ICRNL;
775 mode->c_oflag = mode->c_oflag & ~ONLCR;
778 } else if (info->name == stty_ek) {
779 mode->c_cc[VERASE] = CERASE;
780 mode->c_cc[VKILL] = CKILL;
781 } else if (info->name == stty_sane)
783 else if (info->name == cbreak) {
785 mode->c_lflag |= ICANON;
787 mode->c_lflag &= ~ICANON;
788 } else if (info->name == stty_pass8) {
790 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
791 mode->c_iflag |= ISTRIP;
793 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
794 mode->c_iflag &= ~ISTRIP;
796 } else if (info->name == litout) {
798 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
799 mode->c_iflag |= ISTRIP;
800 mode->c_oflag |= OPOST;
802 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
803 mode->c_iflag &= ~ISTRIP;
804 mode->c_oflag &= ~OPOST;
806 } else if (info->name == raw || info->name == cooked) {
807 if ((info->name[0] == 'r' && reversed)
808 || (info->name[0] == 'c' && !reversed)) {
810 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
811 mode->c_oflag |= OPOST;
812 mode->c_lflag |= ISIG | ICANON;
814 mode->c_cc[VEOF] = CEOF;
817 mode->c_cc[VEOL] = CEOL;
822 mode->c_oflag &= ~OPOST;
823 mode->c_lflag &= ~(ISIG | ICANON
828 mode->c_cc[VMIN] = 1;
829 mode->c_cc[VTIME] = 0;
833 else if (info->name == decctlq) {
835 mode->c_iflag |= IXANY;
837 mode->c_iflag &= ~IXANY;
841 else if (info->name == stty_tabs) {
843 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
845 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
849 else if (info->name == stty_tabs) {
851 mode->c_oflag = mode->c_oflag | OXTABS;
853 mode->c_oflag = mode->c_oflag & ~OXTABS;
857 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
858 else if (info->name == stty_lcase || info->name == stty_LCASE) {
860 mode->c_lflag &= ~XCASE;
861 mode->c_iflag &= ~IUCLC;
862 mode->c_oflag &= ~OLCUC;
864 mode->c_lflag |= XCASE;
865 mode->c_iflag |= IUCLC;
866 mode->c_oflag |= OLCUC;
870 else if (info->name == stty_crt)
871 mode->c_lflag |= ECHOE
879 else if (info->name == stty_dec) {
880 mode->c_cc[VINTR] = 3; /* ^C */
881 mode->c_cc[VERASE] = 127; /* DEL */
882 mode->c_cc[VKILL] = 21; /* ^U */
883 mode->c_lflag |= ECHOE
892 mode->c_iflag &= ~IXANY;
896 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
898 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
904 set_control_char(const struct control_info *info, const char *arg,
905 struct termios *mode)
909 if (info->name == stty_min || info->name == stty_time)
910 value = bb_xparse_number(arg, stty_suffixes);
911 else if (arg[0] == '\0' || arg[1] == '\0')
913 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
914 value = _POSIX_VDISABLE;
915 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
919 value = arg[1] & ~0140; /* Non-letters get weird results. */
921 value = bb_xparse_number(arg, stty_suffixes);
922 mode->c_cc[info->offset] = value;
926 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
930 baud = string_to_baud(arg);
932 if (type != output_speed) { /* either input or both */
933 cfsetispeed(mode, baud);
935 if (type != input_speed) { /* either output or both */
936 cfsetospeed(mode, baud);
942 static int get_win_size(int fd, struct winsize *win)
944 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
950 set_window_size(int rows, int cols, int fd)
954 if (get_win_size(fd, &win)) {
956 perror_on_device("%s");
957 memset(&win, 0, sizeof(win));
966 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
967 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
968 This comment from sys/ttold.h describes Sun's twisted logic - a better
969 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
970 At any rate, the problem is gone in Solaris 2.x. */
972 if (win.ws_row == 0 || win.ws_col == 0) {
973 struct ttysize ttysz;
975 ttysz.ts_lines = win.ws_row;
976 ttysz.ts_cols = win.ws_col;
978 win.ws_row = win.ws_col = 1;
980 if ((ioctl(fd, TIOCSWINSZ, (char *) &win) != 0)
981 || (ioctl(fd, TIOCSSIZE, (char *) &ttysz) != 0)) {
982 perror_on_device("%s");
988 if (ioctl(fd, TIOCSWINSZ, (char *) &win))
989 perror_on_device("%s");
992 static void display_window_size(int fancy, int fd)
994 const char *fmt_str = "%s" "\0" "%s: no size information for this device";
997 if (get_win_size(fd, &win)) {
998 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
999 perror_on_device(fmt_str);
1002 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
1003 win.ws_row, win.ws_col);
1010 static int screen_columns(void)
1018 /* With Solaris 2.[123], this ioctl fails and errno is set to
1019 EINVAL for telnet (but not rlogin) sessions.
1020 On ISC 3.0, it fails for the console and the serial port
1021 (but it works for ptys).
1022 It can also fail on any system when stdout isn't a tty.
1023 In case of any failure, just use the default. */
1024 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1029 if ((s = getenv("COLUMNS"))) {
1035 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1037 static const unsigned char tcflag_offsets[] = {
1038 offsetof(struct termios, c_cflag), /* control */
1039 offsetof(struct termios, c_iflag), /* input */
1040 offsetof(struct termios, c_oflag), /* output */
1041 offsetof(struct termios, c_lflag) /* local */
1044 if (((unsigned int) type) <= local) {
1045 return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
1050 static void display_changed(struct termios *mode, int fd)
1056 enum mode_type prev_type = control;
1058 display_speed(mode, 1);
1060 wrapf("line = %d;", mode->c_line);
1066 for (i = 0; control_info[i].name != stty_min; ++i) {
1067 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1069 /* If swtch is the same as susp, don't print both. */
1071 if (control_info[i].name == stty_swtch)
1074 /* If eof uses the same slot as min, only print whichever applies. */
1076 if ((mode->c_lflag & ICANON) == 0
1077 && (control_info[i].name == stty_eof
1078 || control_info[i].name == stty_eol)) continue;
1082 wrapf("%s = %s;", control_info[i].name,
1083 visible(mode->c_cc[control_info[i].offset]));
1085 if ((mode->c_lflag & ICANON) == 0) {
1086 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1087 (int) mode->c_cc[VTIME]);
1088 } else if (empty_line == 0)
1093 for (i = 0; i < NUM_mode_info; ++i) {
1094 if (mode_info[i].flags & OMIT)
1096 if (mode_info[i].type != prev_type) {
1097 if (empty_line == 0) {
1102 prev_type = mode_info[i].type;
1105 bitsp = mode_type_flag(mode_info[i].type, mode);
1106 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1107 if ((*bitsp & mask) == mode_info[i].bits) {
1108 if (mode_info[i].flags & SANE_UNSET) {
1109 wrapf("%s", mode_info[i].name);
1113 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1115 wrapf("-%s", mode_info[i].name);
1119 if (empty_line == 0)
1125 display_all(struct termios *mode, int fd)
1130 enum mode_type prev_type = control;
1132 display_speed(mode, 1);
1134 display_window_size(1, fd);
1137 wrapf("line = %d;", mode->c_line);
1142 for (i = 0; control_info[i].name != stty_min; ++i) {
1143 /* If swtch is the same as susp, don't print both. */
1145 if (control_info[i].name == stty_swtch)
1148 /* If eof uses the same slot as min, only print whichever applies. */
1150 if ((mode->c_lflag & ICANON) == 0
1151 && (control_info[i].name == stty_eof
1152 || control_info[i].name == stty_eol)) continue;
1154 wrapf("%s = %s;", control_info[i].name,
1155 visible(mode->c_cc[control_info[i].offset]));
1158 if ((mode->c_lflag & ICANON) == 0)
1160 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1161 if (current_col != 0)
1165 for (i = 0; i < NUM_mode_info; ++i) {
1166 if (mode_info[i].flags & OMIT)
1168 if (mode_info[i].type != prev_type) {
1171 prev_type = mode_info[i].type;
1174 bitsp = mode_type_flag(mode_info[i].type, mode);
1175 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1176 if ((*bitsp & mask) == mode_info[i].bits)
1177 wrapf("%s", mode_info[i].name);
1178 else if (mode_info[i].flags & REV)
1179 wrapf("-%s", mode_info[i].name);
1185 static void display_speed(struct termios *mode, int fancy)
1187 unsigned long ispeed, ospeed;
1188 const char *fmt_str =
1189 "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
1190 "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
1192 ospeed = ispeed = cfgetispeed(mode);
1193 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1194 ispeed = ospeed; /* in case ispeed was 0 */
1200 wrapf(fmt_str, bb_baud_to_value(ispeed), bb_baud_to_value(ospeed));
1205 static void display_recoverable(struct termios *mode, int fd)
1209 printf("%lx:%lx:%lx:%lx",
1210 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1211 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1212 for (i = 0; i < NCCS; ++i)
1213 printf(":%x", (unsigned int) mode->c_cc[i]);
1217 static int recover_mode(char *arg, struct termios *mode)
1221 unsigned long iflag, oflag, cflag, lflag;
1223 /* Scan into temporaries since it is too much trouble to figure out
1224 the right format for `tcflag_t'. */
1225 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1226 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1228 mode->c_iflag = iflag;
1229 mode->c_oflag = oflag;
1230 mode->c_cflag = cflag;
1231 mode->c_lflag = lflag;
1233 for (i = 0; i < NCCS; ++i) {
1234 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1236 mode->c_cc[i] = chr;
1240 /* Fail if there are too many fields. */
1247 static speed_t string_to_baud(const char *arg)
1249 return bb_value_to_baud(bb_xparse_number(arg, 0));
1252 static void sane_mode(struct termios *mode)
1257 for (i = 0; i < NUM_control_info; ++i) {
1259 if (control_info[i].name == stty_min)
1262 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1265 for (i = 0; i < NUM_mode_info; ++i) {
1266 if (mode_info[i].flags & SANE_SET) {
1267 bitsp = mode_type_flag(mode_info[i].type, mode);
1268 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1269 | mode_info[i].bits;
1270 } else if (mode_info[i].flags & SANE_UNSET) {
1271 bitsp = mode_type_flag(mode_info[i].type, mode);
1272 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1273 & ~mode_info[i].bits;
1278 /* Return a string that is the printable representation of character CH. */
1279 /* Adapted from `cat' by Torbjorn Granlund. */
1281 static const char *visible(unsigned int ch)
1283 static char buf[10];
1286 if (ch == _POSIX_VDISABLE) {
1299 } else if (ch < 127) {
1307 return (const char *) buf;
1312 const char *bb_applet_name = "stty";