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