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