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 GPLv2 or later, see file LICENSE in this source tree.
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
24 //usage:#define stty_trivial_usage
25 //usage: "[-a|g] [-F DEVICE] [SETTING]..."
26 //usage:#define stty_full_usage "\n\n"
27 //usage: "Without arguments, prints baud rate, line discipline,\n"
28 //usage: "and deviations from stty sane\n"
30 //usage: "\n -F DEVICE Open device instead of stdin"
31 //usage: "\n -a Print all current settings in human-readable form"
32 //usage: "\n -g Print in stty-readable form"
33 //usage: "\n [SETTING] See manpage"
37 #ifndef _POSIX_VDISABLE
38 # define _POSIX_VDISABLE ((unsigned char) 0)
41 #define Control(c) ((c) & 0x1f)
42 /* Canonical values for control characters */
44 # define CINTR Control('c')
53 # define CKILL Control('u')
56 # define CEOF Control('d')
59 # define CEOL _POSIX_VDISABLE
62 # define CSTART Control('q')
65 # define CSTOP Control('s')
68 # define CSUSP Control('z')
70 #if defined(VEOL2) && !defined(CEOL2)
71 # define CEOL2 _POSIX_VDISABLE
73 /* glibc-2.12.1 uses only VSWTC name */
74 #if defined(VSWTC) && !defined(VSWTCH)
77 /* ISC renamed swtch to susp for termios, but we'll accept either name */
78 #if defined(VSUSP) && !defined(VSWTCH)
82 #if defined(VSWTCH) && !defined(CSWTCH)
83 # define CSWTCH _POSIX_VDISABLE
86 /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
87 So the default is to disable 'swtch.' */
88 #if defined(__sparc__) && defined(__svr4__)
90 # define CSWTCH _POSIX_VDISABLE
93 #if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
94 # define VWERASE VWERSE
96 #if defined(VDSUSP) && !defined(CDSUSP)
97 # define CDSUSP Control('y')
99 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
100 # define VREPRINT VRPRNT
102 #if defined(VREPRINT) && !defined(CRPRNT)
103 # define CRPRNT Control('r')
105 #if defined(VWERASE) && !defined(CWERASE)
106 # define CWERASE Control('w')
108 #if defined(VLNEXT) && !defined(CLNEXT)
109 # define CLNEXT Control('v')
111 #if defined(VDISCARD) && !defined(VFLUSHO)
112 # define VFLUSHO VDISCARD
114 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
115 # define VFLUSHO VFLUSH
117 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
118 # define ECHOCTL CTLECH
120 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
121 # define ECHOCTL TCTLECH
123 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
124 # define ECHOKE CRTKIL
126 #if defined(VFLUSHO) && !defined(CFLUSHO)
127 # define CFLUSHO Control('o')
129 #if defined(VSTATUS) && !defined(CSTATUS)
130 # define CSTATUS Control('t')
133 /* Save us from #ifdef forest plague */
243 /* Which speeds to set */
245 input_speed, output_speed, both_speeds
248 /* Which member(s) of 'struct termios' a mode uses */
250 /* Do NOT change the order or values, as mode_type_flag()
252 control, input, output, local, combination
255 /* Flags for 'struct mode_info' */
256 #define SANE_SET 1 /* Set in 'sane' mode */
257 #define SANE_UNSET 2 /* Unset in 'sane' mode */
258 #define REV 4 /* Can be turned off by prepending '-' */
259 #define OMIT 8 /* Don't display value */
263 * This structure should be kept as small as humanly possible.
266 const uint8_t type; /* Which structure element to change */
267 const uint8_t flags; /* Setting and display options */
268 /* only these values are ever used, so... */
269 #if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
271 #elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
274 const tcflag_t mask; /* Other bits to turn off for this mode */
276 /* was using short here, but ppc32 was unhappy */
277 const tcflag_t bits; /* Bits to set for this mode */
281 /* Must match mode_name[] and mode_info[] order! */
301 #if XCASE && IUCLC && OLCUC
307 #define MI_ENTRY(N,T,F,B,M) N "\0"
309 /* Mode names given on command line */
310 static const char mode_name[] =
311 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
312 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
313 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
314 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
315 MI_ENTRY("ek", combination, OMIT, 0, 0 )
316 MI_ENTRY("sane", combination, OMIT, 0, 0 )
317 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
318 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
319 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
320 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
321 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
322 MI_ENTRY("crt", combination, OMIT, 0, 0 )
323 MI_ENTRY("dec", combination, OMIT, 0, 0 )
325 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
328 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
330 #if XCASE && IUCLC && OLCUC
331 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
334 MI_ENTRY("parenb", control, REV, PARENB, 0 )
335 MI_ENTRY("parodd", control, REV, PARODD, 0 )
336 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
337 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
338 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
339 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
340 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
341 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
342 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
343 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
344 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
346 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
348 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
349 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
350 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
351 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
352 MI_ENTRY("inpck", input, REV, INPCK, 0 )
353 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
354 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
355 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
356 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
357 MI_ENTRY("ixon", input, REV, IXON, 0 )
358 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
359 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
361 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
364 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
367 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
370 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
372 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
374 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
377 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
380 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
383 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
386 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
389 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
392 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
395 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
396 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
399 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
400 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
401 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
402 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
406 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
408 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
411 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
413 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
416 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
421 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
422 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
425 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
426 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
429 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
430 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
432 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
433 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
435 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
437 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
438 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
439 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
440 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
441 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
442 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
444 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
447 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
450 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
451 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
454 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
455 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
458 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
459 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
464 #define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
466 static const struct mode_info mode_info[] = {
467 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
468 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
469 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
470 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
471 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
472 MI_ENTRY("ek", combination, OMIT, 0, 0 )
473 MI_ENTRY("sane", combination, OMIT, 0, 0 )
474 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
475 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
476 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
477 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
478 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
479 MI_ENTRY("crt", combination, OMIT, 0, 0 )
480 MI_ENTRY("dec", combination, OMIT, 0, 0 )
482 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
485 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
487 #if XCASE && IUCLC && OLCUC
488 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
489 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
491 MI_ENTRY("parenb", control, REV, PARENB, 0 )
492 MI_ENTRY("parodd", control, REV, PARODD, 0 )
493 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
494 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
495 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
496 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
497 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
498 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
499 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
500 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
501 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
503 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
505 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
506 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
507 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
508 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
509 MI_ENTRY("inpck", input, REV, INPCK, 0 )
510 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
511 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
512 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
513 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
514 MI_ENTRY("ixon", input, REV, IXON, 0 )
515 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
516 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
518 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
521 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
524 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
527 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
529 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
531 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
534 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
537 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
540 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
543 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
546 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
549 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
552 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
553 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
556 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
557 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
558 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
559 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
563 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
565 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
568 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
570 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
573 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
578 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
579 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
582 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
583 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
586 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
587 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
589 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
590 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
592 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
594 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
595 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
596 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
597 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
598 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
599 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
601 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
604 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
607 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
608 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
611 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
612 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
615 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
616 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
621 NUM_mode_info = ARRAY_SIZE(mode_info)
625 /* Control characters */
626 struct control_info {
627 const uint8_t saneval; /* Value to set for 'stty sane' */
628 const uint8_t offset; /* Offset in c_cc */
632 /* Must match control_name[] and control_info[] order! */
670 #define CI_ENTRY(n,s,o) n "\0"
672 /* Name given on command line */
673 static const char control_name[] =
674 CI_ENTRY("intr", CINTR, VINTR )
675 CI_ENTRY("quit", CQUIT, VQUIT )
676 CI_ENTRY("erase", CERASE, VERASE )
677 CI_ENTRY("kill", CKILL, VKILL )
678 CI_ENTRY("eof", CEOF, VEOF )
679 CI_ENTRY("eol", CEOL, VEOL )
681 CI_ENTRY("eol2", CEOL2, VEOL2 )
684 CI_ENTRY("swtch", CSWTCH, VSWTCH )
686 CI_ENTRY("start", CSTART, VSTART )
687 CI_ENTRY("stop", CSTOP, VSTOP )
688 CI_ENTRY("susp", CSUSP, VSUSP )
690 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
693 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
696 CI_ENTRY("werase", CWERASE, VWERASE )
699 CI_ENTRY("lnext", CLNEXT, VLNEXT )
702 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
705 CI_ENTRY("status", CSTATUS, VSTATUS )
707 /* These must be last because of the display routines */
708 CI_ENTRY("min", 1, VMIN )
709 CI_ENTRY("time", 0, VTIME )
713 #define CI_ENTRY(n,s,o) { s, o },
715 static const struct control_info control_info[] = {
716 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
717 CI_ENTRY("intr", CINTR, VINTR )
718 CI_ENTRY("quit", CQUIT, VQUIT )
719 CI_ENTRY("erase", CERASE, VERASE )
720 CI_ENTRY("kill", CKILL, VKILL )
721 CI_ENTRY("eof", CEOF, VEOF )
722 CI_ENTRY("eol", CEOL, VEOL )
724 CI_ENTRY("eol2", CEOL2, VEOL2 )
727 CI_ENTRY("swtch", CSWTCH, VSWTCH )
729 CI_ENTRY("start", CSTART, VSTART )
730 CI_ENTRY("stop", CSTOP, VSTOP )
731 CI_ENTRY("susp", CSUSP, VSUSP )
733 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
736 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
739 CI_ENTRY("werase", CWERASE, VWERASE )
742 CI_ENTRY("lnext", CLNEXT, VLNEXT )
745 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
748 CI_ENTRY("status", CSTATUS, VSTATUS )
750 /* These must be last because of the display routines */
751 CI_ENTRY("min", 1, VMIN )
752 CI_ENTRY("time", 0, VTIME )
756 NUM_control_info = ARRAY_SIZE(control_info)
761 const char *device_name;
762 /* The width of the screen, for output wrapping */
764 /* Current position, to know when to wrap */
765 unsigned current_col;
768 #define G (*(struct globals*)&bb_common_bufsiz1)
769 #define INIT_G() do { \
770 G.device_name = bb_msg_standard_input; \
775 /* Return a string that is the printable representation of character CH */
776 /* Adapted from 'cat' by Torbjorn Granlund */
777 static const char *visible(unsigned ch)
781 if (ch == _POSIX_VDISABLE)
793 } else if (ch < 127) {
804 static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
806 static const uint8_t tcflag_offsets[] ALIGN1 = {
807 offsetof(struct termios, c_cflag), /* control */
808 offsetof(struct termios, c_iflag), /* input */
809 offsetof(struct termios, c_oflag), /* output */
810 offsetof(struct termios, c_lflag) /* local */
814 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
819 static void set_speed_or_die(enum speed_setting type, const char *arg,
820 struct termios *mode)
824 baud = tty_value_to_baud(xatou(arg));
826 if (type != output_speed) { /* either input or both */
827 cfsetispeed(mode, baud);
829 if (type != input_speed) { /* either output or both */
830 cfsetospeed(mode, baud);
834 static NORETURN void perror_on_device_and_die(const char *fmt)
836 bb_perror_msg_and_die(fmt, G.device_name);
839 static void perror_on_device(const char *fmt)
841 bb_perror_msg(fmt, G.device_name);
844 /* Print format string MESSAGE and optional args.
845 Wrap to next line first if it won't fit.
846 Print a space first unless MESSAGE will start a new line */
847 static void wrapf(const char *message, ...)
853 va_start(args, message);
854 buflen = vsnprintf(buf, sizeof(buf), message, args);
856 /* We seem to be called only with suitable lengths, but check if
857 somebody failed to adhere to this assumption just to be sure. */
858 if (!buflen || buflen >= sizeof(buf)) return;
860 if (G.current_col > 0) {
862 if (buf[0] != '\n') {
863 if (G.current_col + buflen >= G.max_col) {
871 G.current_col += buflen;
872 if (buf[buflen-1] == '\n')
876 static void newline(void)
878 if (G.current_col != 0)
883 static void set_window_size(int rows, int cols)
885 struct winsize win = { 0, 0, 0, 0 };
887 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
888 if (errno != EINVAL) {
891 memset(&win, 0, sizeof(win));
899 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
901 perror_on_device("%s");
905 static void display_window_size(int fancy)
907 const char *fmt_str = "%s\0%s: no size information for this device";
908 unsigned width, height;
910 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
911 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
912 perror_on_device(fmt_str);
915 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
920 static const struct suffix_mult stty_suffixes[] = {
927 static const struct mode_info *find_mode(const char *name)
929 int i = index_in_strings(mode_name, name);
930 return i >= 0 ? &mode_info[i] : NULL;
933 static const struct control_info *find_control(const char *name)
935 int i = index_in_strings(control_name, name);
936 return i >= 0 ? &control_info[i] : NULL;
940 param_need_arg = 0x80,
941 param_line = 1 | 0x80,
942 param_rows = 2 | 0x80,
943 param_cols = 3 | 0x80,
944 param_columns = 4 | 0x80,
947 param_ispeed = 7 | 0x80,
948 param_ospeed = 8 | 0x80,
951 static int find_param(const char *name)
953 static const char params[] ALIGN1 =
962 int i = index_in_strings(params, name) + 1;
965 if (i != 5 && i != 6)
970 static int recover_mode(const char *arg, struct termios *mode)
974 unsigned long iflag, oflag, cflag, lflag;
976 /* Scan into temporaries since it is too much trouble to figure out
977 the right format for 'tcflag_t' */
978 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
979 &iflag, &oflag, &cflag, &lflag, &n) != 4)
981 mode->c_iflag = iflag;
982 mode->c_oflag = oflag;
983 mode->c_cflag = cflag;
984 mode->c_lflag = lflag;
986 for (i = 0; i < NCCS; ++i) {
987 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
993 /* Fail if there are too many fields */
1000 static void display_recoverable(const struct termios *mode,
1001 int UNUSED_PARAM dummy)
1004 printf("%lx:%lx:%lx:%lx",
1005 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1006 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1007 for (i = 0; i < NCCS; ++i)
1008 printf(":%x", (unsigned int) mode->c_cc[i]);
1012 static void display_speed(const struct termios *mode, int fancy)
1014 //____________________ 01234567 8 9
1015 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
1016 unsigned long ispeed, ospeed;
1018 ispeed = cfgetispeed(mode);
1019 ospeed = cfgetospeed(mode);
1020 if (ispeed == 0 || ispeed == ospeed) {
1021 ispeed = ospeed; /* in case ispeed was 0 */
1022 //________ 0123 4 5 6 7 8 9
1023 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
1025 if (fancy) fmt_str += 9;
1026 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1029 static void do_display(const struct termios *mode, int all)
1034 int prev_type = control;
1036 display_speed(mode, 1);
1038 display_window_size(1);
1040 wrapf("line = %u;\n", mode->c_line);
1045 for (i = 0; i != CIDX_min; ++i) {
1046 /* If swtch is the same as susp, don't print both */
1048 if (i == CIDX_swtch)
1051 /* If eof uses the same slot as min, only print whichever applies */
1053 if (!(mode->c_lflag & ICANON)
1054 && (i == CIDX_eof || i == CIDX_eol)
1059 wrapf("%s = %s;", nth_string(control_name, i),
1060 visible(mode->c_cc[control_info[i].offset]));
1063 if ((mode->c_lflag & ICANON) == 0)
1065 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1068 for (i = 0; i < NUM_mode_info; ++i) {
1069 if (mode_info[i].flags & OMIT)
1071 if (mode_info[i].type != prev_type) {
1073 prev_type = mode_info[i].type;
1076 bitsp = mode_type_flag(mode_info[i].type, mode);
1077 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1078 if ((*bitsp & mask) == mode_info[i].bits) {
1079 if (all || (mode_info[i].flags & SANE_UNSET))
1080 wrapf("-%s"+1, nth_string(mode_name, i));
1082 if ((all && mode_info[i].flags & REV)
1083 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1085 wrapf("-%s", nth_string(mode_name, i));
1092 static void sane_mode(struct termios *mode)
1097 for (i = 0; i < NUM_control_info; ++i) {
1102 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1105 for (i = 0; i < NUM_mode_info; ++i) {
1106 if (mode_info[i].flags & SANE_SET) {
1107 bitsp = mode_type_flag(mode_info[i].type, mode);
1108 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1109 | mode_info[i].bits;
1110 } else if (mode_info[i].flags & SANE_UNSET) {
1111 bitsp = mode_type_flag(mode_info[i].type, mode);
1112 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1113 & ~mode_info[i].bits;
1118 static void set_mode(const struct mode_info *info, int reversed,
1119 struct termios *mode)
1123 bitsp = mode_type_flag(info->type, mode);
1127 *bitsp = *bitsp & ~info->mask & ~info->bits;
1129 *bitsp = (*bitsp & ~info->mask) | info->bits;
1133 /* Combination mode */
1134 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1136 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1138 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1139 } else if (info == &mode_info[IDX_oddp]) {
1141 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1143 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1144 } else if (info == &mode_info[IDX_nl]) {
1146 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1147 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
1149 mode->c_iflag = mode->c_iflag & ~ICRNL;
1150 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1152 } else if (info == &mode_info[IDX_ek]) {
1153 mode->c_cc[VERASE] = CERASE;
1154 mode->c_cc[VKILL] = CKILL;
1155 } else if (info == &mode_info[IDX_sane]) {
1157 } else if (info == &mode_info[IDX_cbreak]) {
1159 mode->c_lflag |= ICANON;
1161 mode->c_lflag &= ~ICANON;
1162 } else if (info == &mode_info[IDX_pass8]) {
1164 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1165 mode->c_iflag |= ISTRIP;
1167 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1168 mode->c_iflag &= ~ISTRIP;
1170 } else if (info == &mode_info[IDX_litout]) {
1172 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1173 mode->c_iflag |= ISTRIP;
1174 mode->c_oflag |= OPOST;
1176 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1177 mode->c_iflag &= ~ISTRIP;
1178 mode->c_oflag &= ~OPOST;
1180 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
1181 if ((info == &mode_info[IDX_raw] && reversed)
1182 || (info == &mode_info[IDX_cooked] && !reversed)
1185 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1186 mode->c_oflag |= OPOST;
1187 mode->c_lflag |= ISIG | ICANON;
1189 mode->c_cc[VEOF] = CEOF;
1192 mode->c_cc[VEOL] = CEOL;
1197 mode->c_oflag &= ~OPOST;
1198 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1199 mode->c_cc[VMIN] = 1;
1200 mode->c_cc[VTIME] = 0;
1204 else if (info == &mode_info[IDX_decctlq]) {
1206 mode->c_iflag |= IXANY;
1208 mode->c_iflag &= ~IXANY;
1212 else if (info == &mode_info[IDX_tabs]) {
1214 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1216 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1220 else if (info == &mode_info[IDX_tabs]) {
1222 mode->c_oflag |= OXTABS;
1224 mode->c_oflag &= ~OXTABS;
1227 #if XCASE && IUCLC && OLCUC
1228 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
1230 mode->c_lflag &= ~XCASE;
1231 mode->c_iflag &= ~IUCLC;
1232 mode->c_oflag &= ~OLCUC;
1234 mode->c_lflag |= XCASE;
1235 mode->c_iflag |= IUCLC;
1236 mode->c_oflag |= OLCUC;
1240 else if (info == &mode_info[IDX_crt]) {
1241 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1242 } else if (info == &mode_info[IDX_dec]) {
1243 mode->c_cc[VINTR] = 3; /* ^C */
1244 mode->c_cc[VERASE] = 127; /* DEL */
1245 mode->c_cc[VKILL] = 21; /* ^U */
1246 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1247 if (IXANY) mode->c_iflag &= ~IXANY;
1251 static void set_control_char_or_die(const struct control_info *info,
1252 const char *arg, struct termios *mode)
1254 unsigned char value;
1256 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
1257 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1258 else if (arg[0] == '\0' || arg[1] == '\0')
1260 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
1261 value = _POSIX_VDISABLE;
1262 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1263 value = arg[1] & 0x1f; /* Non-letters get weird results */
1267 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1268 mode->c_cc[info->offset] = value;
1271 #define STTY_require_set_attr (1 << 0)
1272 #define STTY_speed_was_set (1 << 1)
1273 #define STTY_verbose_output (1 << 2)
1274 #define STTY_recoverable_output (1 << 3)
1275 #define STTY_noargs (1 << 4)
1277 int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1278 int stty_main(int argc UNUSED_PARAM, char **argv)
1280 struct termios mode;
1281 void (*output_func)(const struct termios *, int);
1282 const char *file_name = NULL;
1283 int display_all = 0;
1289 stty_state = STTY_noargs;
1290 output_func = do_display;
1292 /* First pass: only parse/verify command line params */
1295 const struct mode_info *mp;
1296 const struct control_info *cp;
1297 const char *arg = argv[k];
1298 const char *argnext = argv[k+1];
1301 if (arg[0] == '-') {
1303 mp = find_mode(arg+1);
1305 if (!(mp->flags & REV))
1306 goto invalid_argument;
1307 stty_state &= ~STTY_noargs;
1310 /* It is an option - parse it */
1315 stty_state |= STTY_verbose_output;
1316 output_func = do_display;
1320 stty_state |= STTY_recoverable_output;
1321 output_func = display_recoverable;
1325 bb_error_msg_and_die("only one device may be specified");
1326 file_name = &arg[i+1]; /* "-Fdevice" ? */
1327 if (!file_name[0]) { /* nope, "-F device" */
1328 int p = k+1; /* argv[p] is argnext */
1329 file_name = argnext;
1331 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1332 /* remove -F param from arg[vc] */
1334 argv[p] = argv[p+1];
1340 goto invalid_argument;
1347 mp = find_mode(arg);
1349 stty_state &= ~STTY_noargs;
1353 cp = find_control(arg);
1356 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1357 /* called for the side effect of xfunc death only */
1358 set_control_char_or_die(cp, argnext, &mode);
1359 stty_state &= ~STTY_noargs;
1364 param = find_param(arg);
1365 if (param & param_need_arg) {
1367 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1375 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1377 # endif /* else fall-through */
1383 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1390 /* called for the side effect of xfunc death only */
1391 set_speed_or_die(input_speed, argnext, &mode);
1394 /* called for the side effect of xfunc death only */
1395 set_speed_or_die(output_speed, argnext, &mode);
1398 if (recover_mode(arg, &mode) == 1) break;
1399 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1401 bb_error_msg_and_die("invalid argument '%s'", arg);
1403 stty_state &= ~STTY_noargs;
1406 /* Specifying both -a and -g is an error */
1407 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1408 (STTY_verbose_output | STTY_recoverable_output))
1409 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1410 /* Specifying -a or -g with non-options is an error */
1411 if (!(stty_state & STTY_noargs)
1412 && (stty_state & (STTY_verbose_output | STTY_recoverable_output))
1414 bb_error_msg_and_die("modes may not be set when specifying an output style");
1417 /* Now it is safe to start doing things */
1419 G.device_name = file_name;
1420 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1421 ndelay_off(STDIN_FILENO);
1424 /* Initialize to all zeroes so there is no risk memcmp will report a
1425 spurious difference in an uninitialized portion of the structure */
1426 memset(&mode, 0, sizeof(mode));
1427 if (tcgetattr(STDIN_FILENO, &mode))
1428 perror_on_device_and_die("%s");
1430 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
1431 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
1432 output_func(&mode, display_all);
1433 return EXIT_SUCCESS;
1436 /* Second pass: perform actions */
1439 const struct mode_info *mp;
1440 const struct control_info *cp;
1441 const char *arg = argv[k];
1442 const char *argnext = argv[k+1];
1445 if (arg[0] == '-') {
1446 mp = find_mode(arg+1);
1448 set_mode(mp, 1 /* reversed */, &mode);
1449 stty_state |= STTY_require_set_attr;
1451 /* It is an option - already parsed. Skip it */
1455 mp = find_mode(arg);
1457 set_mode(mp, 0 /* non-reversed */, &mode);
1458 stty_state |= STTY_require_set_attr;
1462 cp = find_control(arg);
1465 set_control_char_or_die(cp, argnext, &mode);
1466 stty_state |= STTY_require_set_attr;
1470 param = find_param(arg);
1471 if (param & param_need_arg) {
1478 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
1479 stty_state |= STTY_require_set_attr;
1485 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
1488 display_window_size(0);
1491 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1495 display_speed(&mode, 0);
1498 set_speed_or_die(input_speed, argnext, &mode);
1499 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1502 set_speed_or_die(output_speed, argnext, &mode);
1503 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1506 if (recover_mode(arg, &mode) == 1)
1507 stty_state |= STTY_require_set_attr;
1508 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
1509 set_speed_or_die(both_speeds, arg, &mode);
1510 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1511 } /* else - impossible (caught in the first pass):
1512 bb_error_msg_and_die("invalid argument '%s'", arg); */
1516 if (stty_state & STTY_require_set_attr) {
1517 struct termios new_mode;
1519 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1520 perror_on_device_and_die("%s");
1522 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1523 it performs *any* of the requested operations. This means it
1524 can report 'success' when it has actually failed to perform
1525 some proper subset of the requested operations. To detect
1526 this partial failure, get the current terminal attributes and
1527 compare them to the requested ones */
1529 /* Initialize to all zeroes so there is no risk memcmp will report a
1530 spurious difference in an uninitialized portion of the structure */
1531 memset(&new_mode, 0, sizeof(new_mode));
1532 if (tcgetattr(STDIN_FILENO, &new_mode))
1533 perror_on_device_and_die("%s");
1535 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1537 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1538 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1539 sometimes (m1 != m2). The only difference is in the four bits
1540 of the c_cflag field corresponding to the baud rate. To save
1541 Sun users a little confusion, don't report an error if this
1542 happens. But suppress the error only if we haven't tried to
1543 set the baud rate explicitly -- otherwise we'd never give an
1544 error for a true failure to set the baud rate */
1546 new_mode.c_cflag &= (~CIBAUD);
1547 if ((stty_state & STTY_speed_was_set)
1548 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
1550 perror_on_device_and_die("%s: cannot perform all requested operations");
1554 return EXIT_SUCCESS;