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