blob: ba2b78317a5098a62a9125bc08ae30c890d2a685 [file] [log] [blame]
Eric Andersen98e599c2001-02-14 18:47:33 +00001/* vi: set sw=4 ts=4: */
Denys Vlasenkoa02a4e92017-10-05 15:19:25 +02002/*
3 * stty -- change and print terminal line settings
Denys Vlasenkoebe6d9d2017-10-05 14:40:24 +02004 * Copyright (C) 1990-1999 Free Software Foundation, Inc.
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7 */
Denys Vlasenko4a674862019-02-27 16:45:39 +01008/* David MacKenzie <djm@gnu.ai.mit.edu>
Denys Vlasenkoebe6d9d2017-10-05 14:40:24 +02009 *
10 * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
11 */
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010012//config:config STTY
Denys Vlasenkob097a842018-12-28 03:20:17 +010013//config: bool "stty (8.9 kb)"
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010014//config: default y
15//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020016//config: stty is used to change and print terminal line settings.
Eric Andersen98e599c2001-02-14 18:47:33 +000017
Denys Vlasenko692eeb82017-08-04 20:07:19 +020018//applet:IF_STTY(APPLET_NOEXEC(stty, stty, BB_DIR_BIN, BB_SUID_DROP, stty))
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010019
20//kbuild:lib-$(CONFIG_STTY) += stty.o
Eric Andersen98e599c2001-02-14 18:47:33 +000021
Pere Orga34425382011-03-31 14:43:25 +020022//usage:#define stty_trivial_usage
23//usage: "[-a|g] [-F DEVICE] [SETTING]..."
24//usage:#define stty_full_usage "\n\n"
25//usage: "Without arguments, prints baud rate, line discipline,\n"
26//usage: "and deviations from stty sane\n"
Pere Orga34425382011-03-31 14:43:25 +020027//usage: "\n -F DEVICE Open device instead of stdin"
28//usage: "\n -a Print all current settings in human-readable form"
29//usage: "\n -g Print in stty-readable form"
30//usage: "\n [SETTING] See manpage"
31
Denys Vlasenko4a674862019-02-27 16:45:39 +010032/* If no args are given, write to stdout the baud rate and settings that
33 * have been changed from their defaults. Mode reading and changes
34 * are done on the specified device, or stdin if none was specified.
35 */
36
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000037#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020038#include "common_bufsiz.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000039
Eric Andersen98e599c2001-02-14 18:47:33 +000040#ifndef _POSIX_VDISABLE
41# define _POSIX_VDISABLE ((unsigned char) 0)
42#endif
43
44#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000045/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000046#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000047# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000048#endif
49#ifndef CQUIT
50# define CQUIT 28
51#endif
52#ifndef CERASE
53# define CERASE 127
54#endif
55#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000056# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000057#endif
58#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000059# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000060#endif
61#ifndef CEOL
62# define CEOL _POSIX_VDISABLE
63#endif
64#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000065# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000066#endif
67#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000068# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000069#endif
70#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000071# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000072#endif
73#if defined(VEOL2) && !defined(CEOL2)
74# define CEOL2 _POSIX_VDISABLE
75#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +010076/* glibc-2.12.1 uses only VSWTC name */
77#if defined(VSWTC) && !defined(VSWTCH)
78# define VSWTCH VSWTC
79#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000080/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000081#if defined(VSUSP) && !defined(VSWTCH)
82# define VSWTCH VSUSP
83# define CSWTCH CSUSP
84#endif
85#if defined(VSWTCH) && !defined(CSWTCH)
86# define CSWTCH _POSIX_VDISABLE
87#endif
88
Denis Vlasenko79deb662006-09-19 15:12:12 +000089/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
90 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000091#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000092# undef CSWTCH
93# define CSWTCH _POSIX_VDISABLE
94#endif
95
Denis Vlasenkoff131b92007-04-10 15:42:06 +000096#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +000097# define VWERASE VWERSE
98#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +000099#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000100# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +0000101#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000102#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000103# define VREPRINT VRPRNT
104#endif
105#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000106# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +0000107#endif
108#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000109# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +0000110#endif
111#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000112# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +0000113#endif
114#if defined(VDISCARD) && !defined(VFLUSHO)
115# define VFLUSHO VDISCARD
116#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000117#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000118# define VFLUSHO VFLUSH
119#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000120#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000121# define ECHOCTL CTLECH
122#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000123#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000124# define ECHOCTL TCTLECH
125#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000126#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000127# define ECHOKE CRTKIL
128#endif
129#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000130# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000131#endif
132#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000133# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000134#endif
135
Jeremie Koenig138ce542010-07-30 06:01:37 +0200136/* Save us from #ifdef forest plague */
137#ifndef BSDLY
138# define BSDLY 0
139#endif
140#ifndef CIBAUD
141# define CIBAUD 0
142#endif
143#ifndef CRDLY
144# define CRDLY 0
145#endif
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200146#ifndef CMSPAR
147# define CMSPAR 0
148#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200149#ifndef CRTSCTS
150# define CRTSCTS 0
151#endif
152#ifndef ECHOCTL
153# define ECHOCTL 0
154#endif
155#ifndef ECHOKE
156# define ECHOKE 0
157#endif
158#ifndef ECHOPRT
159# define ECHOPRT 0
160#endif
161#ifndef FFDLY
162# define FFDLY 0
163#endif
164#ifndef IEXTEN
165# define IEXTEN 0
166#endif
167#ifndef IMAXBEL
168# define IMAXBEL 0
169#endif
170#ifndef IUCLC
171# define IUCLC 0
172#endif
173#ifndef IXANY
174# define IXANY 0
175#endif
176#ifndef NLDLY
177# define NLDLY 0
178#endif
179#ifndef OCRNL
180# define OCRNL 0
181#endif
182#ifndef OFDEL
183# define OFDEL 0
184#endif
185#ifndef OFILL
186# define OFILL 0
187#endif
188#ifndef OLCUC
189# define OLCUC 0
190#endif
191#ifndef ONLCR
192# define ONLCR 0
193#endif
194#ifndef ONLRET
195# define ONLRET 0
196#endif
197#ifndef ONOCR
198# define ONOCR 0
199#endif
200#ifndef OXTABS
201# define OXTABS 0
202#endif
203#ifndef TABDLY
204# define TABDLY 0
205#endif
206#ifndef TAB1
207# define TAB1 0
208#endif
209#ifndef TAB2
210# define TAB2 0
211#endif
212#ifndef TOSTOP
213# define TOSTOP 0
214#endif
215#ifndef VDSUSP
216# define VDSUSP 0
217#endif
218#ifndef VEOL2
219# define VEOL2 0
220#endif
221#ifndef VFLUSHO
222# define VFLUSHO 0
223#endif
224#ifndef VLNEXT
225# define VLNEXT 0
226#endif
227#ifndef VREPRINT
228# define VREPRINT 0
229#endif
230#ifndef VSTATUS
231# define VSTATUS 0
232#endif
233#ifndef VSWTCH
234# define VSWTCH 0
235#endif
236#ifndef VTDLY
237# define VTDLY 0
238#endif
239#ifndef VWERASE
240# define VWERASE 0
241#endif
242#ifndef XCASE
243# define XCASE 0
244#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100245#ifndef IUTF8
246# define IUTF8 0
247#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200248
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000249/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000250enum speed_setting {
251 input_speed, output_speed, both_speeds
252};
253
Denis Vlasenko79deb662006-09-19 15:12:12 +0000254/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000255enum {
Eric Andersen98e599c2001-02-14 18:47:33 +0000256 control, input, output, local, combination
257};
Denys Vlasenkoe9581b62013-05-17 18:06:49 +0200258static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode)
259{
260 static const uint8_t tcflag_offsets[] ALIGN1 = {
261 offsetof(struct termios, c_cflag), /* control */
262 offsetof(struct termios, c_iflag), /* input */
263 offsetof(struct termios, c_oflag), /* output */
264 offsetof(struct termios, c_lflag) /* local */
265 };
266 if (type <= local) {
267 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
268 }
269 return NULL;
270}
Eric Andersen98e599c2001-02-14 18:47:33 +0000271
Denis Vlasenko79deb662006-09-19 15:12:12 +0000272/* Flags for 'struct mode_info' */
273#define SANE_SET 1 /* Set in 'sane' mode */
274#define SANE_UNSET 2 /* Unset in 'sane' mode */
275#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000276#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000277
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000278
279/* Each mode.
280 * This structure should be kept as small as humanly possible.
281 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000282struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000283 const uint8_t type; /* Which structure element to change */
284 const uint8_t flags; /* Setting and display options */
285 /* only these values are ever used, so... */
286#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
287 const uint8_t mask;
288#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
289 const uint16_t mask;
290#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000291 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000292#endif
293 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000294 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000295};
296
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000297enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000298 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000299 IDX_evenp = 0,
300 IDX_parity,
301 IDX_oddp,
302 IDX_nl,
303 IDX_ek,
304 IDX_sane,
305 IDX_cooked,
306 IDX_raw,
307 IDX_pass8,
308 IDX_litout,
309 IDX_cbreak,
310 IDX_crt,
311 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200312#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000313 IDX_decctlq,
314#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200315#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000316 IDX_tabs,
317#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200318#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000319 IDX_lcase,
320 IDX_LCASE,
321#endif
322};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000323
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000324#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000325
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000326/* Mode names given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200327static const char mode_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000328 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
329 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
330 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
331 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("ek", combination, OMIT, 0, 0 )
333 MI_ENTRY("sane", combination, OMIT, 0, 0 )
334 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
335 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
336 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
337 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
338 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
339 MI_ENTRY("crt", combination, OMIT, 0, 0 )
340 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200341#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000342 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000343#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200344#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000345 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000346#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200347#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000348 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
349 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000350#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000351 MI_ENTRY("parenb", control, REV, PARENB, 0 )
352 MI_ENTRY("parodd", control, REV, PARODD, 0 )
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200353#if CMSPAR
354 MI_ENTRY("cmspar", control, REV, CMSPAR, 0 )
355#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000356 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
357 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
358 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
359 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
360 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
361 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
362 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
363 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
364 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200365#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000366 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000367#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000368 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
369 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
370 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
371 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
372 MI_ENTRY("inpck", input, REV, INPCK, 0 )
373 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
374 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
375 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
376 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
377 MI_ENTRY("ixon", input, REV, IXON, 0 )
378 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100379 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200380#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000381 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000382#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200383#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000384 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000385#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200386#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000387 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000388#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100389#if IUTF8
390 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
391#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000392 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200393#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000394 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000395#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200396#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000397 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000398#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200399#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000400 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000401#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200402#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000403 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000404#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200405#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000406 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000407#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200408#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000409 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000410#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200411#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000412 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000413#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200414#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000415 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
416 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000417#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200418#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000419 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
420 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
421 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
422 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000423#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000424
Jeremie Koenig138ce542010-07-30 06:01:37 +0200425#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000426 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200427# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000428 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200429# endif
430# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000431 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200432# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000433 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000434#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200435# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000436 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000437# endif
438#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000439
Jeremie Koenig138ce542010-07-30 06:01:37 +0200440#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000441 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
442 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000443#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200444#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000445 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
446 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000447#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200448#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000449 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
450 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000451#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000452 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
453 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200454#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000455 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000456#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000457 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
458 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100459 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000460 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
461 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
462 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200463#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000464 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000465#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200466#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000467 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000468#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200469#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000470 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100471 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000472#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200473#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000474 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100475 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000476#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200477#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000478 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100479 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000480#endif
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200481 MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 )
482#ifdef EXTPROC
483 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
484#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000485 ;
486
487#undef MI_ENTRY
488#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
489
Denys Vlasenko965b7952020-11-30 13:03:03 +0100490static const struct mode_info mode_info[] ALIGN4 = {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000491 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
492 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
493 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
494 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
495 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
496 MI_ENTRY("ek", combination, OMIT, 0, 0 )
497 MI_ENTRY("sane", combination, OMIT, 0, 0 )
498 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
499 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
500 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
501 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
502 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
503 MI_ENTRY("crt", combination, OMIT, 0, 0 )
504 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200505#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000506 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
507#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200508#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000509 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
510#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200511#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000512 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
513 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
514#endif
515 MI_ENTRY("parenb", control, REV, PARENB, 0 )
516 MI_ENTRY("parodd", control, REV, PARODD, 0 )
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200517#if CMSPAR
518 MI_ENTRY("cmspar", control, REV, CMSPAR, 0 )
519#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000520 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
521 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
522 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
523 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
524 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
525 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
526 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
527 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
528 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200529#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000530 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
531#endif
532 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
533 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
534 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
535 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
536 MI_ENTRY("inpck", input, REV, INPCK, 0 )
537 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
538 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
539 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
540 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
541 MI_ENTRY("ixon", input, REV, IXON, 0 )
542 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100543 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200544#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000545 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
546#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200547#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000548 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
549#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200550#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000551 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
552#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100553#if IUTF8
554 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
555#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000556 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200557#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000558 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
559#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200560#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000561 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
562#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200563#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000564 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
565#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200566#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000567 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
568#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200569#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000570 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
571#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200572#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000573 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
574#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200575#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000576 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
577#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200578#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000579 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
580 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
581#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200582#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000583 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
584 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
585 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
586 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
587#endif
588
Jeremie Koenig138ce542010-07-30 06:01:37 +0200589#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000590 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200591# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000592 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200593# endif
594# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000595 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200596# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000597 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
598#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200599# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000600 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
601# endif
602#endif
603
Jeremie Koenig138ce542010-07-30 06:01:37 +0200604#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000605 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
606 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
607#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200608#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000609 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
610 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
611#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200612#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000613 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
614 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
615#endif
616 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
617 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200618#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000619 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
620#endif
621 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
622 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100623 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000624 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
625 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
626 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200627#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000628 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
629#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200630#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000631 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
632#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200633#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000634 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100635 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000636#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200637#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000638 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100639 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000640#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200641#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000642 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100643 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000644#endif
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200645 MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 )
646#ifdef EXTPROC
647 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
648#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000649};
650
Rob Landleybc68cd12006-03-10 19:22:06 +0000651enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000652 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000653};
Eric Andersen98e599c2001-02-14 18:47:33 +0000654
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000655
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000656/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000657struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000658 const uint8_t saneval; /* Value to set for 'stty sane' */
659 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000660};
661
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000662enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000663 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000664 CIDX_intr = 0,
665 CIDX_quit,
666 CIDX_erase,
667 CIDX_kill,
668 CIDX_eof,
669 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200670#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000671 CIDX_eol2,
672#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200673#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000674 CIDX_swtch,
675#endif
676 CIDX_start,
677 CIDX_stop,
678 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200679#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000680 CIDX_dsusp,
681#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200682#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000683 CIDX_rprnt,
684#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200685#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000686 CIDX_werase,
687#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200688#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000689 CIDX_lnext,
690#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200691#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000692 CIDX_flush,
693#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200694#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000695 CIDX_status,
696#endif
697 CIDX_min,
698 CIDX_time,
699};
Eric Andersen98e599c2001-02-14 18:47:33 +0000700
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000701#define CI_ENTRY(n,s,o) n "\0"
702
703/* Name given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200704static const char control_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000705 CI_ENTRY("intr", CINTR, VINTR )
706 CI_ENTRY("quit", CQUIT, VQUIT )
707 CI_ENTRY("erase", CERASE, VERASE )
708 CI_ENTRY("kill", CKILL, VKILL )
709 CI_ENTRY("eof", CEOF, VEOF )
710 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200711#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000712 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000713#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200714#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000715 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000716#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000717 CI_ENTRY("start", CSTART, VSTART )
718 CI_ENTRY("stop", CSTOP, VSTOP )
719 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200720#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000721 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000722#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200723#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000724 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000725#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200726#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000727 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000728#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200729#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000730 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000731#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200732#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000733 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000734#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200735#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000736 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000737#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000738 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000739 CI_ENTRY("min", 1, VMIN )
740 CI_ENTRY("time", 0, VTIME )
741 ;
742
743#undef CI_ENTRY
744#define CI_ENTRY(n,s,o) { s, o },
745
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200746static const struct control_info control_info[] ALIGN2 = {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000747 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
748 CI_ENTRY("intr", CINTR, VINTR )
749 CI_ENTRY("quit", CQUIT, VQUIT )
750 CI_ENTRY("erase", CERASE, VERASE )
751 CI_ENTRY("kill", CKILL, VKILL )
752 CI_ENTRY("eof", CEOF, VEOF )
753 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200754#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000755 CI_ENTRY("eol2", CEOL2, VEOL2 )
756#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200757#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000758 CI_ENTRY("swtch", CSWTCH, VSWTCH )
759#endif
760 CI_ENTRY("start", CSTART, VSTART )
761 CI_ENTRY("stop", CSTOP, VSTOP )
762 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200763#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000764 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
765#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200766#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000767 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
768#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200769#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000770 CI_ENTRY("werase", CWERASE, VWERASE )
771#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200772#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000773 CI_ENTRY("lnext", CLNEXT, VLNEXT )
774#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200775#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000776 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
777#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200778#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000779 CI_ENTRY("status", CSTATUS, VSTATUS )
780#endif
781 /* These must be last because of the display routines */
782 CI_ENTRY("min", 1, VMIN )
783 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000784};
785
Rob Landleybc68cd12006-03-10 19:22:06 +0000786enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000787 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000788};
Eric Andersen98e599c2001-02-14 18:47:33 +0000789
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000790
791struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100792 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000793 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100794 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000795 /* Current position, to know when to wrap */
796 unsigned current_col;
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100797} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200798#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000799#define INIT_G() do { \
Denys Vlasenkob9be7802017-08-06 21:23:03 +0200800 setup_common_bufsiz(); \
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000801 G.device_name = bb_msg_standard_input; \
802 G.max_col = 80; \
Denys Vlasenko184c7382017-08-06 20:55:56 +0200803 G.current_col = 0; /* we are noexec, must clear */ \
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000804} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000805
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000806static void set_speed_or_die(enum speed_setting type, const char *arg,
807 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000808{
809 speed_t baud;
810
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000811 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000812
813 if (type != output_speed) { /* either input or both */
814 cfsetispeed(mode, baud);
815 }
816 if (type != input_speed) { /* either output or both */
817 cfsetospeed(mode, baud);
818 }
819}
820
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000821static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000822{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000823 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000824}
825
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000826static void perror_on_device(const char *fmt)
827{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000828 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000829}
830
Eric Andersen98e599c2001-02-14 18:47:33 +0000831/* Print format string MESSAGE and optional args.
832 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000833 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000834static void wrapf(const char *message, ...)
835{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000836 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000837 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000838 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000839
840 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000841 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000842 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000843 /* We seem to be called only with suitable lengths, but check if
844 somebody failed to adhere to this assumption just to be sure. */
845 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000846
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000847 if (G.current_col > 0) {
848 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000849 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000850 if (G.current_col + buflen >= G.max_col) {
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000851 G.current_col = 0;
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200852 bb_putchar('\n');
853 } else {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000854 bb_putchar(' ');
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200855 }
Denis Vlasenko79deb662006-09-19 15:12:12 +0000856 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000857 }
Ron Yorstoncad3fc72021-02-03 20:47:14 +0100858 fputs_stdout(buf);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000859 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000860 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000861 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000862}
863
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100864static void newline(void)
865{
866 if (G.current_col != 0)
867 wrapf("\n");
868}
869
Jeremie Koenig138ce542010-07-30 06:01:37 +0200870#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100871static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000872{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000873 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000874
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000875 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000876 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000877 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000878 }
879 memset(&win, 0, sizeof(win));
880 }
881
882 if (rows >= 0)
883 win.ws_row = rows;
884 if (cols >= 0)
885 win.ws_col = cols;
886
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000887 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000888bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000889 perror_on_device("%s");
890}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200891#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000892
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100893static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000894{
895 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000896 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000897
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000898 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000899 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
900 perror_on_device(fmt_str);
901 }
902 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100903 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000904 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000905 }
906}
907
Denys Vlasenko965b7952020-11-30 13:03:03 +0100908static const struct suffix_mult stty_suffixes[] ALIGN_SUFFIX = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000909 { "b", 512 },
910 { "k", 1024 },
911 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200912 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000913};
914
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000915static const struct mode_info *find_mode(const char *name)
916{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000917 int i = index_in_strings(mode_name, name);
918 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000919}
920
921static const struct control_info *find_control(const char *name)
922{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000923 int i = index_in_strings(control_name, name);
924 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000925}
926
927enum {
928 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000929 param_line = 1 | 0x80,
930 param_rows = 2 | 0x80,
931 param_cols = 3 | 0x80,
932 param_columns = 4 | 0x80,
933 param_size = 5,
934 param_speed = 6,
935 param_ispeed = 7 | 0x80,
936 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000937};
938
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000939static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000940{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000941 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000942 "line\0" /* 1 */
943 "rows\0" /* 2 */
944 "cols\0" /* 3 */
945 "columns\0" /* 4 */
946 "size\0" /* 5 */
947 "speed\0" /* 6 */
948 "ispeed\0"
949 "ospeed\0";
950 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000951 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000952 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000953 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000954 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000955 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000956}
957
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000958static int recover_mode(const char *arg, struct termios *mode)
959{
960 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000961 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000962 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000963
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000964 /* Scan into temporaries since it is too much trouble to figure out
965 the right format for 'tcflag_t' */
966 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
967 &iflag, &oflag, &cflag, &lflag, &n) != 4)
968 return 0;
969 mode->c_iflag = iflag;
970 mode->c_oflag = oflag;
971 mode->c_cflag = cflag;
972 mode->c_lflag = lflag;
973 arg += n;
974 for (i = 0; i < NCCS; ++i) {
975 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
976 return 0;
977 mode->c_cc[i] = chr;
978 arg += n;
979 }
980
981 /* Fail if there are too many fields */
982 if (*arg != '\0')
983 return 0;
984
985 return 1;
986}
987
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000988static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000989 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000990{
991 int i;
992 printf("%lx:%lx:%lx:%lx",
993 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
994 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
995 for (i = 0; i < NCCS; ++i)
996 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +0000997 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000998}
999
1000static void display_speed(const struct termios *mode, int fancy)
1001{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001002 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001003 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
1004 unsigned long ispeed, ospeed;
1005
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001006 ispeed = cfgetispeed(mode);
1007 ospeed = cfgetospeed(mode);
1008 if (ispeed == 0 || ispeed == ospeed) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001009 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001010 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001011 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
1012 }
1013 if (fancy) fmt_str += 9;
1014 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1015}
1016
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001017static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001018{
1019 int i;
1020 tcflag_t *bitsp;
1021 unsigned long mask;
1022 int prev_type = control;
1023
1024 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001025 if (all)
1026 display_window_size(1);
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001027#ifdef __linux__
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001028 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001029#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001030 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001031#endif
1032
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001033 for (i = 0; i != CIDX_min; ++i) {
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001034 char ch;
Denys Vlasenko184c7382017-08-06 20:55:56 +02001035 char buf10[10];
1036
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001037 /* If swtch is the same as susp, don't print both */
1038#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001039 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001040 continue;
1041#endif
1042 /* If eof uses the same slot as min, only print whichever applies */
1043#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001044 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001045 && (i == CIDX_eof || i == CIDX_eol)
1046 ) {
1047 continue;
1048 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001049#endif
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001050 ch = mode->c_cc[control_info[i].offset];
1051 if (ch == _POSIX_VDISABLE)
Denys Vlasenko184c7382017-08-06 20:55:56 +02001052 strcpy(buf10, "<undef>");
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001053 else
Denys Vlasenko184c7382017-08-06 20:55:56 +02001054 visible(ch, buf10, 0);
1055 wrapf("%s = %s;", nth_string(control_name, i), buf10);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001056 }
1057#if VEOF == VMIN
1058 if ((mode->c_lflag & ICANON) == 0)
1059#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001060 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1061 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001062
1063 for (i = 0; i < NUM_mode_info; ++i) {
1064 if (mode_info[i].flags & OMIT)
1065 continue;
1066 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001067 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001068 prev_type = mode_info[i].type;
1069 }
1070
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001071 bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001072 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001073 if ((*bitsp & mask) == mode_info[i].bits) {
1074 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001075 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001076 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001077 if ((all && mode_info[i].flags & REV)
1078 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1079 ) {
1080 wrapf("-%s", nth_string(mode_name, i));
1081 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001082 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001083 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001084 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001085}
1086
1087static void sane_mode(struct termios *mode)
1088{
1089 int i;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001090
1091 for (i = 0; i < NUM_control_info; ++i) {
1092#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001093 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001094 break;
1095#endif
1096 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1097 }
1098
1099 for (i = 0; i < NUM_mode_info; ++i) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001100 tcflag_t val;
1101 tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
1102
1103 if (!bitsp)
1104 continue;
1105 val = *bitsp & ~((unsigned long)mode_info[i].mask);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001106 if (mode_info[i].flags & SANE_SET) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001107 *bitsp = val | mode_info[i].bits;
1108 } else
1109 if (mode_info[i].flags & SANE_UNSET) {
1110 *bitsp = val & ~mode_info[i].bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001111 }
1112 }
1113}
1114
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001115static void set_mode(const struct mode_info *info, int reversed,
1116 struct termios *mode)
1117{
1118 tcflag_t *bitsp;
1119
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001120 bitsp = get_ptr_to_tcflag(info->type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001121
1122 if (bitsp) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001123 tcflag_t val = *bitsp & ~info->mask;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001124 if (reversed)
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001125 *bitsp = val & ~info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001126 else
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001127 *bitsp = val | info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001128 return;
1129 }
1130
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001131 /* !bitsp - it's a "combination" mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001132 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001133 if (reversed)
1134 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1135 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001136 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001137 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001138 if (reversed)
1139 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1140 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001141 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001142 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001143 if (reversed) {
1144 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001145 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001146 } else {
1147 mode->c_iflag = mode->c_iflag & ~ICRNL;
1148 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1149 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001150 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001151 mode->c_cc[VERASE] = CERASE;
1152 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001153 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001154 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001155 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001156 if (reversed)
1157 mode->c_lflag |= ICANON;
1158 else
1159 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001160 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001161 if (reversed) {
1162 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1163 mode->c_iflag |= ISTRIP;
1164 } else {
1165 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1166 mode->c_iflag &= ~ISTRIP;
1167 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001168 } else if (info == &mode_info[IDX_litout]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001169 if (reversed) {
1170 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1171 mode->c_iflag |= ISTRIP;
1172 mode->c_oflag |= OPOST;
1173 } else {
1174 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1175 mode->c_iflag &= ~ISTRIP;
1176 mode->c_oflag &= ~OPOST;
1177 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001178 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001179 if ((info == &mode_info[IDX_raw] && reversed)
1180 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001181 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001182 /* Cooked mode */
1183 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1184 mode->c_oflag |= OPOST;
1185 mode->c_lflag |= ISIG | ICANON;
1186#if VMIN == VEOF
1187 mode->c_cc[VEOF] = CEOF;
1188#endif
1189#if VTIME == VEOL
1190 mode->c_cc[VEOL] = CEOL;
1191#endif
1192 } else {
1193 /* Raw mode */
1194 mode->c_iflag = 0;
1195 mode->c_oflag &= ~OPOST;
1196 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1197 mode->c_cc[VMIN] = 1;
1198 mode->c_cc[VTIME] = 0;
1199 }
1200 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001201#if IXANY
1202 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001203 if (reversed)
1204 mode->c_iflag |= IXANY;
1205 else
1206 mode->c_iflag &= ~IXANY;
1207 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001208#endif
1209#if TABDLY
1210 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001211 if (reversed)
1212 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1213 else
1214 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1215 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001216#endif
1217#if OXTABS
1218 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001219 if (reversed)
1220 mode->c_oflag |= OXTABS;
1221 else
1222 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001223 }
1224#endif
1225#if XCASE && IUCLC && OLCUC
1226 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001227 if (reversed) {
1228 mode->c_lflag &= ~XCASE;
1229 mode->c_iflag &= ~IUCLC;
1230 mode->c_oflag &= ~OLCUC;
1231 } else {
1232 mode->c_lflag |= XCASE;
1233 mode->c_iflag |= IUCLC;
1234 mode->c_oflag |= OLCUC;
1235 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001236 }
1237#endif
1238 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001239 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001240 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001241 mode->c_cc[VINTR] = 3; /* ^C */
1242 mode->c_cc[VERASE] = 127; /* DEL */
1243 mode->c_cc[VKILL] = 21; /* ^U */
1244 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1245 if (IXANY) mode->c_iflag &= ~IXANY;
1246 }
1247}
1248
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001249static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001250 const char *arg, struct termios *mode)
1251{
1252 unsigned char value;
1253
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001254 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001255 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1256 else if (arg[0] == '\0' || arg[1] == '\0')
1257 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001258 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001259 value = _POSIX_VDISABLE;
1260 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1261 value = arg[1] & 0x1f; /* Non-letters get weird results */
1262 if (arg[1] == '?')
1263 value = 127;
1264 } else
1265 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1266 mode->c_cc[info->offset] = value;
1267}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001268
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001269#define STTY_require_set_attr (1 << 0)
1270#define STTY_speed_was_set (1 << 1)
1271#define STTY_verbose_output (1 << 2)
1272#define STTY_recoverable_output (1 << 3)
1273#define STTY_noargs (1 << 4)
1274
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001275int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001276int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001277{
1278 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001279 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001280 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001281 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001282 int stty_state;
1283 int k;
1284
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001285 INIT_G();
1286
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001287 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001288 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001289
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001290 /* First pass: only parse/verify command line params */
1291 k = 0;
1292 while (argv[++k]) {
1293 const struct mode_info *mp;
1294 const struct control_info *cp;
1295 const char *arg = argv[k];
1296 const char *argnext = argv[k+1];
1297 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001298
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001299 if (arg[0] == '-') {
1300 int i;
1301 mp = find_mode(arg+1);
1302 if (mp) {
1303 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001304 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001305 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001306 continue;
1307 }
1308 /* It is an option - parse it */
1309 i = 0;
1310 while (arg[++i]) {
1311 switch (arg[i]) {
1312 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001313 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001314 output_func = do_display;
1315 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001316 break;
1317 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001318 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001319 output_func = display_recoverable;
1320 break;
1321 case 'F':
1322 if (file_name)
James Byrne69374872019-07-02 11:35:03 +02001323 bb_simple_error_msg_and_die("only one device may be specified");
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001324 file_name = &arg[i+1]; /* "-Fdevice" ? */
1325 if (!file_name[0]) { /* nope, "-F device" */
1326 int p = k+1; /* argv[p] is argnext */
1327 file_name = argnext;
1328 if (!file_name)
1329 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1330 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001331 while (argv[p]) {
1332 argv[p] = argv[p+1];
1333 ++p;
1334 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001335 }
1336 goto end_option;
1337 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001338 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001339 }
1340 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001341 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001342 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001343 }
1344
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001345 mp = find_mode(arg);
1346 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001347 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001348 continue;
1349 }
1350
1351 cp = find_control(arg);
1352 if (cp) {
1353 if (!argnext)
1354 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001355 /* called for the side effect of xfunc death only */
1356 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001357 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001358 ++k;
1359 continue;
1360 }
1361
1362 param = find_param(arg);
1363 if (param & param_need_arg) {
1364 if (!argnext)
1365 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1366 ++k;
1367 }
1368
1369 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001370#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001371 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001372# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001373 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001374 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001375# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001376#endif
1377#ifdef TIOCGWINSZ
1378 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001379 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001380 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001381 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001382 break;
1383 case param_size:
1384#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001385 case param_speed:
1386 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001387 case param_ispeed:
1388 /* called for the side effect of xfunc death only */
1389 set_speed_or_die(input_speed, argnext, &mode);
1390 break;
1391 case param_ospeed:
1392 /* called for the side effect of xfunc death only */
1393 set_speed_or_die(output_speed, argnext, &mode);
1394 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001395 default:
1396 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001397 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001398 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001399 bb_error_msg_and_die("invalid argument '%s'", arg);
1400 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001401 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001402 }
1403
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001404 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001405 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001406 (STTY_verbose_output | STTY_recoverable_output)
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001407 ) {
James Byrne69374872019-07-02 11:35:03 +02001408 bb_simple_error_msg_and_die("-a and -g are mutually exclusive");
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001409 }
1410 /* Specifying -a or -g with non-options is an error */
1411 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
1412 && !(stty_state & STTY_noargs)
1413 ) {
James Byrne69374872019-07-02 11:35:03 +02001414 bb_simple_error_msg_and_die("modes may not be set when -a or -g is used");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001415 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001416
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001417 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001418 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001419 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001420 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1421 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001422 }
1423
1424 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001425 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001426 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001427 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001428 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001429
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001430 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denys Vlasenko641caae2015-10-23 01:44:22 +02001431 G.max_col = get_terminal_width(STDOUT_FILENO);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001432 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001433 return EXIT_SUCCESS;
1434 }
1435
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001436 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001437 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001438 while (argv[++k]) {
1439 const struct mode_info *mp;
1440 const struct control_info *cp;
1441 const char *arg = argv[k];
1442 const char *argnext = argv[k+1];
1443 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001444
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001445 if (arg[0] == '-') {
1446 mp = find_mode(arg+1);
1447 if (mp) {
1448 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001449 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001450 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001451 /* It is an option - already parsed. Skip it */
1452 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001453 }
Mark Whitley446dd272001-03-02 20:00:54 +00001454
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001455 mp = find_mode(arg);
1456 if (mp) {
1457 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001458 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001459 continue;
1460 }
Mark Whitley446dd272001-03-02 20:00:54 +00001461
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001462 cp = find_control(arg);
1463 if (cp) {
1464 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001465 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001466 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001467 continue;
1468 }
Mark Whitley446dd272001-03-02 20:00:54 +00001469
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001470 param = find_param(arg);
1471 if (param & param_need_arg) {
1472 ++k;
1473 }
1474
1475 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001476#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001477 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001478 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001479 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001480 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001481#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001482#ifdef TIOCGWINSZ
1483 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001484 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001485 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001486 break;
1487 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001488 display_window_size(0);
1489 break;
1490 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001491 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001492 break;
1493#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001494 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001495 display_speed(&mode, 0);
1496 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001497 case param_ispeed:
1498 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001499 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001500 break;
1501 case param_ospeed:
1502 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001503 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001504 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001505 default:
1506 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001507 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001508 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001509 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001510 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001511 } /* else - impossible (caught in the first pass):
1512 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001513 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001514 }
1515
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001516 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001517 struct termios new_mode;
1518
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001519 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001520 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001521
1522 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1523 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001524 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001525 some proper subset of the requested operations. To detect
1526 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001527 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001528
1529 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001530 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001531 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001532 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001533 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001534
Eric Andersen98e599c2001-02-14 18:47:33 +00001535 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Denys Vlasenkoae0cf2a2013-05-17 20:08:12 +02001536/*
1537 * I think the below chunk is not necessary on Linux.
1538 * If you are deleting it, also delete STTY_speed_was_set bit -
1539 * it is only ever checked here.
1540 */
1541#if 0 /* was "if CIBAUD" */
Eric Andersen98e599c2001-02-14 18:47:33 +00001542 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1543 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1544 sometimes (m1 != m2). The only difference is in the four bits
1545 of the c_cflag field corresponding to the baud rate. To save
1546 Sun users a little confusion, don't report an error if this
1547 happens. But suppress the error only if we haven't tried to
1548 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001549 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001550
1551 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001552 if ((stty_state & STTY_speed_was_set)
1553 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001554#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001555 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001556 }
1557 }
1558
1559 return EXIT_SUCCESS;
1560}