blob: e818d579c6446e84563239ce7b5fc9de67fa5544 [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
Denys Vlasenko0ef64bd2010-08-16 20:14:46 +02005 Licensed under GPLv2 or later, see file LICENSE in this source tree.
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +00006*/
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
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010021*/
22//config:config STTY
23//config: bool "stty"
24//config: default y
25//config: help
26//config: stty is used to change and print terminal line settings.
Eric Andersen98e599c2001-02-14 18:47:33 +000027
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010028//applet:IF_STTY(APPLET(stty, BB_DIR_BIN, BB_SUID_DROP))
29
30//kbuild:lib-$(CONFIG_STTY) += stty.o
Eric Andersen98e599c2001-02-14 18:47:33 +000031
Pere Orga34425382011-03-31 14:43:25 +020032//usage:#define stty_trivial_usage
33//usage: "[-a|g] [-F DEVICE] [SETTING]..."
34//usage:#define stty_full_usage "\n\n"
35//usage: "Without arguments, prints baud rate, line discipline,\n"
36//usage: "and deviations from stty sane\n"
Pere Orga34425382011-03-31 14:43:25 +020037//usage: "\n -F DEVICE Open device instead of stdin"
38//usage: "\n -a Print all current settings in human-readable form"
39//usage: "\n -g Print in stty-readable form"
40//usage: "\n [SETTING] See manpage"
41
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000042#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020043#include "common_bufsiz.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000044
Eric Andersen98e599c2001-02-14 18:47:33 +000045#ifndef _POSIX_VDISABLE
46# define _POSIX_VDISABLE ((unsigned char) 0)
47#endif
48
49#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000050/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000051#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000052# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000053#endif
54#ifndef CQUIT
55# define CQUIT 28
56#endif
57#ifndef CERASE
58# define CERASE 127
59#endif
60#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000061# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000062#endif
63#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000064# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000065#endif
66#ifndef CEOL
67# define CEOL _POSIX_VDISABLE
68#endif
69#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000070# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000071#endif
72#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000073# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000074#endif
75#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000076# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000077#endif
78#if defined(VEOL2) && !defined(CEOL2)
79# define CEOL2 _POSIX_VDISABLE
80#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +010081/* glibc-2.12.1 uses only VSWTC name */
82#if defined(VSWTC) && !defined(VSWTCH)
83# define VSWTCH VSWTC
84#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000085/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000086#if defined(VSUSP) && !defined(VSWTCH)
87# define VSWTCH VSUSP
88# define CSWTCH CSUSP
89#endif
90#if defined(VSWTCH) && !defined(CSWTCH)
91# define CSWTCH _POSIX_VDISABLE
92#endif
93
Denis Vlasenko79deb662006-09-19 15:12:12 +000094/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
95 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000096#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000097# undef CSWTCH
98# define CSWTCH _POSIX_VDISABLE
99#endif
100
Denis Vlasenkoff131b92007-04-10 15:42:06 +0000101#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000102# define VWERASE VWERSE
103#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +0000104#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000105# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +0000106#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000107#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000108# define VREPRINT VRPRNT
109#endif
110#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000111# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +0000112#endif
113#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000114# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +0000115#endif
116#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000117# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +0000118#endif
119#if defined(VDISCARD) && !defined(VFLUSHO)
120# define VFLUSHO VDISCARD
121#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000122#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000123# define VFLUSHO VFLUSH
124#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000125#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000126# define ECHOCTL CTLECH
127#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000128#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000129# define ECHOCTL TCTLECH
130#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000131#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000132# define ECHOKE CRTKIL
133#endif
134#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000135# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000136#endif
137#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000138# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000139#endif
140
Jeremie Koenig138ce542010-07-30 06:01:37 +0200141/* Save us from #ifdef forest plague */
142#ifndef BSDLY
143# define BSDLY 0
144#endif
145#ifndef CIBAUD
146# define CIBAUD 0
147#endif
148#ifndef CRDLY
149# define CRDLY 0
150#endif
151#ifndef CRTSCTS
152# define CRTSCTS 0
153#endif
154#ifndef ECHOCTL
155# define ECHOCTL 0
156#endif
157#ifndef ECHOKE
158# define ECHOKE 0
159#endif
160#ifndef ECHOPRT
161# define ECHOPRT 0
162#endif
163#ifndef FFDLY
164# define FFDLY 0
165#endif
166#ifndef IEXTEN
167# define IEXTEN 0
168#endif
169#ifndef IMAXBEL
170# define IMAXBEL 0
171#endif
172#ifndef IUCLC
173# define IUCLC 0
174#endif
175#ifndef IXANY
176# define IXANY 0
177#endif
178#ifndef NLDLY
179# define NLDLY 0
180#endif
181#ifndef OCRNL
182# define OCRNL 0
183#endif
184#ifndef OFDEL
185# define OFDEL 0
186#endif
187#ifndef OFILL
188# define OFILL 0
189#endif
190#ifndef OLCUC
191# define OLCUC 0
192#endif
193#ifndef ONLCR
194# define ONLCR 0
195#endif
196#ifndef ONLRET
197# define ONLRET 0
198#endif
199#ifndef ONOCR
200# define ONOCR 0
201#endif
202#ifndef OXTABS
203# define OXTABS 0
204#endif
205#ifndef TABDLY
206# define TABDLY 0
207#endif
208#ifndef TAB1
209# define TAB1 0
210#endif
211#ifndef TAB2
212# define TAB2 0
213#endif
214#ifndef TOSTOP
215# define TOSTOP 0
216#endif
217#ifndef VDSUSP
218# define VDSUSP 0
219#endif
220#ifndef VEOL2
221# define VEOL2 0
222#endif
223#ifndef VFLUSHO
224# define VFLUSHO 0
225#endif
226#ifndef VLNEXT
227# define VLNEXT 0
228#endif
229#ifndef VREPRINT
230# define VREPRINT 0
231#endif
232#ifndef VSTATUS
233# define VSTATUS 0
234#endif
235#ifndef VSWTCH
236# define VSWTCH 0
237#endif
238#ifndef VTDLY
239# define VTDLY 0
240#endif
241#ifndef VWERASE
242# define VWERASE 0
243#endif
244#ifndef XCASE
245# define XCASE 0
246#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100247#ifndef IUTF8
248# define IUTF8 0
249#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200250
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000251/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000252enum speed_setting {
253 input_speed, output_speed, both_speeds
254};
255
Denis Vlasenko79deb662006-09-19 15:12:12 +0000256/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000257enum {
Eric Andersen98e599c2001-02-14 18:47:33 +0000258 control, input, output, local, combination
259};
Denys Vlasenkoe9581b62013-05-17 18:06:49 +0200260static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode)
261{
262 static const uint8_t tcflag_offsets[] ALIGN1 = {
263 offsetof(struct termios, c_cflag), /* control */
264 offsetof(struct termios, c_iflag), /* input */
265 offsetof(struct termios, c_oflag), /* output */
266 offsetof(struct termios, c_lflag) /* local */
267 };
268 if (type <= local) {
269 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
270 }
271 return NULL;
272}
Eric Andersen98e599c2001-02-14 18:47:33 +0000273
Denis Vlasenko79deb662006-09-19 15:12:12 +0000274/* Flags for 'struct mode_info' */
275#define SANE_SET 1 /* Set in 'sane' mode */
276#define SANE_UNSET 2 /* Unset in 'sane' mode */
277#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000278#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000279
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000280
281/* Each mode.
282 * This structure should be kept as small as humanly possible.
283 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000284struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000285 const uint8_t type; /* Which structure element to change */
286 const uint8_t flags; /* Setting and display options */
287 /* only these values are ever used, so... */
288#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
289 const uint8_t mask;
290#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
291 const uint16_t mask;
292#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000293 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000294#endif
295 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000296 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000297};
298
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000299enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000300 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000301 IDX_evenp = 0,
302 IDX_parity,
303 IDX_oddp,
304 IDX_nl,
305 IDX_ek,
306 IDX_sane,
307 IDX_cooked,
308 IDX_raw,
309 IDX_pass8,
310 IDX_litout,
311 IDX_cbreak,
312 IDX_crt,
313 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200314#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000315 IDX_decctlq,
316#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200317#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000318 IDX_tabs,
319#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200320#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000321 IDX_lcase,
322 IDX_LCASE,
323#endif
324};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000325
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000326#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000327
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000328/* Mode names given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200329static const char mode_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000330 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
331 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
333 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
334 MI_ENTRY("ek", combination, OMIT, 0, 0 )
335 MI_ENTRY("sane", combination, OMIT, 0, 0 )
336 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
337 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
338 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
339 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
340 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
341 MI_ENTRY("crt", combination, OMIT, 0, 0 )
342 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200343#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000344 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000345#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200346#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000347 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000348#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200349#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000350 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
351 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000352#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000353 MI_ENTRY("parenb", control, REV, PARENB, 0 )
354 MI_ENTRY("parodd", control, REV, PARODD, 0 )
355 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
356 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
357 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
358 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
359 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
360 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
361 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
362 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
363 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200364#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000365 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000366#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000367 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
368 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
369 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
370 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
371 MI_ENTRY("inpck", input, REV, INPCK, 0 )
372 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
373 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
374 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
375 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
376 MI_ENTRY("ixon", input, REV, IXON, 0 )
377 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100378 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200379#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000380 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000381#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200382#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000383 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000384#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200385#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000386 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000387#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100388#if IUTF8
389 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
390#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000391 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200392#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000393 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000394#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200395#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000396 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000397#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200398#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000399 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000400#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200401#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000402 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000403#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200404#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000405 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000406#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200407#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000408 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000409#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200410#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000411 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000412#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200413#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000414 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
415 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000416#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200417#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000418 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
419 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
420 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
421 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000422#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000423
Jeremie Koenig138ce542010-07-30 06:01:37 +0200424#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000425 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200426# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000427 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200428# endif
429# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000430 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200431# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000432 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000433#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200434# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000435 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000436# endif
437#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000438
Jeremie Koenig138ce542010-07-30 06:01:37 +0200439#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000440 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
441 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000442#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200443#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000444 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
445 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000446#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200447#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000448 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
449 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000450#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000451 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
452 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200453#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000454 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000455#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000456 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
457 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100458 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000459 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
460 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
461 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200462#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000463 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000464#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200465#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000466 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000467#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200468#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000469 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100470 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000471#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200472#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000473 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100474 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000475#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200476#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000477 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100478 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000479#endif
480 ;
481
482#undef MI_ENTRY
483#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
484
485static const struct mode_info mode_info[] = {
486 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
487 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
488 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
489 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
490 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
491 MI_ENTRY("ek", combination, OMIT, 0, 0 )
492 MI_ENTRY("sane", combination, OMIT, 0, 0 )
493 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
494 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
495 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
496 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
497 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
498 MI_ENTRY("crt", combination, OMIT, 0, 0 )
499 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200500#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000501 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
502#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200503#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000504 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
505#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200506#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000507 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
508 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
509#endif
510 MI_ENTRY("parenb", control, REV, PARENB, 0 )
511 MI_ENTRY("parodd", control, REV, PARODD, 0 )
512 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
513 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
514 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
515 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
516 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
517 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
518 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
519 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
520 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200521#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000522 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
523#endif
524 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
525 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
526 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
527 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
528 MI_ENTRY("inpck", input, REV, INPCK, 0 )
529 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
530 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
531 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
532 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
533 MI_ENTRY("ixon", input, REV, IXON, 0 )
534 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100535 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200536#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000537 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
538#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200539#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000540 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
541#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200542#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000543 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
544#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100545#if IUTF8
546 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
547#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000548 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200549#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000550 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
551#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200552#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000553 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
554#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200555#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000556 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
557#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200558#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000559 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
560#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200561#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000562 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
563#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200564#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000565 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
566#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200567#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000568 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
569#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200570#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000571 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
572 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
573#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200574#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000575 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
576 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
577 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
578 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
579#endif
580
Jeremie Koenig138ce542010-07-30 06:01:37 +0200581#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000582 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200583# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000584 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200585# endif
586# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000587 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200588# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000589 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
590#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200591# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000592 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
593# endif
594#endif
595
Jeremie Koenig138ce542010-07-30 06:01:37 +0200596#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000597 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
598 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
599#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200600#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000601 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
602 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
603#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200604#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000605 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
606 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
607#endif
608 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
609 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200610#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000611 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
612#endif
613 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
614 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100615 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000616 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
617 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
618 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200619#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000620 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
621#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200622#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000623 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
624#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200625#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000626 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100627 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000628#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200629#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000630 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100631 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000632#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200633#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000634 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100635 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000636#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000637};
638
Rob Landleybc68cd12006-03-10 19:22:06 +0000639enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000640 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000641};
Eric Andersen98e599c2001-02-14 18:47:33 +0000642
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000643
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000644/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000645struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000646 const uint8_t saneval; /* Value to set for 'stty sane' */
647 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000648};
649
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000650enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000651 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000652 CIDX_intr = 0,
653 CIDX_quit,
654 CIDX_erase,
655 CIDX_kill,
656 CIDX_eof,
657 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200658#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000659 CIDX_eol2,
660#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200661#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000662 CIDX_swtch,
663#endif
664 CIDX_start,
665 CIDX_stop,
666 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200667#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000668 CIDX_dsusp,
669#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200670#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000671 CIDX_rprnt,
672#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200673#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000674 CIDX_werase,
675#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200676#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000677 CIDX_lnext,
678#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200679#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000680 CIDX_flush,
681#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200682#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000683 CIDX_status,
684#endif
685 CIDX_min,
686 CIDX_time,
687};
Eric Andersen98e599c2001-02-14 18:47:33 +0000688
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000689#define CI_ENTRY(n,s,o) n "\0"
690
691/* Name given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200692static const char control_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000693 CI_ENTRY("intr", CINTR, VINTR )
694 CI_ENTRY("quit", CQUIT, VQUIT )
695 CI_ENTRY("erase", CERASE, VERASE )
696 CI_ENTRY("kill", CKILL, VKILL )
697 CI_ENTRY("eof", CEOF, VEOF )
698 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200699#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000700 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000701#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200702#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000703 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000704#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000705 CI_ENTRY("start", CSTART, VSTART )
706 CI_ENTRY("stop", CSTOP, VSTOP )
707 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200708#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000709 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000710#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200711#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000712 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000713#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200714#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000715 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000716#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200717#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000718 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000719#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200720#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000721 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000722#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200723#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000724 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000725#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000726 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000727 CI_ENTRY("min", 1, VMIN )
728 CI_ENTRY("time", 0, VTIME )
729 ;
730
731#undef CI_ENTRY
732#define CI_ENTRY(n,s,o) { s, o },
733
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200734static const struct control_info control_info[] ALIGN2 = {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000735 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
736 CI_ENTRY("intr", CINTR, VINTR )
737 CI_ENTRY("quit", CQUIT, VQUIT )
738 CI_ENTRY("erase", CERASE, VERASE )
739 CI_ENTRY("kill", CKILL, VKILL )
740 CI_ENTRY("eof", CEOF, VEOF )
741 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200742#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000743 CI_ENTRY("eol2", CEOL2, VEOL2 )
744#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200745#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000746 CI_ENTRY("swtch", CSWTCH, VSWTCH )
747#endif
748 CI_ENTRY("start", CSTART, VSTART )
749 CI_ENTRY("stop", CSTOP, VSTOP )
750 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200751#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000752 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
753#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200754#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000755 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
756#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200757#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000758 CI_ENTRY("werase", CWERASE, VWERASE )
759#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200760#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000761 CI_ENTRY("lnext", CLNEXT, VLNEXT )
762#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200763#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000764 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
765#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200766#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000767 CI_ENTRY("status", CSTATUS, VSTATUS )
768#endif
769 /* These must be last because of the display routines */
770 CI_ENTRY("min", 1, VMIN )
771 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000772};
773
Rob Landleybc68cd12006-03-10 19:22:06 +0000774enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000775 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000776};
Eric Andersen98e599c2001-02-14 18:47:33 +0000777
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000778
779struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100780 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000781 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100782 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000783 /* Current position, to know when to wrap */
784 unsigned current_col;
785 char buf[10];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100786} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200787#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000788#define INIT_G() do { \
789 G.device_name = bb_msg_standard_input; \
790 G.max_col = 80; \
791} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000792
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000793static void set_speed_or_die(enum speed_setting type, const char *arg,
794 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000795{
796 speed_t baud;
797
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000798 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000799
800 if (type != output_speed) { /* either input or both */
801 cfsetispeed(mode, baud);
802 }
803 if (type != input_speed) { /* either output or both */
804 cfsetospeed(mode, baud);
805 }
806}
807
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000808static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000809{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000810 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000811}
812
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000813static void perror_on_device(const char *fmt)
814{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000815 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000816}
817
Eric Andersen98e599c2001-02-14 18:47:33 +0000818/* Print format string MESSAGE and optional args.
819 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000820 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000821static void wrapf(const char *message, ...)
822{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000823 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000824 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000825 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000826
827 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000828 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000829 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000830 /* We seem to be called only with suitable lengths, but check if
831 somebody failed to adhere to this assumption just to be sure. */
832 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000833
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000834 if (G.current_col > 0) {
835 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000836 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000837 if (G.current_col + buflen >= G.max_col) {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000838 bb_putchar('\n');
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000839 G.current_col = 0;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000840 } else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000841 bb_putchar(' ');
Denis Vlasenko79deb662006-09-19 15:12:12 +0000842 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000843 }
844 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000845 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000846 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000847 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000848}
849
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100850static void newline(void)
851{
852 if (G.current_col != 0)
853 wrapf("\n");
854}
855
Jeremie Koenig138ce542010-07-30 06:01:37 +0200856#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100857static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000858{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000859 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000860
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000861 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000862 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000863 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000864 }
865 memset(&win, 0, sizeof(win));
866 }
867
868 if (rows >= 0)
869 win.ws_row = rows;
870 if (cols >= 0)
871 win.ws_col = cols;
872
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000873 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000874bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000875 perror_on_device("%s");
876}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200877#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000878
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100879static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000880{
881 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000882 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000883
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000884 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000885 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
886 perror_on_device(fmt_str);
887 }
888 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100889 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000890 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000891 }
892}
893
Eric Andersen98e599c2001-02-14 18:47:33 +0000894static const struct suffix_mult stty_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000895 { "b", 512 },
896 { "k", 1024 },
897 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200898 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000899};
900
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000901static const struct mode_info *find_mode(const char *name)
902{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000903 int i = index_in_strings(mode_name, name);
904 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000905}
906
907static const struct control_info *find_control(const char *name)
908{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000909 int i = index_in_strings(control_name, name);
910 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000911}
912
913enum {
914 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000915 param_line = 1 | 0x80,
916 param_rows = 2 | 0x80,
917 param_cols = 3 | 0x80,
918 param_columns = 4 | 0x80,
919 param_size = 5,
920 param_speed = 6,
921 param_ispeed = 7 | 0x80,
922 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000923};
924
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000925static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000926{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000927 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000928 "line\0" /* 1 */
929 "rows\0" /* 2 */
930 "cols\0" /* 3 */
931 "columns\0" /* 4 */
932 "size\0" /* 5 */
933 "speed\0" /* 6 */
934 "ispeed\0"
935 "ospeed\0";
936 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000937 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000938 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000939 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000940 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000941 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000942}
943
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000944static int recover_mode(const char *arg, struct termios *mode)
945{
946 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000947 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000948 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000949
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000950 /* Scan into temporaries since it is too much trouble to figure out
951 the right format for 'tcflag_t' */
952 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
953 &iflag, &oflag, &cflag, &lflag, &n) != 4)
954 return 0;
955 mode->c_iflag = iflag;
956 mode->c_oflag = oflag;
957 mode->c_cflag = cflag;
958 mode->c_lflag = lflag;
959 arg += n;
960 for (i = 0; i < NCCS; ++i) {
961 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
962 return 0;
963 mode->c_cc[i] = chr;
964 arg += n;
965 }
966
967 /* Fail if there are too many fields */
968 if (*arg != '\0')
969 return 0;
970
971 return 1;
972}
973
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000974static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000975 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000976{
977 int i;
978 printf("%lx:%lx:%lx:%lx",
979 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
980 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
981 for (i = 0; i < NCCS; ++i)
982 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000983 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000984}
985
986static void display_speed(const struct termios *mode, int fancy)
987{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100988 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000989 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
990 unsigned long ispeed, ospeed;
991
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +0100992 ispeed = cfgetispeed(mode);
993 ospeed = cfgetospeed(mode);
994 if (ispeed == 0 || ispeed == ospeed) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000995 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100996 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000997 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
998 }
999 if (fancy) fmt_str += 9;
1000 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1001}
1002
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001003static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001004{
1005 int i;
1006 tcflag_t *bitsp;
1007 unsigned long mask;
1008 int prev_type = control;
1009
1010 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001011 if (all)
1012 display_window_size(1);
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001013#ifdef __linux__
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001014 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001015#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001016 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001017#endif
1018
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001019 for (i = 0; i != CIDX_min; ++i) {
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001020 char ch;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001021 /* If swtch is the same as susp, don't print both */
1022#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001023 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001024 continue;
1025#endif
1026 /* If eof uses the same slot as min, only print whichever applies */
1027#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001028 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001029 && (i == CIDX_eof || i == CIDX_eol)
1030 ) {
1031 continue;
1032 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001033#endif
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001034 ch = mode->c_cc[control_info[i].offset];
1035 if (ch == _POSIX_VDISABLE)
1036 strcpy(G.buf, "<undef>");
1037 else
1038 visible(ch, G.buf, 0);
1039 wrapf("%s = %s;", nth_string(control_name, i), G.buf);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001040 }
1041#if VEOF == VMIN
1042 if ((mode->c_lflag & ICANON) == 0)
1043#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001044 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1045 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001046
1047 for (i = 0; i < NUM_mode_info; ++i) {
1048 if (mode_info[i].flags & OMIT)
1049 continue;
1050 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001051 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001052 prev_type = mode_info[i].type;
1053 }
1054
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001055 bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001056 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001057 if ((*bitsp & mask) == mode_info[i].bits) {
1058 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001059 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001060 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001061 if ((all && mode_info[i].flags & REV)
1062 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1063 ) {
1064 wrapf("-%s", nth_string(mode_name, i));
1065 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001066 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001067 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001068 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001069}
1070
1071static void sane_mode(struct termios *mode)
1072{
1073 int i;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001074
1075 for (i = 0; i < NUM_control_info; ++i) {
1076#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001077 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001078 break;
1079#endif
1080 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1081 }
1082
1083 for (i = 0; i < NUM_mode_info; ++i) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001084 tcflag_t val;
1085 tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
1086
1087 if (!bitsp)
1088 continue;
1089 val = *bitsp & ~((unsigned long)mode_info[i].mask);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001090 if (mode_info[i].flags & SANE_SET) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001091 *bitsp = val | mode_info[i].bits;
1092 } else
1093 if (mode_info[i].flags & SANE_UNSET) {
1094 *bitsp = val & ~mode_info[i].bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001095 }
1096 }
1097}
1098
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001099static void set_mode(const struct mode_info *info, int reversed,
1100 struct termios *mode)
1101{
1102 tcflag_t *bitsp;
1103
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001104 bitsp = get_ptr_to_tcflag(info->type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001105
1106 if (bitsp) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001107 tcflag_t val = *bitsp & ~info->mask;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001108 if (reversed)
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001109 *bitsp = val & ~info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001110 else
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001111 *bitsp = val | info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001112 return;
1113 }
1114
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001115 /* !bitsp - it's a "combination" mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001116 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001117 if (reversed)
1118 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1119 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001120 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001121 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001122 if (reversed)
1123 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1124 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001125 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001126 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001127 if (reversed) {
1128 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001129 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001130 } else {
1131 mode->c_iflag = mode->c_iflag & ~ICRNL;
1132 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1133 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001134 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001135 mode->c_cc[VERASE] = CERASE;
1136 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001137 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001138 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001139 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001140 if (reversed)
1141 mode->c_lflag |= ICANON;
1142 else
1143 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001144 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001145 if (reversed) {
1146 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1147 mode->c_iflag |= ISTRIP;
1148 } else {
1149 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1150 mode->c_iflag &= ~ISTRIP;
1151 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001152 } else if (info == &mode_info[IDX_litout]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001153 if (reversed) {
1154 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1155 mode->c_iflag |= ISTRIP;
1156 mode->c_oflag |= OPOST;
1157 } else {
1158 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1159 mode->c_iflag &= ~ISTRIP;
1160 mode->c_oflag &= ~OPOST;
1161 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001162 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001163 if ((info == &mode_info[IDX_raw] && reversed)
1164 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001165 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001166 /* Cooked mode */
1167 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1168 mode->c_oflag |= OPOST;
1169 mode->c_lflag |= ISIG | ICANON;
1170#if VMIN == VEOF
1171 mode->c_cc[VEOF] = CEOF;
1172#endif
1173#if VTIME == VEOL
1174 mode->c_cc[VEOL] = CEOL;
1175#endif
1176 } else {
1177 /* Raw mode */
1178 mode->c_iflag = 0;
1179 mode->c_oflag &= ~OPOST;
1180 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1181 mode->c_cc[VMIN] = 1;
1182 mode->c_cc[VTIME] = 0;
1183 }
1184 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001185#if IXANY
1186 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001187 if (reversed)
1188 mode->c_iflag |= IXANY;
1189 else
1190 mode->c_iflag &= ~IXANY;
1191 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001192#endif
1193#if TABDLY
1194 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001195 if (reversed)
1196 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1197 else
1198 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1199 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001200#endif
1201#if OXTABS
1202 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001203 if (reversed)
1204 mode->c_oflag |= OXTABS;
1205 else
1206 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001207 }
1208#endif
1209#if XCASE && IUCLC && OLCUC
1210 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001211 if (reversed) {
1212 mode->c_lflag &= ~XCASE;
1213 mode->c_iflag &= ~IUCLC;
1214 mode->c_oflag &= ~OLCUC;
1215 } else {
1216 mode->c_lflag |= XCASE;
1217 mode->c_iflag |= IUCLC;
1218 mode->c_oflag |= OLCUC;
1219 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001220 }
1221#endif
1222 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001223 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001224 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001225 mode->c_cc[VINTR] = 3; /* ^C */
1226 mode->c_cc[VERASE] = 127; /* DEL */
1227 mode->c_cc[VKILL] = 21; /* ^U */
1228 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1229 if (IXANY) mode->c_iflag &= ~IXANY;
1230 }
1231}
1232
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001233static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001234 const char *arg, struct termios *mode)
1235{
1236 unsigned char value;
1237
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001238 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001239 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1240 else if (arg[0] == '\0' || arg[1] == '\0')
1241 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001242 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001243 value = _POSIX_VDISABLE;
1244 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1245 value = arg[1] & 0x1f; /* Non-letters get weird results */
1246 if (arg[1] == '?')
1247 value = 127;
1248 } else
1249 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1250 mode->c_cc[info->offset] = value;
1251}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001252
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001253#define STTY_require_set_attr (1 << 0)
1254#define STTY_speed_was_set (1 << 1)
1255#define STTY_verbose_output (1 << 2)
1256#define STTY_recoverable_output (1 << 3)
1257#define STTY_noargs (1 << 4)
1258
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001259int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001260int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001261{
1262 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001263 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001264 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001265 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001266 int stty_state;
1267 int k;
1268
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001269 INIT_G();
1270
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001271 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001272 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001273
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001274 /* First pass: only parse/verify command line params */
1275 k = 0;
1276 while (argv[++k]) {
1277 const struct mode_info *mp;
1278 const struct control_info *cp;
1279 const char *arg = argv[k];
1280 const char *argnext = argv[k+1];
1281 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001282
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001283 if (arg[0] == '-') {
1284 int i;
1285 mp = find_mode(arg+1);
1286 if (mp) {
1287 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001288 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001289 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001290 continue;
1291 }
1292 /* It is an option - parse it */
1293 i = 0;
1294 while (arg[++i]) {
1295 switch (arg[i]) {
1296 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001297 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001298 output_func = do_display;
1299 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001300 break;
1301 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001302 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001303 output_func = display_recoverable;
1304 break;
1305 case 'F':
1306 if (file_name)
1307 bb_error_msg_and_die("only one device may be specified");
1308 file_name = &arg[i+1]; /* "-Fdevice" ? */
1309 if (!file_name[0]) { /* nope, "-F device" */
1310 int p = k+1; /* argv[p] is argnext */
1311 file_name = argnext;
1312 if (!file_name)
1313 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1314 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001315 while (argv[p]) {
1316 argv[p] = argv[p+1];
1317 ++p;
1318 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001319 }
1320 goto end_option;
1321 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001322 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001323 }
1324 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001325 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001326 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001327 }
1328
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001329 mp = find_mode(arg);
1330 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001331 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001332 continue;
1333 }
1334
1335 cp = find_control(arg);
1336 if (cp) {
1337 if (!argnext)
1338 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001339 /* called for the side effect of xfunc death only */
1340 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001341 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001342 ++k;
1343 continue;
1344 }
1345
1346 param = find_param(arg);
1347 if (param & param_need_arg) {
1348 if (!argnext)
1349 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1350 ++k;
1351 }
1352
1353 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001354#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001355 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001356# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001357 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001358 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001359# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001360#endif
1361#ifdef TIOCGWINSZ
1362 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001363 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001364 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001365 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001366 break;
1367 case param_size:
1368#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001369 case param_speed:
1370 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001371 case param_ispeed:
1372 /* called for the side effect of xfunc death only */
1373 set_speed_or_die(input_speed, argnext, &mode);
1374 break;
1375 case param_ospeed:
1376 /* called for the side effect of xfunc death only */
1377 set_speed_or_die(output_speed, argnext, &mode);
1378 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001379 default:
1380 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001381 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001382 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001383 bb_error_msg_and_die("invalid argument '%s'", arg);
1384 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001385 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001386 }
1387
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001388 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001389 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001390 (STTY_verbose_output | STTY_recoverable_output)
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001391 ) {
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001392 bb_error_msg_and_die("-a and -g are mutually exclusive");
1393 }
1394 /* Specifying -a or -g with non-options is an error */
1395 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
1396 && !(stty_state & STTY_noargs)
1397 ) {
1398 bb_error_msg_and_die("modes may not be set when -a or -g is used");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001399 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001400
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001401 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001402 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001403 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001404 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1405 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001406 }
1407
1408 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001409 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001410 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001411 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001412 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001413
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001414 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denys Vlasenko641caae2015-10-23 01:44:22 +02001415 G.max_col = get_terminal_width(STDOUT_FILENO);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001416 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001417 return EXIT_SUCCESS;
1418 }
1419
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001420 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001421 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001422 while (argv[++k]) {
1423 const struct mode_info *mp;
1424 const struct control_info *cp;
1425 const char *arg = argv[k];
1426 const char *argnext = argv[k+1];
1427 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001428
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001429 if (arg[0] == '-') {
1430 mp = find_mode(arg+1);
1431 if (mp) {
1432 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001433 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001434 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001435 /* It is an option - already parsed. Skip it */
1436 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001437 }
Mark Whitley446dd272001-03-02 20:00:54 +00001438
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001439 mp = find_mode(arg);
1440 if (mp) {
1441 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001442 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001443 continue;
1444 }
Mark Whitley446dd272001-03-02 20:00:54 +00001445
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001446 cp = find_control(arg);
1447 if (cp) {
1448 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001449 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001450 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001451 continue;
1452 }
Mark Whitley446dd272001-03-02 20:00:54 +00001453
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001454 param = find_param(arg);
1455 if (param & param_need_arg) {
1456 ++k;
1457 }
1458
1459 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001460#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001461 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001462 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001463 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001464 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001465#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001466#ifdef TIOCGWINSZ
1467 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001468 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001469 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001470 break;
1471 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001472 display_window_size(0);
1473 break;
1474 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001475 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001476 break;
1477#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001478 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001479 display_speed(&mode, 0);
1480 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001481 case param_ispeed:
1482 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001483 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001484 break;
1485 case param_ospeed:
1486 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001487 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001488 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001489 default:
1490 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001491 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001492 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001493 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001494 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001495 } /* else - impossible (caught in the first pass):
1496 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001497 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001498 }
1499
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001500 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001501 struct termios new_mode;
1502
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001503 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001504 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001505
1506 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1507 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001508 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001509 some proper subset of the requested operations. To detect
1510 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001511 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001512
1513 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001514 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001515 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001516 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001517 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001518
Eric Andersen98e599c2001-02-14 18:47:33 +00001519 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Denys Vlasenkoae0cf2a2013-05-17 20:08:12 +02001520/*
1521 * I think the below chunk is not necessary on Linux.
1522 * If you are deleting it, also delete STTY_speed_was_set bit -
1523 * it is only ever checked here.
1524 */
1525#if 0 /* was "if CIBAUD" */
Eric Andersen98e599c2001-02-14 18:47:33 +00001526 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1527 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1528 sometimes (m1 != m2). The only difference is in the four bits
1529 of the c_cflag field corresponding to the baud rate. To save
1530 Sun users a little confusion, don't report an error if this
1531 happens. But suppress the error only if we haven't tried to
1532 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001533 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001534
1535 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001536 if ((stty_state & STTY_speed_was_set)
1537 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001538#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001539 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001540 }
1541 }
1542
1543 return EXIT_SUCCESS;
1544}