blob: 7493192e9c855f2dad0300290ee4e584da36a33f [file] [log] [blame]
Eric Andersen98e599c2001-02-14 18:47:33 +00001/* vi: set sw=4 ts=4: */
2/* stty -- change and print terminal line settings
3 Copyright (C) 1990-1999 Free Software Foundation, Inc.
4
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00005 Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
6*/
Eric Andersen98e599c2001-02-14 18:47:33 +00007/* Usage: stty [-ag] [-F device] [setting...]
8
9 Options:
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
13
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.
17
18 David MacKenzie <djm@gnu.ai.mit.edu>
19
Eric Andersen7467c8d2001-07-12 20:26:32 +000020 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
Eric Andersen98e599c2001-02-14 18:47:33 +000021
22 */
23
Bernhard Reutner-Fischer19008b82006-06-07 20:17:41 +000024#include "busybox.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000025
Eric Andersen98e599c2001-02-14 18:47:33 +000026#ifndef _POSIX_VDISABLE
27# define _POSIX_VDISABLE ((unsigned char) 0)
28#endif
29
30#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000031/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000032#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000033# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000034#endif
35#ifndef CQUIT
36# define CQUIT 28
37#endif
38#ifndef CERASE
39# define CERASE 127
40#endif
41#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000042# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000043#endif
44#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000045# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000046#endif
47#ifndef CEOL
48# define CEOL _POSIX_VDISABLE
49#endif
50#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000051# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000052#endif
53#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000054# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000055#endif
56#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000057# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000058#endif
59#if defined(VEOL2) && !defined(CEOL2)
60# define CEOL2 _POSIX_VDISABLE
61#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000062/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000063#if defined(VSUSP) && !defined(VSWTCH)
64# define VSWTCH VSUSP
65# define CSWTCH CSUSP
66#endif
67#if defined(VSWTCH) && !defined(CSWTCH)
68# define CSWTCH _POSIX_VDISABLE
69#endif
70
Denis Vlasenko79deb662006-09-19 15:12:12 +000071/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
72 So the default is to disable 'swtch.' */
Eric Andersen98e599c2001-02-14 18:47:33 +000073#if defined (__sparc__) && defined (__svr4__)
74# undef CSWTCH
75# define CSWTCH _POSIX_VDISABLE
76#endif
77
Mark Whitley446dd272001-03-02 20:00:54 +000078#if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000079# define VWERASE VWERSE
80#endif
81#if defined(VDSUSP) && !defined (CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000082# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +000083#endif
Mark Whitley446dd272001-03-02 20:00:54 +000084#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000085# define VREPRINT VRPRNT
86#endif
87#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000088# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +000089#endif
90#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000091# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +000092#endif
93#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000094# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +000095#endif
96#if defined(VDISCARD) && !defined(VFLUSHO)
97# define VFLUSHO VDISCARD
98#endif
Mark Whitley446dd272001-03-02 20:00:54 +000099#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000100# define VFLUSHO VFLUSH
101#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000102#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000103# define ECHOCTL CTLECH
104#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000105#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000106# define ECHOCTL TCTLECH
107#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000108#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000109# define ECHOKE CRTKIL
110#endif
111#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000112# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000113#endif
114#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000115# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000116#endif
117
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000118/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000119enum speed_setting {
120 input_speed, output_speed, both_speeds
121};
122
Denis Vlasenko79deb662006-09-19 15:12:12 +0000123/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000124enum {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000125 /* Do NOT change the order or values, as mode_type_flag()
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000126 * depends on them */
Eric Andersen98e599c2001-02-14 18:47:33 +0000127 control, input, output, local, combination
128};
129
Mark Whitley446dd272001-03-02 20:00:54 +0000130static const char evenp [] = "evenp";
131static const char raw [] = "raw";
132static const char stty_min [] = "min";
133static const char stty_time [] = "time";
Eric Andersen98e599c2001-02-14 18:47:33 +0000134static const char stty_swtch[] = "swtch";
Mark Whitley446dd272001-03-02 20:00:54 +0000135static const char stty_eol [] = "eol";
136static const char stty_eof [] = "eof";
137static const char parity [] = "parity";
138static const char stty_oddp [] = "oddp";
139static const char stty_nl [] = "nl";
140static const char stty_ek [] = "ek";
141static const char stty_sane [] = "sane";
142static const char cbreak [] = "cbreak";
Eric Andersen98e599c2001-02-14 18:47:33 +0000143static const char stty_pass8[] = "pass8";
Mark Whitley446dd272001-03-02 20:00:54 +0000144static const char litout [] = "litout";
145static const char cooked [] = "cooked";
146static const char decctlq [] = "decctlq";
147static const char stty_tabs [] = "tabs";
Eric Andersen98e599c2001-02-14 18:47:33 +0000148static const char stty_lcase[] = "lcase";
149static const char stty_LCASE[] = "LCASE";
Mark Whitley446dd272001-03-02 20:00:54 +0000150static const char stty_crt [] = "crt";
151static const char stty_dec [] = "dec";
Eric Andersen98e599c2001-02-14 18:47:33 +0000152
Denis Vlasenko79deb662006-09-19 15:12:12 +0000153/* Flags for 'struct mode_info' */
154#define SANE_SET 1 /* Set in 'sane' mode */
155#define SANE_UNSET 2 /* Unset in 'sane' mode */
156#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000157#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000158
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000159/* Each mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000160struct mode_info {
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000161 const char * const name; /* Name given on command line */
162 const unsigned char type; /* Which structure element to change */
163 const unsigned char flags; /* Setting and display options */
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000164 /* were using short here, but ppc32 was unhappy: */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000165 const tcflag_t mask; /* Other bits to turn off for this mode */
166 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000167};
168
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000169/* We can optimize it further by using name[8] instead of char *name */
170/* but beware of "if (info->name == evenp)" checks! */
171/* Need to replace them with "if (info == &mode_info[EVENP_INDX])" */
172
Manuel Novoa III cad53642003-03-19 09:13:01 +0000173#define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
174
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000175static const struct mode_info mode_info[] = {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000176 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
177 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
178 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
179 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
180 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
181 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
182 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
183 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
184 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
185 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
186 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000187#ifdef CRTSCTS
Manuel Novoa III cad53642003-03-19 09:13:01 +0000188 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000189#endif
Manuel Novoa III cad53642003-03-19 09:13:01 +0000190 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
191 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
192 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
193 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
194 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
195 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
196 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
197 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
198 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
199 MI_ENTRY("ixon", input, REV, IXON, 0 ),
200 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
201 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000202#ifdef IUCLC
Manuel Novoa III cad53642003-03-19 09:13:01 +0000203 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000204#endif
205#ifdef IXANY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000206 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000207#endif
208#ifdef IMAXBEL
Manuel Novoa III cad53642003-03-19 09:13:01 +0000209 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000210#endif
Manuel Novoa III cad53642003-03-19 09:13:01 +0000211 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000212#ifdef OLCUC
Manuel Novoa III cad53642003-03-19 09:13:01 +0000213 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000214#endif
215#ifdef OCRNL
Manuel Novoa III cad53642003-03-19 09:13:01 +0000216 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000217#endif
218#ifdef ONLCR
Manuel Novoa III cad53642003-03-19 09:13:01 +0000219 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000220#endif
221#ifdef ONOCR
Manuel Novoa III cad53642003-03-19 09:13:01 +0000222 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000223#endif
224#ifdef ONLRET
Manuel Novoa III cad53642003-03-19 09:13:01 +0000225 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000226#endif
227#ifdef OFILL
Manuel Novoa III cad53642003-03-19 09:13:01 +0000228 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000229#endif
230#ifdef OFDEL
Manuel Novoa III cad53642003-03-19 09:13:01 +0000231 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000232#endif
233#ifdef NLDLY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000234 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
235 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
Eric Andersen98e599c2001-02-14 18:47:33 +0000236#endif
237#ifdef CRDLY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000238 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
239 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
240 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
241 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
Eric Andersen98e599c2001-02-14 18:47:33 +0000242#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000243
Eric Andersen98e599c2001-02-14 18:47:33 +0000244#ifdef TABDLY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000245 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
246 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
247 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
248 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
Eric Andersen98e599c2001-02-14 18:47:33 +0000249#else
250# ifdef OXTABS
Manuel Novoa III cad53642003-03-19 09:13:01 +0000251 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000252# endif
253#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000254
Eric Andersen98e599c2001-02-14 18:47:33 +0000255#ifdef BSDLY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000256 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
257 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
Eric Andersen98e599c2001-02-14 18:47:33 +0000258#endif
259#ifdef VTDLY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000260 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
261 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
Eric Andersen98e599c2001-02-14 18:47:33 +0000262#endif
263#ifdef FFDLY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000264 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
265 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
Eric Andersen98e599c2001-02-14 18:47:33 +0000266#endif
Manuel Novoa III cad53642003-03-19 09:13:01 +0000267 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
268 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000269#ifdef IEXTEN
Manuel Novoa III cad53642003-03-19 09:13:01 +0000270 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000271#endif
Manuel Novoa III cad53642003-03-19 09:13:01 +0000272 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
273 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
274 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
275 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
276 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
277 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000278#ifdef XCASE
Manuel Novoa III cad53642003-03-19 09:13:01 +0000279 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000280#endif
281#ifdef TOSTOP
Manuel Novoa III cad53642003-03-19 09:13:01 +0000282 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000283#endif
284#ifdef ECHOPRT
Manuel Novoa III cad53642003-03-19 09:13:01 +0000285 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
286 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000287#endif
288#ifdef ECHOCTL
Manuel Novoa III cad53642003-03-19 09:13:01 +0000289 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
290 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000291#endif
292#ifdef ECHOKE
Manuel Novoa III cad53642003-03-19 09:13:01 +0000293 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
294 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000295#endif
Manuel Novoa III cad53642003-03-19 09:13:01 +0000296 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
297 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
298 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
299 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
300 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
301 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
302 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
303 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
304 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
305 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
306 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000307#ifdef IXANY
Manuel Novoa III cad53642003-03-19 09:13:01 +0000308 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000309#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000310#if defined(TABDLY) || defined(OXTABS)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000311 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000312#endif
313#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000314 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
315 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000316#endif
Manuel Novoa III cad53642003-03-19 09:13:01 +0000317 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
318 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
Eric Andersen98e599c2001-02-14 18:47:33 +0000319};
320
Rob Landleybc68cd12006-03-10 19:22:06 +0000321enum {
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000322 NUM_mode_info = (sizeof(mode_info) / sizeof(mode_info[0]))
Rob Landleybc68cd12006-03-10 19:22:06 +0000323};
Eric Andersen98e599c2001-02-14 18:47:33 +0000324
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000325/* Control character settings */
Eric Andersen98e599c2001-02-14 18:47:33 +0000326struct control_info {
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000327 const char * const name; /* Name given on command line */
328 const unsigned char saneval; /* Value to set for 'stty sane' */
329 const unsigned char offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000330};
331
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000332/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000333
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000334static const struct control_info control_info[] = {
Mark Whitley446dd272001-03-02 20:00:54 +0000335 {"intr", CINTR, VINTR},
336 {"quit", CQUIT, VQUIT},
337 {"erase", CERASE, VERASE},
338 {"kill", CKILL, VKILL},
339 {stty_eof, CEOF, VEOF},
340 {stty_eol, CEOL, VEOL},
Eric Andersen98e599c2001-02-14 18:47:33 +0000341#ifdef VEOL2
Mark Whitley446dd272001-03-02 20:00:54 +0000342 {"eol2", CEOL2, VEOL2},
Eric Andersen98e599c2001-02-14 18:47:33 +0000343#endif
344#ifdef VSWTCH
Mark Whitley446dd272001-03-02 20:00:54 +0000345 {stty_swtch, CSWTCH, VSWTCH},
Eric Andersen98e599c2001-02-14 18:47:33 +0000346#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000347 {"start", CSTART, VSTART},
348 {"stop", CSTOP, VSTOP},
349 {"susp", CSUSP, VSUSP},
Eric Andersen98e599c2001-02-14 18:47:33 +0000350#ifdef VDSUSP
Mark Whitley446dd272001-03-02 20:00:54 +0000351 {"dsusp", CDSUSP, VDSUSP},
Eric Andersen98e599c2001-02-14 18:47:33 +0000352#endif
353#ifdef VREPRINT
Mark Whitley446dd272001-03-02 20:00:54 +0000354 {"rprnt", CRPRNT, VREPRINT},
Eric Andersen98e599c2001-02-14 18:47:33 +0000355#endif
356#ifdef VWERASE
Mark Whitley446dd272001-03-02 20:00:54 +0000357 {"werase", CWERASE, VWERASE},
Eric Andersen98e599c2001-02-14 18:47:33 +0000358#endif
359#ifdef VLNEXT
Mark Whitley446dd272001-03-02 20:00:54 +0000360 {"lnext", CLNEXT, VLNEXT},
Eric Andersen98e599c2001-02-14 18:47:33 +0000361#endif
362#ifdef VFLUSHO
Mark Whitley446dd272001-03-02 20:00:54 +0000363 {"flush", CFLUSHO, VFLUSHO},
Eric Andersen98e599c2001-02-14 18:47:33 +0000364#endif
365#ifdef VSTATUS
Mark Whitley446dd272001-03-02 20:00:54 +0000366 {"status", CSTATUS, VSTATUS},
Eric Andersen98e599c2001-02-14 18:47:33 +0000367#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000368 /* These must be last because of the display routines */
Mark Whitley446dd272001-03-02 20:00:54 +0000369 {stty_min, 1, VMIN},
370 {stty_time, 0, VTIME},
Eric Andersen98e599c2001-02-14 18:47:33 +0000371};
372
Rob Landleybc68cd12006-03-10 19:22:06 +0000373enum {
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000374 NUM_control_info = (sizeof(control_info) / sizeof(control_info[0]))
Rob Landleybc68cd12006-03-10 19:22:06 +0000375};
Eric Andersen98e599c2001-02-14 18:47:33 +0000376
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000377/* The width of the screen, for output wrapping */
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000378unsigned max_col = 80; /* default */
379
380struct globals {
381 /* Current position, to know when to wrap */
382 unsigned current_col;
383 char buf[10];
384};
385#define G (*(struct globals*)&bb_common_bufsiz1)
386
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000387static const char *device_name = bb_msg_standard_input;
Eric Andersen8876fb22003-06-20 09:01:58 +0000388
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000389/* Return a string that is the printable representation of character CH */
Denis Vlasenko79deb662006-09-19 15:12:12 +0000390/* Adapted from 'cat' by Torbjorn Granlund */
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000391static const char *visible(unsigned ch)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000392{
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000393 char *bpout = G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000394
395 if (ch == _POSIX_VDISABLE)
396 return "<undef>";
397
398 if (ch >= 128) {
399 ch -= 128;
400 *bpout++ = 'M';
401 *bpout++ = '-';
402 }
403
404 if (ch < 32) {
405 *bpout++ = '^';
406 *bpout++ = ch + 64;
407 } else if (ch < 127) {
408 *bpout++ = ch;
409 } else {
410 *bpout++ = '^';
411 *bpout++ = '?';
412 }
413
414 *bpout = '\0';
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000415 return G.buf;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000416}
417
418static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
419{
420 static const unsigned char tcflag_offsets[] = {
421 offsetof(struct termios, c_cflag), /* control */
422 offsetof(struct termios, c_iflag), /* input */
423 offsetof(struct termios, c_oflag), /* output */
424 offsetof(struct termios, c_lflag), /* local */
425 };
426
427 if (type <= local) {
428 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
429 }
430 return NULL;
431}
432
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000433static void set_speed_or_die(enum speed_setting type, const char * const arg,
434 struct termios * const mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000435{
436 speed_t baud;
437
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000438 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000439
440 if (type != output_speed) { /* either input or both */
441 cfsetispeed(mode, baud);
442 }
443 if (type != input_speed) { /* either output or both */
444 cfsetospeed(mode, baud);
445 }
446}
447
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000448static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000449{
450 bb_perror_msg_and_die(fmt, device_name);
451}
452
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000453static void perror_on_device(const char *fmt)
454{
455 bb_perror_msg(fmt, device_name);
456}
457
Eric Andersen98e599c2001-02-14 18:47:33 +0000458/* Print format string MESSAGE and optional args.
459 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000460 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000461static void wrapf(const char *message, ...)
462{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000463 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000464 va_list args;
Eric Andersen98e599c2001-02-14 18:47:33 +0000465 int buflen;
466
467 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000468 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000469 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000470 /* We seem to be called only with suitable lengths, but check if
471 somebody failed to adhere to this assumption just to be sure. */
472 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000473
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000474 if (G.current_col > 0) {
475 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000476 if (buf[0] != '\n') {
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000477 if (G.current_col + buflen >= max_col) {
Denis Vlasenko79deb662006-09-19 15:12:12 +0000478 putchar('\n');
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000479 G.current_col = 0;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000480 } else
481 putchar(' ');
482 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000483 }
484 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000485 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000486 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000487 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000488}
489
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000490static void set_window_size(const int rows, const int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000491{
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000492 struct winsize win = { 0, 0, 0, 0};
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000493
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000494 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000495 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000496 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000497 }
498 memset(&win, 0, sizeof(win));
499 }
500
501 if (rows >= 0)
502 win.ws_row = rows;
503 if (cols >= 0)
504 win.ws_col = cols;
505
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000506 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000507bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000508 perror_on_device("%s");
509}
510
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000511static void display_window_size(const int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000512{
513 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000514 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000515
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000516 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000517 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
518 perror_on_device(fmt_str);
519 }
520 } else {
521 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000522 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000523 }
524}
525
Eric Andersen98e599c2001-02-14 18:47:33 +0000526static const struct suffix_mult stty_suffixes[] = {
Mark Whitley446dd272001-03-02 20:00:54 +0000527 {"b", 512 },
528 {"k", 1024},
529 {"B", 1024},
530 {NULL, 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000531};
532
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000533static const struct mode_info *find_mode(const char *name)
534{
535 int i;
536 for (i = 0; i < NUM_mode_info; ++i)
Bernhard Reutner-Fischer79cc5592007-01-17 19:46:46 +0000537 if (!strcmp(name, mode_info[i].name))
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000538 return &mode_info[i];
539 return 0;
540}
541
542static const struct control_info *find_control(const char *name)
543{
544 int i;
545 for (i = 0; i < NUM_control_info; ++i)
Bernhard Reutner-Fischer79cc5592007-01-17 19:46:46 +0000546 if (!strcmp(name, control_info[i].name))
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000547 return &control_info[i];
548 return 0;
549}
550
551enum {
552 param_need_arg = 0x80,
553 param_line = 1 | 0x80,
554 param_rows = 2 | 0x80,
555 param_cols = 3 | 0x80,
556 param_size = 4,
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000557 param_speed = 5,
558 param_ispeed = 6 | 0x80,
559 param_ospeed = 7 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000560};
561
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000562static int find_param(const char * const name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000563{
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000564 static const char * const params[] = {
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000565 "line",
566 "rows",
567 "cols",
568 "columns",
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000569 "size", /* 4 */
570 "speed", /* 5 */
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000571 "ispeed",
572 "ospeed",
573 NULL
574 };
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000575 int i = index_in_str_array(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000576 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000577 return 0;
578 if (!(i == 4 || i == 5))
579 i |= 0x80;
580
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000581 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000582}
583
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000584static int recover_mode(const char *arg, struct termios *mode)
585{
586 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000587 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000588 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000589
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000590 /* Scan into temporaries since it is too much trouble to figure out
591 the right format for 'tcflag_t' */
592 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
593 &iflag, &oflag, &cflag, &lflag, &n) != 4)
594 return 0;
595 mode->c_iflag = iflag;
596 mode->c_oflag = oflag;
597 mode->c_cflag = cflag;
598 mode->c_lflag = lflag;
599 arg += n;
600 for (i = 0; i < NCCS; ++i) {
601 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
602 return 0;
603 mode->c_cc[i] = chr;
604 arg += n;
605 }
606
607 /* Fail if there are too many fields */
608 if (*arg != '\0')
609 return 0;
610
611 return 1;
612}
613
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000614static void display_recoverable(const struct termios *mode,
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000615 int ATTRIBUTE_UNUSED dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000616{
617 int i;
618 printf("%lx:%lx:%lx:%lx",
619 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
620 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
621 for (i = 0; i < NCCS; ++i)
622 printf(":%x", (unsigned int) mode->c_cc[i]);
623 putchar('\n');
624}
625
626static void display_speed(const struct termios *mode, int fancy)
627{
628 //01234567 8 9
629 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
630 unsigned long ispeed, ospeed;
631
632 ospeed = ispeed = cfgetispeed(mode);
633 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
634 ispeed = ospeed; /* in case ispeed was 0 */
635 //0123 4 5 6 7 8 9
636 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
637 }
638 if (fancy) fmt_str += 9;
639 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
640}
641
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000642static void do_display(const struct termios *mode, const int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000643{
644 int i;
645 tcflag_t *bitsp;
646 unsigned long mask;
647 int prev_type = control;
648
649 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000650 if (all)
651 display_window_size(1);
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000652#ifdef HAVE_C_LINE
653 wrapf("line = %d;\n", mode->c_line);
654#else
655 wrapf("\n");
656#endif
657
658 for (i = 0; control_info[i].name != stty_min; ++i) {
659 /* If swtch is the same as susp, don't print both */
660#if VSWTCH == VSUSP
661 if (control_info[i].name == stty_swtch)
662 continue;
663#endif
664 /* If eof uses the same slot as min, only print whichever applies */
665#if VEOF == VMIN
666 if ((mode->c_lflag & ICANON) == 0
667 && (control_info[i].name == stty_eof
668 || control_info[i].name == stty_eol)) continue;
669#endif
670 wrapf("%s = %s;", control_info[i].name,
671 visible(mode->c_cc[control_info[i].offset]));
672 }
673#if VEOF == VMIN
674 if ((mode->c_lflag & ICANON) == 0)
675#endif
676 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000677 if (G.current_col) wrapf("\n");
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000678
679 for (i = 0; i < NUM_mode_info; ++i) {
680 if (mode_info[i].flags & OMIT)
681 continue;
682 if (mode_info[i].type != prev_type) {
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000683 /* wrapf("\n"); */
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000684 if (G.current_col) wrapf("\n");
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000685 prev_type = mode_info[i].type;
686 }
687
688 bitsp = mode_type_flag(mode_info[i].type, mode);
689 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000690 if ((*bitsp & mask) == mode_info[i].bits) {
691 if (all || (mode_info[i].flags & SANE_UNSET))
692 wrapf("%s", mode_info[i].name);
693 } else {
694 if ((all && mode_info[i].flags & REV) ||
695 (!all &&
696 (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)))
697 wrapf("-%s", mode_info[i].name);
698 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000699 }
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000700 if (G.current_col) wrapf("\n");
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000701}
702
703static void sane_mode(struct termios *mode)
704{
705 int i;
706 tcflag_t *bitsp;
707
708 for (i = 0; i < NUM_control_info; ++i) {
709#if VMIN == VEOF
710 if (control_info[i].name == stty_min)
711 break;
712#endif
713 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
714 }
715
716 for (i = 0; i < NUM_mode_info; ++i) {
717 if (mode_info[i].flags & SANE_SET) {
718 bitsp = mode_type_flag(mode_info[i].type, mode);
719 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
720 | mode_info[i].bits;
721 } else if (mode_info[i].flags & SANE_UNSET) {
722 bitsp = mode_type_flag(mode_info[i].type, mode);
723 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
724 & ~mode_info[i].bits;
725 }
726 }
727}
728
729/* Save set_mode from #ifdef forest plague */
730#ifndef ONLCR
731#define ONLCR 0
732#endif
733#ifndef OCRNL
734#define OCRNL 0
735#endif
736#ifndef ONLRET
737#define ONLRET 0
738#endif
739#ifndef XCASE
740#define XCASE 0
741#endif
742#ifndef IXANY
743#define IXANY 0
744#endif
745#ifndef TABDLY
746#define TABDLY 0
747#endif
748#ifndef OXTABS
749#define OXTABS 0
750#endif
751#ifndef IUCLC
752#define IUCLC 0
753#endif
754#ifndef OLCUC
755#define OLCUC 0
756#endif
757#ifndef ECHOCTL
758#define ECHOCTL 0
759#endif
760#ifndef ECHOKE
761#define ECHOKE 0
762#endif
763
764static void set_mode(const struct mode_info *info, int reversed,
765 struct termios *mode)
766{
767 tcflag_t *bitsp;
768
769 bitsp = mode_type_flag(info->type, mode);
770
771 if (bitsp) {
772 if (reversed)
773 *bitsp = *bitsp & ~info->mask & ~info->bits;
774 else
775 *bitsp = (*bitsp & ~info->mask) | info->bits;
776 return;
777 }
778
779 /* Combination mode */
780 if (info->name == evenp || info->name == parity) {
781 if (reversed)
782 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
783 else
784 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
785 } else if (info->name == stty_oddp) {
786 if (reversed)
787 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
788 else
789 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
790 } else if (info->name == stty_nl) {
791 if (reversed) {
792 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
793 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
794 } else {
795 mode->c_iflag = mode->c_iflag & ~ICRNL;
796 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
797 }
798 } else if (info->name == stty_ek) {
799 mode->c_cc[VERASE] = CERASE;
800 mode->c_cc[VKILL] = CKILL;
801 } else if (info->name == stty_sane) {
802 sane_mode(mode);
803 }
804 else if (info->name == cbreak) {
805 if (reversed)
806 mode->c_lflag |= ICANON;
807 else
808 mode->c_lflag &= ~ICANON;
809 } else if (info->name == stty_pass8) {
810 if (reversed) {
811 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
812 mode->c_iflag |= ISTRIP;
813 } else {
814 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
815 mode->c_iflag &= ~ISTRIP;
816 }
817 } else if (info->name == litout) {
818 if (reversed) {
819 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
820 mode->c_iflag |= ISTRIP;
821 mode->c_oflag |= OPOST;
822 } else {
823 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
824 mode->c_iflag &= ~ISTRIP;
825 mode->c_oflag &= ~OPOST;
826 }
827 } else if (info->name == raw || info->name == cooked) {
828 if ((info->name[0] == 'r' && reversed)
829 || (info->name[0] == 'c' && !reversed)) {
830 /* Cooked mode */
831 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
832 mode->c_oflag |= OPOST;
833 mode->c_lflag |= ISIG | ICANON;
834#if VMIN == VEOF
835 mode->c_cc[VEOF] = CEOF;
836#endif
837#if VTIME == VEOL
838 mode->c_cc[VEOL] = CEOL;
839#endif
840 } else {
841 /* Raw mode */
842 mode->c_iflag = 0;
843 mode->c_oflag &= ~OPOST;
844 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
845 mode->c_cc[VMIN] = 1;
846 mode->c_cc[VTIME] = 0;
847 }
848 }
849 else if (IXANY && info->name == decctlq) {
850 if (reversed)
851 mode->c_iflag |= IXANY;
852 else
853 mode->c_iflag &= ~IXANY;
854 }
855 else if (TABDLY && info->name == stty_tabs) {
856 if (reversed)
857 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
858 else
859 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
860 }
861 else if (OXTABS && info->name == stty_tabs) {
862 if (reversed)
863 mode->c_oflag |= OXTABS;
864 else
865 mode->c_oflag &= ~OXTABS;
866 }
867 else if (XCASE && IUCLC && OLCUC
868 && (info->name == stty_lcase || info->name == stty_LCASE)) {
869 if (reversed) {
870 mode->c_lflag &= ~XCASE;
871 mode->c_iflag &= ~IUCLC;
872 mode->c_oflag &= ~OLCUC;
873 } else {
874 mode->c_lflag |= XCASE;
875 mode->c_iflag |= IUCLC;
876 mode->c_oflag |= OLCUC;
877 }
878 }
879 else if (info->name == stty_crt) {
880 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
881 }
882 else if (info->name == stty_dec) {
883 mode->c_cc[VINTR] = 3; /* ^C */
884 mode->c_cc[VERASE] = 127; /* DEL */
885 mode->c_cc[VKILL] = 21; /* ^U */
886 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
887 if (IXANY) mode->c_iflag &= ~IXANY;
888 }
889}
890
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000891static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000892 const char *arg, struct termios *mode)
893{
894 unsigned char value;
895
896 if (info->name == stty_min || info->name == stty_time)
897 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
898 else if (arg[0] == '\0' || arg[1] == '\0')
899 value = arg[0];
Bernhard Reutner-Fischer79cc5592007-01-17 19:46:46 +0000900 else if (!strcmp(arg, "^-") || !strcmp(arg, "undef"))
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000901 value = _POSIX_VDISABLE;
902 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
903 value = arg[1] & 0x1f; /* Non-letters get weird results */
904 if (arg[1] == '?')
905 value = 127;
906 } else
907 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
908 mode->c_cc[info->offset] = value;
909}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000910
Denis Vlasenko41aaefc2007-01-18 00:53:35 +0000911#define STTY_require_set_attr (1<<0)
912#define STTY_speed_was_set (1<<1)
913#define STTY_verbose_output (1<<2)
914#define STTY_recoverable_output (1<<3)
915#define STTY_noargs (1<<4)
Denis Vlasenko06af2162007-02-03 17:28:39 +0000916int stty_main(int argc, char **argv);
Rob Landleydfba7412006-03-06 20:47:33 +0000917int stty_main(int argc, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +0000918{
919 struct termios mode;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000920 void (*output_func)(const struct termios *, const int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000921 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000922 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +0000923 int stty_state;
924 int k;
925
926 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000927 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +0000928
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000929 /* First pass: only parse/verify command line params */
930 k = 0;
931 while (argv[++k]) {
932 const struct mode_info *mp;
933 const struct control_info *cp;
934 const char *arg = argv[k];
935 const char *argnext = argv[k+1];
936 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +0000937
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000938 if (arg[0] == '-') {
939 int i;
940 mp = find_mode(arg+1);
941 if (mp) {
942 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +0000943 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +0000944 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000945 continue;
946 }
947 /* It is an option - parse it */
948 i = 0;
949 while (arg[++i]) {
950 switch (arg[i]) {
951 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +0000952 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000953 output_func = do_display;
954 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000955 break;
956 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +0000957 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000958 output_func = display_recoverable;
959 break;
960 case 'F':
961 if (file_name)
962 bb_error_msg_and_die("only one device may be specified");
963 file_name = &arg[i+1]; /* "-Fdevice" ? */
964 if (!file_name[0]) { /* nope, "-F device" */
965 int p = k+1; /* argv[p] is argnext */
966 file_name = argnext;
967 if (!file_name)
968 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
969 /* remove -F param from arg[vc] */
970 --argc;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000971 while (argv[p]) { argv[p] = argv[p+1]; ++p; }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000972 }
973 goto end_option;
974 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +0000975 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000976 }
977 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000978 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000979 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +0000980 }
981
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000982 mp = find_mode(arg);
983 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +0000984 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000985 continue;
986 }
987
988 cp = find_control(arg);
989 if (cp) {
990 if (!argnext)
991 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000992 /* called for the side effect of xfunc death only */
993 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +0000994 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000995 ++k;
996 continue;
997 }
998
999 param = find_param(arg);
1000 if (param & param_need_arg) {
1001 if (!argnext)
1002 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1003 ++k;
1004 }
1005
1006 switch (param) {
1007#ifdef HAVE_C_LINE
1008 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001009# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001010 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001011 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001012# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001013#endif
1014#ifdef TIOCGWINSZ
1015 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001016 case param_cols:
Denis Vlasenko13858992006-10-08 12:49:22 +00001017 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001018 break;
1019 case param_size:
1020#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001021 case param_speed:
1022 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001023 case param_ispeed:
1024 /* called for the side effect of xfunc death only */
1025 set_speed_or_die(input_speed, argnext, &mode);
1026 break;
1027 case param_ospeed:
1028 /* called for the side effect of xfunc death only */
1029 set_speed_or_die(output_speed, argnext, &mode);
1030 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001031 default:
1032 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001033 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001034 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001035 bb_error_msg_and_die("invalid argument '%s'", arg);
1036 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001037 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001038 }
1039
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001040 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001041 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001042 (STTY_verbose_output | STTY_recoverable_output))
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001043 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1044 /* Specifying -a or -g with non-options is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001045 if (!(stty_state & STTY_noargs) &&
1046 (stty_state & (STTY_verbose_output | STTY_recoverable_output)))
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001047 bb_error_msg_and_die("modes may not be set when specifying an output style");
Eric Andersen98e599c2001-02-14 18:47:33 +00001048
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001049 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001050 if (file_name) {
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001051 int fd, fdflags;
Eric Andersen98e599c2001-02-14 18:47:33 +00001052 device_name = file_name;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001053 fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
Denis Vlasenko79deb662006-09-19 15:12:12 +00001054 if (fd != STDIN_FILENO) {
1055 dup2(fd, STDIN_FILENO);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001056 close(fd);
1057 }
Denis Vlasenkobd8f43d2006-09-08 17:31:55 +00001058 fdflags = fcntl(STDIN_FILENO, F_GETFL);
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001059 if (fdflags < 0 ||
1060 fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
Denis Vlasenkoa9595882006-09-29 21:30:43 +00001061 perror_on_device_and_die("%s: cannot reset non-blocking mode");
Eric Andersen98e599c2001-02-14 18:47:33 +00001062 }
1063
1064 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001065 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001066 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001067 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001068 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001069
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001070 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +00001071 get_terminal_width_height(STDOUT_FILENO, &max_col, NULL);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001072 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001073 return EXIT_SUCCESS;
1074 }
1075
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001076 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001077 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001078 while (argv[++k]) {
1079 const struct mode_info *mp;
1080 const struct control_info *cp;
1081 const char *arg = argv[k];
1082 const char *argnext = argv[k+1];
1083 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001084
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001085 if (arg[0] == '-') {
1086 mp = find_mode(arg+1);
1087 if (mp) {
1088 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001089 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001090 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001091 /* It is an option - already parsed. Skip it */
1092 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001093 }
Mark Whitley446dd272001-03-02 20:00:54 +00001094
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001095 mp = find_mode(arg);
1096 if (mp) {
1097 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001098 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001099 continue;
1100 }
Mark Whitley446dd272001-03-02 20:00:54 +00001101
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001102 cp = find_control(arg);
1103 if (cp) {
1104 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001105 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001106 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001107 continue;
1108 }
Mark Whitley446dd272001-03-02 20:00:54 +00001109
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001110 param = find_param(arg);
1111 if (param & param_need_arg) {
1112 ++k;
1113 }
1114
1115 switch (param) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001116#ifdef HAVE_C_LINE
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001117 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001118 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001119 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001120 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001121#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001122#ifdef TIOCGWINSZ
1123 case param_cols:
Denis Vlasenko13858992006-10-08 12:49:22 +00001124 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001125 break;
1126 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001127 display_window_size(0);
1128 break;
1129 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001130 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001131 break;
1132#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001133 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001134 display_speed(&mode, 0);
1135 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001136 case param_ispeed:
1137 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001138 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001139 break;
1140 case param_ospeed:
1141 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001142 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001143 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001144 default:
1145 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001146 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001147 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001148 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001149 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001150 } /* else - impossible (caught in the first pass):
1151 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001152 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001153 }
1154
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001155 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001156 struct termios new_mode;
1157
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001158 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001159 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001160
1161 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1162 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001163 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001164 some proper subset of the requested operations. To detect
1165 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001166 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001167
1168 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001169 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001170 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001171 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001172 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001173
Eric Andersen98e599c2001-02-14 18:47:33 +00001174 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1175#ifdef CIBAUD
1176 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1177 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1178 sometimes (m1 != m2). The only difference is in the four bits
1179 of the c_cflag field corresponding to the baud rate. To save
1180 Sun users a little confusion, don't report an error if this
1181 happens. But suppress the error only if we haven't tried to
1182 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001183 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001184
1185 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001186 if ((stty_state & STTY_speed_was_set)
1187 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001188#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001189 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001190 }
1191 }
1192
1193 return EXIT_SUCCESS;
1194}