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 newline(void)
738{
739 if (G.current_col != 0)
740 wrapf("\n");
741}
742
743static void set_window_size(int rows, int cols)
744{
745 struct winsize win = { 0, 0, 0, 0 };
746
747 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
748 if (errno != EINVAL) {
749 goto bail;
750 }
751 memset(&win, 0, sizeof(win));
752 }
753
754 if (rows >= 0)
755 win.ws_row = rows;
756 if (cols >= 0)
757 win.ws_col = cols;
758
759 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
760bail:
761 perror_on_device("%s");
762}
763
764static void display_window_size(int fancy)
765{
766 const char *fmt_str = "%s\0%s: no size information for this device";
767 unsigned width, height;
768
769 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
770 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
771 perror_on_device(fmt_str);
772 }
773 } else {
774 wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n",
775 height, width);
776 }
777}
778
779static const struct suffix_mult stty_suffixes[] = {
780 { "b", 512 },
781 { "k", 1024 },
782 { "B", 1024 },
783 { "", 0 }
784};
785
786static const struct mode_info *find_mode(const char *name)
787{
788 int i = index_in_strings(mode_name, name);
789 return i >= 0 ? &mode_info[i] : NULL;
790}
791
792static const struct control_info *find_control(const char *name)
793{
794 int i = index_in_strings(control_name, name);
795 return i >= 0 ? &control_info[i] : NULL;
796}
797
798enum {
799 param_need_arg = 0x80,
800 param_line = 1 | 0x80,
801 param_rows = 2 | 0x80,
802 param_cols = 3 | 0x80,
803 param_columns = 4 | 0x80,
804 param_size = 5,
805 param_speed = 6,
806 param_ispeed = 7 | 0x80,
807 param_ospeed = 8 | 0x80,
808};
809
810static int find_param(const char *name)
811{
812 static const char params[] ALIGN1 =
813 "line\0"
814 "rows\0"
815 "cols\0"
816 "columns\0"
817 "size\0"
818 "speed\0"
819 "ispeed\0"
820 "ospeed\0";
821 int i = index_in_strings(params, name) + 1;
822 if (i == 0)
823 return 0;
824 if (i != 5 && i != 6)
825 i |= 0x80;
826 return i;
827}
828
829static int recover_mode(const char *arg, struct termios *mode)
830{
831 int i, n;
832 unsigned chr;
833 unsigned long iflag, oflag, cflag, lflag;
834
835
836
837 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
838 &iflag, &oflag, &cflag, &lflag, &n) != 4)
839 return 0;
840 mode->c_iflag = iflag;
841 mode->c_oflag = oflag;
842 mode->c_cflag = cflag;
843 mode->c_lflag = lflag;
844 arg += n;
845 for (i = 0; i < NCCS; ++i) {
846 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
847 return 0;
848 mode->c_cc[i] = chr;
849 arg += n;
850 }
851
852
853 if (*arg != '\0')
854 return 0;
855
856 return 1;
857}
858
859static void display_recoverable(const struct termios *mode,
860 int UNUSED_PARAM dummy)
861{
862 int i;
863 printf("%lx:%lx:%lx:%lx",
864 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
865 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
866 for (i = 0; i < NCCS; ++i)
867 printf(":%x", (unsigned int) mode->c_cc[i]);
868 bb_putchar('\n');
869}
870
871static void display_speed(const struct termios *mode, int fancy)
872{
873
874 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
875 unsigned long ispeed, ospeed;
876
877 ospeed = ispeed = cfgetispeed(mode);
878 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
879 ispeed = ospeed;
880
881 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
882 }
883 if (fancy) fmt_str += 9;
884 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
885}
886
887static void do_display(const struct termios *mode, int all)
888{
889 int i;
890 tcflag_t *bitsp;
891 unsigned long mask;
892 int prev_type = control;
893
894 display_speed(mode, 1);
895 if (all)
896 display_window_size(1);
897#ifdef HAVE_C_LINE
898 wrapf("line = %u;\n", mode->c_line);
899#else
900 newline();
901#endif
902
903 for (i = 0; i != CIDX_min; ++i) {
904
905#if VSWTCH == VSUSP
906 if (i == CIDX_swtch)
907 continue;
908#endif
909
910#if VEOF == VMIN
911 if (!(mode->c_lflag & ICANON)
912 && (i == CIDX_eof || i == CIDX_eol)
913 ) {
914 continue;
915 }
916#endif
917 wrapf("%s = %s;", nth_string(control_name, i),
918 visible(mode->c_cc[control_info[i].offset]));
919 }
920#if VEOF == VMIN
921 if ((mode->c_lflag & ICANON) == 0)
922#endif
923 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
924 newline();
925
926 for (i = 0; i < NUM_mode_info; ++i) {
927 if (mode_info[i].flags & OMIT)
928 continue;
929 if (mode_info[i].type != prev_type) {
930 newline();
931 prev_type = mode_info[i].type;
932 }
933
934 bitsp = mode_type_flag(mode_info[i].type, mode);
935 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
936 if ((*bitsp & mask) == mode_info[i].bits) {
937 if (all || (mode_info[i].flags & SANE_UNSET))
938 wrapf("-%s"+1, nth_string(mode_name, i));
939 } else {
940 if ((all && mode_info[i].flags & REV)
941 || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
942 ) {
943 wrapf("-%s", nth_string(mode_name, i));
944 }
945 }
946 }
947 newline();
948}
949
950static void sane_mode(struct termios *mode)
951{
952 int i;
953 tcflag_t *bitsp;
954
955 for (i = 0; i < NUM_control_info; ++i) {
956#if VMIN == VEOF
957 if (i == CIDX_min)
958 break;
959#endif
960 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
961 }
962
963 for (i = 0; i < NUM_mode_info; ++i) {
964 if (mode_info[i].flags & SANE_SET) {
965 bitsp = mode_type_flag(mode_info[i].type, mode);
966 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
967 | mode_info[i].bits;
968 } else if (mode_info[i].flags & SANE_UNSET) {
969 bitsp = mode_type_flag(mode_info[i].type, mode);
970 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
971 & ~mode_info[i].bits;
972 }
973 }
974}
975
976
977#ifndef ONLCR
978#define ONLCR 0
979#endif
980#ifndef OCRNL
981#define OCRNL 0
982#endif
983#ifndef ONLRET
984#define ONLRET 0
985#endif
986#ifndef XCASE
987#define XCASE 0
988#endif
989#ifndef IXANY
990#define IXANY 0
991#endif
992#ifndef TABDLY
993#define TABDLY 0
994#endif
995#ifndef OXTABS
996#define OXTABS 0
997#endif
998#ifndef IUCLC
999#define IUCLC 0
1000#endif
1001#ifndef OLCUC
1002#define OLCUC 0
1003#endif
1004#ifndef ECHOCTL
1005#define ECHOCTL 0
1006#endif
1007#ifndef ECHOKE
1008#define ECHOKE 0
1009#endif
1010
1011static void set_mode(const struct mode_info *info, int reversed,
1012 struct termios *mode)
1013{
1014 tcflag_t *bitsp;
1015
1016 bitsp = mode_type_flag(info->type, mode);
1017
1018 if (bitsp) {
1019 if (reversed)
1020 *bitsp = *bitsp & ~info->mask & ~info->bits;
1021 else
1022 *bitsp = (*bitsp & ~info->mask) | info->bits;
1023 return;
1024 }
1025
1026
1027 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1028 if (reversed)
1029 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1030 else
1031 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1032 } else if (info == &mode_info[IDX_oddp]) {
1033 if (reversed)
1034 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1035 else
1036 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1037 } else if (info == &mode_info[IDX_nl]) {
1038 if (reversed) {
1039 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1040 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
1041 } else {
1042 mode->c_iflag = mode->c_iflag & ~ICRNL;
1043 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
1044 }
1045 } else if (info == &mode_info[IDX_ek]) {
1046 mode->c_cc[VERASE] = CERASE;
1047 mode->c_cc[VKILL] = CKILL;
1048 } else if (info == &mode_info[IDX_sane]) {
1049 sane_mode(mode);
1050 } else if (info == &mode_info[IDX_cbreak]) {
1051 if (reversed)
1052 mode->c_lflag |= ICANON;
1053 else
1054 mode->c_lflag &= ~ICANON;
1055 } else if (info == &mode_info[IDX_pass8]) {
1056 if (reversed) {
1057 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1058 mode->c_iflag |= ISTRIP;
1059 } else {
1060 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1061 mode->c_iflag &= ~ISTRIP;
1062 }
1063 } else if (info == &mode_info[IDX_litout]) {
1064 if (reversed) {
1065 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1066 mode->c_iflag |= ISTRIP;
1067 mode->c_oflag |= OPOST;
1068 } else {
1069 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1070 mode->c_iflag &= ~ISTRIP;
1071 mode->c_oflag &= ~OPOST;
1072 }
1073 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
1074 if ((info == &mode_info[IDX_raw] && reversed)
1075 || (info == &mode_info[IDX_cooked] && !reversed)
1076 ) {
1077
1078 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1079 mode->c_oflag |= OPOST;
1080 mode->c_lflag |= ISIG | ICANON;
1081#if VMIN == VEOF
1082 mode->c_cc[VEOF] = CEOF;
1083#endif
1084#if VTIME == VEOL
1085 mode->c_cc[VEOL] = CEOL;
1086#endif
1087 } else {
1088
1089 mode->c_iflag = 0;
1090 mode->c_oflag &= ~OPOST;
1091 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1092 mode->c_cc[VMIN] = 1;
1093 mode->c_cc[VTIME] = 0;
1094 }
1095 }
1096 else if (IXANY && info == &mode_info[IDX_decctlq]) {
1097 if (reversed)
1098 mode->c_iflag |= IXANY;
1099 else
1100 mode->c_iflag &= ~IXANY;
1101 }
1102 else if (TABDLY && info == &mode_info[IDX_tabs]) {
1103 if (reversed)
1104 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1105 else
1106 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1107 }
1108 else if (OXTABS && info == &mode_info[IDX_tabs]) {
1109 if (reversed)
1110 mode->c_oflag |= OXTABS;
1111 else
1112 mode->c_oflag &= ~OXTABS;
1113 } else
1114 if (XCASE && IUCLC && OLCUC
1115 && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE])
1116 ) {
1117 if (reversed) {
1118 mode->c_lflag &= ~XCASE;
1119 mode->c_iflag &= ~IUCLC;
1120 mode->c_oflag &= ~OLCUC;
1121 } else {
1122 mode->c_lflag |= XCASE;
1123 mode->c_iflag |= IUCLC;
1124 mode->c_oflag |= OLCUC;
1125 }
1126 } else if (info == &mode_info[IDX_crt]) {
1127 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1128 } else if (info == &mode_info[IDX_dec]) {
1129 mode->c_cc[VINTR] = 3;
1130 mode->c_cc[VERASE] = 127;
1131 mode->c_cc[VKILL] = 21;
1132 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1133 if (IXANY) mode->c_iflag &= ~IXANY;
1134 }
1135}
1136
1137static void set_control_char_or_die(const struct control_info *info,
1138 const char *arg, struct termios *mode)
1139{
1140 unsigned char value;
1141
1142 if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time])
1143 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1144 else if (arg[0] == '\0' || arg[1] == '\0')
1145 value = arg[0];
1146 else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0)
1147 value = _POSIX_VDISABLE;
1148 else if (arg[0] == '^') {
1149 value = arg[1] & 0x1f;
1150 if (arg[1] == '?')
1151 value = 127;
1152 } else
1153 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1154 mode->c_cc[info->offset] = value;
1155}
1156
1157#define STTY_require_set_attr (1 << 0)
1158#define STTY_speed_was_set (1 << 1)
1159#define STTY_verbose_output (1 << 2)
1160#define STTY_recoverable_output (1 << 3)
1161#define STTY_noargs (1 << 4)
1162
1163int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1164int stty_main(int argc UNUSED_PARAM, char **argv)
1165{
1166 struct termios mode;
1167 void (*output_func)(const struct termios *, int);
1168 const char *file_name = NULL;
1169 int display_all = 0;
1170 int stty_state;
1171 int k;
1172
1173 INIT_G();
1174
1175 stty_state = STTY_noargs;
1176 output_func = do_display;
1177
1178
1179 k = 0;
1180 while (argv[++k]) {
1181 const struct mode_info *mp;
1182 const struct control_info *cp;
1183 const char *arg = argv[k];
1184 const char *argnext = argv[k+1];
1185 int param;
1186
1187 if (arg[0] == '-') {
1188 int i;
1189 mp = find_mode(arg+1);
1190 if (mp) {
1191 if (!(mp->flags & REV))
1192 goto invalid_argument;
1193 stty_state &= ~STTY_noargs;
1194 continue;
1195 }
1196
1197 i = 0;
1198 while (arg[++i]) {
1199 switch (arg[i]) {
1200 case 'a':
1201 stty_state |= STTY_verbose_output;
1202 output_func = do_display;
1203 display_all = 1;
1204 break;
1205 case 'g':
1206 stty_state |= STTY_recoverable_output;
1207 output_func = display_recoverable;
1208 break;
1209 case 'F':
1210 if (file_name)
1211 bb_error_msg_and_die("only one device may be specified");
1212 file_name = &arg[i+1];
1213 if (!file_name[0]) {
1214 int p = k+1;
1215 file_name = argnext;
1216 if (!file_name)
1217 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
1218
1219 while (argv[p]) {
1220 argv[p] = argv[p+1];
1221 ++p;
1222 }
1223 }
1224 goto end_option;
1225 default:
1226 goto invalid_argument;
1227 }
1228 }
1229 end_option:
1230 continue;
1231 }
1232
1233 mp = find_mode(arg);
1234 if (mp) {
1235 stty_state &= ~STTY_noargs;
1236 continue;
1237 }
1238
1239 cp = find_control(arg);
1240 if (cp) {
1241 if (!argnext)
1242 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1243
1244 set_control_char_or_die(cp, argnext, &mode);
1245 stty_state &= ~STTY_noargs;
1246 ++k;
1247 continue;
1248 }
1249
1250 param = find_param(arg);
1251 if (param & param_need_arg) {
1252 if (!argnext)
1253 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1254 ++k;
1255 }
1256
1257 switch (param) {
1258#ifdef HAVE_C_LINE
1259 case param_line:
1260# ifndef TIOCGWINSZ
1261 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1262 break;
1263# endif
1264#endif
1265#ifdef TIOCGWINSZ
1266 case param_rows:
1267 case param_cols:
1268 case param_columns:
1269 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1270 break;
1271 case param_size:
1272#endif
1273 case param_speed:
1274 break;
1275 case param_ispeed:
1276
1277 set_speed_or_die(input_speed, argnext, &mode);
1278 break;
1279 case param_ospeed:
1280
1281 set_speed_or_die(output_speed, argnext, &mode);
1282 break;
1283 default:
1284 if (recover_mode(arg, &mode) == 1) break;
1285 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1286 invalid_argument:
1287 bb_error_msg_and_die("invalid argument '%s'", arg);
1288 }
1289 stty_state &= ~STTY_noargs;
1290 }
1291
1292
1293 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1294 (STTY_verbose_output | STTY_recoverable_output))
1295 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1296
1297 if (!(stty_state & STTY_noargs)
1298 && (stty_state & (STTY_verbose_output | STTY_recoverable_output))
1299 ) {
1300 bb_error_msg_and_die("modes may not be set when specifying an output style");
1301 }
1302
1303
1304 if (file_name) {
1305 G.device_name = file_name;
1306 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1307 ndelay_off(STDIN_FILENO);
1308 }
1309
1310
1311
1312 memset(&mode, 0, sizeof(mode));
1313 if (tcgetattr(STDIN_FILENO, &mode))
1314 perror_on_device_and_die("%s");
1315
1316 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
1317 get_terminal_width_height(STDOUT_FILENO, &G.max_col, NULL);
1318 output_func(&mode, display_all);
1319 return EXIT_SUCCESS;
1320 }
1321
1322
1323 k = 0;
1324 while (argv[++k]) {
1325 const struct mode_info *mp;
1326 const struct control_info *cp;
1327 const char *arg = argv[k];
1328 const char *argnext = argv[k+1];
1329 int param;
1330
1331 if (arg[0] == '-') {
1332 mp = find_mode(arg+1);
1333 if (mp) {
1334 set_mode(mp, 1 , &mode);
1335 stty_state |= STTY_require_set_attr;
1336 }
1337
1338 continue;
1339 }
1340
1341 mp = find_mode(arg);
1342 if (mp) {
1343 set_mode(mp, 0 , &mode);
1344 stty_state |= STTY_require_set_attr;
1345 continue;
1346 }
1347
1348 cp = find_control(arg);
1349 if (cp) {
1350 ++k;
1351 set_control_char_or_die(cp, argnext, &mode);
1352 stty_state |= STTY_require_set_attr;
1353 continue;
1354 }
1355
1356 param = find_param(arg);
1357 if (param & param_need_arg) {
1358 ++k;
1359 }
1360
1361 switch (param) {
1362#ifdef HAVE_C_LINE
1363 case param_line:
1364 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
1365 stty_state |= STTY_require_set_attr;
1366 break;
1367#endif
1368#ifdef TIOCGWINSZ
1369 case param_cols:
1370 case param_columns:
1371 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
1372 break;
1373 case param_size:
1374 display_window_size(0);
1375 break;
1376 case param_rows:
1377 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1378 break;
1379#endif
1380 case param_speed:
1381 display_speed(&mode, 0);
1382 break;
1383 case param_ispeed:
1384 set_speed_or_die(input_speed, argnext, &mode);
1385 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1386 break;
1387 case param_ospeed:
1388 set_speed_or_die(output_speed, argnext, &mode);
1389 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1390 break;
1391 default:
1392 if (recover_mode(arg, &mode) == 1)
1393 stty_state |= STTY_require_set_attr;
1394 else {
1395 set_speed_or_die(both_speeds, arg, &mode);
1396 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1397 }
1398
1399 }
1400 }
1401
1402 if (stty_state & STTY_require_set_attr) {
1403 struct termios new_mode;
1404
1405 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1406 perror_on_device_and_die("%s");
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417 memset(&new_mode, 0, sizeof(new_mode));
1418 if (tcgetattr(STDIN_FILENO, &new_mode))
1419 perror_on_device_and_die("%s");
1420
1421 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1422#ifdef CIBAUD
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432 new_mode.c_cflag &= (~CIBAUD);
1433 if ((stty_state & STTY_speed_was_set)
1434 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
1435#endif
1436 perror_on_device_and_die("%s: cannot perform all requested operations");
1437 }
1438 }
1439
1440 return EXIT_SUCCESS;
1441}
1442