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(const char *arg, struct termios *mode);
384 static int screen_columns(void);
385 static void 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 = bb_msg_standard_input;
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 static const struct mode_info *find_mode(const char *name)
451 for (i = 0; i < NUM_mode_info; ++i)
452 if (STREQ(name, mode_info[i].name))
453 return &mode_info[i];
457 static const struct control_info *find_control(const char *name)
460 for (i = 0; i < NUM_control_info; ++i)
461 if (STREQ(name, control_info[i].name))
462 return &control_info[i];
467 param_need_arg = 0x80,
468 param_line = 1 | 0x80,
469 param_rows = 2 | 0x80,
470 param_cols = 3 | 0x80,
472 param_ispeed = 5 | 0x80,
473 param_ospeed = 6 | 0x80,
477 static int find_param(const char *name)
480 if (STREQ(name, "line")) return param_line;
483 if (STREQ(name, "rows")) return param_rows;
484 if (STREQ(name, "cols")) return param_cols;
485 if (STREQ(name, "columns")) return param_cols;
486 if (STREQ(name, "size")) return param_size;
488 if (STREQ(name, "ispeed")) return param_ispeed;
489 if (STREQ(name, "ospeed")) return param_ospeed;
490 if (STREQ(name, "speed")) return param_speed;
495 int stty_main(int argc, char **argv)
498 void (*output_func)(struct termios *);
499 const char *file_name = NULL;
500 int require_set_attr;
503 int recoverable_output;
507 output_func = display_changed;
510 require_set_attr = 0;
512 recoverable_output = 0;
514 /* First pass: only parse/verify command line params */
517 const struct mode_info *mp;
518 const struct control_info *cp;
519 const char *arg = argv[k];
520 const char *argnext = argv[k+1];
525 mp = find_mode(arg+1);
527 if (!(mp->flags & REV))
528 bb_error_msg_and_die("invalid argument '%s'", arg);
532 /* It is an option - parse it */
538 output_func = display_all;
541 recoverable_output = 1;
542 output_func = display_recoverable;
546 bb_error_msg_and_die("only one device may be specified");
547 file_name = &arg[i+1]; /* "-Fdevice" ? */
548 if (!file_name[0]) { /* nope, "-F device" */
549 int p = k+1; /* argv[p] is argnext */
552 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
553 /* remove -F param from arg[vc] */
555 while (argv[p+1]) { argv[p] = argv[p+1]; ++p; }
559 bb_error_msg_and_die("invalid argument '%s'", arg);
572 cp = find_control(arg);
575 bb_error_msg_and_die(bb_msg_requires_arg, arg);
581 param = find_param(arg);
582 if (param & param_need_arg) {
584 bb_error_msg_and_die(bb_msg_requires_arg, arg);
591 bb_xparse_number(argnext, stty_suffixes);
596 bb_xparse_number(argnext, stty_suffixes);
599 bb_xparse_number(argnext, stty_suffixes);
608 if (recover_mode(arg, &mode) == 1) break;
609 if (string_to_baud(arg) != (speed_t) -1) break;
610 bb_error_msg_and_die("invalid argument '%s'", arg);
615 /* Specifying both -a and -g is an error */
616 if (verbose_output && recoverable_output)
617 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
618 /* Specifying -a or -g with non-options is an error */
619 if (!noargs && (verbose_output || recoverable_output))
620 bb_error_msg_and_die("modes may not be set when specifying an output style");
622 /* Now it is safe to start doing things */
625 device_name = file_name;
626 fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
631 fdflags = fcntl(STDIN_FILENO, F_GETFL);
632 if (fdflags == -1 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
633 perror_on_device("%s: couldn't reset non-blocking mode");
636 /* Initialize to all zeroes so there is no risk memcmp will report a
637 spurious difference in an uninitialized portion of the structure. */
638 memset(&mode, 0, sizeof(mode));
639 if (tcgetattr(STDIN_FILENO, &mode))
640 perror_on_device("%s");
642 if (verbose_output || recoverable_output || noargs) {
643 max_col = screen_columns();
649 /* Second pass: perform actions */
652 const struct mode_info *mp;
653 const struct control_info *cp;
654 const char *arg = argv[k];
655 const char *argnext = argv[k+1];
659 mp = find_mode(arg+1);
661 set_mode(mp, 1 /* reversed */, &mode);
663 /* It is an option - already parsed. Skip it */
669 set_mode(mp, 0 /* non-reversed */, &mode);
673 cp = find_control(arg);
676 set_control_char(cp, argnext, &mode);
680 param = find_param(arg);
681 if (param & param_need_arg) {
688 mode.c_line = bb_xparse_number(argnext, stty_suffixes);
689 require_set_attr = 1;
694 set_window_size(-1, (int) bb_xparse_number(argnext, stty_suffixes));
697 max_col = screen_columns();
699 display_window_size(0);
702 set_window_size((int) bb_xparse_number(argnext, stty_suffixes), -1);
706 set_speed(input_speed, argnext, &mode);
708 require_set_attr = 1;
711 set_speed(output_speed, argnext, &mode);
713 require_set_attr = 1;
716 max_col = screen_columns();
717 display_speed(&mode, 0);
720 if (recover_mode(arg, &mode) == 1)
721 require_set_attr = 1;
722 else /* true: if (string_to_baud(arg) != (speed_t) -1) */ {
723 set_speed(both_speeds, arg, &mode);
725 require_set_attr = 1;
726 } /* else - impossible (caught in the first pass):
727 bb_error_msg_and_die("invalid argument '%s'", arg); */
731 if (require_set_attr) {
732 struct termios new_mode;
734 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
735 perror_on_device("%s");
737 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
738 it performs *any* of the requested operations. This means it
739 can report `success' when it has actually failed to perform
740 some proper subset of the requested operations. To detect
741 this partial failure, get the current terminal attributes and
742 compare them to the requested ones. */
744 /* Initialize to all zeroes so there is no risk memcmp will report a
745 spurious difference in an uninitialized portion of the structure. */
746 memset(&new_mode, 0, sizeof(new_mode));
747 if (tcgetattr(STDIN_FILENO, &new_mode))
748 perror_on_device("%s");
750 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
752 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
753 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
754 sometimes (m1 != m2). The only difference is in the four bits
755 of the c_cflag field corresponding to the baud rate. To save
756 Sun users a little confusion, don't report an error if this
757 happens. But suppress the error only if we haven't tried to
758 set the baud rate explicitly -- otherwise we'd never give an
759 error for a true failure to set the baud rate. */
761 new_mode.c_cflag &= (~CIBAUD);
762 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
764 perror_on_device ("%s: unable to perform all requested operations");
771 /* Return 0 if not applied because not reversible; otherwise return 1. */
774 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
778 bitsp = mode_type_flag(EMT(info->type), mode);
781 /* Combination mode. */
782 if (info->name == evenp || info->name == parity) {
784 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
787 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
788 } else if (info->name == stty_oddp) {
790 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
793 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
794 } else if (info->name == stty_nl) {
796 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
797 mode->c_oflag = (mode->c_oflag
810 mode->c_iflag = mode->c_iflag & ~ICRNL;
812 mode->c_oflag = mode->c_oflag & ~ONLCR;
815 } else if (info->name == stty_ek) {
816 mode->c_cc[VERASE] = CERASE;
817 mode->c_cc[VKILL] = CKILL;
818 } else if (info->name == stty_sane)
820 else if (info->name == cbreak) {
822 mode->c_lflag |= ICANON;
824 mode->c_lflag &= ~ICANON;
825 } else if (info->name == stty_pass8) {
827 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
828 mode->c_iflag |= ISTRIP;
830 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
831 mode->c_iflag &= ~ISTRIP;
833 } else if (info->name == litout) {
835 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
836 mode->c_iflag |= ISTRIP;
837 mode->c_oflag |= OPOST;
839 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
840 mode->c_iflag &= ~ISTRIP;
841 mode->c_oflag &= ~OPOST;
843 } else if (info->name == raw || info->name == cooked) {
844 if ((info->name[0] == 'r' && reversed)
845 || (info->name[0] == 'c' && !reversed)) {
847 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
848 mode->c_oflag |= OPOST;
849 mode->c_lflag |= ISIG | ICANON;
851 mode->c_cc[VEOF] = CEOF;
854 mode->c_cc[VEOL] = CEOL;
859 mode->c_oflag &= ~OPOST;
860 mode->c_lflag &= ~(ISIG | ICANON
865 mode->c_cc[VMIN] = 1;
866 mode->c_cc[VTIME] = 0;
870 else if (info->name == decctlq) {
872 mode->c_iflag |= IXANY;
874 mode->c_iflag &= ~IXANY;
878 else if (info->name == stty_tabs) {
880 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
882 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
886 else if (info->name == stty_tabs) {
888 mode->c_oflag = mode->c_oflag | OXTABS;
890 mode->c_oflag = mode->c_oflag & ~OXTABS;
894 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
895 else if (info->name == stty_lcase || info->name == stty_LCASE) {
897 mode->c_lflag &= ~XCASE;
898 mode->c_iflag &= ~IUCLC;
899 mode->c_oflag &= ~OLCUC;
901 mode->c_lflag |= XCASE;
902 mode->c_iflag |= IUCLC;
903 mode->c_oflag |= OLCUC;
907 else if (info->name == stty_crt)
908 mode->c_lflag |= ECHOE
916 else if (info->name == stty_dec) {
917 mode->c_cc[VINTR] = 3; /* ^C */
918 mode->c_cc[VERASE] = 127; /* DEL */
919 mode->c_cc[VKILL] = 21; /* ^U */
920 mode->c_lflag |= ECHOE
929 mode->c_iflag &= ~IXANY;
933 *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
935 *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
939 set_control_char(const struct control_info *info, const char *arg,
940 struct termios *mode)
944 if (info->name == stty_min || info->name == stty_time)
945 value = bb_xparse_number(arg, stty_suffixes);
946 else if (arg[0] == '\0' || arg[1] == '\0')
948 else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
949 value = _POSIX_VDISABLE;
950 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */
954 value = arg[1] & ~0140; /* Non-letters get weird results. */
956 value = bb_xparse_number(arg, stty_suffixes);
957 mode->c_cc[info->offset] = value;
961 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
965 baud = string_to_baud(arg);
967 if (type != output_speed) { /* either input or both */
968 cfsetispeed(mode, baud);
970 if (type != input_speed) { /* either output or both */
971 cfsetospeed(mode, baud);
977 static int get_win_size(int fd, struct winsize *win)
979 int err = ioctl(fd, TIOCGWINSZ, (char *) win);
985 set_window_size(int rows, int cols)
989 if (get_win_size(STDIN_FILENO, &win)) {
991 perror_on_device("%s");
992 memset(&win, 0, sizeof(win));
1001 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1002 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1003 This comment from sys/ttold.h describes Sun's twisted logic - a better
1004 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1005 At any rate, the problem is gone in Solaris 2.x. */
1007 if (win.ws_row == 0 || win.ws_col == 0) {
1008 struct ttysize ttysz;
1010 ttysz.ts_lines = win.ws_row;
1011 ttysz.ts_cols = win.ws_col;
1013 win.ws_row = win.ws_col = 1;
1015 if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
1016 || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
1017 perror_on_device("%s");
1023 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1024 perror_on_device("%s");
1027 static void display_window_size(int fancy)
1029 const char *fmt_str = "%s" "\0" "%s: no size information for this device";
1032 if (get_win_size(STDIN_FILENO, &win)) {
1033 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
1034 perror_on_device(fmt_str);
1037 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
1038 win.ws_row, win.ws_col);
1045 static int screen_columns(void)
1053 /* With Solaris 2.[123], this ioctl fails and errno is set to
1054 EINVAL for telnet (but not rlogin) sessions.
1055 On ISC 3.0, it fails for the console and the serial port
1056 (but it works for ptys).
1057 It can also fail on any system when stdout isn't a tty.
1058 In case of any failure, just use the default. */
1059 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1064 if ((s = getenv("COLUMNS"))) {
1070 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
1072 static const unsigned char tcflag_offsets[] = {
1073 offsetof(struct termios, c_cflag), /* control */
1074 offsetof(struct termios, c_iflag), /* input */
1075 offsetof(struct termios, c_oflag), /* output */
1076 offsetof(struct termios, c_lflag) /* local */
1079 if (((unsigned int) type) <= local) {
1080 return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
1085 static void display_changed(struct termios *mode)
1091 enum mode_type prev_type = control;
1093 display_speed(mode, 1);
1095 wrapf("line = %d;", mode->c_line);
1101 for (i = 0; control_info[i].name != stty_min; ++i) {
1102 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1104 /* If swtch is the same as susp, don't print both. */
1106 if (control_info[i].name == stty_swtch)
1109 /* If eof uses the same slot as min, only print whichever applies. */
1111 if ((mode->c_lflag & ICANON) == 0
1112 && (control_info[i].name == stty_eof
1113 || control_info[i].name == stty_eol)) continue;
1117 wrapf("%s = %s;", control_info[i].name,
1118 visible(mode->c_cc[control_info[i].offset]));
1120 if ((mode->c_lflag & ICANON) == 0) {
1121 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1122 (int) mode->c_cc[VTIME]);
1123 } else if (empty_line == 0)
1128 for (i = 0; i < NUM_mode_info; ++i) {
1129 if (mode_info[i].flags & OMIT)
1131 if (EMT(mode_info[i].type) != prev_type) {
1132 if (empty_line == 0) {
1137 prev_type = EMT(mode_info[i].type);
1140 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1141 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1142 if ((*bitsp & mask) == mode_info[i].bits) {
1143 if (mode_info[i].flags & SANE_UNSET) {
1144 wrapf("%s", mode_info[i].name);
1148 else if ((mode_info[i].flags & (SANE_SET | REV)) ==
1150 wrapf("-%s", mode_info[i].name);
1154 if (empty_line == 0)
1160 display_all(struct termios *mode)
1165 enum mode_type prev_type = control;
1167 display_speed(mode, 1);
1169 display_window_size(1);
1172 wrapf("line = %d;", mode->c_line);
1177 for (i = 0; control_info[i].name != stty_min; ++i) {
1178 /* If swtch is the same as susp, don't print both. */
1180 if (control_info[i].name == stty_swtch)
1183 /* If eof uses the same slot as min, only print whichever applies. */
1185 if ((mode->c_lflag & ICANON) == 0
1186 && (control_info[i].name == stty_eof
1187 || control_info[i].name == stty_eol)) continue;
1189 wrapf("%s = %s;", control_info[i].name,
1190 visible(mode->c_cc[control_info[i].offset]));
1193 if ((mode->c_lflag & ICANON) == 0)
1195 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1196 if (current_col != 0)
1200 for (i = 0; i < NUM_mode_info; ++i) {
1201 if (mode_info[i].flags & OMIT)
1203 if (EMT(mode_info[i].type) != prev_type) {
1206 prev_type = EMT(mode_info[i].type);
1209 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1210 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1211 if ((*bitsp & mask) == mode_info[i].bits)
1212 wrapf("%s", mode_info[i].name);
1213 else if (mode_info[i].flags & REV)
1214 wrapf("-%s", mode_info[i].name);
1220 static void display_speed(struct termios *mode, int fancy)
1222 unsigned long ispeed, ospeed;
1223 const char *fmt_str =
1224 "%lu %lu\n\0" "ispeed %lu baud; ospeed %lu baud;\0"
1225 "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
1227 ospeed = ispeed = cfgetispeed(mode);
1228 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
1229 ispeed = ospeed; /* in case ispeed was 0 */
1235 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1240 static void display_recoverable(struct termios *mode)
1244 printf("%lx:%lx:%lx:%lx",
1245 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1246 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1247 for (i = 0; i < NCCS; ++i)
1248 printf(":%x", (unsigned int) mode->c_cc[i]);
1252 static int recover_mode(const char *arg, struct termios *mode)
1256 unsigned long iflag, oflag, cflag, lflag;
1258 /* Scan into temporaries since it is too much trouble to figure out
1259 the right format for `tcflag_t'. */
1260 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
1261 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1263 mode->c_iflag = iflag;
1264 mode->c_oflag = oflag;
1265 mode->c_cflag = cflag;
1266 mode->c_lflag = lflag;
1268 for (i = 0; i < NCCS; ++i) {
1269 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
1271 mode->c_cc[i] = chr;
1275 /* Fail if there are too many fields. */
1282 static speed_t string_to_baud(const char *arg)
1284 return tty_value_to_baud(bb_xparse_number(arg, 0));
1287 static void sane_mode(struct termios *mode)
1292 for (i = 0; i < NUM_control_info; ++i) {
1294 if (control_info[i].name == stty_min)
1297 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1300 for (i = 0; i < NUM_mode_info; ++i) {
1301 if (mode_info[i].flags & SANE_SET) {
1302 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1303 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1304 | mode_info[i].bits;
1305 } else if (mode_info[i].flags & SANE_UNSET) {
1306 bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
1307 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1308 & ~mode_info[i].bits;
1313 /* Return a string that is the printable representation of character CH. */
1314 /* Adapted from `cat' by Torbjorn Granlund. */
1316 static const char *visible(unsigned int ch)
1318 static char buf[10];
1321 if (ch == _POSIX_VDISABLE) {
1334 } else if (ch < 127) {