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 #ifndef _POSIX_VDISABLE
27 # define _POSIX_VDISABLE ((unsigned char) 0)
30 #define Control(c) ((c) & 0x1f)
31 /* Canonical values for control characters */
33 # define CINTR Control('c')
42 # define CKILL Control('u')
45 # define CEOF Control('d')
48 # define CEOL _POSIX_VDISABLE
51 # define CSTART Control('q')
54 # define CSTOP Control('s')
57 # define CSUSP Control('z')
59 #if defined(VEOL2) && !defined(CEOL2)
60 # define CEOL2 _POSIX_VDISABLE
62 /* ISC renamed swtch to susp for termios, but we'll accept either name */
63 #if defined(VSUSP) && !defined(VSWTCH)
67 #if defined(VSWTCH) && !defined(CSWTCH)
68 # define CSWTCH _POSIX_VDISABLE
71 /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
72 So the default is to disable 'swtch.' */
73 #if defined(__sparc__) && defined(__svr4__)
75 # define CSWTCH _POSIX_VDISABLE
78 #if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
79 # define VWERASE VWERSE
81 #if defined(VDSUSP) && !defined(CDSUSP)
82 # define CDSUSP Control('y')
84 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
85 # define VREPRINT VRPRNT
87 #if defined(VREPRINT) && !defined(CRPRNT)
88 # define CRPRNT Control('r')
90 #if defined(VWERASE) && !defined(CWERASE)
91 # define CWERASE Control('w')
93 #if defined(VLNEXT) && !defined(CLNEXT)
94 # define CLNEXT Control('v')
96 #if defined(VDISCARD) && !defined(VFLUSHO)
97 # define VFLUSHO VDISCARD
99 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
100 # define VFLUSHO VFLUSH
102 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
103 # define ECHOCTL CTLECH
105 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
106 # define ECHOCTL TCTLECH
108 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
109 # define ECHOKE CRTKIL
111 #if defined(VFLUSHO) && !defined(CFLUSHO)
112 # define CFLUSHO Control('o')
114 #if defined(VSTATUS) && !defined(CSTATUS)
115 # define CSTATUS Control('t')
118 /* Which speeds to set */
120 input_speed, output_speed, both_speeds
123 /* Which member(s) of 'struct termios' a mode uses */
125 /* Do NOT change the order or values, as mode_type_flag()
127 control, input, output, local, combination
130 /* Flags for 'struct mode_info' */
131 #define SANE_SET 1 /* Set in 'sane' mode */
132 #define SANE_UNSET 2 /* Unset in 'sane' mode */
133 #define REV 4 /* Can be turned off by prepending '-' */
134 #define OMIT 8 /* Don't display value */
138 * This structure should be kept as small as humanly possible.
141 const uint8_t type; /* Which structure element to change */
142 const uint8_t flags; /* Setting and display options */
143 /* only these values are ever used, so... */
144 #if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
146 #elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
149 const tcflag_t mask; /* Other bits to turn off for this mode */
151 /* was using short here, but ppc32 was unhappy */
152 const tcflag_t bits; /* Bits to set for this mode */
156 /* Must match mode_name[] and mode_info[] order! */
173 #if defined(TABDLY) || defined(OXTABS)
176 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
182 #define MI_ENTRY(N,T,F,B,M) N "\0"
184 /* Mode names given on command line */
185 static const char mode_name[] =
186 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
187 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
188 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
189 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
190 MI_ENTRY("ek", combination, OMIT, 0, 0 )
191 MI_ENTRY("sane", combination, OMIT, 0, 0 )
192 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
193 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
194 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
195 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
196 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
197 MI_ENTRY("crt", combination, OMIT, 0, 0 )
198 MI_ENTRY("dec", combination, OMIT, 0, 0 )
200 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
202 #if defined(TABDLY) || defined(OXTABS)
203 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
205 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
206 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
207 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
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 )
332 #define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
334 static const struct mode_info mode_info[] = {
335 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
336 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
337 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
338 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
339 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
340 MI_ENTRY("ek", combination, OMIT, 0, 0 )
341 MI_ENTRY("sane", combination, OMIT, 0, 0 )
342 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
343 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
344 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
345 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
346 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
347 MI_ENTRY("crt", combination, OMIT, 0, 0 )
348 MI_ENTRY("dec", combination, OMIT, 0, 0 )
350 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
352 #if defined(TABDLY) || defined(OXTABS)
353 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
355 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
356 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
357 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
359 MI_ENTRY("parenb", control, REV, PARENB, 0 )
360 MI_ENTRY("parodd", control, REV, PARODD, 0 )
361 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
362 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
363 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
364 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
365 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
366 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
367 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
368 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
369 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
371 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
373 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
374 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
375 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
376 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
377 MI_ENTRY("inpck", input, REV, INPCK, 0 )
378 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
379 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
380 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
381 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
382 MI_ENTRY("ixon", input, REV, IXON, 0 )
383 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
384 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
386 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
389 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
392 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
394 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
396 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
399 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
402 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
405 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
408 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
411 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
414 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
417 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
418 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
421 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
422 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
423 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
424 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
428 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
429 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
430 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
431 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
434 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
439 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
440 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
443 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
444 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
447 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
448 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
450 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
451 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
453 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
455 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
456 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
457 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
458 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
459 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
460 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
462 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
465 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
468 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
469 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
472 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
473 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
476 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
477 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
482 NUM_mode_info = ARRAY_SIZE(mode_info)
486 /* Control characters */
487 struct control_info {
488 const uint8_t saneval; /* Value to set for 'stty sane' */
489 const uint8_t offset; /* Offset in c_cc */
493 /* Must match control_name[] and control_info[] order! */
531 #define CI_ENTRY(n,s,o) n "\0"
533 /* Name given on command line */
534 static const char control_name[] =
535 CI_ENTRY("intr", CINTR, VINTR )
536 CI_ENTRY("quit", CQUIT, VQUIT )
537 CI_ENTRY("erase", CERASE, VERASE )
538 CI_ENTRY("kill", CKILL, VKILL )
539 CI_ENTRY("eof", CEOF, VEOF )
540 CI_ENTRY("eol", CEOL, VEOL )
542 CI_ENTRY("eol2", CEOL2, VEOL2 )
545 CI_ENTRY("swtch", CSWTCH, VSWTCH )
547 CI_ENTRY("start", CSTART, VSTART )
548 CI_ENTRY("stop", CSTOP, VSTOP )
549 CI_ENTRY("susp", CSUSP, VSUSP )
551 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
554 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
557 CI_ENTRY("werase", CWERASE, VWERASE )
560 CI_ENTRY("lnext", CLNEXT, VLNEXT )
563 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
566 CI_ENTRY("status", CSTATUS, VSTATUS )
568 /* These must be last because of the display routines */
569 CI_ENTRY("min", 1, VMIN )
570 CI_ENTRY("time", 0, VTIME )
574 #define CI_ENTRY(n,s,o) { s, o },
576 static const struct control_info control_info[] = {
577 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
578 CI_ENTRY("intr", CINTR, VINTR )
579 CI_ENTRY("quit", CQUIT, VQUIT )
580 CI_ENTRY("erase", CERASE, VERASE )
581 CI_ENTRY("kill", CKILL, VKILL )
582 CI_ENTRY("eof", CEOF, VEOF )
583 CI_ENTRY("eol", CEOL, VEOL )
585 CI_ENTRY("eol2", CEOL2, VEOL2 )
588 CI_ENTRY("swtch", CSWTCH, VSWTCH )
590 CI_ENTRY("start", CSTART, VSTART )
591 CI_ENTRY("stop", CSTOP, VSTOP )
592 CI_ENTRY("susp", CSUSP, VSUSP )
594 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
597 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
600 CI_ENTRY("werase", CWERASE, VWERASE )
603 CI_ENTRY("lnext", CLNEXT, VLNEXT )
606 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
609 CI_ENTRY("status", CSTATUS, VSTATUS )
611 /* These must be last because of the display routines */
612 CI_ENTRY("min", 1, VMIN )
613 CI_ENTRY("time", 0, VTIME )
617 NUM_control_info = ARRAY_SIZE(control_info)
622 const char *device_name;
623 /* The width of the screen, for output wrapping */
625 /* Current position, to know when to wrap */
626 unsigned current_col;
629 #define G (*(struct globals*)&bb_common_bufsiz1)
630 #define INIT_G() do { \
631 G.device_name = bb_msg_standard_input; \
636 /* Return a string that is the printable representation of character CH */
637 /* Adapted from 'cat' by Torbjorn Granlund */
638 static const char *visible(unsigned ch)
642 if (ch == _POSIX_VDISABLE)
654 } else if (ch < 127) {
665 static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
667 static const uint8_t tcflag_offsets[] ALIGN1 = {
668 offsetof(struct termios, c_cflag), /* control */
669 offsetof(struct termios, c_iflag), /* input */
670 offsetof(struct termios, c_oflag), /* output */
671 offsetof(struct termios, c_lflag) /* local */
675 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
680 static void set_speed_or_die(enum speed_setting type, const char *arg,
681 struct termios *mode)
685 baud = tty_value_to_baud(xatou(arg));
687 if (type != output_speed) { /* either input or both */
688 cfsetispeed(mode, baud);
690 if (type != input_speed) { /* either output or both */
691 cfsetospeed(mode, baud);
695 static NORETURN void perror_on_device_and_die(const char *fmt)
697 bb_perror_msg_and_die(fmt, G.device_name);
700 static void perror_on_device(const char *fmt)
702 bb_perror_msg(fmt, G.device_name);
705 /* Print format string MESSAGE and optional args.
706 Wrap to next line first if it won't fit.
707 Print a space first unless MESSAGE will start a new line */
708 static void wrapf(const char *message, ...)
714 va_start(args, message);
715 buflen = vsnprintf(buf, sizeof(buf), message, args);
717 /* We seem to be called only with suitable lengths, but check if
718 somebody failed to adhere to this assumption just to be sure. */
719 if (!buflen || buflen >= sizeof(buf)) return;
721 if (G.current_col > 0) {
723 if (buf[0] != '\n') {
724 if (G.current_col + buflen >= G.max_col) {
732 G.current_col += buflen;
733 if (buf[buflen-1] == '\n')
737 static void newline(void)
739 if (G.current_col != 0)
743 static void set_window_size(int rows, int cols)
745 struct winsize win = { 0, 0, 0, 0 };
747 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
748 if (errno != EINVAL) {
751 memset(&win, 0, sizeof(win));
759 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
761 perror_on_device("%s");
764 static void display_window_size(int fancy)
766 const char *fmt_str = "%s\0%s: no size information for this device";
767 unsigned width, height;
769 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
770 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
771 perror_on_device(fmt_str);
774 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
779 static const struct suffix_mult stty_suffixes[] = {
786 static const struct mode_info *find_mode(const char *name)
788 int i = index_in_strings(mode_name, name);
789 return i >= 0 ? &mode_info[i] : NULL;
792 static const struct control_info *find_control(const char *name)
794 int i = index_in_strings(control_name, name);
795 return i >= 0 ? &control_info[i] : NULL;
799 param_need_arg = 0x80,
800 param_line = 1 | 0x80,
801 param_rows = 2 | 0x80,
802 param_cols = 3 | 0x80,
803 param_columns = 4 | 0x80,
806 param_ispeed = 7 | 0x80,
807 param_ospeed = 8 | 0x80,
810 static int find_param(const char *name)
812 static const char params[] ALIGN1 =
821 int i = index_in_strings(params, name) + 1;
824 if (i != 5 && i != 6)
829 static int recover_mode(const char *arg, struct termios *mode)
833 unsigned long iflag, oflag, cflag, lflag;
835 /* Scan into temporaries since it is too much trouble to figure out
836 the right format for 'tcflag_t' */
837 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
838 &iflag, &oflag, &cflag, &lflag, &n) != 4)
840 mode->c_iflag = iflag;
841 mode->c_oflag = oflag;
842 mode->c_cflag = cflag;
843 mode->c_lflag = lflag;
845 for (i = 0; i < NCCS; ++i) {
846 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
852 /* Fail if there are too many fields */
859 static void display_recoverable(const struct termios *mode,
860 int UNUSED_PARAM dummy)
863 printf("%lx:%lx:%lx:%lx",
864 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
865 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
866 for (i = 0; i < NCCS; ++i)
867 printf(":%x", (unsigned int) mode->c_cc[i]);
871 static void display_speed(const struct termios *mode, int fancy)
873 //____________________ 01234567 8 9
874 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
875 unsigned long ispeed, ospeed;
877 ospeed = ispeed = cfgetispeed(mode);
878 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
879 ispeed = ospeed; /* in case ispeed was 0 */
880 //________ 0123 4 5 6 7 8 9
881 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
883 if (fancy) fmt_str += 9;
884 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
887 static void do_display(const struct termios *mode, int all)
892 int prev_type = control;
894 display_speed(mode, 1);
896 display_window_size(1);
898 wrapf("line = %u;\n", mode->c_line);
903 for (i = 0; i != CIDX_min; ++i) {
904 /* If swtch is the same as susp, don't print both */
909 /* If eof uses the same slot as min, only print whichever applies */
911 if (!(mode->c_lflag & ICANON)
912 && (i == CIDX_eof || i == CIDX_eol)
917 wrapf("%s = %s;", nth_string(control_name, i),
918 visible(mode->c_cc[control_info[i].offset]));
921 if ((mode->c_lflag & ICANON) == 0)
923 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
926 for (i = 0; i < NUM_mode_info; ++i) {
927 if (mode_info[i].flags & OMIT)
929 if (mode_info[i].type != prev_type) {
931 prev_type = mode_info[i].type;
934 bitsp = mode_type_flag(mode_info[i].type, mode);
935 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
936 if ((*bitsp & mask) == mode_info[i].bits) {
937 if (all || (mode_info[i].flags & SANE_UNSET))
938 wrapf("-%s"+1, nth_string(mode_name, i));
940 if ((all && mode_info[i].flags & REV)
941 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
943 wrapf("-%s", nth_string(mode_name, i));
950 static void sane_mode(struct termios *mode)
955 for (i = 0; i < NUM_control_info; ++i) {
960 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
963 for (i = 0; i < NUM_mode_info; ++i) {
964 if (mode_info[i].flags & SANE_SET) {
965 bitsp = mode_type_flag(mode_info[i].type, mode);
966 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
968 } else if (mode_info[i].flags & SANE_UNSET) {
969 bitsp = mode_type_flag(mode_info[i].type, mode);
970 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
971 & ~mode_info[i].bits;
976 /* Save set_mode from #ifdef forest plague */
1011 static void set_mode(const struct mode_info *info, int reversed,
1012 struct termios *mode)
1016 bitsp = mode_type_flag(info->type, mode);
1020 *bitsp = *bitsp & ~info->mask & ~info->bits;
1022 *bitsp = (*bitsp & ~info->mask) | info->bits;
1026 /* Combination mode */
1027 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1029 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1031 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1032 } else if (info == &mode_info[IDX_oddp]) {
1034 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1036 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1037 } else if (info == &mode_info[IDX_nl]) {
1039 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1040 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
1042 mode->c_iflag = mode->c_iflag & ~ICRNL;
1043 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1045 } else if (info == &mode_info[IDX_ek]) {
1046 mode->c_cc[VERASE] = CERASE;
1047 mode->c_cc[VKILL] = CKILL;
1048 } else if (info == &mode_info[IDX_sane]) {
1050 } else if (info == &mode_info[IDX_cbreak]) {
1052 mode->c_lflag |= ICANON;
1054 mode->c_lflag &= ~ICANON;
1055 } else if (info == &mode_info[IDX_pass8]) {
1057 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1058 mode->c_iflag |= ISTRIP;
1060 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1061 mode->c_iflag &= ~ISTRIP;
1063 } else if (info == &mode_info[IDX_litout]) {
1065 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1066 mode->c_iflag |= ISTRIP;
1067 mode->c_oflag |= OPOST;
1069 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1070 mode->c_iflag &= ~ISTRIP;
1071 mode->c_oflag &= ~OPOST;
1073 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
1074 if ((info == &mode_info[IDX_raw] && reversed)
1075 || (info == &mode_info[IDX_cooked] && !reversed)
1078 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1079 mode->c_oflag |= OPOST;
1080 mode->c_lflag |= ISIG | ICANON;
1082 mode->c_cc[VEOF] = CEOF;
1085 mode->c_cc[VEOL] = CEOL;
1090 mode->c_oflag &= ~OPOST;
1091 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1092 mode->c_cc[VMIN] = 1;
1093 mode->c_cc[VTIME] = 0;
1096 else if (IXANY && info == &mode_info[IDX_decctlq]) {
1098 mode->c_iflag |= IXANY;
1100 mode->c_iflag &= ~IXANY;
1102 else if (TABDLY && info == &mode_info[IDX_tabs]) {
1104 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1106 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1108 else if (OXTABS && info == &mode_info[IDX_tabs]) {
1110 mode->c_oflag |= OXTABS;
1112 mode->c_oflag &= ~OXTABS;
1114 if (XCASE && IUCLC && OLCUC
1115 && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE])
1118 mode->c_lflag &= ~XCASE;
1119 mode->c_iflag &= ~IUCLC;
1120 mode->c_oflag &= ~OLCUC;
1122 mode->c_lflag |= XCASE;
1123 mode->c_iflag |= IUCLC;
1124 mode->c_oflag |= OLCUC;
1126 } else if (info == &mode_info[IDX_crt]) {
1127 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1128 } else if (info == &mode_info[IDX_dec]) {
1129 mode->c_cc[VINTR] = 3; /* ^C */
1130 mode->c_cc[VERASE] = 127; /* DEL */
1131 mode->c_cc[VKILL] = 21; /* ^U */
1132 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1133 if (IXANY) mode->c_iflag &= ~IXANY;
1137 static void set_control_char_or_die(const struct control_info *info,
1138 const char *arg, struct termios *mode)
1140 unsigned char value;
1142 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
1143 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1144 else if (arg[0] == '\0' || arg[1] == '\0')
1146 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
1147 value = _POSIX_VDISABLE;
1148 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1149 value = arg[1] & 0x1f; /* Non-letters get weird results */
1153 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1154 mode->c_cc[info->offset] = value;
1157 #define STTY_require_set_attr (1 << 0)
1158 #define STTY_speed_was_set (1 << 1)
1159 #define STTY_verbose_output (1 << 2)
1160 #define STTY_recoverable_output (1 << 3)
1161 #define STTY_noargs (1 << 4)
1163 int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1164 int stty_main(int argc UNUSED_PARAM, char **argv)
1166 struct termios mode;
1167 void (*output_func)(const struct termios *, int);
1168 const char *file_name = NULL;
1169 int display_all = 0;
1175 stty_state = STTY_noargs;
1176 output_func = do_display;
1178 /* First pass: only parse/verify command line params */
1181 const struct mode_info *mp;
1182 const struct control_info *cp;
1183 const char *arg = argv[k];
1184 const char *argnext = argv[k+1];
1187 if (arg[0] == '-') {
1189 mp = find_mode(arg+1);
1191 if (!(mp->flags & REV))
1192 goto invalid_argument;
1193 stty_state &= ~STTY_noargs;
1196 /* It is an option - parse it */
1201 stty_state |= STTY_verbose_output;
1202 output_func = do_display;
1206 stty_state |= STTY_recoverable_output;
1207 output_func = display_recoverable;
1211 bb_error_msg_and_die("only one device may be specified");
1212 file_name = &arg[i+1]; /* "-Fdevice" ? */
1213 if (!file_name[0]) { /* nope, "-F device" */
1214 int p = k+1; /* argv[p] is argnext */
1215 file_name = argnext;
1217 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1218 /* remove -F param from arg[vc] */
1220 argv[p] = argv[p+1];
1226 goto invalid_argument;
1233 mp = find_mode(arg);
1235 stty_state &= ~STTY_noargs;
1239 cp = find_control(arg);
1242 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1243 /* called for the side effect of xfunc death only */
1244 set_control_char_or_die(cp, argnext, &mode);
1245 stty_state &= ~STTY_noargs;
1250 param = find_param(arg);
1251 if (param & param_need_arg) {
1253 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1261 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1263 # endif /* else fall-through */
1269 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1276 /* called for the side effect of xfunc death only */
1277 set_speed_or_die(input_speed, argnext, &mode);
1280 /* called for the side effect of xfunc death only */
1281 set_speed_or_die(output_speed, argnext, &mode);
1284 if (recover_mode(arg, &mode) == 1) break;
1285 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1287 bb_error_msg_and_die("invalid argument '%s'", arg);
1289 stty_state &= ~STTY_noargs;
1292 /* Specifying both -a and -g is an error */
1293 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1294 (STTY_verbose_output | STTY_recoverable_output))
1295 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1296 /* Specifying -a or -g with non-options is an error */
1297 if (!(stty_state & STTY_noargs)
1298 && (stty_state & (STTY_verbose_output | STTY_recoverable_output))
1300 bb_error_msg_and_die("modes may not be set when specifying an output style");
1303 /* Now it is safe to start doing things */
1305 G.device_name = file_name;
1306 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1307 ndelay_off(STDIN_FILENO);
1310 /* Initialize to all zeroes so there is no risk memcmp will report a
1311 spurious difference in an uninitialized portion of the structure */
1312 memset(&mode, 0, sizeof(mode));
1313 if (tcgetattr(STDIN_FILENO, &mode))
1314 perror_on_device_and_die("%s");
1316 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
1317 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
1318 output_func(&mode, display_all);
1319 return EXIT_SUCCESS;
1322 /* Second pass: perform actions */
1325 const struct mode_info *mp;
1326 const struct control_info *cp;
1327 const char *arg = argv[k];
1328 const char *argnext = argv[k+1];
1331 if (arg[0] == '-') {
1332 mp = find_mode(arg+1);
1334 set_mode(mp, 1 /* reversed */, &mode);
1335 stty_state |= STTY_require_set_attr;
1337 /* It is an option - already parsed. Skip it */
1341 mp = find_mode(arg);
1343 set_mode(mp, 0 /* non-reversed */, &mode);
1344 stty_state |= STTY_require_set_attr;
1348 cp = find_control(arg);
1351 set_control_char_or_die(cp, argnext, &mode);
1352 stty_state |= STTY_require_set_attr;
1356 param = find_param(arg);
1357 if (param & param_need_arg) {
1364 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
1365 stty_state |= STTY_require_set_attr;
1371 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
1374 display_window_size(0);
1377 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1381 display_speed(&mode, 0);
1384 set_speed_or_die(input_speed, argnext, &mode);
1385 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1388 set_speed_or_die(output_speed, argnext, &mode);
1389 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1392 if (recover_mode(arg, &mode) == 1)
1393 stty_state |= STTY_require_set_attr;
1394 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
1395 set_speed_or_die(both_speeds, arg, &mode);
1396 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1397 } /* else - impossible (caught in the first pass):
1398 bb_error_msg_and_die("invalid argument '%s'", arg); */
1402 if (stty_state & STTY_require_set_attr) {
1403 struct termios new_mode;
1405 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1406 perror_on_device_and_die("%s");
1408 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1409 it performs *any* of the requested operations. This means it
1410 can report 'success' when it has actually failed to perform
1411 some proper subset of the requested operations. To detect
1412 this partial failure, get the current terminal attributes and
1413 compare them to the requested ones */
1415 /* Initialize to all zeroes so there is no risk memcmp will report a
1416 spurious difference in an uninitialized portion of the structure */
1417 memset(&new_mode, 0, sizeof(new_mode));
1418 if (tcgetattr(STDIN_FILENO, &new_mode))
1419 perror_on_device_and_die("%s");
1421 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1423 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1424 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1425 sometimes (m1 != m2). The only difference is in the four bits
1426 of the c_cflag field corresponding to the baud rate. To save
1427 Sun users a little confusion, don't report an error if this
1428 happens. But suppress the error only if we haven't tried to
1429 set the baud rate explicitly -- otherwise we'd never give an
1430 error for a true failure to set the baud rate */
1432 new_mode.c_cflag &= (~CIBAUD);
1433 if ((stty_state & STTY_speed_was_set)
1434 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
1436 perror_on_device_and_die("%s: cannot perform all requested operations");
1440 return EXIT_SUCCESS;