blob: b63b0b91af7bce562f8d47b753129234583e9937 [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
Eric Andersen98e599c2001-02-14 18:47:33 +000021
22 */
23
Pere Orga34425382011-03-31 14:43:25 +020024//usage:#define stty_trivial_usage
25//usage: "[-a|g] [-F DEVICE] [SETTING]..."
26//usage:#define stty_full_usage "\n\n"
27//usage: "Without arguments, prints baud rate, line discipline,\n"
28//usage: "and deviations from stty sane\n"
Pere Orga34425382011-03-31 14:43:25 +020029//usage: "\n -F DEVICE Open device instead of stdin"
30//usage: "\n -a Print all current settings in human-readable form"
31//usage: "\n -g Print in stty-readable form"
32//usage: "\n [SETTING] See manpage"
33
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000034#include "libbb.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000035
Eric Andersen98e599c2001-02-14 18:47:33 +000036#ifndef _POSIX_VDISABLE
37# define _POSIX_VDISABLE ((unsigned char) 0)
38#endif
39
40#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000041/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000042#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000043# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000044#endif
45#ifndef CQUIT
46# define CQUIT 28
47#endif
48#ifndef CERASE
49# define CERASE 127
50#endif
51#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000052# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000053#endif
54#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000055# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000056#endif
57#ifndef CEOL
58# define CEOL _POSIX_VDISABLE
59#endif
60#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000061# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000062#endif
63#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000064# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000065#endif
66#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000067# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000068#endif
69#if defined(VEOL2) && !defined(CEOL2)
70# define CEOL2 _POSIX_VDISABLE
71#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +010072/* glibc-2.12.1 uses only VSWTC name */
73#if defined(VSWTC) && !defined(VSWTCH)
74# define VSWTCH VSWTC
75#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000076/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000077#if defined(VSUSP) && !defined(VSWTCH)
78# define VSWTCH VSUSP
79# define CSWTCH CSUSP
80#endif
81#if defined(VSWTCH) && !defined(CSWTCH)
82# define CSWTCH _POSIX_VDISABLE
83#endif
84
Denis Vlasenko79deb662006-09-19 15:12:12 +000085/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
86 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000087#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000088# undef CSWTCH
89# define CSWTCH _POSIX_VDISABLE
90#endif
91
Denis Vlasenkoff131b92007-04-10 15:42:06 +000092#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000093# define VWERASE VWERSE
94#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +000095#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000096# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +000097#endif
Mark Whitley446dd272001-03-02 20:00:54 +000098#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000099# define VREPRINT VRPRNT
100#endif
101#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000102# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +0000103#endif
104#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000105# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +0000106#endif
107#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000108# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +0000109#endif
110#if defined(VDISCARD) && !defined(VFLUSHO)
111# define VFLUSHO VDISCARD
112#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000113#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000114# define VFLUSHO VFLUSH
115#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000116#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000117# define ECHOCTL CTLECH
118#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000119#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000120# define ECHOCTL TCTLECH
121#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000122#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000123# define ECHOKE CRTKIL
124#endif
125#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000126# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000127#endif
128#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000129# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000130#endif
131
Jeremie Koenig138ce542010-07-30 06:01:37 +0200132/* Save us from #ifdef forest plague */
133#ifndef BSDLY
134# define BSDLY 0
135#endif
136#ifndef CIBAUD
137# define CIBAUD 0
138#endif
139#ifndef CRDLY
140# define CRDLY 0
141#endif
142#ifndef CRTSCTS
143# define CRTSCTS 0
144#endif
145#ifndef ECHOCTL
146# define ECHOCTL 0
147#endif
148#ifndef ECHOKE
149# define ECHOKE 0
150#endif
151#ifndef ECHOPRT
152# define ECHOPRT 0
153#endif
154#ifndef FFDLY
155# define FFDLY 0
156#endif
157#ifndef IEXTEN
158# define IEXTEN 0
159#endif
160#ifndef IMAXBEL
161# define IMAXBEL 0
162#endif
163#ifndef IUCLC
164# define IUCLC 0
165#endif
166#ifndef IXANY
167# define IXANY 0
168#endif
169#ifndef NLDLY
170# define NLDLY 0
171#endif
172#ifndef OCRNL
173# define OCRNL 0
174#endif
175#ifndef OFDEL
176# define OFDEL 0
177#endif
178#ifndef OFILL
179# define OFILL 0
180#endif
181#ifndef OLCUC
182# define OLCUC 0
183#endif
184#ifndef ONLCR
185# define ONLCR 0
186#endif
187#ifndef ONLRET
188# define ONLRET 0
189#endif
190#ifndef ONOCR
191# define ONOCR 0
192#endif
193#ifndef OXTABS
194# define OXTABS 0
195#endif
196#ifndef TABDLY
197# define TABDLY 0
198#endif
199#ifndef TAB1
200# define TAB1 0
201#endif
202#ifndef TAB2
203# define TAB2 0
204#endif
205#ifndef TOSTOP
206# define TOSTOP 0
207#endif
208#ifndef VDSUSP
209# define VDSUSP 0
210#endif
211#ifndef VEOL2
212# define VEOL2 0
213#endif
214#ifndef VFLUSHO
215# define VFLUSHO 0
216#endif
217#ifndef VLNEXT
218# define VLNEXT 0
219#endif
220#ifndef VREPRINT
221# define VREPRINT 0
222#endif
223#ifndef VSTATUS
224# define VSTATUS 0
225#endif
226#ifndef VSWTCH
227# define VSWTCH 0
228#endif
229#ifndef VTDLY
230# define VTDLY 0
231#endif
232#ifndef VWERASE
233# define VWERASE 0
234#endif
235#ifndef XCASE
236# define XCASE 0
237#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100238#ifndef IUTF8
239# define IUTF8 0
240#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200241
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000242/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000243enum speed_setting {
244 input_speed, output_speed, both_speeds
245};
246
Denis Vlasenko79deb662006-09-19 15:12:12 +0000247/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000248enum {
Eric Andersen98e599c2001-02-14 18:47:33 +0000249 control, input, output, local, combination
250};
Denys Vlasenkoe9581b62013-05-17 18:06:49 +0200251static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode)
252{
253 static const uint8_t tcflag_offsets[] ALIGN1 = {
254 offsetof(struct termios, c_cflag), /* control */
255 offsetof(struct termios, c_iflag), /* input */
256 offsetof(struct termios, c_oflag), /* output */
257 offsetof(struct termios, c_lflag) /* local */
258 };
259 if (type <= local) {
260 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
261 }
262 return NULL;
263}
Eric Andersen98e599c2001-02-14 18:47:33 +0000264
Denis Vlasenko79deb662006-09-19 15:12:12 +0000265/* Flags for 'struct mode_info' */
266#define SANE_SET 1 /* Set in 'sane' mode */
267#define SANE_UNSET 2 /* Unset in 'sane' mode */
268#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000269#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000270
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000271
272/* Each mode.
273 * This structure should be kept as small as humanly possible.
274 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000275struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000276 const uint8_t type; /* Which structure element to change */
277 const uint8_t flags; /* Setting and display options */
278 /* only these values are ever used, so... */
279#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
280 const uint8_t mask;
281#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
282 const uint16_t mask;
283#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000284 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000285#endif
286 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000287 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000288};
289
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000290enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000291 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000292 IDX_evenp = 0,
293 IDX_parity,
294 IDX_oddp,
295 IDX_nl,
296 IDX_ek,
297 IDX_sane,
298 IDX_cooked,
299 IDX_raw,
300 IDX_pass8,
301 IDX_litout,
302 IDX_cbreak,
303 IDX_crt,
304 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200305#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000306 IDX_decctlq,
307#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200308#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000309 IDX_tabs,
310#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200311#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000312 IDX_lcase,
313 IDX_LCASE,
314#endif
315};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000316
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000317#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000318
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000319/* Mode names given on command line */
320static const char mode_name[] =
321 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
322 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
323 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
324 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
325 MI_ENTRY("ek", combination, OMIT, 0, 0 )
326 MI_ENTRY("sane", combination, OMIT, 0, 0 )
327 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
328 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
329 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
330 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
331 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("crt", combination, OMIT, 0, 0 )
333 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200334#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000335 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000336#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200337#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000338 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000339#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200340#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000341 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
342 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000343#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000344 MI_ENTRY("parenb", control, REV, PARENB, 0 )
345 MI_ENTRY("parodd", control, REV, PARODD, 0 )
346 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
347 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
348 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
349 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
350 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
351 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
352 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
353 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
354 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200355#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000356 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000357#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000358 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
359 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
360 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
361 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
362 MI_ENTRY("inpck", input, REV, INPCK, 0 )
363 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
364 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
365 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
366 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
367 MI_ENTRY("ixon", input, REV, IXON, 0 )
368 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100369 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200370#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000371 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000372#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200373#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000374 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000375#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200376#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000377 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000378#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100379#if IUTF8
380 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
381#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000382 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200383#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000384 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000385#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200386#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000387 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000388#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200389#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000390 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000391#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200392#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000393 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000394#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200395#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000396 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000397#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200398#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000399 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000400#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200401#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000402 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000403#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200404#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000405 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
406 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000407#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200408#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000409 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
410 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
411 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
412 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000413#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000414
Jeremie Koenig138ce542010-07-30 06:01:37 +0200415#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000416 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200417# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000418 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200419# endif
420# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000421 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200422# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000423 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000424#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200425# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000426 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000427# endif
428#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000429
Jeremie Koenig138ce542010-07-30 06:01:37 +0200430#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000431 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
432 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000433#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200434#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000435 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
436 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000437#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200438#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000439 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
440 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000441#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000442 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
443 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200444#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000445 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000446#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000447 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
448 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100449 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000450 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
451 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
452 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200453#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000454 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000455#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200456#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000457 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000458#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200459#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000460 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100461 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000462#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200463#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000464 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100465 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000466#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200467#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000468 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100469 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000470#endif
471 ;
472
473#undef MI_ENTRY
474#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
475
476static const struct mode_info mode_info[] = {
477 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
478 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
479 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
480 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
481 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
482 MI_ENTRY("ek", combination, OMIT, 0, 0 )
483 MI_ENTRY("sane", combination, OMIT, 0, 0 )
484 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
485 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
486 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
487 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
488 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
489 MI_ENTRY("crt", combination, OMIT, 0, 0 )
490 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200491#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000492 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
493#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200494#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000495 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
496#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200497#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000498 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
499 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
500#endif
501 MI_ENTRY("parenb", control, REV, PARENB, 0 )
502 MI_ENTRY("parodd", control, REV, PARODD, 0 )
503 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
504 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
505 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
506 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
507 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
508 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
509 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
510 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
511 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200512#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000513 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
514#endif
515 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
516 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
517 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
518 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
519 MI_ENTRY("inpck", input, REV, INPCK, 0 )
520 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
521 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
522 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
523 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
524 MI_ENTRY("ixon", input, REV, IXON, 0 )
525 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100526 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200527#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000528 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
529#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200530#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000531 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
532#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200533#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000534 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
535#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100536#if IUTF8
537 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
538#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000539 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200540#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000541 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
542#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200543#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000544 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
545#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200546#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000547 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
548#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200549#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000550 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
551#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200552#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000553 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
554#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200555#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000556 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
557#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200558#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000559 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
560#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200561#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000562 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
563 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
564#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200565#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000566 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
567 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
568 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
569 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
570#endif
571
Jeremie Koenig138ce542010-07-30 06:01:37 +0200572#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000573 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200574# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000575 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200576# endif
577# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000578 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200579# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000580 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
581#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200582# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000583 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
584# endif
585#endif
586
Jeremie Koenig138ce542010-07-30 06:01:37 +0200587#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000588 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
589 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
590#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200591#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000592 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
593 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
594#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200595#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000596 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
597 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
598#endif
599 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
600 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200601#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000602 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
603#endif
604 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
605 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100606 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000607 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
608 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
609 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200610#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000611 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
612#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200613#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000614 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
615#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200616#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000617 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100618 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000619#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200620#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000621 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100622 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000623#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200624#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000625 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100626 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000627#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000628};
629
Rob Landleybc68cd12006-03-10 19:22:06 +0000630enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000631 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000632};
Eric Andersen98e599c2001-02-14 18:47:33 +0000633
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000634
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000635/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000636struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000637 const uint8_t saneval; /* Value to set for 'stty sane' */
638 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000639};
640
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000641enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000642 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000643 CIDX_intr = 0,
644 CIDX_quit,
645 CIDX_erase,
646 CIDX_kill,
647 CIDX_eof,
648 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200649#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000650 CIDX_eol2,
651#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200652#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000653 CIDX_swtch,
654#endif
655 CIDX_start,
656 CIDX_stop,
657 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200658#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000659 CIDX_dsusp,
660#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200661#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000662 CIDX_rprnt,
663#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200664#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000665 CIDX_werase,
666#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200667#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000668 CIDX_lnext,
669#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200670#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000671 CIDX_flush,
672#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200673#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000674 CIDX_status,
675#endif
676 CIDX_min,
677 CIDX_time,
678};
Eric Andersen98e599c2001-02-14 18:47:33 +0000679
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000680#define CI_ENTRY(n,s,o) n "\0"
681
682/* Name given on command line */
683static const char control_name[] =
684 CI_ENTRY("intr", CINTR, VINTR )
685 CI_ENTRY("quit", CQUIT, VQUIT )
686 CI_ENTRY("erase", CERASE, VERASE )
687 CI_ENTRY("kill", CKILL, VKILL )
688 CI_ENTRY("eof", CEOF, VEOF )
689 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200690#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000691 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000692#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200693#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000694 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000695#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000696 CI_ENTRY("start", CSTART, VSTART )
697 CI_ENTRY("stop", CSTOP, VSTOP )
698 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200699#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000700 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000701#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200702#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000703 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000704#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200705#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000706 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000707#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200708#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000709 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000710#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200711#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000712 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000713#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200714#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000715 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000716#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000717 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000718 CI_ENTRY("min", 1, VMIN )
719 CI_ENTRY("time", 0, VTIME )
720 ;
721
722#undef CI_ENTRY
723#define CI_ENTRY(n,s,o) { s, o },
724
725static const struct control_info control_info[] = {
726 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
727 CI_ENTRY("intr", CINTR, VINTR )
728 CI_ENTRY("quit", CQUIT, VQUIT )
729 CI_ENTRY("erase", CERASE, VERASE )
730 CI_ENTRY("kill", CKILL, VKILL )
731 CI_ENTRY("eof", CEOF, VEOF )
732 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200733#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000734 CI_ENTRY("eol2", CEOL2, VEOL2 )
735#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200736#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000737 CI_ENTRY("swtch", CSWTCH, VSWTCH )
738#endif
739 CI_ENTRY("start", CSTART, VSTART )
740 CI_ENTRY("stop", CSTOP, VSTOP )
741 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200742#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000743 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
744#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200745#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000746 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
747#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200748#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000749 CI_ENTRY("werase", CWERASE, VWERASE )
750#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200751#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000752 CI_ENTRY("lnext", CLNEXT, VLNEXT )
753#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200754#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000755 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
756#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200757#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000758 CI_ENTRY("status", CSTATUS, VSTATUS )
759#endif
760 /* These must be last because of the display routines */
761 CI_ENTRY("min", 1, VMIN )
762 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000763};
764
Rob Landleybc68cd12006-03-10 19:22:06 +0000765enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000766 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000767};
Eric Andersen98e599c2001-02-14 18:47:33 +0000768
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000769
770struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100771 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000772 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100773 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000774 /* Current position, to know when to wrap */
775 unsigned current_col;
776 char buf[10];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100777} FIX_ALIASING;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000778#define G (*(struct globals*)&bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000779#define INIT_G() do { \
780 G.device_name = bb_msg_standard_input; \
781 G.max_col = 80; \
782} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000783
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000784static void set_speed_or_die(enum speed_setting type, const char *arg,
785 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000786{
787 speed_t baud;
788
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000789 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000790
791 if (type != output_speed) { /* either input or both */
792 cfsetispeed(mode, baud);
793 }
794 if (type != input_speed) { /* either output or both */
795 cfsetospeed(mode, baud);
796 }
797}
798
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000799static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000800{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000801 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000802}
803
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000804static void perror_on_device(const char *fmt)
805{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000806 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000807}
808
Eric Andersen98e599c2001-02-14 18:47:33 +0000809/* Print format string MESSAGE and optional args.
810 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000811 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000812static void wrapf(const char *message, ...)
813{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000814 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000815 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000816 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000817
818 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000819 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000820 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000821 /* We seem to be called only with suitable lengths, but check if
822 somebody failed to adhere to this assumption just to be sure. */
823 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000824
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000825 if (G.current_col > 0) {
826 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000827 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000828 if (G.current_col + buflen >= G.max_col) {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000829 bb_putchar('\n');
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000830 G.current_col = 0;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000831 } else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000832 bb_putchar(' ');
Denis Vlasenko79deb662006-09-19 15:12:12 +0000833 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000834 }
835 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000836 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000837 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000838 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000839}
840
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100841static void newline(void)
842{
843 if (G.current_col != 0)
844 wrapf("\n");
845}
846
Jeremie Koenig138ce542010-07-30 06:01:37 +0200847#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100848static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000849{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000850 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000851
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000852 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000853 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000854 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000855 }
856 memset(&win, 0, sizeof(win));
857 }
858
859 if (rows >= 0)
860 win.ws_row = rows;
861 if (cols >= 0)
862 win.ws_col = cols;
863
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000864 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000865bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000866 perror_on_device("%s");
867}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200868#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000869
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100870static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000871{
872 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000873 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000874
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000875 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000876 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
877 perror_on_device(fmt_str);
878 }
879 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100880 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000881 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000882 }
883}
884
Eric Andersen98e599c2001-02-14 18:47:33 +0000885static const struct suffix_mult stty_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000886 { "b", 512 },
887 { "k", 1024 },
888 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200889 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000890};
891
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000892static const struct mode_info *find_mode(const char *name)
893{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000894 int i = index_in_strings(mode_name, name);
895 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000896}
897
898static const struct control_info *find_control(const char *name)
899{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000900 int i = index_in_strings(control_name, name);
901 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000902}
903
904enum {
905 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000906 param_line = 1 | 0x80,
907 param_rows = 2 | 0x80,
908 param_cols = 3 | 0x80,
909 param_columns = 4 | 0x80,
910 param_size = 5,
911 param_speed = 6,
912 param_ispeed = 7 | 0x80,
913 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000914};
915
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000916static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000917{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000918 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000919 "line\0" /* 1 */
920 "rows\0" /* 2 */
921 "cols\0" /* 3 */
922 "columns\0" /* 4 */
923 "size\0" /* 5 */
924 "speed\0" /* 6 */
925 "ispeed\0"
926 "ospeed\0";
927 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000928 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000929 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000930 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000931 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000932 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000933}
934
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000935static int recover_mode(const char *arg, struct termios *mode)
936{
937 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000938 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000939 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000940
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000941 /* Scan into temporaries since it is too much trouble to figure out
942 the right format for 'tcflag_t' */
943 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
944 &iflag, &oflag, &cflag, &lflag, &n) != 4)
945 return 0;
946 mode->c_iflag = iflag;
947 mode->c_oflag = oflag;
948 mode->c_cflag = cflag;
949 mode->c_lflag = lflag;
950 arg += n;
951 for (i = 0; i < NCCS; ++i) {
952 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
953 return 0;
954 mode->c_cc[i] = chr;
955 arg += n;
956 }
957
958 /* Fail if there are too many fields */
959 if (*arg != '\0')
960 return 0;
961
962 return 1;
963}
964
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000965static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000966 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000967{
968 int i;
969 printf("%lx:%lx:%lx:%lx",
970 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
971 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
972 for (i = 0; i < NCCS; ++i)
973 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000974 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000975}
976
977static void display_speed(const struct termios *mode, int fancy)
978{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100979 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000980 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
981 unsigned long ispeed, ospeed;
982
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +0100983 ispeed = cfgetispeed(mode);
984 ospeed = cfgetospeed(mode);
985 if (ispeed == 0 || ispeed == ospeed) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000986 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100987 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000988 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
989 }
990 if (fancy) fmt_str += 9;
991 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
992}
993
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100994static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000995{
996 int i;
997 tcflag_t *bitsp;
998 unsigned long mask;
999 int prev_type = control;
1000
1001 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001002 if (all)
1003 display_window_size(1);
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001004#ifdef __linux__
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001005 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001006#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001007 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001008#endif
1009
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001010 for (i = 0; i != CIDX_min; ++i) {
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001011 char ch;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001012 /* If swtch is the same as susp, don't print both */
1013#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001014 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001015 continue;
1016#endif
1017 /* If eof uses the same slot as min, only print whichever applies */
1018#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001019 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001020 && (i == CIDX_eof || i == CIDX_eol)
1021 ) {
1022 continue;
1023 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001024#endif
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001025 ch = mode->c_cc[control_info[i].offset];
1026 if (ch == _POSIX_VDISABLE)
1027 strcpy(G.buf, "<undef>");
1028 else
1029 visible(ch, G.buf, 0);
1030 wrapf("%s = %s;", nth_string(control_name, i), G.buf);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001031 }
1032#if VEOF == VMIN
1033 if ((mode->c_lflag & ICANON) == 0)
1034#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001035 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1036 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001037
1038 for (i = 0; i < NUM_mode_info; ++i) {
1039 if (mode_info[i].flags & OMIT)
1040 continue;
1041 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001042 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001043 prev_type = mode_info[i].type;
1044 }
1045
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001046 bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001047 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001048 if ((*bitsp & mask) == mode_info[i].bits) {
1049 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001050 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001051 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001052 if ((all && mode_info[i].flags & REV)
1053 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1054 ) {
1055 wrapf("-%s", nth_string(mode_name, i));
1056 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001057 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001058 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001059 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001060}
1061
1062static void sane_mode(struct termios *mode)
1063{
1064 int i;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001065
1066 for (i = 0; i < NUM_control_info; ++i) {
1067#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001068 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001069 break;
1070#endif
1071 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1072 }
1073
1074 for (i = 0; i < NUM_mode_info; ++i) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001075 tcflag_t val;
1076 tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
1077
1078 if (!bitsp)
1079 continue;
1080 val = *bitsp & ~((unsigned long)mode_info[i].mask);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001081 if (mode_info[i].flags & SANE_SET) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001082 *bitsp = val | mode_info[i].bits;
1083 } else
1084 if (mode_info[i].flags & SANE_UNSET) {
1085 *bitsp = val & ~mode_info[i].bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001086 }
1087 }
1088}
1089
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001090static void set_mode(const struct mode_info *info, int reversed,
1091 struct termios *mode)
1092{
1093 tcflag_t *bitsp;
1094
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001095 bitsp = get_ptr_to_tcflag(info->type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001096
1097 if (bitsp) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001098 tcflag_t val = *bitsp & ~info->mask;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001099 if (reversed)
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001100 *bitsp = val & ~info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001101 else
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001102 *bitsp = val | info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001103 return;
1104 }
1105
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001106 /* !bitsp - it's a "combination" mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001107 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001108 if (reversed)
1109 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1110 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001111 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001112 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001113 if (reversed)
1114 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1115 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001116 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001117 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001118 if (reversed) {
1119 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001120 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001121 } else {
1122 mode->c_iflag = mode->c_iflag & ~ICRNL;
1123 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1124 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001125 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001126 mode->c_cc[VERASE] = CERASE;
1127 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001128 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001129 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001130 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001131 if (reversed)
1132 mode->c_lflag |= ICANON;
1133 else
1134 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001135 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001136 if (reversed) {
1137 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1138 mode->c_iflag |= ISTRIP;
1139 } else {
1140 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1141 mode->c_iflag &= ~ISTRIP;
1142 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001143 } else if (info == &mode_info[IDX_litout]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001144 if (reversed) {
1145 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1146 mode->c_iflag |= ISTRIP;
1147 mode->c_oflag |= OPOST;
1148 } else {
1149 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1150 mode->c_iflag &= ~ISTRIP;
1151 mode->c_oflag &= ~OPOST;
1152 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001153 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001154 if ((info == &mode_info[IDX_raw] && reversed)
1155 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001156 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001157 /* Cooked mode */
1158 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1159 mode->c_oflag |= OPOST;
1160 mode->c_lflag |= ISIG | ICANON;
1161#if VMIN == VEOF
1162 mode->c_cc[VEOF] = CEOF;
1163#endif
1164#if VTIME == VEOL
1165 mode->c_cc[VEOL] = CEOL;
1166#endif
1167 } else {
1168 /* Raw mode */
1169 mode->c_iflag = 0;
1170 mode->c_oflag &= ~OPOST;
1171 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1172 mode->c_cc[VMIN] = 1;
1173 mode->c_cc[VTIME] = 0;
1174 }
1175 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001176#if IXANY
1177 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001178 if (reversed)
1179 mode->c_iflag |= IXANY;
1180 else
1181 mode->c_iflag &= ~IXANY;
1182 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001183#endif
1184#if TABDLY
1185 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001186 if (reversed)
1187 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1188 else
1189 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1190 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001191#endif
1192#if OXTABS
1193 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001194 if (reversed)
1195 mode->c_oflag |= OXTABS;
1196 else
1197 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001198 }
1199#endif
1200#if XCASE && IUCLC && OLCUC
1201 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001202 if (reversed) {
1203 mode->c_lflag &= ~XCASE;
1204 mode->c_iflag &= ~IUCLC;
1205 mode->c_oflag &= ~OLCUC;
1206 } else {
1207 mode->c_lflag |= XCASE;
1208 mode->c_iflag |= IUCLC;
1209 mode->c_oflag |= OLCUC;
1210 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001211 }
1212#endif
1213 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001214 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001215 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001216 mode->c_cc[VINTR] = 3; /* ^C */
1217 mode->c_cc[VERASE] = 127; /* DEL */
1218 mode->c_cc[VKILL] = 21; /* ^U */
1219 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1220 if (IXANY) mode->c_iflag &= ~IXANY;
1221 }
1222}
1223
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001224static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001225 const char *arg, struct termios *mode)
1226{
1227 unsigned char value;
1228
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001229 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001230 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1231 else if (arg[0] == '\0' || arg[1] == '\0')
1232 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001233 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001234 value = _POSIX_VDISABLE;
1235 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1236 value = arg[1] & 0x1f; /* Non-letters get weird results */
1237 if (arg[1] == '?')
1238 value = 127;
1239 } else
1240 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1241 mode->c_cc[info->offset] = value;
1242}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001243
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001244#define STTY_require_set_attr (1 << 0)
1245#define STTY_speed_was_set (1 << 1)
1246#define STTY_verbose_output (1 << 2)
1247#define STTY_recoverable_output (1 << 3)
1248#define STTY_noargs (1 << 4)
1249
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001250int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001251int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001252{
1253 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001254 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001255 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001256 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001257 int stty_state;
1258 int k;
1259
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001260 INIT_G();
1261
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001262 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001263 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001264
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001265 /* First pass: only parse/verify command line params */
1266 k = 0;
1267 while (argv[++k]) {
1268 const struct mode_info *mp;
1269 const struct control_info *cp;
1270 const char *arg = argv[k];
1271 const char *argnext = argv[k+1];
1272 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001273
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001274 if (arg[0] == '-') {
1275 int i;
1276 mp = find_mode(arg+1);
1277 if (mp) {
1278 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001279 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001280 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001281 continue;
1282 }
1283 /* It is an option - parse it */
1284 i = 0;
1285 while (arg[++i]) {
1286 switch (arg[i]) {
1287 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001288 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001289 output_func = do_display;
1290 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001291 break;
1292 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001293 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001294 output_func = display_recoverable;
1295 break;
1296 case 'F':
1297 if (file_name)
1298 bb_error_msg_and_die("only one device may be specified");
1299 file_name = &arg[i+1]; /* "-Fdevice" ? */
1300 if (!file_name[0]) { /* nope, "-F device" */
1301 int p = k+1; /* argv[p] is argnext */
1302 file_name = argnext;
1303 if (!file_name)
1304 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1305 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001306 while (argv[p]) {
1307 argv[p] = argv[p+1];
1308 ++p;
1309 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001310 }
1311 goto end_option;
1312 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001313 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001314 }
1315 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001316 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001317 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001318 }
1319
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001320 mp = find_mode(arg);
1321 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001322 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001323 continue;
1324 }
1325
1326 cp = find_control(arg);
1327 if (cp) {
1328 if (!argnext)
1329 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001330 /* called for the side effect of xfunc death only */
1331 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001332 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001333 ++k;
1334 continue;
1335 }
1336
1337 param = find_param(arg);
1338 if (param & param_need_arg) {
1339 if (!argnext)
1340 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1341 ++k;
1342 }
1343
1344 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001345#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001346 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001347# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001348 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001349 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001350# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001351#endif
1352#ifdef TIOCGWINSZ
1353 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001354 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001355 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001356 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001357 break;
1358 case param_size:
1359#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001360 case param_speed:
1361 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001362 case param_ispeed:
1363 /* called for the side effect of xfunc death only */
1364 set_speed_or_die(input_speed, argnext, &mode);
1365 break;
1366 case param_ospeed:
1367 /* called for the side effect of xfunc death only */
1368 set_speed_or_die(output_speed, argnext, &mode);
1369 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001370 default:
1371 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001372 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001373 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001374 bb_error_msg_and_die("invalid argument '%s'", arg);
1375 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001376 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001377 }
1378
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001379 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001380 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001381 (STTY_verbose_output | STTY_recoverable_output)
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001382 ) {
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001383 bb_error_msg_and_die("-a and -g are mutually exclusive");
1384 }
1385 /* Specifying -a or -g with non-options is an error */
1386 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
1387 && !(stty_state & STTY_noargs)
1388 ) {
1389 bb_error_msg_and_die("modes may not be set when -a or -g is used");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001390 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001391
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001392 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001393 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001394 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001395 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1396 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001397 }
1398
1399 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001400 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001401 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001402 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001403 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001404
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001405 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denys Vlasenko641caae2015-10-23 01:44:22 +02001406 G.max_col = get_terminal_width(STDOUT_FILENO);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001407 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001408 return EXIT_SUCCESS;
1409 }
1410
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001411 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001412 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001413 while (argv[++k]) {
1414 const struct mode_info *mp;
1415 const struct control_info *cp;
1416 const char *arg = argv[k];
1417 const char *argnext = argv[k+1];
1418 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001419
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001420 if (arg[0] == '-') {
1421 mp = find_mode(arg+1);
1422 if (mp) {
1423 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001424 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001425 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001426 /* It is an option - already parsed. Skip it */
1427 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001428 }
Mark Whitley446dd272001-03-02 20:00:54 +00001429
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001430 mp = find_mode(arg);
1431 if (mp) {
1432 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001433 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001434 continue;
1435 }
Mark Whitley446dd272001-03-02 20:00:54 +00001436
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001437 cp = find_control(arg);
1438 if (cp) {
1439 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001440 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001441 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001442 continue;
1443 }
Mark Whitley446dd272001-03-02 20:00:54 +00001444
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001445 param = find_param(arg);
1446 if (param & param_need_arg) {
1447 ++k;
1448 }
1449
1450 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001451#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001452 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001453 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001454 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001455 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001456#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001457#ifdef TIOCGWINSZ
1458 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001459 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001460 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001461 break;
1462 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001463 display_window_size(0);
1464 break;
1465 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001466 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001467 break;
1468#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001469 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001470 display_speed(&mode, 0);
1471 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001472 case param_ispeed:
1473 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001474 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001475 break;
1476 case param_ospeed:
1477 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001478 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001479 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001480 default:
1481 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001482 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001483 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001484 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001485 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001486 } /* else - impossible (caught in the first pass):
1487 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001488 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001489 }
1490
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001491 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001492 struct termios new_mode;
1493
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001494 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001495 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001496
1497 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1498 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001499 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001500 some proper subset of the requested operations. To detect
1501 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001502 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001503
1504 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001505 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001506 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001507 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001508 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001509
Eric Andersen98e599c2001-02-14 18:47:33 +00001510 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Denys Vlasenkoae0cf2a2013-05-17 20:08:12 +02001511/*
1512 * I think the below chunk is not necessary on Linux.
1513 * If you are deleting it, also delete STTY_speed_was_set bit -
1514 * it is only ever checked here.
1515 */
1516#if 0 /* was "if CIBAUD" */
Eric Andersen98e599c2001-02-14 18:47:33 +00001517 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1518 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1519 sometimes (m1 != m2). The only difference is in the four bits
1520 of the c_cflag field corresponding to the baud rate. To save
1521 Sun users a little confusion, don't report an error if this
1522 happens. But suppress the error only if we haven't tried to
1523 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001524 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001525
1526 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001527 if ((stty_state & STTY_speed_was_set)
1528 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001529#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001530 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001531 }
1532 }
1533
1534 return EXIT_SUCCESS;
1535}