source: MondoRescue/branches/3.0/mindi-busybox/coreutils/stty.c@ 2899

Last change on this file since 2899 was 2725, checked in by Bruno Cornec, 13 years ago
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File size: 42.0 KB
Line 
1/* vi: set sw=4 ts=4: */
2/* stty -- change and print terminal line settings
3 Copyright (C) 1990-1999 Free Software Foundation, Inc.
4
5 Licensed under GPLv2 or later, see file LICENSE in this source tree.
6*/
7/* Usage: stty [-ag] [-F device] [setting...]
8
9 Options:
10 -a Write all current settings to stdout in human-readable form.
11 -g Write all current settings to stdout in stty-readable form.
12 -F Open and use the specified device instead of stdin
13
14 If no args are given, write to stdout the baud rate and settings that
15 have been changed from their defaults. Mode reading and changes
16 are done on the specified device, or stdin if none was specified.
17
18 David MacKenzie <djm@gnu.ai.mit.edu>
19
20 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
21
22 */
23
24#include "libbb.h"
25
26#ifndef _POSIX_VDISABLE
27# define _POSIX_VDISABLE ((unsigned char) 0)
28#endif
29
30#define Control(c) ((c) & 0x1f)
31/* Canonical values for control characters */
32#ifndef CINTR
33# define CINTR Control('c')
34#endif
35#ifndef CQUIT
36# define CQUIT 28
37#endif
38#ifndef CERASE
39# define CERASE 127
40#endif
41#ifndef CKILL
42# define CKILL Control('u')
43#endif
44#ifndef CEOF
45# define CEOF Control('d')
46#endif
47#ifndef CEOL
48# define CEOL _POSIX_VDISABLE
49#endif
50#ifndef CSTART
51# define CSTART Control('q')
52#endif
53#ifndef CSTOP
54# define CSTOP Control('s')
55#endif
56#ifndef CSUSP
57# define CSUSP Control('z')
58#endif
59#if defined(VEOL2) && !defined(CEOL2)
60# define CEOL2 _POSIX_VDISABLE
61#endif
62/* ISC renamed swtch to susp for termios, but we'll accept either name */
63#if defined(VSUSP) && !defined(VSWTCH)
64# define VSWTCH VSUSP
65# define CSWTCH CSUSP
66#endif
67#if defined(VSWTCH) && !defined(CSWTCH)
68# define CSWTCH _POSIX_VDISABLE
69#endif
70
71/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
72 So the default is to disable 'swtch.' */
73#if defined(__sparc__) && defined(__svr4__)
74# undef CSWTCH
75# define CSWTCH _POSIX_VDISABLE
76#endif
77
78#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
79# define VWERASE VWERSE
80#endif
81#if defined(VDSUSP) && !defined(CDSUSP)
82# define CDSUSP Control('y')
83#endif
84#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
85# define VREPRINT VRPRNT
86#endif
87#if defined(VREPRINT) && !defined(CRPRNT)
88# define CRPRNT Control('r')
89#endif
90#if defined(VWERASE) && !defined(CWERASE)
91# define CWERASE Control('w')
92#endif
93#if defined(VLNEXT) && !defined(CLNEXT)
94# define CLNEXT Control('v')
95#endif
96#if defined(VDISCARD) && !defined(VFLUSHO)
97# define VFLUSHO VDISCARD
98#endif
99#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
100# define VFLUSHO VFLUSH
101#endif
102#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
103# define ECHOCTL CTLECH
104#endif
105#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
106# define ECHOCTL TCTLECH
107#endif
108#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
109# define ECHOKE CRTKIL
110#endif
111#if defined(VFLUSHO) && !defined(CFLUSHO)
112# define CFLUSHO Control('o')
113#endif
114#if defined(VSTATUS) && !defined(CSTATUS)
115# define CSTATUS Control('t')
116#endif
117
118/* Save us from #ifdef forest plague */
119#ifndef BSDLY
120# define BSDLY 0
121#endif
122#ifndef CIBAUD
123# define CIBAUD 0
124#endif
125#ifndef CRDLY
126# define CRDLY 0
127#endif
128#ifndef CRTSCTS
129# define CRTSCTS 0
130#endif
131#ifndef ECHOCTL
132# define ECHOCTL 0
133#endif
134#ifndef ECHOKE
135# define ECHOKE 0
136#endif
137#ifndef ECHOPRT
138# define ECHOPRT 0
139#endif
140#ifndef FFDLY
141# define FFDLY 0
142#endif
143#ifndef IEXTEN
144# define IEXTEN 0
145#endif
146#ifndef IMAXBEL
147# define IMAXBEL 0
148#endif
149#ifndef IUCLC
150# define IUCLC 0
151#endif
152#ifndef IXANY
153# define IXANY 0
154#endif
155#ifndef NLDLY
156# define NLDLY 0
157#endif
158#ifndef OCRNL
159# define OCRNL 0
160#endif
161#ifndef OFDEL
162# define OFDEL 0
163#endif
164#ifndef OFILL
165# define OFILL 0
166#endif
167#ifndef OLCUC
168# define OLCUC 0
169#endif
170#ifndef ONLCR
171# define ONLCR 0
172#endif
173#ifndef ONLRET
174# define ONLRET 0
175#endif
176#ifndef ONOCR
177# define ONOCR 0
178#endif
179#ifndef OXTABS
180# define OXTABS 0
181#endif
182#ifndef TABDLY
183# define TABDLY 0
184#endif
185#ifndef TAB1
186# define TAB1 0
187#endif
188#ifndef TAB2
189# define TAB2 0
190#endif
191#ifndef TOSTOP
192# define TOSTOP 0
193#endif
194#ifndef VDSUSP
195# define VDSUSP 0
196#endif
197#ifndef VEOL2
198# define VEOL2 0
199#endif
200#ifndef VFLUSHO
201# define VFLUSHO 0
202#endif
203#ifndef VLNEXT
204# define VLNEXT 0
205#endif
206#ifndef VREPRINT
207# define VREPRINT 0
208#endif
209#ifndef VSTATUS
210# define VSTATUS 0
211#endif
212#ifndef VSWTCH
213# define VSWTCH 0
214#endif
215#ifndef VTDLY
216# define VTDLY 0
217#endif
218#ifndef VWERASE
219# define VWERASE 0
220#endif
221#ifndef XCASE
222# define XCASE 0
223#endif
224
225/* Which speeds to set */
226enum speed_setting {
227 input_speed, output_speed, both_speeds
228};
229
230/* Which member(s) of 'struct termios' a mode uses */
231enum {
232 /* Do NOT change the order or values, as mode_type_flag()
233 * depends on them */
234 control, input, output, local, combination
235};
236
237/* Flags for 'struct mode_info' */
238#define SANE_SET 1 /* Set in 'sane' mode */
239#define SANE_UNSET 2 /* Unset in 'sane' mode */
240#define REV 4 /* Can be turned off by prepending '-' */
241#define OMIT 8 /* Don't display value */
242
243
244/* Each mode.
245 * This structure should be kept as small as humanly possible.
246 */
247struct mode_info {
248 const uint8_t type; /* Which structure element to change */
249 const uint8_t flags; /* Setting and display options */
250 /* only these values are ever used, so... */
251#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100
252 const uint8_t mask;
253#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000
254 const uint16_t mask;
255#else
256 const tcflag_t mask; /* Other bits to turn off for this mode */
257#endif
258 /* was using short here, but ppc32 was unhappy */
259 const tcflag_t bits; /* Bits to set for this mode */
260};
261
262enum {
263 /* Must match mode_name[] and mode_info[] order! */
264 IDX_evenp = 0,
265 IDX_parity,
266 IDX_oddp,
267 IDX_nl,
268 IDX_ek,
269 IDX_sane,
270 IDX_cooked,
271 IDX_raw,
272 IDX_pass8,
273 IDX_litout,
274 IDX_cbreak,
275 IDX_crt,
276 IDX_dec,
277#if IXANY
278 IDX_decctlq,
279#endif
280#if TABDLY || OXTABS
281 IDX_tabs,
282#endif
283#if XCASE && IUCLC && OLCUC
284 IDX_lcase,
285 IDX_LCASE,
286#endif
287};
288
289#define MI_ENTRY(N,T,F,B,M) N "\0"
290
291/* Mode names given on command line */
292static const char mode_name[] =
293 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
294 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
295 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
296 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
297 MI_ENTRY("ek", combination, OMIT, 0, 0 )
298 MI_ENTRY("sane", combination, OMIT, 0, 0 )
299 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
300 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
301 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
302 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
303 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
304 MI_ENTRY("crt", combination, OMIT, 0, 0 )
305 MI_ENTRY("dec", combination, OMIT, 0, 0 )
306#if IXANY
307 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
308#endif
309#if TABDLY || OXTABS
310 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
311#endif
312#if XCASE && IUCLC && OLCUC
313 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
314 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
315#endif
316 MI_ENTRY("parenb", control, REV, PARENB, 0 )
317 MI_ENTRY("parodd", control, REV, PARODD, 0 )
318 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
319 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
320 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
321 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
322 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
323 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
324 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
325 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
326 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
327#if CRTSCTS
328 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
329#endif
330 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
331 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
332 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
333 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
334 MI_ENTRY("inpck", input, REV, INPCK, 0 )
335 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
336 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
337 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
338 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
339 MI_ENTRY("ixon", input, REV, IXON, 0 )
340 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
341 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
342#if IUCLC
343 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
344#endif
345#if IXANY
346 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
347#endif
348#if IMAXBEL
349 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
350#endif
351 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
352#if OLCUC
353 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
354#endif
355#if OCRNL
356 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
357#endif
358#if ONLCR
359 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
360#endif
361#if ONOCR
362 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
363#endif
364#if ONLRET
365 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
366#endif
367#if OFILL
368 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
369#endif
370#if OFDEL
371 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
372#endif
373#if NLDLY
374 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
375 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
376#endif
377#if CRDLY
378 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
379 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
380 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
381 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
382#endif
383
384#if TABDLY
385 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
386# if TAB2
387 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
388# endif
389# if TAB1
390 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
391# endif
392 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
393#else
394# if OXTABS
395 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
396# endif
397#endif
398
399#if BSDLY
400 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
401 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
402#endif
403#if VTDLY
404 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
405 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
406#endif
407#if FFDLY
408 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
409 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
410#endif
411 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
412 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
413#if IEXTEN
414 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
415#endif
416 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
417 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
418 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
419 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
420 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
421 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
422#if XCASE
423 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
424#endif
425#if TOSTOP
426 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
427#endif
428#if ECHOPRT
429 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
430 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
431#endif
432#if ECHOCTL
433 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
434 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
435#endif
436#if ECHOKE
437 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
438 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
439#endif
440 ;
441
442#undef MI_ENTRY
443#define MI_ENTRY(N,T,F,B,M) { T, F, M, B },
444
445static const struct mode_info mode_info[] = {
446 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
447 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
448 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
449 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
450 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
451 MI_ENTRY("ek", combination, OMIT, 0, 0 )
452 MI_ENTRY("sane", combination, OMIT, 0, 0 )
453 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
454 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
455 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
456 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
457 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
458 MI_ENTRY("crt", combination, OMIT, 0, 0 )
459 MI_ENTRY("dec", combination, OMIT, 0, 0 )
460#if IXANY
461 MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 )
462#endif
463#if TABDLY || OXTABS
464 MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 )
465#endif
466#if XCASE && IUCLC && OLCUC
467 MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 )
468 MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 )
469#endif
470 MI_ENTRY("parenb", control, REV, PARENB, 0 )
471 MI_ENTRY("parodd", control, REV, PARODD, 0 )
472 MI_ENTRY("cs5", control, 0, CS5, CSIZE)
473 MI_ENTRY("cs6", control, 0, CS6, CSIZE)
474 MI_ENTRY("cs7", control, 0, CS7, CSIZE)
475 MI_ENTRY("cs8", control, 0, CS8, CSIZE)
476 MI_ENTRY("hupcl", control, REV, HUPCL, 0 )
477 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 )
478 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 )
479 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 )
480 MI_ENTRY("clocal", control, REV, CLOCAL, 0 )
481#if CRTSCTS
482 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 )
483#endif
484 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 )
485 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 )
486 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 )
487 MI_ENTRY("parmrk", input, REV, PARMRK, 0 )
488 MI_ENTRY("inpck", input, REV, INPCK, 0 )
489 MI_ENTRY("istrip", input, REV, ISTRIP, 0 )
490 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 )
491 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 )
492 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 )
493 MI_ENTRY("ixon", input, REV, IXON, 0 )
494 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 )
495 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 )
496#if IUCLC
497 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 )
498#endif
499#if IXANY
500 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 )
501#endif
502#if IMAXBEL
503 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 )
504#endif
505 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 )
506#if OLCUC
507 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 )
508#endif
509#if OCRNL
510 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 )
511#endif
512#if ONLCR
513 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 )
514#endif
515#if ONOCR
516 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 )
517#endif
518#if ONLRET
519 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 )
520#endif
521#if OFILL
522 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 )
523#endif
524#if OFDEL
525 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 )
526#endif
527#if NLDLY
528 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY)
529 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY)
530#endif
531#if CRDLY
532 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY)
533 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY)
534 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY)
535 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY)
536#endif
537
538#if TABDLY
539 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY)
540# if TAB2
541 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY)
542# endif
543# if TAB1
544 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY)
545# endif
546 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY)
547#else
548# if OXTABS
549 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 )
550# endif
551#endif
552
553#if BSDLY
554 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY)
555 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY)
556#endif
557#if VTDLY
558 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY)
559 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY)
560#endif
561#if FFDLY
562 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY)
563 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY)
564#endif
565 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 )
566 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 )
567#if IEXTEN
568 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
569#endif
570 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
571 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
572 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 )
573 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
574 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 )
575 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 )
576#if XCASE
577 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 )
578#endif
579#if TOSTOP
580 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 )
581#endif
582#if ECHOPRT
583 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 )
584 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 )
585#endif
586#if ECHOCTL
587 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 )
588 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 )
589#endif
590#if ECHOKE
591 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 )
592 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 )
593#endif
594};
595
596enum {
597 NUM_mode_info = ARRAY_SIZE(mode_info)
598};
599
600
601/* Control characters */
602struct control_info {
603 const uint8_t saneval; /* Value to set for 'stty sane' */
604 const uint8_t offset; /* Offset in c_cc */
605};
606
607enum {
608 /* Must match control_name[] and control_info[] order! */
609 CIDX_intr = 0,
610 CIDX_quit,
611 CIDX_erase,
612 CIDX_kill,
613 CIDX_eof,
614 CIDX_eol,
615#if VEOL2
616 CIDX_eol2,
617#endif
618#if VSWTCH
619 CIDX_swtch,
620#endif
621 CIDX_start,
622 CIDX_stop,
623 CIDX_susp,
624#if VDSUSP
625 CIDX_dsusp,
626#endif
627#if VREPRINT
628 CIDX_rprnt,
629#endif
630#if VWERASE
631 CIDX_werase,
632#endif
633#if VLNEXT
634 CIDX_lnext,
635#endif
636#if VFLUSHO
637 CIDX_flush,
638#endif
639#if VSTATUS
640 CIDX_status,
641#endif
642 CIDX_min,
643 CIDX_time,
644};
645
646#define CI_ENTRY(n,s,o) n "\0"
647
648/* Name given on command line */
649static const char control_name[] =
650 CI_ENTRY("intr", CINTR, VINTR )
651 CI_ENTRY("quit", CQUIT, VQUIT )
652 CI_ENTRY("erase", CERASE, VERASE )
653 CI_ENTRY("kill", CKILL, VKILL )
654 CI_ENTRY("eof", CEOF, VEOF )
655 CI_ENTRY("eol", CEOL, VEOL )
656#if VEOL2
657 CI_ENTRY("eol2", CEOL2, VEOL2 )
658#endif
659#if VSWTCH
660 CI_ENTRY("swtch", CSWTCH, VSWTCH )
661#endif
662 CI_ENTRY("start", CSTART, VSTART )
663 CI_ENTRY("stop", CSTOP, VSTOP )
664 CI_ENTRY("susp", CSUSP, VSUSP )
665#if VDSUSP
666 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
667#endif
668#if VREPRINT
669 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
670#endif
671#if VWERASE
672 CI_ENTRY("werase", CWERASE, VWERASE )
673#endif
674#if VLNEXT
675 CI_ENTRY("lnext", CLNEXT, VLNEXT )
676#endif
677#if VFLUSHO
678 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
679#endif
680#if VSTATUS
681 CI_ENTRY("status", CSTATUS, VSTATUS )
682#endif
683 /* These must be last because of the display routines */
684 CI_ENTRY("min", 1, VMIN )
685 CI_ENTRY("time", 0, VTIME )
686 ;
687
688#undef CI_ENTRY
689#define CI_ENTRY(n,s,o) { s, o },
690
691static const struct control_info control_info[] = {
692 /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */
693 CI_ENTRY("intr", CINTR, VINTR )
694 CI_ENTRY("quit", CQUIT, VQUIT )
695 CI_ENTRY("erase", CERASE, VERASE )
696 CI_ENTRY("kill", CKILL, VKILL )
697 CI_ENTRY("eof", CEOF, VEOF )
698 CI_ENTRY("eol", CEOL, VEOL )
699#if VEOL2
700 CI_ENTRY("eol2", CEOL2, VEOL2 )
701#endif
702#if VSWTCH
703 CI_ENTRY("swtch", CSWTCH, VSWTCH )
704#endif
705 CI_ENTRY("start", CSTART, VSTART )
706 CI_ENTRY("stop", CSTOP, VSTOP )
707 CI_ENTRY("susp", CSUSP, VSUSP )
708#if VDSUSP
709 CI_ENTRY("dsusp", CDSUSP, VDSUSP )
710#endif
711#if VREPRINT
712 CI_ENTRY("rprnt", CRPRNT, VREPRINT)
713#endif
714#if VWERASE
715 CI_ENTRY("werase", CWERASE, VWERASE )
716#endif
717#if VLNEXT
718 CI_ENTRY("lnext", CLNEXT, VLNEXT )
719#endif
720#if VFLUSHO
721 CI_ENTRY("flush", CFLUSHO, VFLUSHO )
722#endif
723#if VSTATUS
724 CI_ENTRY("status", CSTATUS, VSTATUS )
725#endif
726 /* These must be last because of the display routines */
727 CI_ENTRY("min", 1, VMIN )
728 CI_ENTRY("time", 0, VTIME )
729};
730
731enum {
732 NUM_control_info = ARRAY_SIZE(control_info)
733};
734
735
736struct globals {
737 const char *device_name;
738 /* The width of the screen, for output wrapping */
739 unsigned max_col;
740 /* Current position, to know when to wrap */
741 unsigned current_col;
742 char buf[10];
743} FIX_ALIASING;
744#define G (*(struct globals*)&bb_common_bufsiz1)
745#define INIT_G() do { \
746 G.device_name = bb_msg_standard_input; \
747 G.max_col = 80; \
748} while (0)
749
750
751/* Return a string that is the printable representation of character CH */
752/* Adapted from 'cat' by Torbjorn Granlund */
753static const char *visible(unsigned ch)
754{
755 char *bpout = G.buf;
756
757 if (ch == _POSIX_VDISABLE)
758 return "<undef>";
759
760 if (ch >= 128) {
761 ch -= 128;
762 *bpout++ = 'M';
763 *bpout++ = '-';
764 }
765
766 if (ch < 32) {
767 *bpout++ = '^';
768 *bpout++ = ch + 64;
769 } else if (ch < 127) {
770 *bpout++ = ch;
771 } else {
772 *bpout++ = '^';
773 *bpout++ = '?';
774 }
775
776 *bpout = '\0';
777 return G.buf;
778}
779
780static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
781{
782 static const uint8_t tcflag_offsets[] ALIGN1 = {
783 offsetof(struct termios, c_cflag), /* control */
784 offsetof(struct termios, c_iflag), /* input */
785 offsetof(struct termios, c_oflag), /* output */
786 offsetof(struct termios, c_lflag) /* local */
787 };
788
789 if (type <= local) {
790 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
791 }
792 return NULL;
793}
794
795static void set_speed_or_die(enum speed_setting type, const char *arg,
796 struct termios *mode)
797{
798 speed_t baud;
799
800 baud = tty_value_to_baud(xatou(arg));
801
802 if (type != output_speed) { /* either input or both */
803 cfsetispeed(mode, baud);
804 }
805 if (type != input_speed) { /* either output or both */
806 cfsetospeed(mode, baud);
807 }
808}
809
810static NORETURN void perror_on_device_and_die(const char *fmt)
811{
812 bb_perror_msg_and_die(fmt, G.device_name);
813}
814
815static void perror_on_device(const char *fmt)
816{
817 bb_perror_msg(fmt, G.device_name);
818}
819
820/* Print format string MESSAGE and optional args.
821 Wrap to next line first if it won't fit.
822 Print a space first unless MESSAGE will start a new line */
823static void wrapf(const char *message, ...)
824{
825 char buf[128];
826 va_list args;
827 unsigned buflen;
828
829 va_start(args, message);
830 buflen = vsnprintf(buf, sizeof(buf), message, args);
831 va_end(args);
832 /* We seem to be called only with suitable lengths, but check if
833 somebody failed to adhere to this assumption just to be sure. */
834 if (!buflen || buflen >= sizeof(buf)) return;
835
836 if (G.current_col > 0) {
837 G.current_col++;
838 if (buf[0] != '\n') {
839 if (G.current_col + buflen >= G.max_col) {
840 bb_putchar('\n');
841 G.current_col = 0;
842 } else
843 bb_putchar(' ');
844 }
845 }
846 fputs(buf, stdout);
847 G.current_col += buflen;
848 if (buf[buflen-1] == '\n')
849 G.current_col = 0;
850}
851
852static void newline(void)
853{
854 if (G.current_col != 0)
855 wrapf("\n");
856}
857
858#ifdef TIOCGWINSZ
859static void set_window_size(int rows, int cols)
860{
861 struct winsize win = { 0, 0, 0, 0 };
862
863 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
864 if (errno != EINVAL) {
865 goto bail;
866 }
867 memset(&win, 0, sizeof(win));
868 }
869
870 if (rows >= 0)
871 win.ws_row = rows;
872 if (cols >= 0)
873 win.ws_col = cols;
874
875 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
876bail:
877 perror_on_device("%s");
878}
879#endif
880
881static void display_window_size(int fancy)
882{
883 const char *fmt_str = "%s\0%s: no size information for this device";
884 unsigned width, height;
885
886 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
887 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
888 perror_on_device(fmt_str);
889 }
890 } else {
891 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
892 height, width);
893 }
894}
895
896static const struct suffix_mult stty_suffixes[] = {
897 { "b", 512 },
898 { "k", 1024 },
899 { "B", 1024 },
900 { "", 0 }
901};
902
903static const struct mode_info *find_mode(const char *name)
904{
905 int i = index_in_strings(mode_name, name);
906 return i >= 0 ? &mode_info[i] : NULL;
907}
908
909static const struct control_info *find_control(const char *name)
910{
911 int i = index_in_strings(control_name, name);
912 return i >= 0 ? &control_info[i] : NULL;
913}
914
915enum {
916 param_need_arg = 0x80,
917 param_line = 1 | 0x80,
918 param_rows = 2 | 0x80,
919 param_cols = 3 | 0x80,
920 param_columns = 4 | 0x80,
921 param_size = 5,
922 param_speed = 6,
923 param_ispeed = 7 | 0x80,
924 param_ospeed = 8 | 0x80,
925};
926
927static int find_param(const char *name)
928{
929 static const char params[] ALIGN1 =
930 "line\0" /* 1 */
931 "rows\0" /* 2 */
932 "cols\0" /* 3 */
933 "columns\0" /* 4 */
934 "size\0" /* 5 */
935 "speed\0" /* 6 */
936 "ispeed\0"
937 "ospeed\0";
938 int i = index_in_strings(params, name) + 1;
939 if (i == 0)
940 return 0;
941 if (i != 5 && i != 6)
942 i |= 0x80;
943 return i;
944}
945
946static int recover_mode(const char *arg, struct termios *mode)
947{
948 int i, n;
949 unsigned chr;
950 unsigned long iflag, oflag, cflag, lflag;
951
952 /* Scan into temporaries since it is too much trouble to figure out
953 the right format for 'tcflag_t' */
954 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
955 &iflag, &oflag, &cflag, &lflag, &n) != 4)
956 return 0;
957 mode->c_iflag = iflag;
958 mode->c_oflag = oflag;
959 mode->c_cflag = cflag;
960 mode->c_lflag = lflag;
961 arg += n;
962 for (i = 0; i < NCCS; ++i) {
963 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
964 return 0;
965 mode->c_cc[i] = chr;
966 arg += n;
967 }
968
969 /* Fail if there are too many fields */
970 if (*arg != '\0')
971 return 0;
972
973 return 1;
974}
975
976static void display_recoverable(const struct termios *mode,
977 int UNUSED_PARAM dummy)
978{
979 int i;
980 printf("%lx:%lx:%lx:%lx",
981 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
982 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
983 for (i = 0; i < NCCS; ++i)
984 printf(":%x", (unsigned int) mode->c_cc[i]);
985 bb_putchar('\n');
986}
987
988static void display_speed(const struct termios *mode, int fancy)
989{
990 //____________________ 01234567 8 9
991 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
992 unsigned long ispeed, ospeed;
993
994 ospeed = ispeed = cfgetispeed(mode);
995 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
996 ispeed = ospeed; /* in case ispeed was 0 */
997 //________ 0123 4 5 6 7 8 9
998 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
999 }
1000 if (fancy) fmt_str += 9;
1001 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1002}
1003
1004static void do_display(const struct termios *mode, int all)
1005{
1006 int i;
1007 tcflag_t *bitsp;
1008 unsigned long mask;
1009 int prev_type = control;
1010
1011 display_speed(mode, 1);
1012 if (all)
1013 display_window_size(1);
1014#ifdef HAVE_C_LINE
1015 wrapf("line = %u;\n", mode->c_line);
1016#else
1017 newline();
1018#endif
1019
1020 for (i = 0; i != CIDX_min; ++i) {
1021 /* If swtch is the same as susp, don't print both */
1022#if VSWTCH == VSUSP
1023 if (i == CIDX_swtch)
1024 continue;
1025#endif
1026 /* If eof uses the same slot as min, only print whichever applies */
1027#if VEOF == VMIN
1028 if (!(mode->c_lflag & ICANON)
1029 && (i == CIDX_eof || i == CIDX_eol)
1030 ) {
1031 continue;
1032 }
1033#endif
1034 wrapf("%s = %s;", nth_string(control_name, i),
1035 visible(mode->c_cc[control_info[i].offset]));
1036 }
1037#if VEOF == VMIN
1038 if ((mode->c_lflag & ICANON) == 0)
1039#endif
1040 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1041 newline();
1042
1043 for (i = 0; i < NUM_mode_info; ++i) {
1044 if (mode_info[i].flags & OMIT)
1045 continue;
1046 if (mode_info[i].type != prev_type) {
1047 newline();
1048 prev_type = mode_info[i].type;
1049 }
1050
1051 bitsp = mode_type_flag(mode_info[i].type, mode);
1052 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1053 if ((*bitsp & mask) == mode_info[i].bits) {
1054 if (all || (mode_info[i].flags & SANE_UNSET))
1055 wrapf("-%s"+1, nth_string(mode_name, i));
1056 } else {
1057 if ((all && mode_info[i].flags & REV)
1058 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1059 ) {
1060 wrapf("-%s", nth_string(mode_name, i));
1061 }
1062 }
1063 }
1064 newline();
1065}
1066
1067static void sane_mode(struct termios *mode)
1068{
1069 int i;
1070 tcflag_t *bitsp;
1071
1072 for (i = 0; i < NUM_control_info; ++i) {
1073#if VMIN == VEOF
1074 if (i == CIDX_min)
1075 break;
1076#endif
1077 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1078 }
1079
1080 for (i = 0; i < NUM_mode_info; ++i) {
1081 if (mode_info[i].flags & SANE_SET) {
1082 bitsp = mode_type_flag(mode_info[i].type, mode);
1083 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
1084 | mode_info[i].bits;
1085 } else if (mode_info[i].flags & SANE_UNSET) {
1086 bitsp = mode_type_flag(mode_info[i].type, mode);
1087 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
1088 & ~mode_info[i].bits;
1089 }
1090 }
1091}
1092
1093static void set_mode(const struct mode_info *info, int reversed,
1094 struct termios *mode)
1095{
1096 tcflag_t *bitsp;
1097
1098 bitsp = mode_type_flag(info->type, mode);
1099
1100 if (bitsp) {
1101 if (reversed)
1102 *bitsp = *bitsp & ~info->mask & ~info->bits;
1103 else
1104 *bitsp = (*bitsp & ~info->mask) | info->bits;
1105 return;
1106 }
1107
1108 /* Combination mode */
1109 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1110 if (reversed)
1111 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1112 else
1113 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1114 } else if (info == &mode_info[IDX_oddp]) {
1115 if (reversed)
1116 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1117 else
1118 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1119 } else if (info == &mode_info[IDX_nl]) {
1120 if (reversed) {
1121 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1122 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
1123 } else {
1124 mode->c_iflag = mode->c_iflag & ~ICRNL;
1125 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1126 }
1127 } else if (info == &mode_info[IDX_ek]) {
1128 mode->c_cc[VERASE] = CERASE;
1129 mode->c_cc[VKILL] = CKILL;
1130 } else if (info == &mode_info[IDX_sane]) {
1131 sane_mode(mode);
1132 } else if (info == &mode_info[IDX_cbreak]) {
1133 if (reversed)
1134 mode->c_lflag |= ICANON;
1135 else
1136 mode->c_lflag &= ~ICANON;
1137 } else if (info == &mode_info[IDX_pass8]) {
1138 if (reversed) {
1139 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1140 mode->c_iflag |= ISTRIP;
1141 } else {
1142 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1143 mode->c_iflag &= ~ISTRIP;
1144 }
1145 } else if (info == &mode_info[IDX_litout]) {
1146 if (reversed) {
1147 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1148 mode->c_iflag |= ISTRIP;
1149 mode->c_oflag |= OPOST;
1150 } else {
1151 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1152 mode->c_iflag &= ~ISTRIP;
1153 mode->c_oflag &= ~OPOST;
1154 }
1155 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
1156 if ((info == &mode_info[IDX_raw] && reversed)
1157 || (info == &mode_info[IDX_cooked] && !reversed)
1158 ) {
1159 /* Cooked mode */
1160 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1161 mode->c_oflag |= OPOST;
1162 mode->c_lflag |= ISIG | ICANON;
1163#if VMIN == VEOF
1164 mode->c_cc[VEOF] = CEOF;
1165#endif
1166#if VTIME == VEOL
1167 mode->c_cc[VEOL] = CEOL;
1168#endif
1169 } else {
1170 /* Raw mode */
1171 mode->c_iflag = 0;
1172 mode->c_oflag &= ~OPOST;
1173 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1174 mode->c_cc[VMIN] = 1;
1175 mode->c_cc[VTIME] = 0;
1176 }
1177 }
1178#if IXANY
1179 else if (info == &mode_info[IDX_decctlq]) {
1180 if (reversed)
1181 mode->c_iflag |= IXANY;
1182 else
1183 mode->c_iflag &= ~IXANY;
1184 }
1185#endif
1186#if TABDLY
1187 else if (info == &mode_info[IDX_tabs]) {
1188 if (reversed)
1189 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1190 else
1191 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1192 }
1193#endif
1194#if OXTABS
1195 else if (info == &mode_info[IDX_tabs]) {
1196 if (reversed)
1197 mode->c_oflag |= OXTABS;
1198 else
1199 mode->c_oflag &= ~OXTABS;
1200 }
1201#endif
1202#if XCASE && IUCLC && OLCUC
1203 else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) {
1204 if (reversed) {
1205 mode->c_lflag &= ~XCASE;
1206 mode->c_iflag &= ~IUCLC;
1207 mode->c_oflag &= ~OLCUC;
1208 } else {
1209 mode->c_lflag |= XCASE;
1210 mode->c_iflag |= IUCLC;
1211 mode->c_oflag |= OLCUC;
1212 }
1213 }
1214#endif
1215 else if (info == &mode_info[IDX_crt]) {
1216 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1217 } else if (info == &mode_info[IDX_dec]) {
1218 mode->c_cc[VINTR] = 3; /* ^C */
1219 mode->c_cc[VERASE] = 127; /* DEL */
1220 mode->c_cc[VKILL] = 21; /* ^U */
1221 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1222 if (IXANY) mode->c_iflag &= ~IXANY;
1223 }
1224}
1225
1226static void set_control_char_or_die(const struct control_info *info,
1227 const char *arg, struct termios *mode)
1228{
1229 unsigned char value;
1230
1231 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
1232 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1233 else if (arg[0] == '\0' || arg[1] == '\0')
1234 value = arg[0];
1235 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
1236 value = _POSIX_VDISABLE;
1237 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
1238 value = arg[1] & 0x1f; /* Non-letters get weird results */
1239 if (arg[1] == '?')
1240 value = 127;
1241 } else
1242 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1243 mode->c_cc[info->offset] = value;
1244}
1245
1246#define STTY_require_set_attr (1 << 0)
1247#define STTY_speed_was_set (1 << 1)
1248#define STTY_verbose_output (1 << 2)
1249#define STTY_recoverable_output (1 << 3)
1250#define STTY_noargs (1 << 4)
1251
1252int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1253int stty_main(int argc UNUSED_PARAM, char **argv)
1254{
1255 struct termios mode;
1256 void (*output_func)(const struct termios *, int);
1257 const char *file_name = NULL;
1258 int display_all = 0;
1259 int stty_state;
1260 int k;
1261
1262 INIT_G();
1263
1264 stty_state = STTY_noargs;
1265 output_func = do_display;
1266
1267 /* First pass: only parse/verify command line params */
1268 k = 0;
1269 while (argv[++k]) {
1270 const struct mode_info *mp;
1271 const struct control_info *cp;
1272 const char *arg = argv[k];
1273 const char *argnext = argv[k+1];
1274 int param;
1275
1276 if (arg[0] == '-') {
1277 int i;
1278 mp = find_mode(arg+1);
1279 if (mp) {
1280 if (!(mp->flags & REV))
1281 goto invalid_argument;
1282 stty_state &= ~STTY_noargs;
1283 continue;
1284 }
1285 /* It is an option - parse it */
1286 i = 0;
1287 while (arg[++i]) {
1288 switch (arg[i]) {
1289 case 'a':
1290 stty_state |= STTY_verbose_output;
1291 output_func = do_display;
1292 display_all = 1;
1293 break;
1294 case 'g':
1295 stty_state |= STTY_recoverable_output;
1296 output_func = display_recoverable;
1297 break;
1298 case 'F':
1299 if (file_name)
1300 bb_error_msg_and_die("only one device may be specified");
1301 file_name = &arg[i+1]; /* "-Fdevice" ? */
1302 if (!file_name[0]) { /* nope, "-F device" */
1303 int p = k+1; /* argv[p] is argnext */
1304 file_name = argnext;
1305 if (!file_name)
1306 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1307 /* remove -F param from arg[vc] */
1308 while (argv[p]) {
1309 argv[p] = argv[p+1];
1310 ++p;
1311 }
1312 }
1313 goto end_option;
1314 default:
1315 goto invalid_argument;
1316 }
1317 }
1318 end_option:
1319 continue;
1320 }
1321
1322 mp = find_mode(arg);
1323 if (mp) {
1324 stty_state &= ~STTY_noargs;
1325 continue;
1326 }
1327
1328 cp = find_control(arg);
1329 if (cp) {
1330 if (!argnext)
1331 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1332 /* called for the side effect of xfunc death only */
1333 set_control_char_or_die(cp, argnext, &mode);
1334 stty_state &= ~STTY_noargs;
1335 ++k;
1336 continue;
1337 }
1338
1339 param = find_param(arg);
1340 if (param & param_need_arg) {
1341 if (!argnext)
1342 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1343 ++k;
1344 }
1345
1346 switch (param) {
1347#ifdef HAVE_C_LINE
1348 case param_line:
1349# ifndef TIOCGWINSZ
1350 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1351 break;
1352# endif /* else fall-through */
1353#endif
1354#ifdef TIOCGWINSZ
1355 case param_rows:
1356 case param_cols:
1357 case param_columns:
1358 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1359 break;
1360 case param_size:
1361#endif
1362 case param_speed:
1363 break;
1364 case param_ispeed:
1365 /* called for the side effect of xfunc death only */
1366 set_speed_or_die(input_speed, argnext, &mode);
1367 break;
1368 case param_ospeed:
1369 /* called for the side effect of xfunc death only */
1370 set_speed_or_die(output_speed, argnext, &mode);
1371 break;
1372 default:
1373 if (recover_mode(arg, &mode) == 1) break;
1374 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1375 invalid_argument:
1376 bb_error_msg_and_die("invalid argument '%s'", arg);
1377 }
1378 stty_state &= ~STTY_noargs;
1379 }
1380
1381 /* Specifying both -a and -g is an error */
1382 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1383 (STTY_verbose_output | STTY_recoverable_output))
1384 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1385 /* Specifying -a or -g with non-options is an error */
1386 if (!(stty_state & STTY_noargs)
1387 && (stty_state & (STTY_verbose_output | STTY_recoverable_output))
1388 ) {
1389 bb_error_msg_and_die("modes may not be set when specifying an output style");
1390 }
1391
1392 /* Now it is safe to start doing things */
1393 if (file_name) {
1394 G.device_name = file_name;
1395 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1396 ndelay_off(STDIN_FILENO);
1397 }
1398
1399 /* Initialize to all zeroes so there is no risk memcmp will report a
1400 spurious difference in an uninitialized portion of the structure */
1401 memset(&mode, 0, sizeof(mode));
1402 if (tcgetattr(STDIN_FILENO, &mode))
1403 perror_on_device_and_die("%s");
1404
1405 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
1406 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
1407 output_func(&mode, display_all);
1408 return EXIT_SUCCESS;
1409 }
1410
1411 /* Second pass: perform actions */
1412 k = 0;
1413 while (argv[++k]) {
1414 const struct mode_info *mp;
1415 const struct control_info *cp;
1416 const char *arg = argv[k];
1417 const char *argnext = argv[k+1];
1418 int param;
1419
1420 if (arg[0] == '-') {
1421 mp = find_mode(arg+1);
1422 if (mp) {
1423 set_mode(mp, 1 /* reversed */, &mode);
1424 stty_state |= STTY_require_set_attr;
1425 }
1426 /* It is an option - already parsed. Skip it */
1427 continue;
1428 }
1429
1430 mp = find_mode(arg);
1431 if (mp) {
1432 set_mode(mp, 0 /* non-reversed */, &mode);
1433 stty_state |= STTY_require_set_attr;
1434 continue;
1435 }
1436
1437 cp = find_control(arg);
1438 if (cp) {
1439 ++k;
1440 set_control_char_or_die(cp, argnext, &mode);
1441 stty_state |= STTY_require_set_attr;
1442 continue;
1443 }
1444
1445 param = find_param(arg);
1446 if (param & param_need_arg) {
1447 ++k;
1448 }
1449
1450 switch (param) {
1451#ifdef HAVE_C_LINE
1452 case param_line:
1453 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
1454 stty_state |= STTY_require_set_attr;
1455 break;
1456#endif
1457#ifdef TIOCGWINSZ
1458 case param_cols:
1459 case param_columns:
1460 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
1461 break;
1462 case param_size:
1463 display_window_size(0);
1464 break;
1465 case param_rows:
1466 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1467 break;
1468#endif
1469 case param_speed:
1470 display_speed(&mode, 0);
1471 break;
1472 case param_ispeed:
1473 set_speed_or_die(input_speed, argnext, &mode);
1474 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1475 break;
1476 case param_ospeed:
1477 set_speed_or_die(output_speed, argnext, &mode);
1478 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1479 break;
1480 default:
1481 if (recover_mode(arg, &mode) == 1)
1482 stty_state |= STTY_require_set_attr;
1483 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
1484 set_speed_or_die(both_speeds, arg, &mode);
1485 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1486 } /* else - impossible (caught in the first pass):
1487 bb_error_msg_and_die("invalid argument '%s'", arg); */
1488 }
1489 }
1490
1491 if (stty_state & STTY_require_set_attr) {
1492 struct termios new_mode;
1493
1494 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1495 perror_on_device_and_die("%s");
1496
1497 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1498 it performs *any* of the requested operations. This means it
1499 can report 'success' when it has actually failed to perform
1500 some proper subset of the requested operations. To detect
1501 this partial failure, get the current terminal attributes and
1502 compare them to the requested ones */
1503
1504 /* Initialize to all zeroes so there is no risk memcmp will report a
1505 spurious difference in an uninitialized portion of the structure */
1506 memset(&new_mode, 0, sizeof(new_mode));
1507 if (tcgetattr(STDIN_FILENO, &new_mode))
1508 perror_on_device_and_die("%s");
1509
1510 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1511#if CIBAUD
1512 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1513 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1514 sometimes (m1 != m2). The only difference is in the four bits
1515 of the c_cflag field corresponding to the baud rate. To save
1516 Sun users a little confusion, don't report an error if this
1517 happens. But suppress the error only if we haven't tried to
1518 set the baud rate explicitly -- otherwise we'd never give an
1519 error for a true failure to set the baud rate */
1520
1521 new_mode.c_cflag &= (~CIBAUD);
1522 if ((stty_state & STTY_speed_was_set)
1523 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
1524#endif
1525 perror_on_device_and_die("%s: cannot perform all requested operations");
1526 }
1527 }
1528
1529 return EXIT_SUCCESS;
1530}
Note: See TracBrowser for help on using the repository browser.