blob: 52967ea8f3510c4c2ffe39132f38d0be3912fa69 [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"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020035#include "common_bufsiz.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000036
Eric Andersen98e599c2001-02-14 18:47:33 +000037#ifndef _POSIX_VDISABLE
38# define _POSIX_VDISABLE ((unsigned char) 0)
39#endif
40
41#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000042/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000043#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000044# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000045#endif
46#ifndef CQUIT
47# define CQUIT 28
48#endif
49#ifndef CERASE
50# define CERASE 127
51#endif
52#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000053# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000054#endif
55#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000056# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000057#endif
58#ifndef CEOL
59# define CEOL _POSIX_VDISABLE
60#endif
61#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000062# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000063#endif
64#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000065# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000066#endif
67#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000068# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000069#endif
70#if defined(VEOL2) && !defined(CEOL2)
71# define CEOL2 _POSIX_VDISABLE
72#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +010073/* glibc-2.12.1 uses only VSWTC name */
74#if defined(VSWTC) && !defined(VSWTCH)
75# define VSWTCH VSWTC
76#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000077/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000078#if defined(VSUSP) && !defined(VSWTCH)
79# define VSWTCH VSUSP
80# define CSWTCH CSUSP
81#endif
82#if defined(VSWTCH) && !defined(CSWTCH)
83# define CSWTCH _POSIX_VDISABLE
84#endif
85
Denis Vlasenko79deb662006-09-19 15:12:12 +000086/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
87 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000088#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000089# undef CSWTCH
90# define CSWTCH _POSIX_VDISABLE
91#endif
92
Denis Vlasenkoff131b92007-04-10 15:42:06 +000093#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000094# define VWERASE VWERSE
95#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +000096#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000097# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +000098#endif
Mark Whitley446dd272001-03-02 20:00:54 +000099#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000100# define VREPRINT VRPRNT
101#endif
102#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000103# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +0000104#endif
105#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000106# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +0000107#endif
108#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000109# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +0000110#endif
111#if defined(VDISCARD) && !defined(VFLUSHO)
112# define VFLUSHO VDISCARD
113#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000114#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000115# define VFLUSHO VFLUSH
116#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000117#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000118# define ECHOCTL CTLECH
119#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000120#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000121# define ECHOCTL TCTLECH
122#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000123#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000124# define ECHOKE CRTKIL
125#endif
126#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000127# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000128#endif
129#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000130# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000131#endif
132
Jeremie Koenig138ce542010-07-30 06:01:37 +0200133/* Save us from #ifdef forest plague */
134#ifndef BSDLY
135# define BSDLY 0
136#endif
137#ifndef CIBAUD
138# define CIBAUD 0
139#endif
140#ifndef CRDLY
141# define CRDLY 0
142#endif
143#ifndef CRTSCTS
144# define CRTSCTS 0
145#endif
146#ifndef ECHOCTL
147# define ECHOCTL 0
148#endif
149#ifndef ECHOKE
150# define ECHOKE 0
151#endif
152#ifndef ECHOPRT
153# define ECHOPRT 0
154#endif
155#ifndef FFDLY
156# define FFDLY 0
157#endif
158#ifndef IEXTEN
159# define IEXTEN 0
160#endif
161#ifndef IMAXBEL
162# define IMAXBEL 0
163#endif
164#ifndef IUCLC
165# define IUCLC 0
166#endif
167#ifndef IXANY
168# define IXANY 0
169#endif
170#ifndef NLDLY
171# define NLDLY 0
172#endif
173#ifndef OCRNL
174# define OCRNL 0
175#endif
176#ifndef OFDEL
177# define OFDEL 0
178#endif
179#ifndef OFILL
180# define OFILL 0
181#endif
182#ifndef OLCUC
183# define OLCUC 0
184#endif
185#ifndef ONLCR
186# define ONLCR 0
187#endif
188#ifndef ONLRET
189# define ONLRET 0
190#endif
191#ifndef ONOCR
192# define ONOCR 0
193#endif
194#ifndef OXTABS
195# define OXTABS 0
196#endif
197#ifndef TABDLY
198# define TABDLY 0
199#endif
200#ifndef TAB1
201# define TAB1 0
202#endif
203#ifndef TAB2
204# define TAB2 0
205#endif
206#ifndef TOSTOP
207# define TOSTOP 0
208#endif
209#ifndef VDSUSP
210# define VDSUSP 0
211#endif
212#ifndef VEOL2
213# define VEOL2 0
214#endif
215#ifndef VFLUSHO
216# define VFLUSHO 0
217#endif
218#ifndef VLNEXT
219# define VLNEXT 0
220#endif
221#ifndef VREPRINT
222# define VREPRINT 0
223#endif
224#ifndef VSTATUS
225# define VSTATUS 0
226#endif
227#ifndef VSWTCH
228# define VSWTCH 0
229#endif
230#ifndef VTDLY
231# define VTDLY 0
232#endif
233#ifndef VWERASE
234# define VWERASE 0
235#endif
236#ifndef XCASE
237# define XCASE 0
238#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100239#ifndef IUTF8
240# define IUTF8 0
241#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200242
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000243/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000244enum speed_setting {
245 input_speed, output_speed, both_speeds
246};
247
Denis Vlasenko79deb662006-09-19 15:12:12 +0000248/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000249enum {
Eric Andersen98e599c2001-02-14 18:47:33 +0000250 control, input, output, local, combination
251};
Denys Vlasenkoe9581b62013-05-17 18:06:49 +0200252static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode)
253{
254 static const uint8_t tcflag_offsets[] ALIGN1 = {
255 offsetof(struct termios, c_cflag), /* control */
256 offsetof(struct termios, c_iflag), /* input */
257 offsetof(struct termios, c_oflag), /* output */
258 offsetof(struct termios, c_lflag) /* local */
259 };
260 if (type <= local) {
261 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
262 }
263 return NULL;
264}
Eric Andersen98e599c2001-02-14 18:47:33 +0000265
Denis Vlasenko79deb662006-09-19 15:12:12 +0000266/* Flags for 'struct mode_info' */
267#define SANE_SET 1 /* Set in 'sane' mode */
268#define SANE_UNSET 2 /* Unset in 'sane' mode */
269#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000270#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000271
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000272
273/* Each mode.
274 * This structure should be kept as small as humanly possible.
275 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000276struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000277 const uint8_t type; /* Which structure element to change */
278 const uint8_t flags; /* Setting and display options */
279 /* only these values are ever used, so... */
280#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
281 const uint8_t mask;
282#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
283 const uint16_t mask;
284#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000285 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000286#endif
287 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000288 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000289};
290
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000291enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000292 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000293 IDX_evenp = 0,
294 IDX_parity,
295 IDX_oddp,
296 IDX_nl,
297 IDX_ek,
298 IDX_sane,
299 IDX_cooked,
300 IDX_raw,
301 IDX_pass8,
302 IDX_litout,
303 IDX_cbreak,
304 IDX_crt,
305 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200306#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000307 IDX_decctlq,
308#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200309#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000310 IDX_tabs,
311#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200312#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000313 IDX_lcase,
314 IDX_LCASE,
315#endif
316};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000317
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000318#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000319
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000320/* Mode names given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200321static const char mode_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000322 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
323 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
324 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
325 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
326 MI_ENTRY("ek", combination, OMIT, 0, 0 )
327 MI_ENTRY("sane", combination, OMIT, 0, 0 )
328 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
329 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
330 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
331 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
333 MI_ENTRY("crt", combination, OMIT, 0, 0 )
334 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200335#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000336 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000337#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200338#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000339 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000340#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200341#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000342 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
343 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000344#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000345 MI_ENTRY("parenb", control, REV, PARENB, 0 )
346 MI_ENTRY("parodd", control, REV, PARODD, 0 )
347 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
348 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
349 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
350 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
351 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
352 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
353 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
354 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
355 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200356#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000357 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000358#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000359 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
360 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
361 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
362 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
363 MI_ENTRY("inpck", input, REV, INPCK, 0 )
364 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
365 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
366 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
367 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
368 MI_ENTRY("ixon", input, REV, IXON, 0 )
369 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100370 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200371#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000372 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000373#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200374#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000375 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000376#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200377#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000378 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000379#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100380#if IUTF8
381 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
382#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000383 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200384#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000385 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000386#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200387#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000388 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000389#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200390#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000391 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000392#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200393#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000394 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000395#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200396#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000397 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000398#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200399#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000400 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000401#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200402#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000403 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000404#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200405#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000406 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
407 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000408#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200409#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000410 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
411 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
412 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
413 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000414#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000415
Jeremie Koenig138ce542010-07-30 06:01:37 +0200416#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000417 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200418# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000419 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200420# endif
421# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000422 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200423# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000424 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000425#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200426# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000427 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000428# endif
429#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000430
Jeremie Koenig138ce542010-07-30 06:01:37 +0200431#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000432 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
433 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000434#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200435#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000436 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
437 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000438#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200439#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000440 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
441 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000442#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000443 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
444 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200445#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000446 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000447#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000448 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
449 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100450 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000451 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
452 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
453 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200454#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000455 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000456#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200457#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000458 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000459#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200460#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000461 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100462 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000463#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200464#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000465 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100466 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000467#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200468#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000469 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100470 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000471#endif
472 ;
473
474#undef MI_ENTRY
475#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
476
477static const struct mode_info mode_info[] = {
478 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
479 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
480 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
481 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
482 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
483 MI_ENTRY("ek", combination, OMIT, 0, 0 )
484 MI_ENTRY("sane", combination, OMIT, 0, 0 )
485 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
486 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
487 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
488 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
489 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
490 MI_ENTRY("crt", combination, OMIT, 0, 0 )
491 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200492#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000493 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
494#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200495#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000496 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
497#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200498#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000499 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
500 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
501#endif
502 MI_ENTRY("parenb", control, REV, PARENB, 0 )
503 MI_ENTRY("parodd", control, REV, PARODD, 0 )
504 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
505 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
506 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
507 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
508 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
509 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
510 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
511 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
512 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200513#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000514 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
515#endif
516 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
517 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
518 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
519 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
520 MI_ENTRY("inpck", input, REV, INPCK, 0 )
521 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
522 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
523 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
524 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
525 MI_ENTRY("ixon", input, REV, IXON, 0 )
526 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100527 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200528#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000529 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
530#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200531#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000532 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
533#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200534#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000535 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
536#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100537#if IUTF8
538 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
539#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000540 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200541#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000542 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
543#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200544#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000545 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
546#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200547#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000548 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
549#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200550#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000551 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
552#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200553#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000554 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
555#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200556#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000557 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
558#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200559#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000560 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
561#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200562#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000563 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
564 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
565#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200566#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000567 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
568 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
569 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
570 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
571#endif
572
Jeremie Koenig138ce542010-07-30 06:01:37 +0200573#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000574 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200575# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000576 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200577# endif
578# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000579 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200580# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000581 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
582#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200583# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000584 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
585# endif
586#endif
587
Jeremie Koenig138ce542010-07-30 06:01:37 +0200588#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000589 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
590 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
591#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200592#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000593 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
594 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
595#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200596#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000597 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
598 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
599#endif
600 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
601 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200602#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000603 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
604#endif
605 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
606 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100607 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000608 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
609 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
610 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200611#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000612 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
613#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200614#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000615 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
616#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200617#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000618 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100619 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000620#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200621#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000622 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100623 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000624#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200625#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000626 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100627 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000628#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000629};
630
Rob Landleybc68cd12006-03-10 19:22:06 +0000631enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000632 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000633};
Eric Andersen98e599c2001-02-14 18:47:33 +0000634
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000635
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000636/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000637struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000638 const uint8_t saneval; /* Value to set for 'stty sane' */
639 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000640};
641
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000642enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000643 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000644 CIDX_intr = 0,
645 CIDX_quit,
646 CIDX_erase,
647 CIDX_kill,
648 CIDX_eof,
649 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200650#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000651 CIDX_eol2,
652#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200653#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000654 CIDX_swtch,
655#endif
656 CIDX_start,
657 CIDX_stop,
658 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200659#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000660 CIDX_dsusp,
661#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200662#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000663 CIDX_rprnt,
664#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200665#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000666 CIDX_werase,
667#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200668#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000669 CIDX_lnext,
670#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200671#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000672 CIDX_flush,
673#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200674#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000675 CIDX_status,
676#endif
677 CIDX_min,
678 CIDX_time,
679};
Eric Andersen98e599c2001-02-14 18:47:33 +0000680
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000681#define CI_ENTRY(n,s,o) n "\0"
682
683/* Name given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200684static const char control_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000685 CI_ENTRY("intr", CINTR, VINTR )
686 CI_ENTRY("quit", CQUIT, VQUIT )
687 CI_ENTRY("erase", CERASE, VERASE )
688 CI_ENTRY("kill", CKILL, VKILL )
689 CI_ENTRY("eof", CEOF, VEOF )
690 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200691#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000692 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000693#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200694#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000695 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000696#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000697 CI_ENTRY("start", CSTART, VSTART )
698 CI_ENTRY("stop", CSTOP, VSTOP )
699 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200700#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000701 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000702#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200703#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000704 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000705#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200706#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000707 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000708#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200709#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000710 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000711#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200712#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000713 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000714#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200715#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000716 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000717#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000718 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000719 CI_ENTRY("min", 1, VMIN )
720 CI_ENTRY("time", 0, VTIME )
721 ;
722
723#undef CI_ENTRY
724#define CI_ENTRY(n,s,o) { s, o },
725
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200726static const struct control_info control_info[] ALIGN2 = {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000727 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
728 CI_ENTRY("intr", CINTR, VINTR )
729 CI_ENTRY("quit", CQUIT, VQUIT )
730 CI_ENTRY("erase", CERASE, VERASE )
731 CI_ENTRY("kill", CKILL, VKILL )
732 CI_ENTRY("eof", CEOF, VEOF )
733 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200734#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000735 CI_ENTRY("eol2", CEOL2, VEOL2 )
736#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200737#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000738 CI_ENTRY("swtch", CSWTCH, VSWTCH )
739#endif
740 CI_ENTRY("start", CSTART, VSTART )
741 CI_ENTRY("stop", CSTOP, VSTOP )
742 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200743#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000744 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
745#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200746#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000747 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
748#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200749#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000750 CI_ENTRY("werase", CWERASE, VWERASE )
751#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200752#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000753 CI_ENTRY("lnext", CLNEXT, VLNEXT )
754#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200755#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000756 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
757#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200758#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000759 CI_ENTRY("status", CSTATUS, VSTATUS )
760#endif
761 /* These must be last because of the display routines */
762 CI_ENTRY("min", 1, VMIN )
763 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000764};
765
Rob Landleybc68cd12006-03-10 19:22:06 +0000766enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000767 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000768};
Eric Andersen98e599c2001-02-14 18:47:33 +0000769
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000770
771struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100772 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000773 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100774 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000775 /* Current position, to know when to wrap */
776 unsigned current_col;
777 char buf[10];
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100778} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200779#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000780#define INIT_G() do { \
781 G.device_name = bb_msg_standard_input; \
782 G.max_col = 80; \
783} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000784
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000785static void set_speed_or_die(enum speed_setting type, const char *arg,
786 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000787{
788 speed_t baud;
789
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000790 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000791
792 if (type != output_speed) { /* either input or both */
793 cfsetispeed(mode, baud);
794 }
795 if (type != input_speed) { /* either output or both */
796 cfsetospeed(mode, baud);
797 }
798}
799
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000800static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000801{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000802 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000803}
804
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000805static void perror_on_device(const char *fmt)
806{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000807 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000808}
809
Eric Andersen98e599c2001-02-14 18:47:33 +0000810/* Print format string MESSAGE and optional args.
811 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000812 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000813static void wrapf(const char *message, ...)
814{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000815 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000816 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000817 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000818
819 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000820 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000821 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000822 /* We seem to be called only with suitable lengths, but check if
823 somebody failed to adhere to this assumption just to be sure. */
824 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000825
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000826 if (G.current_col > 0) {
827 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000828 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000829 if (G.current_col + buflen >= G.max_col) {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000830 bb_putchar('\n');
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000831 G.current_col = 0;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000832 } else
Denis Vlasenko4daad902007-09-27 10:20:47 +0000833 bb_putchar(' ');
Denis Vlasenko79deb662006-09-19 15:12:12 +0000834 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000835 }
836 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000837 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000838 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000839 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000840}
841
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100842static void newline(void)
843{
844 if (G.current_col != 0)
845 wrapf("\n");
846}
847
Jeremie Koenig138ce542010-07-30 06:01:37 +0200848#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100849static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000850{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000851 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000852
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000853 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000854 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000855 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000856 }
857 memset(&win, 0, sizeof(win));
858 }
859
860 if (rows >= 0)
861 win.ws_row = rows;
862 if (cols >= 0)
863 win.ws_col = cols;
864
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000865 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000866bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000867 perror_on_device("%s");
868}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200869#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000870
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100871static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000872{
873 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000874 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000875
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000876 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000877 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
878 perror_on_device(fmt_str);
879 }
880 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100881 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000882 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000883 }
884}
885
Eric Andersen98e599c2001-02-14 18:47:33 +0000886static const struct suffix_mult stty_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000887 { "b", 512 },
888 { "k", 1024 },
889 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200890 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000891};
892
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000893static const struct mode_info *find_mode(const char *name)
894{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000895 int i = index_in_strings(mode_name, name);
896 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000897}
898
899static const struct control_info *find_control(const char *name)
900{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000901 int i = index_in_strings(control_name, name);
902 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000903}
904
905enum {
906 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000907 param_line = 1 | 0x80,
908 param_rows = 2 | 0x80,
909 param_cols = 3 | 0x80,
910 param_columns = 4 | 0x80,
911 param_size = 5,
912 param_speed = 6,
913 param_ispeed = 7 | 0x80,
914 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000915};
916
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000917static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000918{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000919 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000920 "line\0" /* 1 */
921 "rows\0" /* 2 */
922 "cols\0" /* 3 */
923 "columns\0" /* 4 */
924 "size\0" /* 5 */
925 "speed\0" /* 6 */
926 "ispeed\0"
927 "ospeed\0";
928 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000929 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000930 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000931 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000932 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000933 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000934}
935
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000936static int recover_mode(const char *arg, struct termios *mode)
937{
938 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000939 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000940 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000941
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000942 /* Scan into temporaries since it is too much trouble to figure out
943 the right format for 'tcflag_t' */
944 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
945 &iflag, &oflag, &cflag, &lflag, &n) != 4)
946 return 0;
947 mode->c_iflag = iflag;
948 mode->c_oflag = oflag;
949 mode->c_cflag = cflag;
950 mode->c_lflag = lflag;
951 arg += n;
952 for (i = 0; i < NCCS; ++i) {
953 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
954 return 0;
955 mode->c_cc[i] = chr;
956 arg += n;
957 }
958
959 /* Fail if there are too many fields */
960 if (*arg != '\0')
961 return 0;
962
963 return 1;
964}
965
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000966static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000967 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000968{
969 int i;
970 printf("%lx:%lx:%lx:%lx",
971 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
972 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
973 for (i = 0; i < NCCS; ++i)
974 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000975 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000976}
977
978static void display_speed(const struct termios *mode, int fancy)
979{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100980 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000981 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
982 unsigned long ispeed, ospeed;
983
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +0100984 ispeed = cfgetispeed(mode);
985 ospeed = cfgetospeed(mode);
986 if (ispeed == 0 || ispeed == ospeed) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000987 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100988 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000989 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
990 }
991 if (fancy) fmt_str += 9;
992 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
993}
994
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100995static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000996{
997 int i;
998 tcflag_t *bitsp;
999 unsigned long mask;
1000 int prev_type = control;
1001
1002 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001003 if (all)
1004 display_window_size(1);
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001005#ifdef __linux__
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001006 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001007#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001008 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001009#endif
1010
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001011 for (i = 0; i != CIDX_min; ++i) {
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001012 char ch;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001013 /* If swtch is the same as susp, don't print both */
1014#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001015 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001016 continue;
1017#endif
1018 /* If eof uses the same slot as min, only print whichever applies */
1019#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001020 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001021 && (i == CIDX_eof || i == CIDX_eol)
1022 ) {
1023 continue;
1024 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001025#endif
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001026 ch = mode->c_cc[control_info[i].offset];
1027 if (ch == _POSIX_VDISABLE)
1028 strcpy(G.buf, "<undef>");
1029 else
1030 visible(ch, G.buf, 0);
1031 wrapf("%s = %s;", nth_string(control_name, i), G.buf);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001032 }
1033#if VEOF == VMIN
1034 if ((mode->c_lflag & ICANON) == 0)
1035#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001036 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1037 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001038
1039 for (i = 0; i < NUM_mode_info; ++i) {
1040 if (mode_info[i].flags & OMIT)
1041 continue;
1042 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001043 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001044 prev_type = mode_info[i].type;
1045 }
1046
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001047 bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001048 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001049 if ((*bitsp & mask) == mode_info[i].bits) {
1050 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001051 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001052 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001053 if ((all && mode_info[i].flags & REV)
1054 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1055 ) {
1056 wrapf("-%s", nth_string(mode_name, i));
1057 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001058 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001059 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001060 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001061}
1062
1063static void sane_mode(struct termios *mode)
1064{
1065 int i;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001066
1067 for (i = 0; i < NUM_control_info; ++i) {
1068#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001069 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001070 break;
1071#endif
1072 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1073 }
1074
1075 for (i = 0; i < NUM_mode_info; ++i) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001076 tcflag_t val;
1077 tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
1078
1079 if (!bitsp)
1080 continue;
1081 val = *bitsp & ~((unsigned long)mode_info[i].mask);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001082 if (mode_info[i].flags & SANE_SET) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001083 *bitsp = val | mode_info[i].bits;
1084 } else
1085 if (mode_info[i].flags & SANE_UNSET) {
1086 *bitsp = val & ~mode_info[i].bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001087 }
1088 }
1089}
1090
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001091static void set_mode(const struct mode_info *info, int reversed,
1092 struct termios *mode)
1093{
1094 tcflag_t *bitsp;
1095
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001096 bitsp = get_ptr_to_tcflag(info->type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001097
1098 if (bitsp) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001099 tcflag_t val = *bitsp & ~info->mask;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001100 if (reversed)
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001101 *bitsp = val & ~info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001102 else
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001103 *bitsp = val | info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001104 return;
1105 }
1106
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001107 /* !bitsp - it's a "combination" mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001108 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001109 if (reversed)
1110 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1111 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001112 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001113 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001114 if (reversed)
1115 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1116 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001117 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001118 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001119 if (reversed) {
1120 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001121 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001122 } else {
1123 mode->c_iflag = mode->c_iflag & ~ICRNL;
1124 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1125 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001126 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001127 mode->c_cc[VERASE] = CERASE;
1128 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001129 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001130 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001131 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001132 if (reversed)
1133 mode->c_lflag |= ICANON;
1134 else
1135 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001136 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001137 if (reversed) {
1138 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1139 mode->c_iflag |= ISTRIP;
1140 } else {
1141 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1142 mode->c_iflag &= ~ISTRIP;
1143 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001144 } else if (info == &mode_info[IDX_litout]) {
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 mode->c_oflag |= OPOST;
1149 } else {
1150 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1151 mode->c_iflag &= ~ISTRIP;
1152 mode->c_oflag &= ~OPOST;
1153 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001154 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001155 if ((info == &mode_info[IDX_raw] && reversed)
1156 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001157 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001158 /* Cooked mode */
1159 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1160 mode->c_oflag |= OPOST;
1161 mode->c_lflag |= ISIG | ICANON;
1162#if VMIN == VEOF
1163 mode->c_cc[VEOF] = CEOF;
1164#endif
1165#if VTIME == VEOL
1166 mode->c_cc[VEOL] = CEOL;
1167#endif
1168 } else {
1169 /* Raw mode */
1170 mode->c_iflag = 0;
1171 mode->c_oflag &= ~OPOST;
1172 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1173 mode->c_cc[VMIN] = 1;
1174 mode->c_cc[VTIME] = 0;
1175 }
1176 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001177#if IXANY
1178 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001179 if (reversed)
1180 mode->c_iflag |= IXANY;
1181 else
1182 mode->c_iflag &= ~IXANY;
1183 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001184#endif
1185#if TABDLY
1186 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001187 if (reversed)
1188 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1189 else
1190 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1191 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001192#endif
1193#if OXTABS
1194 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001195 if (reversed)
1196 mode->c_oflag |= OXTABS;
1197 else
1198 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001199 }
1200#endif
1201#if XCASE && IUCLC && OLCUC
1202 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001203 if (reversed) {
1204 mode->c_lflag &= ~XCASE;
1205 mode->c_iflag &= ~IUCLC;
1206 mode->c_oflag &= ~OLCUC;
1207 } else {
1208 mode->c_lflag |= XCASE;
1209 mode->c_iflag |= IUCLC;
1210 mode->c_oflag |= OLCUC;
1211 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001212 }
1213#endif
1214 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001215 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001216 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001217 mode->c_cc[VINTR] = 3; /* ^C */
1218 mode->c_cc[VERASE] = 127; /* DEL */
1219 mode->c_cc[VKILL] = 21; /* ^U */
1220 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1221 if (IXANY) mode->c_iflag &= ~IXANY;
1222 }
1223}
1224
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001225static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001226 const char *arg, struct termios *mode)
1227{
1228 unsigned char value;
1229
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001230 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001231 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1232 else if (arg[0] == '\0' || arg[1] == '\0')
1233 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001234 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001235 value = _POSIX_VDISABLE;
1236 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1237 value = arg[1] & 0x1f; /* Non-letters get weird results */
1238 if (arg[1] == '?')
1239 value = 127;
1240 } else
1241 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1242 mode->c_cc[info->offset] = value;
1243}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001244
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001245#define STTY_require_set_attr (1 << 0)
1246#define STTY_speed_was_set (1 << 1)
1247#define STTY_verbose_output (1 << 2)
1248#define STTY_recoverable_output (1 << 3)
1249#define STTY_noargs (1 << 4)
1250
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001251int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001252int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001253{
1254 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001255 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001256 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001257 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001258 int stty_state;
1259 int k;
1260
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001261 INIT_G();
1262
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001263 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001264 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001265
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001266 /* First pass: only parse/verify command line params */
1267 k = 0;
1268 while (argv[++k]) {
1269 const struct mode_info *mp;
1270 const struct control_info *cp;
1271 const char *arg = argv[k];
1272 const char *argnext = argv[k+1];
1273 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001274
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001275 if (arg[0] == '-') {
1276 int i;
1277 mp = find_mode(arg+1);
1278 if (mp) {
1279 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001280 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001281 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001282 continue;
1283 }
1284 /* It is an option - parse it */
1285 i = 0;
1286 while (arg[++i]) {
1287 switch (arg[i]) {
1288 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001289 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001290 output_func = do_display;
1291 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001292 break;
1293 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001294 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001295 output_func = display_recoverable;
1296 break;
1297 case 'F':
1298 if (file_name)
1299 bb_error_msg_and_die("only one device may be specified");
1300 file_name = &arg[i+1]; /* "-Fdevice" ? */
1301 if (!file_name[0]) { /* nope, "-F device" */
1302 int p = k+1; /* argv[p] is argnext */
1303 file_name = argnext;
1304 if (!file_name)
1305 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1306 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001307 while (argv[p]) {
1308 argv[p] = argv[p+1];
1309 ++p;
1310 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001311 }
1312 goto end_option;
1313 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001314 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001315 }
1316 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001317 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001318 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001319 }
1320
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001321 mp = find_mode(arg);
1322 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001323 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001324 continue;
1325 }
1326
1327 cp = find_control(arg);
1328 if (cp) {
1329 if (!argnext)
1330 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001331 /* called for the side effect of xfunc death only */
1332 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001333 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001334 ++k;
1335 continue;
1336 }
1337
1338 param = find_param(arg);
1339 if (param & param_need_arg) {
1340 if (!argnext)
1341 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1342 ++k;
1343 }
1344
1345 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001346#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001347 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001348# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001349 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001350 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001351# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001352#endif
1353#ifdef TIOCGWINSZ
1354 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001355 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001356 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001357 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001358 break;
1359 case param_size:
1360#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001361 case param_speed:
1362 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001363 case param_ispeed:
1364 /* called for the side effect of xfunc death only */
1365 set_speed_or_die(input_speed, argnext, &mode);
1366 break;
1367 case param_ospeed:
1368 /* called for the side effect of xfunc death only */
1369 set_speed_or_die(output_speed, argnext, &mode);
1370 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001371 default:
1372 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001373 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001374 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001375 bb_error_msg_and_die("invalid argument '%s'", arg);
1376 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001377 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001378 }
1379
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001380 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001381 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001382 (STTY_verbose_output | STTY_recoverable_output)
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001383 ) {
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001384 bb_error_msg_and_die("-a and -g are mutually exclusive");
1385 }
1386 /* Specifying -a or -g with non-options is an error */
1387 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
1388 && !(stty_state & STTY_noargs)
1389 ) {
1390 bb_error_msg_and_die("modes may not be set when -a or -g is used");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001391 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001392
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001393 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001394 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001395 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001396 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1397 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001398 }
1399
1400 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001401 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001402 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001403 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001404 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001405
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001406 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denys Vlasenko641caae2015-10-23 01:44:22 +02001407 G.max_col = get_terminal_width(STDOUT_FILENO);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001408 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001409 return EXIT_SUCCESS;
1410 }
1411
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001412 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001413 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001414 while (argv[++k]) {
1415 const struct mode_info *mp;
1416 const struct control_info *cp;
1417 const char *arg = argv[k];
1418 const char *argnext = argv[k+1];
1419 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001420
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001421 if (arg[0] == '-') {
1422 mp = find_mode(arg+1);
1423 if (mp) {
1424 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001425 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001426 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001427 /* It is an option - already parsed. Skip it */
1428 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001429 }
Mark Whitley446dd272001-03-02 20:00:54 +00001430
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001431 mp = find_mode(arg);
1432 if (mp) {
1433 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001434 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001435 continue;
1436 }
Mark Whitley446dd272001-03-02 20:00:54 +00001437
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001438 cp = find_control(arg);
1439 if (cp) {
1440 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001441 set_control_char_or_die(cp, argnext, &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 param = find_param(arg);
1447 if (param & param_need_arg) {
1448 ++k;
1449 }
1450
1451 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001452#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001453 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001454 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001455 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001456 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001457#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001458#ifdef TIOCGWINSZ
1459 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001460 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001461 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001462 break;
1463 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001464 display_window_size(0);
1465 break;
1466 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001467 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001468 break;
1469#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001470 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001471 display_speed(&mode, 0);
1472 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001473 case param_ispeed:
1474 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001475 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001476 break;
1477 case param_ospeed:
1478 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001479 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001480 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001481 default:
1482 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001483 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001484 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001485 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001486 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001487 } /* else - impossible (caught in the first pass):
1488 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001489 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001490 }
1491
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001492 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001493 struct termios new_mode;
1494
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001495 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001496 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001497
1498 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1499 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001500 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001501 some proper subset of the requested operations. To detect
1502 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001503 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001504
1505 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001506 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001507 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001508 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001509 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001510
Eric Andersen98e599c2001-02-14 18:47:33 +00001511 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Denys Vlasenkoae0cf2a2013-05-17 20:08:12 +02001512/*
1513 * I think the below chunk is not necessary on Linux.
1514 * If you are deleting it, also delete STTY_speed_was_set bit -
1515 * it is only ever checked here.
1516 */
1517#if 0 /* was "if CIBAUD" */
Eric Andersen98e599c2001-02-14 18:47:33 +00001518 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1519 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1520 sometimes (m1 != m2). The only difference is in the four bits
1521 of the c_cflag field corresponding to the baud rate. To save
1522 Sun users a little confusion, don't report an error if this
1523 happens. But suppress the error only if we haven't tried to
1524 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001525 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001526
1527 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001528 if ((stty_state & STTY_speed_was_set)
1529 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001530#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001531 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001532 }
1533 }
1534
1535 return EXIT_SUCCESS;
1536}