blob: 424d909cf3c40a4601f7481c1ab6e56e7ed11e9e [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 */
Eric Andersen98e599c2001-02-14 18:47:33 +00008/* Usage: stty [-ag] [-F device] [setting...]
Denys Vlasenkoebe6d9d2017-10-05 14:40:24 +02009 *
10 * Options:
11 * -a Write all current settings to stdout in human-readable form.
12 * -g Write all current settings to stdout in stty-readable form.
13 * -F Open and use the specified device instead of stdin
14 *
15 * If no args are given, write to stdout the baud rate and settings that
16 * have been changed from their defaults. Mode reading and changes
17 * are done on the specified device, or stdin if none was specified.
18 *
19 * David MacKenzie <djm@gnu.ai.mit.edu>
20 *
21 * Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
22 */
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010023//config:config STTY
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020024//config: bool "stty (8.6 kb)"
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010025//config: default y
26//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020027//config: stty is used to change and print terminal line settings.
Eric Andersen98e599c2001-02-14 18:47:33 +000028
Denys Vlasenko692eeb82017-08-04 20:07:19 +020029//applet:IF_STTY(APPLET_NOEXEC(stty, stty, BB_DIR_BIN, BB_SUID_DROP, stty))
Denys Vlasenkoaf3f4202016-11-23 14:46:56 +010030
31//kbuild:lib-$(CONFIG_STTY) += stty.o
Eric Andersen98e599c2001-02-14 18:47:33 +000032
Pere Orga34425382011-03-31 14:43:25 +020033//usage:#define stty_trivial_usage
34//usage: "[-a|g] [-F DEVICE] [SETTING]..."
35//usage:#define stty_full_usage "\n\n"
36//usage: "Without arguments, prints baud rate, line discipline,\n"
37//usage: "and deviations from stty sane\n"
Pere Orga34425382011-03-31 14:43:25 +020038//usage: "\n -F DEVICE Open device instead of stdin"
39//usage: "\n -a Print all current settings in human-readable form"
40//usage: "\n -g Print in stty-readable form"
41//usage: "\n [SETTING] See manpage"
42
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000043#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020044#include "common_bufsiz.h"
Eric Andersen98e599c2001-02-14 18:47:33 +000045
Eric Andersen98e599c2001-02-14 18:47:33 +000046#ifndef _POSIX_VDISABLE
47# define _POSIX_VDISABLE ((unsigned char) 0)
48#endif
49
50#define Control(c) ((c) & 0x1f)
Denis Vlasenko9efb0702006-09-19 14:17:10 +000051/* Canonical values for control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +000052#ifndef CINTR
Denis Vlasenko9efb0702006-09-19 14:17:10 +000053# define CINTR Control('c')
Eric Andersen98e599c2001-02-14 18:47:33 +000054#endif
55#ifndef CQUIT
56# define CQUIT 28
57#endif
58#ifndef CERASE
59# define CERASE 127
60#endif
61#ifndef CKILL
Denis Vlasenko9efb0702006-09-19 14:17:10 +000062# define CKILL Control('u')
Eric Andersen98e599c2001-02-14 18:47:33 +000063#endif
64#ifndef CEOF
Denis Vlasenko9efb0702006-09-19 14:17:10 +000065# define CEOF Control('d')
Eric Andersen98e599c2001-02-14 18:47:33 +000066#endif
67#ifndef CEOL
68# define CEOL _POSIX_VDISABLE
69#endif
70#ifndef CSTART
Denis Vlasenko9efb0702006-09-19 14:17:10 +000071# define CSTART Control('q')
Eric Andersen98e599c2001-02-14 18:47:33 +000072#endif
73#ifndef CSTOP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000074# define CSTOP Control('s')
Eric Andersen98e599c2001-02-14 18:47:33 +000075#endif
76#ifndef CSUSP
Denis Vlasenko9efb0702006-09-19 14:17:10 +000077# define CSUSP Control('z')
Eric Andersen98e599c2001-02-14 18:47:33 +000078#endif
79#if defined(VEOL2) && !defined(CEOL2)
80# define CEOL2 _POSIX_VDISABLE
81#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +010082/* glibc-2.12.1 uses only VSWTC name */
83#if defined(VSWTC) && !defined(VSWTCH)
84# define VSWTCH VSWTC
85#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +000086/* ISC renamed swtch to susp for termios, but we'll accept either name */
Eric Andersen98e599c2001-02-14 18:47:33 +000087#if defined(VSUSP) && !defined(VSWTCH)
88# define VSWTCH VSUSP
89# define CSWTCH CSUSP
90#endif
91#if defined(VSWTCH) && !defined(CSWTCH)
92# define CSWTCH _POSIX_VDISABLE
93#endif
94
Denis Vlasenko79deb662006-09-19 15:12:12 +000095/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
96 So the default is to disable 'swtch.' */
Denis Vlasenkoff131b92007-04-10 15:42:06 +000097#if defined(__sparc__) && defined(__svr4__)
Eric Andersen98e599c2001-02-14 18:47:33 +000098# undef CSWTCH
99# define CSWTCH _POSIX_VDISABLE
100#endif
101
Denis Vlasenkoff131b92007-04-10 15:42:06 +0000102#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000103# define VWERASE VWERSE
104#endif
Denis Vlasenkoff131b92007-04-10 15:42:06 +0000105#if defined(VDSUSP) && !defined(CDSUSP)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000106# define CDSUSP Control('y')
Eric Andersen98e599c2001-02-14 18:47:33 +0000107#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000108#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000109# define VREPRINT VRPRNT
110#endif
111#if defined(VREPRINT) && !defined(CRPRNT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000112# define CRPRNT Control('r')
Eric Andersen98e599c2001-02-14 18:47:33 +0000113#endif
114#if defined(VWERASE) && !defined(CWERASE)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000115# define CWERASE Control('w')
Eric Andersen98e599c2001-02-14 18:47:33 +0000116#endif
117#if defined(VLNEXT) && !defined(CLNEXT)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000118# define CLNEXT Control('v')
Eric Andersen98e599c2001-02-14 18:47:33 +0000119#endif
120#if defined(VDISCARD) && !defined(VFLUSHO)
121# define VFLUSHO VDISCARD
122#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000123#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000124# define VFLUSHO VFLUSH
125#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000126#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000127# define ECHOCTL CTLECH
128#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000129#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000130# define ECHOCTL TCTLECH
131#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000132#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000133# define ECHOKE CRTKIL
134#endif
135#if defined(VFLUSHO) && !defined(CFLUSHO)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000136# define CFLUSHO Control('o')
Eric Andersen98e599c2001-02-14 18:47:33 +0000137#endif
138#if defined(VSTATUS) && !defined(CSTATUS)
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000139# define CSTATUS Control('t')
Eric Andersen98e599c2001-02-14 18:47:33 +0000140#endif
141
Jeremie Koenig138ce542010-07-30 06:01:37 +0200142/* Save us from #ifdef forest plague */
143#ifndef BSDLY
144# define BSDLY 0
145#endif
146#ifndef CIBAUD
147# define CIBAUD 0
148#endif
149#ifndef CRDLY
150# define CRDLY 0
151#endif
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200152#ifndef CMSPAR
153# define CMSPAR 0
154#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200155#ifndef CRTSCTS
156# define CRTSCTS 0
157#endif
158#ifndef ECHOCTL
159# define ECHOCTL 0
160#endif
161#ifndef ECHOKE
162# define ECHOKE 0
163#endif
164#ifndef ECHOPRT
165# define ECHOPRT 0
166#endif
167#ifndef FFDLY
168# define FFDLY 0
169#endif
170#ifndef IEXTEN
171# define IEXTEN 0
172#endif
173#ifndef IMAXBEL
174# define IMAXBEL 0
175#endif
176#ifndef IUCLC
177# define IUCLC 0
178#endif
179#ifndef IXANY
180# define IXANY 0
181#endif
182#ifndef NLDLY
183# define NLDLY 0
184#endif
185#ifndef OCRNL
186# define OCRNL 0
187#endif
188#ifndef OFDEL
189# define OFDEL 0
190#endif
191#ifndef OFILL
192# define OFILL 0
193#endif
194#ifndef OLCUC
195# define OLCUC 0
196#endif
197#ifndef ONLCR
198# define ONLCR 0
199#endif
200#ifndef ONLRET
201# define ONLRET 0
202#endif
203#ifndef ONOCR
204# define ONOCR 0
205#endif
206#ifndef OXTABS
207# define OXTABS 0
208#endif
209#ifndef TABDLY
210# define TABDLY 0
211#endif
212#ifndef TAB1
213# define TAB1 0
214#endif
215#ifndef TAB2
216# define TAB2 0
217#endif
218#ifndef TOSTOP
219# define TOSTOP 0
220#endif
221#ifndef VDSUSP
222# define VDSUSP 0
223#endif
224#ifndef VEOL2
225# define VEOL2 0
226#endif
227#ifndef VFLUSHO
228# define VFLUSHO 0
229#endif
230#ifndef VLNEXT
231# define VLNEXT 0
232#endif
233#ifndef VREPRINT
234# define VREPRINT 0
235#endif
236#ifndef VSTATUS
237# define VSTATUS 0
238#endif
239#ifndef VSWTCH
240# define VSWTCH 0
241#endif
242#ifndef VTDLY
243# define VTDLY 0
244#endif
245#ifndef VWERASE
246# define VWERASE 0
247#endif
248#ifndef XCASE
249# define XCASE 0
250#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100251#ifndef IUTF8
252# define IUTF8 0
253#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200254
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000255/* Which speeds to set */
Eric Andersen98e599c2001-02-14 18:47:33 +0000256enum speed_setting {
257 input_speed, output_speed, both_speeds
258};
259
Denis Vlasenko79deb662006-09-19 15:12:12 +0000260/* Which member(s) of 'struct termios' a mode uses */
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000261enum {
Eric Andersen98e599c2001-02-14 18:47:33 +0000262 control, input, output, local, combination
263};
Denys Vlasenkoe9581b62013-05-17 18:06:49 +0200264static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode)
265{
266 static const uint8_t tcflag_offsets[] ALIGN1 = {
267 offsetof(struct termios, c_cflag), /* control */
268 offsetof(struct termios, c_iflag), /* input */
269 offsetof(struct termios, c_oflag), /* output */
270 offsetof(struct termios, c_lflag) /* local */
271 };
272 if (type <= local) {
273 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
274 }
275 return NULL;
276}
Eric Andersen98e599c2001-02-14 18:47:33 +0000277
Denis Vlasenko79deb662006-09-19 15:12:12 +0000278/* Flags for 'struct mode_info' */
279#define SANE_SET 1 /* Set in 'sane' mode */
280#define SANE_UNSET 2 /* Unset in 'sane' mode */
281#define REV 4 /* Can be turned off by prepending '-' */
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000282#define OMIT 8 /* Don't display value */
Eric Andersen98e599c2001-02-14 18:47:33 +0000283
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000284
285/* Each mode.
286 * This structure should be kept as small as humanly possible.
287 */
Eric Andersen98e599c2001-02-14 18:47:33 +0000288struct mode_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000289 const uint8_t type; /* Which structure element to change */
290 const uint8_t flags; /* Setting and display options */
291 /* only these values are ever used, so... */
292#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
293 const uint8_t mask;
294#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
295 const uint16_t mask;
296#else
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000297 const tcflag_t mask; /* Other bits to turn off for this mode */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000298#endif
299 /* was using short here, but ppc32 was unhappy */
Bernhard Reutner-Fischer21fc7402007-01-17 19:44:24 +0000300 const tcflag_t bits; /* Bits to set for this mode */
Eric Andersen98e599c2001-02-14 18:47:33 +0000301};
302
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000303enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000304 /* Must match mode_name[] and mode_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000305 IDX_evenp = 0,
306 IDX_parity,
307 IDX_oddp,
308 IDX_nl,
309 IDX_ek,
310 IDX_sane,
311 IDX_cooked,
312 IDX_raw,
313 IDX_pass8,
314 IDX_litout,
315 IDX_cbreak,
316 IDX_crt,
317 IDX_dec,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200318#if IXANY
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000319 IDX_decctlq,
320#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200321#if TABDLY || OXTABS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000322 IDX_tabs,
323#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200324#if XCASE && IUCLC && OLCUC
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000325 IDX_lcase,
326 IDX_LCASE,
327#endif
328};
Denis Vlasenkob2abef32007-01-01 18:18:04 +0000329
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000330#define MI_ENTRY(N,T,F,B,M) N "\0"
Manuel Novoa III cad53642003-03-19 09:13:01 +0000331
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000332/* Mode names given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200333static const char mode_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000334 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
335 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
336 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
337 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
338 MI_ENTRY("ek", combination, OMIT, 0, 0 )
339 MI_ENTRY("sane", combination, OMIT, 0, 0 )
340 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
341 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
342 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
343 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
344 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
345 MI_ENTRY("crt", combination, OMIT, 0, 0 )
346 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200347#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000348 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000349#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200350#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000351 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000352#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200353#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000354 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
355 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000356#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000357 MI_ENTRY("parenb", control, REV, PARENB, 0 )
358 MI_ENTRY("parodd", control, REV, PARODD, 0 )
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200359#if CMSPAR
360 MI_ENTRY("cmspar", control, REV, CMSPAR, 0 )
361#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000362 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
363 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
364 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
365 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
366 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
367 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
368 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
369 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
370 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200371#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000372 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000373#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000374 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
375 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
376 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
377 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
378 MI_ENTRY("inpck", input, REV, INPCK, 0 )
379 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
380 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
381 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
382 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
383 MI_ENTRY("ixon", input, REV, IXON, 0 )
384 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100385 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200386#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000387 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000388#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200389#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000390 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000391#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200392#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000393 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000394#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100395#if IUTF8
396 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
397#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000398 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200399#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000400 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000401#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200402#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000403 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000404#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200405#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000406 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000407#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200408#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000409 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000410#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200411#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000412 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000413#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200414#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000415 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000416#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200417#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000418 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000419#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200420#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000421 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
422 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000423#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200424#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000425 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
426 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
427 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
428 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000429#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000430
Jeremie Koenig138ce542010-07-30 06:01:37 +0200431#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000432 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200433# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000434 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200435# endif
436# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000437 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200438# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000439 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000440#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200441# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000442 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000443# endif
444#endif
Mark Whitley446dd272001-03-02 20:00:54 +0000445
Jeremie Koenig138ce542010-07-30 06:01:37 +0200446#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000447 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
448 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000449#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200450#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000451 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
452 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000453#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200454#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000455 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
456 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
Eric Andersen98e599c2001-02-14 18:47:33 +0000457#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000458 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
459 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200460#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000461 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000462#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000463 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
464 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100465 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000466 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
467 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
468 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200469#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000470 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000471#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200472#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000473 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000474#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200475#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000476 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100477 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000478#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200479#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000480 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100481 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000482#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200483#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000484 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100485 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000486#endif
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200487 MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 )
488#ifdef EXTPROC
489 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
490#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000491 ;
492
493#undef MI_ENTRY
494#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
495
496static const struct mode_info mode_info[] = {
497 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
498 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
499 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
500 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
501 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
502 MI_ENTRY("ek", combination, OMIT, 0, 0 )
503 MI_ENTRY("sane", combination, OMIT, 0, 0 )
504 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
505 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
506 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
507 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
508 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
509 MI_ENTRY("crt", combination, OMIT, 0, 0 )
510 MI_ENTRY("dec", combination, OMIT, 0, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200511#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000512 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
513#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200514#if TABDLY || OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000515 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
516#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200517#if XCASE && IUCLC && OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000518 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
519 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
520#endif
521 MI_ENTRY("parenb", control, REV, PARENB, 0 )
522 MI_ENTRY("parodd", control, REV, PARODD, 0 )
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200523#if CMSPAR
524 MI_ENTRY("cmspar", control, REV, CMSPAR, 0 )
525#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000526 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
527 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
528 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
529 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
530 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
531 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
532 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
533 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
534 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200535#if CRTSCTS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000536 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
537#endif
538 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
539 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
540 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
541 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
542 MI_ENTRY("inpck", input, REV, INPCK, 0 )
543 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
544 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
545 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
546 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
547 MI_ENTRY("ixon", input, REV, IXON, 0 )
548 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100549 MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200550#if IUCLC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000551 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
552#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200553#if IXANY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000554 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
555#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200556#if IMAXBEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000557 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
558#endif
Denys Vlasenko271c0ce2011-01-24 16:36:15 +0100559#if IUTF8
560 MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 )
561#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000562 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200563#if OLCUC
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000564 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
565#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200566#if OCRNL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000567 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
568#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200569#if ONLCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000570 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
571#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200572#if ONOCR
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000573 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
574#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200575#if ONLRET
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000576 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
577#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200578#if OFILL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000579 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
580#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200581#if OFDEL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000582 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
583#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200584#if NLDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000585 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
586 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
587#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200588#if CRDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000589 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
590 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
591 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
592 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
593#endif
594
Jeremie Koenig138ce542010-07-30 06:01:37 +0200595#if TABDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000596 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200597# if TAB2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000598 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200599# endif
600# if TAB1
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000601 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
Jeremie Koenig138ce542010-07-30 06:01:37 +0200602# endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000603 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
604#else
Jeremie Koenig138ce542010-07-30 06:01:37 +0200605# if OXTABS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000606 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
607# endif
608#endif
609
Jeremie Koenig138ce542010-07-30 06:01:37 +0200610#if BSDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000611 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
612 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
613#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200614#if VTDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000615 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
616 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
617#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200618#if FFDLY
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000619 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
620 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
621#endif
622 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
623 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200624#if IEXTEN
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000625 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
626#endif
627 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
628 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100629 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000630 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
631 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
632 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200633#if XCASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000634 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
635#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200636#if TOSTOP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000637 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
638#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200639#if ECHOPRT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000640 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100641 MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000642#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200643#if ECHOCTL
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000644 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100645 MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 )
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000646#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200647#if ECHOKE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000648 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
Denys Vlasenkoe3d4c032011-01-26 11:58:37 +0100649 MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000650#endif
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200651 MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 )
652#ifdef EXTPROC
653 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
654#endif
Eric Andersen98e599c2001-02-14 18:47:33 +0000655};
656
Rob Landleybc68cd12006-03-10 19:22:06 +0000657enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000658 NUM_mode_info = ARRAY_SIZE(mode_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000659};
Eric Andersen98e599c2001-02-14 18:47:33 +0000660
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000661
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000662/* Control characters */
Eric Andersen98e599c2001-02-14 18:47:33 +0000663struct control_info {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000664 const uint8_t saneval; /* Value to set for 'stty sane' */
665 const uint8_t offset; /* Offset in c_cc */
Eric Andersen98e599c2001-02-14 18:47:33 +0000666};
667
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000668enum {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000669 /* Must match control_name[] and control_info[] order! */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000670 CIDX_intr = 0,
671 CIDX_quit,
672 CIDX_erase,
673 CIDX_kill,
674 CIDX_eof,
675 CIDX_eol,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200676#if VEOL2
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000677 CIDX_eol2,
678#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200679#if VSWTCH
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000680 CIDX_swtch,
681#endif
682 CIDX_start,
683 CIDX_stop,
684 CIDX_susp,
Jeremie Koenig138ce542010-07-30 06:01:37 +0200685#if VDSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000686 CIDX_dsusp,
687#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200688#if VREPRINT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000689 CIDX_rprnt,
690#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200691#if VWERASE
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000692 CIDX_werase,
693#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200694#if VLNEXT
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000695 CIDX_lnext,
696#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200697#if VFLUSHO
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000698 CIDX_flush,
699#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200700#if VSTATUS
Denis Vlasenko2ea8c402007-10-11 16:02:36 +0000701 CIDX_status,
702#endif
703 CIDX_min,
704 CIDX_time,
705};
Eric Andersen98e599c2001-02-14 18:47:33 +0000706
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000707#define CI_ENTRY(n,s,o) n "\0"
708
709/* Name given on command line */
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200710static const char control_name[] ALIGN1 =
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000711 CI_ENTRY("intr", CINTR, VINTR )
712 CI_ENTRY("quit", CQUIT, VQUIT )
713 CI_ENTRY("erase", CERASE, VERASE )
714 CI_ENTRY("kill", CKILL, VKILL )
715 CI_ENTRY("eof", CEOF, VEOF )
716 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200717#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000718 CI_ENTRY("eol2", CEOL2, VEOL2 )
Eric Andersen98e599c2001-02-14 18:47:33 +0000719#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200720#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000721 CI_ENTRY("swtch", CSWTCH, VSWTCH )
Eric Andersen98e599c2001-02-14 18:47:33 +0000722#endif
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000723 CI_ENTRY("start", CSTART, VSTART )
724 CI_ENTRY("stop", CSTOP, VSTOP )
725 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200726#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000727 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
Eric Andersen98e599c2001-02-14 18:47:33 +0000728#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200729#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000730 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
Eric Andersen98e599c2001-02-14 18:47:33 +0000731#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200732#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000733 CI_ENTRY("werase", CWERASE, VWERASE )
Eric Andersen98e599c2001-02-14 18:47:33 +0000734#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200735#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000736 CI_ENTRY("lnext", CLNEXT, VLNEXT )
Eric Andersen98e599c2001-02-14 18:47:33 +0000737#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200738#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000739 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
Eric Andersen98e599c2001-02-14 18:47:33 +0000740#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200741#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000742 CI_ENTRY("status", CSTATUS, VSTATUS )
Eric Andersen98e599c2001-02-14 18:47:33 +0000743#endif
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000744 /* These must be last because of the display routines */
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000745 CI_ENTRY("min", 1, VMIN )
746 CI_ENTRY("time", 0, VTIME )
747 ;
748
749#undef CI_ENTRY
750#define CI_ENTRY(n,s,o) { s, o },
751
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200752static const struct control_info control_info[] ALIGN2 = {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000753 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
754 CI_ENTRY("intr", CINTR, VINTR )
755 CI_ENTRY("quit", CQUIT, VQUIT )
756 CI_ENTRY("erase", CERASE, VERASE )
757 CI_ENTRY("kill", CKILL, VKILL )
758 CI_ENTRY("eof", CEOF, VEOF )
759 CI_ENTRY("eol", CEOL, VEOL )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200760#if VEOL2
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000761 CI_ENTRY("eol2", CEOL2, VEOL2 )
762#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200763#if VSWTCH
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000764 CI_ENTRY("swtch", CSWTCH, VSWTCH )
765#endif
766 CI_ENTRY("start", CSTART, VSTART )
767 CI_ENTRY("stop", CSTOP, VSTOP )
768 CI_ENTRY("susp", CSUSP, VSUSP )
Jeremie Koenig138ce542010-07-30 06:01:37 +0200769#if VDSUSP
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000770 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
771#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200772#if VREPRINT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000773 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
774#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200775#if VWERASE
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000776 CI_ENTRY("werase", CWERASE, VWERASE )
777#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200778#if VLNEXT
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000779 CI_ENTRY("lnext", CLNEXT, VLNEXT )
780#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200781#if VFLUSHO
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000782 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
783#endif
Jeremie Koenig138ce542010-07-30 06:01:37 +0200784#if VSTATUS
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000785 CI_ENTRY("status", CSTATUS, VSTATUS )
786#endif
787 /* These must be last because of the display routines */
788 CI_ENTRY("min", 1, VMIN )
789 CI_ENTRY("time", 0, VTIME )
Eric Andersen98e599c2001-02-14 18:47:33 +0000790};
791
Rob Landleybc68cd12006-03-10 19:22:06 +0000792enum {
Denis Vlasenko80b8b392007-06-25 10:55:35 +0000793 NUM_control_info = ARRAY_SIZE(control_info)
Rob Landleybc68cd12006-03-10 19:22:06 +0000794};
Eric Andersen98e599c2001-02-14 18:47:33 +0000795
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000796
797struct globals {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100798 const char *device_name;
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000799 /* The width of the screen, for output wrapping */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100800 unsigned max_col;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000801 /* Current position, to know when to wrap */
802 unsigned current_col;
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100803} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200804#define G (*(struct globals*)bb_common_bufsiz1)
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000805#define INIT_G() do { \
Denys Vlasenkob9be7802017-08-06 21:23:03 +0200806 setup_common_bufsiz(); \
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000807 G.device_name = bb_msg_standard_input; \
808 G.max_col = 80; \
Denys Vlasenko184c7382017-08-06 20:55:56 +0200809 G.current_col = 0; /* we are noexec, must clear */ \
Denis Vlasenko7049ff82008-06-25 09:53:17 +0000810} while (0)
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000811
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000812static void set_speed_or_die(enum speed_setting type, const char *arg,
813 struct termios *mode)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000814{
815 speed_t baud;
816
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +0000817 baud = tty_value_to_baud(xatou(arg));
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000818
819 if (type != output_speed) { /* either input or both */
820 cfsetispeed(mode, baud);
821 }
822 if (type != input_speed) { /* either output or both */
823 cfsetospeed(mode, baud);
824 }
825}
826
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000827static NORETURN void perror_on_device_and_die(const char *fmt)
Eric Andersen8876fb22003-06-20 09:01:58 +0000828{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000829 bb_perror_msg_and_die(fmt, G.device_name);
Eric Andersen8876fb22003-06-20 09:01:58 +0000830}
831
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000832static void perror_on_device(const char *fmt)
833{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000834 bb_perror_msg(fmt, G.device_name);
Denis Vlasenko20b253d2006-09-19 14:24:23 +0000835}
836
Eric Andersen98e599c2001-02-14 18:47:33 +0000837/* Print format string MESSAGE and optional args.
838 Wrap to next line first if it won't fit.
Denis Vlasenko9efb0702006-09-19 14:17:10 +0000839 Print a space first unless MESSAGE will start a new line */
Eric Andersen98e599c2001-02-14 18:47:33 +0000840static void wrapf(const char *message, ...)
841{
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000842 char buf[128];
Eric Andersen98e599c2001-02-14 18:47:33 +0000843 va_list args;
Denis Vlasenko77ad97f2008-05-13 02:27:31 +0000844 unsigned buflen;
Eric Andersen98e599c2001-02-14 18:47:33 +0000845
846 va_start(args, message);
Bernhard Reutner-Fischer8eb05492007-01-17 19:46:33 +0000847 buflen = vsnprintf(buf, sizeof(buf), message, args);
Eric Andersen98e599c2001-02-14 18:47:33 +0000848 va_end(args);
Bernhard Reutner-Fischer1a250d92007-01-18 08:41:22 +0000849 /* We seem to be called only with suitable lengths, but check if
850 somebody failed to adhere to this assumption just to be sure. */
851 if (!buflen || buflen >= sizeof(buf)) return;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000852
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000853 if (G.current_col > 0) {
854 G.current_col++;
Denis Vlasenko79deb662006-09-19 15:12:12 +0000855 if (buf[0] != '\n') {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000856 if (G.current_col + buflen >= G.max_col) {
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000857 G.current_col = 0;
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200858 bb_putchar('\n');
859 } else {
Denis Vlasenko4daad902007-09-27 10:20:47 +0000860 bb_putchar(' ');
Denys Vlasenko3f5ba0c2017-09-18 12:16:47 +0200861 }
Denis Vlasenko79deb662006-09-19 15:12:12 +0000862 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000863 }
864 fputs(buf, stdout);
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000865 G.current_col += buflen;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +0000866 if (buf[buflen-1] == '\n')
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000867 G.current_col = 0;
Eric Andersen98e599c2001-02-14 18:47:33 +0000868}
869
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100870static void newline(void)
871{
872 if (G.current_col != 0)
873 wrapf("\n");
874}
875
Jeremie Koenig138ce542010-07-30 06:01:37 +0200876#ifdef TIOCGWINSZ
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100877static void set_window_size(int rows, int cols)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000878{
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +0000879 struct winsize win = { 0, 0, 0, 0 };
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000880
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000881 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000882 if (errno != EINVAL) {
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000883 goto bail;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000884 }
885 memset(&win, 0, sizeof(win));
886 }
887
888 if (rows >= 0)
889 win.ws_row = rows;
890 if (cols >= 0)
891 win.ws_col = cols;
892
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000893 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000894bail:
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000895 perror_on_device("%s");
896}
Jeremie Koenig138ce542010-07-30 06:01:37 +0200897#endif
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000898
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100899static void display_window_size(int fancy)
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000900{
901 const char *fmt_str = "%s\0%s: no size information for this device";
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000902 unsigned width, height;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000903
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000904 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000905 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
906 perror_on_device(fmt_str);
907 }
908 } else {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +0100909 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
Bernhard Reutner-Fischerd4a745c2007-01-17 19:45:36 +0000910 height, width);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +0000911 }
912}
913
Eric Andersen98e599c2001-02-14 18:47:33 +0000914static const struct suffix_mult stty_suffixes[] = {
Denis Vlasenkof8689632007-07-27 15:06:25 +0000915 { "b", 512 },
916 { "k", 1024 },
917 { "B", 1024 },
Denys Vlasenko043b1e52009-09-06 12:47:55 +0200918 { "", 0 }
Eric Andersen98e599c2001-02-14 18:47:33 +0000919};
920
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000921static const struct mode_info *find_mode(const char *name)
922{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000923 int i = index_in_strings(mode_name, name);
924 return i >= 0 ? &mode_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000925}
926
927static const struct control_info *find_control(const char *name)
928{
Denis Vlasenkoda42bd52008-01-27 23:24:31 +0000929 int i = index_in_strings(control_name, name);
930 return i >= 0 ? &control_info[i] : NULL;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000931}
932
933enum {
934 param_need_arg = 0x80,
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000935 param_line = 1 | 0x80,
936 param_rows = 2 | 0x80,
937 param_cols = 3 | 0x80,
938 param_columns = 4 | 0x80,
939 param_size = 5,
940 param_speed = 6,
941 param_ispeed = 7 | 0x80,
942 param_ospeed = 8 | 0x80,
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000943};
944
Denis Vlasenkoc7cc5a92009-04-19 01:27:20 +0000945static int find_param(const char *name)
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000946{
Denis Vlasenko6ca409e2007-08-12 20:58:27 +0000947 static const char params[] ALIGN1 =
Denis Vlasenko990d0f62007-07-24 15:54:42 +0000948 "line\0" /* 1 */
949 "rows\0" /* 2 */
950 "cols\0" /* 3 */
951 "columns\0" /* 4 */
952 "size\0" /* 5 */
953 "speed\0" /* 6 */
954 "ispeed\0"
955 "ospeed\0";
956 int i = index_in_strings(params, name) + 1;
Bernhard Reutner-Fischer3a602442007-04-04 13:59:49 +0000957 if (i == 0)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000958 return 0;
Denis Vlasenko9ace6132007-04-19 19:55:54 +0000959 if (i != 5 && i != 6)
Bernhard Reutner-Fischercbd6e652007-02-04 11:13:57 +0000960 i |= 0x80;
Bernhard Reutner-Fischera6e31ad2007-01-17 19:45:14 +0000961 return i;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000962}
963
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000964static int recover_mode(const char *arg, struct termios *mode)
965{
966 int i, n;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +0000967 unsigned chr;
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000968 unsigned long iflag, oflag, cflag, lflag;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +0000969
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000970 /* Scan into temporaries since it is too much trouble to figure out
971 the right format for 'tcflag_t' */
972 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
973 &iflag, &oflag, &cflag, &lflag, &n) != 4)
974 return 0;
975 mode->c_iflag = iflag;
976 mode->c_oflag = oflag;
977 mode->c_cflag = cflag;
978 mode->c_lflag = lflag;
979 arg += n;
980 for (i = 0; i < NCCS; ++i) {
981 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
982 return 0;
983 mode->c_cc[i] = chr;
984 arg += n;
985 }
986
987 /* Fail if there are too many fields */
988 if (*arg != '\0')
989 return 0;
990
991 return 1;
992}
993
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +0000994static void display_recoverable(const struct termios *mode,
Denis Vlasenkoa60f84e2008-07-05 09:18:54 +0000995 int UNUSED_PARAM dummy)
Denis Vlasenkof8abc102007-01-12 21:02:04 +0000996{
997 int i;
998 printf("%lx:%lx:%lx:%lx",
999 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1000 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1001 for (i = 0; i < NCCS; ++i)
1002 printf(":%x", (unsigned int) mode->c_cc[i]);
Denis Vlasenko4daad902007-09-27 10:20:47 +00001003 bb_putchar('\n');
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001004}
1005
1006static void display_speed(const struct termios *mode, int fancy)
1007{
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001008 //____________________ 01234567 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001009 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
1010 unsigned long ispeed, ospeed;
1011
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001012 ispeed = cfgetispeed(mode);
1013 ospeed = cfgetospeed(mode);
1014 if (ispeed == 0 || ispeed == ospeed) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001015 ispeed = ospeed; /* in case ispeed was 0 */
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001016 //________ 0123 4 5 6 7 8 9
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001017 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
1018 }
1019 if (fancy) fmt_str += 9;
1020 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1021}
1022
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001023static void do_display(const struct termios *mode, int all)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001024{
1025 int i;
1026 tcflag_t *bitsp;
1027 unsigned long mask;
1028 int prev_type = control;
1029
1030 display_speed(mode, 1);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001031 if (all)
1032 display_window_size(1);
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001033#ifdef __linux__
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001034 wrapf("line = %u;\n", mode->c_line);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001035#else
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001036 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001037#endif
1038
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001039 for (i = 0; i != CIDX_min; ++i) {
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001040 char ch;
Denys Vlasenko184c7382017-08-06 20:55:56 +02001041 char buf10[10];
1042
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001043 /* If swtch is the same as susp, don't print both */
1044#if VSWTCH == VSUSP
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001045 if (i == CIDX_swtch)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001046 continue;
1047#endif
1048 /* If eof uses the same slot as min, only print whichever applies */
1049#if VEOF == VMIN
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001050 if (!(mode->c_lflag & ICANON)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001051 && (i == CIDX_eof || i == CIDX_eol)
1052 ) {
1053 continue;
1054 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001055#endif
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001056 ch = mode->c_cc[control_info[i].offset];
1057 if (ch == _POSIX_VDISABLE)
Denys Vlasenko184c7382017-08-06 20:55:56 +02001058 strcpy(buf10, "<undef>");
Bartosz Golaszewski79c618c2013-07-30 06:29:42 +02001059 else
Denys Vlasenko184c7382017-08-06 20:55:56 +02001060 visible(ch, buf10, 0);
1061 wrapf("%s = %s;", nth_string(control_name, i), buf10);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001062 }
1063#if VEOF == VMIN
1064 if ((mode->c_lflag & ICANON) == 0)
1065#endif
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001066 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1067 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001068
1069 for (i = 0; i < NUM_mode_info; ++i) {
1070 if (mode_info[i].flags & OMIT)
1071 continue;
1072 if (mode_info[i].type != prev_type) {
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001073 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001074 prev_type = mode_info[i].type;
1075 }
1076
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001077 bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001078 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001079 if ((*bitsp & mask) == mode_info[i].bits) {
1080 if (all || (mode_info[i].flags & SANE_UNSET))
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001081 wrapf("-%s"+1, nth_string(mode_name, i));
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001082 } else {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001083 if ((all && mode_info[i].flags & REV)
1084 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1085 ) {
1086 wrapf("-%s", nth_string(mode_name, i));
1087 }
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001088 }
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001089 }
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001090 newline();
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001091}
1092
1093static void sane_mode(struct termios *mode)
1094{
1095 int i;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001096
1097 for (i = 0; i < NUM_control_info; ++i) {
1098#if VMIN == VEOF
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001099 if (i == CIDX_min)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001100 break;
1101#endif
1102 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1103 }
1104
1105 for (i = 0; i < NUM_mode_info; ++i) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001106 tcflag_t val;
1107 tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode);
1108
1109 if (!bitsp)
1110 continue;
1111 val = *bitsp & ~((unsigned long)mode_info[i].mask);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001112 if (mode_info[i].flags & SANE_SET) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001113 *bitsp = val | mode_info[i].bits;
1114 } else
1115 if (mode_info[i].flags & SANE_UNSET) {
1116 *bitsp = val & ~mode_info[i].bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001117 }
1118 }
1119}
1120
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001121static void set_mode(const struct mode_info *info, int reversed,
1122 struct termios *mode)
1123{
1124 tcflag_t *bitsp;
1125
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001126 bitsp = get_ptr_to_tcflag(info->type, mode);
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001127
1128 if (bitsp) {
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001129 tcflag_t val = *bitsp & ~info->mask;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001130 if (reversed)
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001131 *bitsp = val & ~info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001132 else
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001133 *bitsp = val | info->bits;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001134 return;
1135 }
1136
Denys Vlasenkoe9581b62013-05-17 18:06:49 +02001137 /* !bitsp - it's a "combination" mode */
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001138 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001139 if (reversed)
1140 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1141 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001142 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001143 } else if (info == &mode_info[IDX_oddp]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001144 if (reversed)
1145 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1146 else
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001147 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001148 } else if (info == &mode_info[IDX_nl]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001149 if (reversed) {
1150 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
Denys Vlasenkoe4dcba12010-10-28 18:57:19 +02001151 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001152 } else {
1153 mode->c_iflag = mode->c_iflag & ~ICRNL;
1154 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1155 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001156 } else if (info == &mode_info[IDX_ek]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001157 mode->c_cc[VERASE] = CERASE;
1158 mode->c_cc[VKILL] = CKILL;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001159 } else if (info == &mode_info[IDX_sane]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001160 sane_mode(mode);
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001161 } else if (info == &mode_info[IDX_cbreak]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001162 if (reversed)
1163 mode->c_lflag |= ICANON;
1164 else
1165 mode->c_lflag &= ~ICANON;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001166 } else if (info == &mode_info[IDX_pass8]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001167 if (reversed) {
1168 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1169 mode->c_iflag |= ISTRIP;
1170 } else {
1171 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1172 mode->c_iflag &= ~ISTRIP;
1173 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001174 } else if (info == &mode_info[IDX_litout]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001175 if (reversed) {
1176 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1177 mode->c_iflag |= ISTRIP;
1178 mode->c_oflag |= OPOST;
1179 } else {
1180 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1181 mode->c_iflag &= ~ISTRIP;
1182 mode->c_oflag &= ~OPOST;
1183 }
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001184 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001185 if ((info == &mode_info[IDX_raw] && reversed)
1186 || (info == &mode_info[IDX_cooked] && !reversed)
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001187 ) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001188 /* Cooked mode */
1189 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1190 mode->c_oflag |= OPOST;
1191 mode->c_lflag |= ISIG | ICANON;
1192#if VMIN == VEOF
1193 mode->c_cc[VEOF] = CEOF;
1194#endif
1195#if VTIME == VEOL
1196 mode->c_cc[VEOL] = CEOL;
1197#endif
1198 } else {
1199 /* Raw mode */
1200 mode->c_iflag = 0;
1201 mode->c_oflag &= ~OPOST;
1202 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1203 mode->c_cc[VMIN] = 1;
1204 mode->c_cc[VTIME] = 0;
1205 }
1206 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001207#if IXANY
1208 else if (info == &mode_info[IDX_decctlq]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001209 if (reversed)
1210 mode->c_iflag |= IXANY;
1211 else
1212 mode->c_iflag &= ~IXANY;
1213 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001214#endif
1215#if TABDLY
1216 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001217 if (reversed)
1218 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1219 else
1220 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1221 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001222#endif
1223#if OXTABS
1224 else if (info == &mode_info[IDX_tabs]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001225 if (reversed)
1226 mode->c_oflag |= OXTABS;
1227 else
1228 mode->c_oflag &= ~OXTABS;
Jeremie Koenig138ce542010-07-30 06:01:37 +02001229 }
1230#endif
1231#if XCASE && IUCLC && OLCUC
1232 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001233 if (reversed) {
1234 mode->c_lflag &= ~XCASE;
1235 mode->c_iflag &= ~IUCLC;
1236 mode->c_oflag &= ~OLCUC;
1237 } else {
1238 mode->c_lflag |= XCASE;
1239 mode->c_iflag |= IUCLC;
1240 mode->c_oflag |= OLCUC;
1241 }
Jeremie Koenig138ce542010-07-30 06:01:37 +02001242 }
1243#endif
1244 else if (info == &mode_info[IDX_crt]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001245 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001246 } else if (info == &mode_info[IDX_dec]) {
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001247 mode->c_cc[VINTR] = 3; /* ^C */
1248 mode->c_cc[VERASE] = 127; /* DEL */
1249 mode->c_cc[VKILL] = 21; /* ^U */
1250 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1251 if (IXANY) mode->c_iflag &= ~IXANY;
1252 }
1253}
1254
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001255static void set_control_char_or_die(const struct control_info *info,
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001256 const char *arg, struct termios *mode)
1257{
1258 unsigned char value;
1259
Denis Vlasenko2ea8c402007-10-11 16:02:36 +00001260 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001261 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1262 else if (arg[0] == '\0' || arg[1] == '\0')
1263 value = arg[0];
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001264 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
Denis Vlasenkof8abc102007-01-12 21:02:04 +00001265 value = _POSIX_VDISABLE;
1266 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1267 value = arg[1] & 0x1f; /* Non-letters get weird results */
1268 if (arg[1] == '?')
1269 value = 127;
1270 } else
1271 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1272 mode->c_cc[info->offset] = value;
1273}
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001274
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001275#define STTY_require_set_attr (1 << 0)
1276#define STTY_speed_was_set (1 << 1)
1277#define STTY_verbose_output (1 << 2)
1278#define STTY_recoverable_output (1 << 3)
1279#define STTY_noargs (1 << 4)
1280
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +00001281int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001282int stty_main(int argc UNUSED_PARAM, char **argv)
Eric Andersen98e599c2001-02-14 18:47:33 +00001283{
1284 struct termios mode;
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001285 void (*output_func)(const struct termios *, int);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001286 const char *file_name = NULL;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001287 int display_all = 0;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001288 int stty_state;
1289 int k;
1290
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001291 INIT_G();
1292
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001293 stty_state = STTY_noargs;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001294 output_func = do_display;
Eric Andersen98e599c2001-02-14 18:47:33 +00001295
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001296 /* First pass: only parse/verify command line params */
1297 k = 0;
1298 while (argv[++k]) {
1299 const struct mode_info *mp;
1300 const struct control_info *cp;
1301 const char *arg = argv[k];
1302 const char *argnext = argv[k+1];
1303 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001304
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001305 if (arg[0] == '-') {
1306 int i;
1307 mp = find_mode(arg+1);
1308 if (mp) {
1309 if (!(mp->flags & REV))
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001310 goto invalid_argument;
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001311 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001312 continue;
1313 }
1314 /* It is an option - parse it */
1315 i = 0;
1316 while (arg[++i]) {
1317 switch (arg[i]) {
1318 case 'a':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001319 stty_state |= STTY_verbose_output;
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001320 output_func = do_display;
1321 display_all = 1;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001322 break;
1323 case 'g':
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001324 stty_state |= STTY_recoverable_output;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001325 output_func = display_recoverable;
1326 break;
1327 case 'F':
1328 if (file_name)
1329 bb_error_msg_and_die("only one device may be specified");
1330 file_name = &arg[i+1]; /* "-Fdevice" ? */
1331 if (!file_name[0]) { /* nope, "-F device" */
1332 int p = k+1; /* argv[p] is argnext */
1333 file_name = argnext;
1334 if (!file_name)
1335 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1336 /* remove -F param from arg[vc] */
Denys Vlasenkoe992bae2009-11-28 15:18:53 +01001337 while (argv[p]) {
1338 argv[p] = argv[p+1];
1339 ++p;
1340 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001341 }
1342 goto end_option;
1343 default:
Bernhard Reutner-Fischer4fa566d2007-01-17 19:42:30 +00001344 goto invalid_argument;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001345 }
1346 }
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001347 end_option:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001348 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001349 }
1350
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001351 mp = find_mode(arg);
1352 if (mp) {
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001353 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001354 continue;
1355 }
1356
1357 cp = find_control(arg);
1358 if (cp) {
1359 if (!argnext)
1360 bb_error_msg_and_die(bb_msg_requires_arg, arg);
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001361 /* called for the side effect of xfunc death only */
1362 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001363 stty_state &= ~STTY_noargs;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001364 ++k;
1365 continue;
1366 }
1367
1368 param = find_param(arg);
1369 if (param & param_need_arg) {
1370 if (!argnext)
1371 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1372 ++k;
1373 }
1374
1375 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001376#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001377 case param_line:
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001378# ifndef TIOCGWINSZ
Denis Vlasenko13858992006-10-08 12:49:22 +00001379 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Eric Andersen98e599c2001-02-14 18:47:33 +00001380 break;
Denis Vlasenkoe40c04b2006-09-19 14:19:42 +00001381# endif /* else fall-through */
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001382#endif
1383#ifdef TIOCGWINSZ
1384 case param_rows:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001385 case param_cols:
Denis Vlasenko9ace6132007-04-19 19:55:54 +00001386 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001387 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001388 break;
1389 case param_size:
1390#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001391 case param_speed:
1392 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001393 case param_ispeed:
1394 /* called for the side effect of xfunc death only */
1395 set_speed_or_die(input_speed, argnext, &mode);
1396 break;
1397 case param_ospeed:
1398 /* called for the side effect of xfunc death only */
1399 set_speed_or_die(output_speed, argnext, &mode);
1400 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001401 default:
1402 if (recover_mode(arg, &mode) == 1) break;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001403 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
Denis Vlasenko240a1cf2007-04-08 16:07:02 +00001404 invalid_argument:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001405 bb_error_msg_and_die("invalid argument '%s'", arg);
1406 }
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001407 stty_state &= ~STTY_noargs;
Eric Andersen98e599c2001-02-14 18:47:33 +00001408 }
1409
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001410 /* Specifying both -a and -g is an error */
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001411 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001412 (STTY_verbose_output | STTY_recoverable_output)
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001413 ) {
Denys Vlasenko5dd1f472011-10-21 19:45:13 +02001414 bb_error_msg_and_die("-a and -g are mutually exclusive");
1415 }
1416 /* Specifying -a or -g with non-options is an error */
1417 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output))
1418 && !(stty_state & STTY_noargs)
1419 ) {
1420 bb_error_msg_and_die("modes may not be set when -a or -g is used");
Denys Vlasenko800ff7c2009-12-11 15:00:17 +01001421 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001422
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001423 /* Now it is safe to start doing things */
Eric Andersen98e599c2001-02-14 18:47:33 +00001424 if (file_name) {
Denis Vlasenkodd8bbfd2007-11-24 04:32:49 +00001425 G.device_name = file_name;
Denys Vlasenkoab19ede2009-11-11 21:05:42 +01001426 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1427 ndelay_off(STDIN_FILENO);
Eric Andersen98e599c2001-02-14 18:47:33 +00001428 }
1429
1430 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001431 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001432 memset(&mode, 0, sizeof(mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001433 if (tcgetattr(STDIN_FILENO, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001434 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001435
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001436 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
Denys Vlasenko641caae2015-10-23 01:44:22 +02001437 G.max_col = get_terminal_width(STDOUT_FILENO);
Bernhard Reutner-Fischer94feb1c2007-01-17 19:46:12 +00001438 output_func(&mode, display_all);
Eric Andersen98e599c2001-02-14 18:47:33 +00001439 return EXIT_SUCCESS;
1440 }
1441
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001442 /* Second pass: perform actions */
Eric Andersenfc059092002-06-06 11:35:29 +00001443 k = 0;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001444 while (argv[++k]) {
1445 const struct mode_info *mp;
1446 const struct control_info *cp;
1447 const char *arg = argv[k];
1448 const char *argnext = argv[k+1];
1449 int param;
Eric Andersen98e599c2001-02-14 18:47:33 +00001450
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001451 if (arg[0] == '-') {
1452 mp = find_mode(arg+1);
1453 if (mp) {
1454 set_mode(mp, 1 /* reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001455 stty_state |= STTY_require_set_attr;
Eric Andersenfc059092002-06-06 11:35:29 +00001456 }
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001457 /* It is an option - already parsed. Skip it */
1458 continue;
Eric Andersen98e599c2001-02-14 18:47:33 +00001459 }
Mark Whitley446dd272001-03-02 20:00:54 +00001460
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001461 mp = find_mode(arg);
1462 if (mp) {
1463 set_mode(mp, 0 /* non-reversed */, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001464 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001465 continue;
1466 }
Mark Whitley446dd272001-03-02 20:00:54 +00001467
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001468 cp = find_control(arg);
1469 if (cp) {
1470 ++k;
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001471 set_control_char_or_die(cp, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001472 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001473 continue;
1474 }
Mark Whitley446dd272001-03-02 20:00:54 +00001475
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001476 param = find_param(arg);
1477 if (param & param_need_arg) {
1478 ++k;
1479 }
1480
1481 switch (param) {
Denys Vlasenkoe54cfc52011-01-24 18:30:35 +01001482#ifdef __linux__
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001483 case param_line:
Denis Vlasenko13858992006-10-08 12:49:22 +00001484 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001485 stty_state |= STTY_require_set_attr;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001486 break;
Eric Andersen98e599c2001-02-14 18:47:33 +00001487#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001488#ifdef TIOCGWINSZ
1489 case param_cols:
Denys Vlasenko9f5a5772009-12-11 14:17:02 +01001490 case param_columns:
Denis Vlasenko13858992006-10-08 12:49:22 +00001491 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001492 break;
1493 case param_size:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001494 display_window_size(0);
1495 break;
1496 case param_rows:
Denis Vlasenko13858992006-10-08 12:49:22 +00001497 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001498 break;
1499#endif
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001500 case param_speed:
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001501 display_speed(&mode, 0);
1502 break;
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001503 case param_ispeed:
1504 set_speed_or_die(input_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001505 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001506 break;
1507 case param_ospeed:
1508 set_speed_or_die(output_speed, argnext, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001509 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001510 break;
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001511 default:
1512 if (recover_mode(arg, &mode) == 1)
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001513 stty_state |= STTY_require_set_attr;
Bernhard Reutner-Fischer4950f012007-01-17 19:44:59 +00001514 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
Denis Vlasenkodebaf2f2006-09-19 14:31:44 +00001515 set_speed_or_die(both_speeds, arg, &mode);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001516 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
Denis Vlasenko7eab79a2006-09-19 14:16:28 +00001517 } /* else - impossible (caught in the first pass):
1518 bb_error_msg_and_die("invalid argument '%s'", arg); */
Eric Andersen98e599c2001-02-14 18:47:33 +00001519 }
Eric Andersen98e599c2001-02-14 18:47:33 +00001520 }
1521
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001522 if (stty_state & STTY_require_set_attr) {
Eric Andersen98e599c2001-02-14 18:47:33 +00001523 struct termios new_mode;
1524
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001525 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001526 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001527
1528 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1529 it performs *any* of the requested operations. This means it
Denis Vlasenko79deb662006-09-19 15:12:12 +00001530 can report 'success' when it has actually failed to perform
Eric Andersen98e599c2001-02-14 18:47:33 +00001531 some proper subset of the requested operations. To detect
1532 this partial failure, get the current terminal attributes and
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001533 compare them to the requested ones */
Eric Andersen98e599c2001-02-14 18:47:33 +00001534
1535 /* Initialize to all zeroes so there is no risk memcmp will report a
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001536 spurious difference in an uninitialized portion of the structure */
Eric Andersen98e599c2001-02-14 18:47:33 +00001537 memset(&new_mode, 0, sizeof(new_mode));
"Vladimir N. Oleynik"9b9a9202006-01-30 12:23:46 +00001538 if (tcgetattr(STDIN_FILENO, &new_mode))
Denis Vlasenko20b253d2006-09-19 14:24:23 +00001539 perror_on_device_and_die("%s");
Eric Andersen98e599c2001-02-14 18:47:33 +00001540
Eric Andersen98e599c2001-02-14 18:47:33 +00001541 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
Denys Vlasenkoae0cf2a2013-05-17 20:08:12 +02001542/*
1543 * I think the below chunk is not necessary on Linux.
1544 * If you are deleting it, also delete STTY_speed_was_set bit -
1545 * it is only ever checked here.
1546 */
1547#if 0 /* was "if CIBAUD" */
Eric Andersen98e599c2001-02-14 18:47:33 +00001548 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1549 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1550 sometimes (m1 != m2). The only difference is in the four bits
1551 of the c_cflag field corresponding to the baud rate. To save
1552 Sun users a little confusion, don't report an error if this
1553 happens. But suppress the error only if we haven't tried to
1554 set the baud rate explicitly -- otherwise we'd never give an
Denis Vlasenko9efb0702006-09-19 14:17:10 +00001555 error for a true failure to set the baud rate */
Eric Andersen98e599c2001-02-14 18:47:33 +00001556
1557 new_mode.c_cflag &= (~CIBAUD);
Denis Vlasenko41aaefc2007-01-18 00:53:35 +00001558 if ((stty_state & STTY_speed_was_set)
1559 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
Eric Andersen98e599c2001-02-14 18:47:33 +00001560#endif
Denis Vlasenko89f0b342006-11-18 22:04:09 +00001561 perror_on_device_and_die("%s: cannot perform all requested operations");
Eric Andersen98e599c2001-02-14 18:47:33 +00001562 }
1563 }
1564
1565 return EXIT_SUCCESS;
1566}