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