source: MondoRescue/branches/stable/mindi-busybox/coreutils/stty.c@ 1770

Last change on this file since 1770 was 1770, checked in by Bruno Cornec, 16 years ago
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File size: 33.8 KB
Line 
1/* vi: set sw=4 ts=4: */
2/* stty -- change and print terminal line settings
3 Copyright (C) 1990-1999 Free Software Foundation, Inc.
4
5 Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
6*/
7/* Usage: stty [-ag] [-F device] [setting...]
8
9 Options:
10 -a Write all current settings to stdout in human-readable form.
11 -g Write all current settings to stdout in stty-readable form.
12 -F Open and use the specified device instead of stdin
13
14 If no args are given, write to stdout the baud rate and settings that
15 have been changed from their defaults. Mode reading and changes
16 are done on the specified device, or stdin if none was specified.
17
18 David MacKenzie <djm@gnu.ai.mit.edu>
19
20 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001
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/* Canonical values for control characters */
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/* ISC renamed swtch to susp for termios, but we'll accept either name */
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/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
72 So the default is to disable 'swtch.' */
73#if defined(__sparc__) && defined(__svr4__)
74# undef CSWTCH
75# define CSWTCH _POSIX_VDISABLE
76#endif
77
78#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */
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) /* Irix 4.0.5 */
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) /* Ultrix 4.2 */
100# define VFLUSHO VFLUSH
101#endif
102#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
103# define ECHOCTL CTLECH
104#endif
105#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
106# define ECHOCTL TCTLECH
107#endif
108#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
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/* Which speeds to set */
119enum speed_setting {
120 input_speed, output_speed, both_speeds
121};
122
123/* Which member(s) of 'struct termios' a mode uses */
124enum {
125 /* Do NOT change the order or values, as mode_type_flag()
126 * depends on them */
127 control, input, output, local, combination
128};
129
130static const char evenp [] ALIGN1 = "evenp";
131static const char raw [] ALIGN1 = "raw";
132static const char stty_min [] ALIGN1 = "min";
133static const char stty_time [] ALIGN1 = "time";
134static const char stty_swtch[] ALIGN1 = "swtch";
135static const char stty_eol [] ALIGN1 = "eol";
136static const char stty_eof [] ALIGN1 = "eof";
137static const char parity [] ALIGN1 = "parity";
138static const char stty_oddp [] ALIGN1 = "oddp";
139static const char stty_nl [] ALIGN1 = "nl";
140static const char stty_ek [] ALIGN1 = "ek";
141static const char stty_sane [] ALIGN1 = "sane";
142static const char cbreak [] ALIGN1 = "cbreak";
143static const char stty_pass8[] ALIGN1 = "pass8";
144static const char litout [] ALIGN1 = "litout";
145static const char cooked [] ALIGN1 = "cooked";
146static const char decctlq [] ALIGN1 = "decctlq";
147static const char stty_tabs [] ALIGN1 = "tabs";
148static const char stty_lcase[] ALIGN1 = "lcase";
149static const char stty_LCASE[] ALIGN1 = "LCASE";
150static const char stty_crt [] ALIGN1 = "crt";
151static const char stty_dec [] ALIGN1 = "dec";
152
153/* Flags for 'struct mode_info' */
154#define SANE_SET 1 /* Set in 'sane' mode */
155#define SANE_UNSET 2 /* Unset in 'sane' mode */
156#define REV 4 /* Can be turned off by prepending '-' */
157#define OMIT 8 /* Don't display value */
158
159/* Each mode */
160struct mode_info {
161 const char *const name; /* Name given on command line */
162 const unsigned char type; /* Which structure element to change */
163 const unsigned char flags; /* Setting and display options */
164 /* were using short here, but ppc32 was unhappy: */
165 const tcflag_t mask; /* Other bits to turn off for this mode */
166 const tcflag_t bits; /* Bits to set for this mode */
167};
168
169/* We can optimize it further by using name[8] instead of char *name */
170/* but beware of "if (info->name == evenp)" checks! */
171/* Need to replace them with "if (info == &mode_info[EVENP_INDX])" */
172
173#define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
174
175static const struct mode_info mode_info[] = {
176 MI_ENTRY("parenb", control, REV, PARENB, 0 ),
177 MI_ENTRY("parodd", control, REV, PARODD, 0 ),
178 MI_ENTRY("cs5", control, 0, CS5, CSIZE),
179 MI_ENTRY("cs6", control, 0, CS6, CSIZE),
180 MI_ENTRY("cs7", control, 0, CS7, CSIZE),
181 MI_ENTRY("cs8", control, 0, CS8, CSIZE),
182 MI_ENTRY("hupcl", control, REV, HUPCL, 0 ),
183 MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ),
184 MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ),
185 MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ),
186 MI_ENTRY("clocal", control, REV, CLOCAL, 0 ),
187#ifdef CRTSCTS
188 MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ),
189#endif
190 MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ),
191 MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ),
192 MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ),
193 MI_ENTRY("parmrk", input, REV, PARMRK, 0 ),
194 MI_ENTRY("inpck", input, REV, INPCK, 0 ),
195 MI_ENTRY("istrip", input, REV, ISTRIP, 0 ),
196 MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ),
197 MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ),
198 MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ),
199 MI_ENTRY("ixon", input, REV, IXON, 0 ),
200 MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ),
201 MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ),
202#ifdef IUCLC
203 MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ),
204#endif
205#ifdef IXANY
206 MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ),
207#endif
208#ifdef IMAXBEL
209 MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ),
210#endif
211 MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ),
212#ifdef OLCUC
213 MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ),
214#endif
215#ifdef OCRNL
216 MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ),
217#endif
218#ifdef ONLCR
219 MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ),
220#endif
221#ifdef ONOCR
222 MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ),
223#endif
224#ifdef ONLRET
225 MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ),
226#endif
227#ifdef OFILL
228 MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ),
229#endif
230#ifdef OFDEL
231 MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ),
232#endif
233#ifdef NLDLY
234 MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY),
235 MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY),
236#endif
237#ifdef CRDLY
238 MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY),
239 MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY),
240 MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY),
241 MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY),
242#endif
243
244#ifdef TABDLY
245 MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY),
246 MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY),
247 MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY),
248 MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY),
249#else
250# ifdef OXTABS
251 MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ),
252# endif
253#endif
254
255#ifdef BSDLY
256 MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY),
257 MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY),
258#endif
259#ifdef VTDLY
260 MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY),
261 MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY),
262#endif
263#ifdef FFDLY
264 MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY),
265 MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY),
266#endif
267 MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ),
268 MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ),
269#ifdef IEXTEN
270 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ),
271#endif
272 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ),
273 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ),
274 MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ),
275 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ),
276 MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ),
277 MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ),
278#ifdef XCASE
279 MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ),
280#endif
281#ifdef TOSTOP
282 MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ),
283#endif
284#ifdef ECHOPRT
285 MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ),
286 MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ),
287#endif
288#ifdef ECHOCTL
289 MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ),
290 MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ),
291#endif
292#ifdef ECHOKE
293 MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ),
294 MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ),
295#endif
296 MI_ENTRY(evenp, combination, REV | OMIT, 0, 0 ),
297 MI_ENTRY(parity, combination, REV | OMIT, 0, 0 ),
298 MI_ENTRY(stty_oddp, combination, REV | OMIT, 0, 0 ),
299 MI_ENTRY(stty_nl, combination, REV | OMIT, 0, 0 ),
300 MI_ENTRY(stty_ek, combination, OMIT, 0, 0 ),
301 MI_ENTRY(stty_sane, combination, OMIT, 0, 0 ),
302 MI_ENTRY(cooked, combination, REV | OMIT, 0, 0 ),
303 MI_ENTRY(raw, combination, REV | OMIT, 0, 0 ),
304 MI_ENTRY(stty_pass8, combination, REV | OMIT, 0, 0 ),
305 MI_ENTRY(litout, combination, REV | OMIT, 0, 0 ),
306 MI_ENTRY(cbreak, combination, REV | OMIT, 0, 0 ),
307#ifdef IXANY
308 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ),
309#endif
310#if defined(TABDLY) || defined(OXTABS)
311 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ),
312#endif
313#if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
314 MI_ENTRY(stty_lcase, combination, REV | OMIT, 0, 0 ),
315 MI_ENTRY(stty_LCASE, combination, REV | OMIT, 0, 0 ),
316#endif
317 MI_ENTRY(stty_crt, combination, OMIT, 0, 0 ),
318 MI_ENTRY(stty_dec, combination, OMIT, 0, 0 ),
319};
320
321enum {
322 NUM_mode_info = ARRAY_SIZE(mode_info)
323};
324
325/* Control character settings */
326struct control_info {
327 const char *const name; /* Name given on command line */
328 const unsigned char saneval; /* Value to set for 'stty sane' */
329 const unsigned char offset; /* Offset in c_cc */
330};
331
332/* Control characters */
333
334static const struct control_info control_info[] = {
335 {"intr", CINTR, VINTR},
336 {"quit", CQUIT, VQUIT},
337 {"erase", CERASE, VERASE},
338 {"kill", CKILL, VKILL},
339 {stty_eof, CEOF, VEOF},
340 {stty_eol, CEOL, VEOL},
341#ifdef VEOL2
342 {"eol2", CEOL2, VEOL2},
343#endif
344#ifdef VSWTCH
345 {stty_swtch, CSWTCH, VSWTCH},
346#endif
347 {"start", CSTART, VSTART},
348 {"stop", CSTOP, VSTOP},
349 {"susp", CSUSP, VSUSP},
350#ifdef VDSUSP
351 {"dsusp", CDSUSP, VDSUSP},
352#endif
353#ifdef VREPRINT
354 {"rprnt", CRPRNT, VREPRINT},
355#endif
356#ifdef VWERASE
357 {"werase", CWERASE, VWERASE},
358#endif
359#ifdef VLNEXT
360 {"lnext", CLNEXT, VLNEXT},
361#endif
362#ifdef VFLUSHO
363 {"flush", CFLUSHO, VFLUSHO},
364#endif
365#ifdef VSTATUS
366 {"status", CSTATUS, VSTATUS},
367#endif
368 /* These must be last because of the display routines */
369 {stty_min, 1, VMIN},
370 {stty_time, 0, VTIME},
371};
372
373enum {
374 NUM_control_info = ARRAY_SIZE(control_info)
375};
376
377/* The width of the screen, for output wrapping */
378unsigned max_col = 80; /* default */
379
380struct globals {
381 /* Current position, to know when to wrap */
382 unsigned current_col;
383 char buf[10];
384};
385#define G (*(struct globals*)&bb_common_bufsiz1)
386
387static const char *device_name = bb_msg_standard_input;
388
389/* Return a string that is the printable representation of character CH */
390/* Adapted from 'cat' by Torbjorn Granlund */
391static const char *visible(unsigned ch)
392{
393 char *bpout = G.buf;
394
395 if (ch == _POSIX_VDISABLE)
396 return "<undef>";
397
398 if (ch >= 128) {
399 ch -= 128;
400 *bpout++ = 'M';
401 *bpout++ = '-';
402 }
403
404 if (ch < 32) {
405 *bpout++ = '^';
406 *bpout++ = ch + 64;
407 } else if (ch < 127) {
408 *bpout++ = ch;
409 } else {
410 *bpout++ = '^';
411 *bpout++ = '?';
412 }
413
414 *bpout = '\0';
415 return G.buf;
416}
417
418static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode)
419{
420 static const unsigned char tcflag_offsets[] ALIGN1 = {
421 offsetof(struct termios, c_cflag), /* control */
422 offsetof(struct termios, c_iflag), /* input */
423 offsetof(struct termios, c_oflag), /* output */
424 offsetof(struct termios, c_lflag) /* local */
425 };
426
427 if (type <= local) {
428 return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]);
429 }
430 return NULL;
431}
432
433static void set_speed_or_die(enum speed_setting type, const char *const arg,
434 struct termios * const mode)
435{
436 speed_t baud;
437
438 baud = tty_value_to_baud(xatou(arg));
439
440 if (type != output_speed) { /* either input or both */
441 cfsetispeed(mode, baud);
442 }
443 if (type != input_speed) { /* either output or both */
444 cfsetospeed(mode, baud);
445 }
446}
447
448static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt)
449{
450 bb_perror_msg_and_die(fmt, device_name);
451}
452
453static void perror_on_device(const char *fmt)
454{
455 bb_perror_msg(fmt, device_name);
456}
457
458/* Print format string MESSAGE and optional args.
459 Wrap to next line first if it won't fit.
460 Print a space first unless MESSAGE will start a new line */
461static void wrapf(const char *message, ...)
462{
463 char buf[128];
464 va_list args;
465 int buflen;
466
467 va_start(args, message);
468 buflen = vsnprintf(buf, sizeof(buf), message, args);
469 va_end(args);
470 /* We seem to be called only with suitable lengths, but check if
471 somebody failed to adhere to this assumption just to be sure. */
472 if (!buflen || buflen >= sizeof(buf)) return;
473
474 if (G.current_col > 0) {
475 G.current_col++;
476 if (buf[0] != '\n') {
477 if (G.current_col + buflen >= max_col) {
478 putchar('\n');
479 G.current_col = 0;
480 } else
481 putchar(' ');
482 }
483 }
484 fputs(buf, stdout);
485 G.current_col += buflen;
486 if (buf[buflen-1] == '\n')
487 G.current_col = 0;
488}
489
490static void set_window_size(const int rows, const int cols)
491{
492 struct winsize win = { 0, 0, 0, 0};
493
494 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) {
495 if (errno != EINVAL) {
496 goto bail;
497 }
498 memset(&win, 0, sizeof(win));
499 }
500
501 if (rows >= 0)
502 win.ws_row = rows;
503 if (cols >= 0)
504 win.ws_col = cols;
505
506 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
507bail:
508 perror_on_device("%s");
509}
510
511static void display_window_size(const int fancy)
512{
513 const char *fmt_str = "%s\0%s: no size information for this device";
514 unsigned width, height;
515
516 if (get_terminal_width_height(STDIN_FILENO, &width, &height)) {
517 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
518 perror_on_device(fmt_str);
519 }
520 } else {
521 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
522 height, width);
523 }
524}
525
526static const struct suffix_mult stty_suffixes[] = {
527 { "b", 512 },
528 { "k", 1024 },
529 { "B", 1024 },
530 { }
531};
532
533static const struct mode_info *find_mode(const char *name)
534{
535 int i;
536 for (i = 0; i < NUM_mode_info; ++i)
537 if (!strcmp(name, mode_info[i].name))
538 return &mode_info[i];
539 return 0;
540}
541
542static const struct control_info *find_control(const char *name)
543{
544 int i;
545 for (i = 0; i < NUM_control_info; ++i)
546 if (!strcmp(name, control_info[i].name))
547 return &control_info[i];
548 return 0;
549}
550
551enum {
552 param_need_arg = 0x80,
553 param_line = 1 | 0x80,
554 param_rows = 2 | 0x80,
555 param_cols = 3 | 0x80,
556 param_columns = 4 | 0x80,
557 param_size = 5,
558 param_speed = 6,
559 param_ispeed = 7 | 0x80,
560 param_ospeed = 8 | 0x80,
561};
562
563static int find_param(const char *const name)
564{
565 static const char params[] ALIGN1 =
566 "line\0" /* 1 */
567 "rows\0" /* 2 */
568 "cols\0" /* 3 */
569 "columns\0" /* 4 */
570 "size\0" /* 5 */
571 "speed\0" /* 6 */
572 "ispeed\0"
573 "ospeed\0";
574 int i = index_in_strings(params, name) + 1;
575 if (i == 0)
576 return 0;
577 if (i != 5 && i != 6)
578 i |= 0x80;
579 return i;
580}
581
582static int recover_mode(const char *arg, struct termios *mode)
583{
584 int i, n;
585 unsigned chr;
586 unsigned long iflag, oflag, cflag, lflag;
587
588 /* Scan into temporaries since it is too much trouble to figure out
589 the right format for 'tcflag_t' */
590 if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
591 &iflag, &oflag, &cflag, &lflag, &n) != 4)
592 return 0;
593 mode->c_iflag = iflag;
594 mode->c_oflag = oflag;
595 mode->c_cflag = cflag;
596 mode->c_lflag = lflag;
597 arg += n;
598 for (i = 0; i < NCCS; ++i) {
599 if (sscanf(arg, ":%x%n", &chr, &n) != 1)
600 return 0;
601 mode->c_cc[i] = chr;
602 arg += n;
603 }
604
605 /* Fail if there are too many fields */
606 if (*arg != '\0')
607 return 0;
608
609 return 1;
610}
611
612static void display_recoverable(const struct termios *mode,
613 int ATTRIBUTE_UNUSED dummy)
614{
615 int i;
616 printf("%lx:%lx:%lx:%lx",
617 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
618 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
619 for (i = 0; i < NCCS; ++i)
620 printf(":%x", (unsigned int) mode->c_cc[i]);
621 putchar('\n');
622}
623
624static void display_speed(const struct termios *mode, int fancy)
625{
626 //01234567 8 9
627 const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;";
628 unsigned long ispeed, ospeed;
629
630 ospeed = ispeed = cfgetispeed(mode);
631 if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
632 ispeed = ospeed; /* in case ispeed was 0 */
633 //0123 4 5 6 7 8 9
634 fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;";
635 }
636 if (fancy) fmt_str += 9;
637 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
638}
639
640static void do_display(const struct termios *mode, const int all)
641{
642 int i;
643 tcflag_t *bitsp;
644 unsigned long mask;
645 int prev_type = control;
646
647 display_speed(mode, 1);
648 if (all)
649 display_window_size(1);
650#ifdef HAVE_C_LINE
651 wrapf("line = %d;\n", mode->c_line);
652#else
653 wrapf("\n");
654#endif
655
656 for (i = 0; control_info[i].name != stty_min; ++i) {
657 /* If swtch is the same as susp, don't print both */
658#if VSWTCH == VSUSP
659 if (control_info[i].name == stty_swtch)
660 continue;
661#endif
662 /* If eof uses the same slot as min, only print whichever applies */
663#if VEOF == VMIN
664 if ((mode->c_lflag & ICANON) == 0
665 && (control_info[i].name == stty_eof
666 || control_info[i].name == stty_eol)) continue;
667#endif
668 wrapf("%s = %s;", control_info[i].name,
669 visible(mode->c_cc[control_info[i].offset]));
670 }
671#if VEOF == VMIN
672 if ((mode->c_lflag & ICANON) == 0)
673#endif
674 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
675 if (G.current_col) wrapf("\n");
676
677 for (i = 0; i < NUM_mode_info; ++i) {
678 if (mode_info[i].flags & OMIT)
679 continue;
680 if (mode_info[i].type != prev_type) {
681 /* wrapf("\n"); */
682 if (G.current_col) wrapf("\n");
683 prev_type = mode_info[i].type;
684 }
685
686 bitsp = mode_type_flag(mode_info[i].type, mode);
687 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
688 if ((*bitsp & mask) == mode_info[i].bits) {
689 if (all || (mode_info[i].flags & SANE_UNSET))
690 wrapf("%s", mode_info[i].name);
691 } else {
692 if ((all && mode_info[i].flags & REV) ||
693 (!all &&
694 (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)))
695 wrapf("-%s", mode_info[i].name);
696 }
697 }
698 if (G.current_col) wrapf("\n");
699}
700
701static void sane_mode(struct termios *mode)
702{
703 int i;
704 tcflag_t *bitsp;
705
706 for (i = 0; i < NUM_control_info; ++i) {
707#if VMIN == VEOF
708 if (control_info[i].name == stty_min)
709 break;
710#endif
711 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
712 }
713
714 for (i = 0; i < NUM_mode_info; ++i) {
715 if (mode_info[i].flags & SANE_SET) {
716 bitsp = mode_type_flag(mode_info[i].type, mode);
717 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
718 | mode_info[i].bits;
719 } else if (mode_info[i].flags & SANE_UNSET) {
720 bitsp = mode_type_flag(mode_info[i].type, mode);
721 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
722 & ~mode_info[i].bits;
723 }
724 }
725}
726
727/* Save set_mode from #ifdef forest plague */
728#ifndef ONLCR
729#define ONLCR 0
730#endif
731#ifndef OCRNL
732#define OCRNL 0
733#endif
734#ifndef ONLRET
735#define ONLRET 0
736#endif
737#ifndef XCASE
738#define XCASE 0
739#endif
740#ifndef IXANY
741#define IXANY 0
742#endif
743#ifndef TABDLY
744#define TABDLY 0
745#endif
746#ifndef OXTABS
747#define OXTABS 0
748#endif
749#ifndef IUCLC
750#define IUCLC 0
751#endif
752#ifndef OLCUC
753#define OLCUC 0
754#endif
755#ifndef ECHOCTL
756#define ECHOCTL 0
757#endif
758#ifndef ECHOKE
759#define ECHOKE 0
760#endif
761
762static void set_mode(const struct mode_info *info, int reversed,
763 struct termios *mode)
764{
765 tcflag_t *bitsp;
766
767 bitsp = mode_type_flag(info->type, mode);
768
769 if (bitsp) {
770 if (reversed)
771 *bitsp = *bitsp & ~info->mask & ~info->bits;
772 else
773 *bitsp = (*bitsp & ~info->mask) | info->bits;
774 return;
775 }
776
777 /* Combination mode */
778 if (info->name == evenp || info->name == parity) {
779 if (reversed)
780 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
781 else
782 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
783 } else if (info->name == stty_oddp) {
784 if (reversed)
785 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
786 else
787 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
788 } else if (info->name == stty_nl) {
789 if (reversed) {
790 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
791 mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET;
792 } else {
793 mode->c_iflag = mode->c_iflag & ~ICRNL;
794 if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR;
795 }
796 } else if (info->name == stty_ek) {
797 mode->c_cc[VERASE] = CERASE;
798 mode->c_cc[VKILL] = CKILL;
799 } else if (info->name == stty_sane) {
800 sane_mode(mode);
801 }
802 else if (info->name == cbreak) {
803 if (reversed)
804 mode->c_lflag |= ICANON;
805 else
806 mode->c_lflag &= ~ICANON;
807 } else if (info->name == stty_pass8) {
808 if (reversed) {
809 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
810 mode->c_iflag |= ISTRIP;
811 } else {
812 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
813 mode->c_iflag &= ~ISTRIP;
814 }
815 } else if (info->name == litout) {
816 if (reversed) {
817 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
818 mode->c_iflag |= ISTRIP;
819 mode->c_oflag |= OPOST;
820 } else {
821 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
822 mode->c_iflag &= ~ISTRIP;
823 mode->c_oflag &= ~OPOST;
824 }
825 } else if (info->name == raw || info->name == cooked) {
826 if ((info->name[0] == 'r' && reversed)
827 || (info->name[0] == 'c' && !reversed)) {
828 /* Cooked mode */
829 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
830 mode->c_oflag |= OPOST;
831 mode->c_lflag |= ISIG | ICANON;
832#if VMIN == VEOF
833 mode->c_cc[VEOF] = CEOF;
834#endif
835#if VTIME == VEOL
836 mode->c_cc[VEOL] = CEOL;
837#endif
838 } else {
839 /* Raw mode */
840 mode->c_iflag = 0;
841 mode->c_oflag &= ~OPOST;
842 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
843 mode->c_cc[VMIN] = 1;
844 mode->c_cc[VTIME] = 0;
845 }
846 }
847 else if (IXANY && info->name == decctlq) {
848 if (reversed)
849 mode->c_iflag |= IXANY;
850 else
851 mode->c_iflag &= ~IXANY;
852 }
853 else if (TABDLY && info->name == stty_tabs) {
854 if (reversed)
855 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
856 else
857 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
858 }
859 else if (OXTABS && info->name == stty_tabs) {
860 if (reversed)
861 mode->c_oflag |= OXTABS;
862 else
863 mode->c_oflag &= ~OXTABS;
864 }
865 else if (XCASE && IUCLC && OLCUC
866 && (info->name == stty_lcase || info->name == stty_LCASE)) {
867 if (reversed) {
868 mode->c_lflag &= ~XCASE;
869 mode->c_iflag &= ~IUCLC;
870 mode->c_oflag &= ~OLCUC;
871 } else {
872 mode->c_lflag |= XCASE;
873 mode->c_iflag |= IUCLC;
874 mode->c_oflag |= OLCUC;
875 }
876 }
877 else if (info->name == stty_crt) {
878 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
879 }
880 else if (info->name == stty_dec) {
881 mode->c_cc[VINTR] = 3; /* ^C */
882 mode->c_cc[VERASE] = 127; /* DEL */
883 mode->c_cc[VKILL] = 21; /* ^U */
884 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
885 if (IXANY) mode->c_iflag &= ~IXANY;
886 }
887}
888
889static void set_control_char_or_die(const struct control_info *info,
890 const char *arg, struct termios *mode)
891{
892 unsigned char value;
893
894 if (info->name == stty_min || info->name == stty_time)
895 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
896 else if (arg[0] == '\0' || arg[1] == '\0')
897 value = arg[0];
898 else if (!strcmp(arg, "^-") || !strcmp(arg, "undef"))
899 value = _POSIX_VDISABLE;
900 else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */
901 value = arg[1] & 0x1f; /* Non-letters get weird results */
902 if (arg[1] == '?')
903 value = 127;
904 } else
905 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
906 mode->c_cc[info->offset] = value;
907}
908
909#define STTY_require_set_attr (1<<0)
910#define STTY_speed_was_set (1<<1)
911#define STTY_verbose_output (1<<2)
912#define STTY_recoverable_output (1<<3)
913#define STTY_noargs (1<<4)
914int stty_main(int argc, char **argv);
915int stty_main(int argc, char **argv)
916{
917 struct termios mode;
918 void (*output_func)(const struct termios *, const int);
919 const char *file_name = NULL;
920 int display_all = 0;
921 int stty_state;
922 int k;
923
924 stty_state = STTY_noargs;
925 output_func = do_display;
926
927 /* First pass: only parse/verify command line params */
928 k = 0;
929 while (argv[++k]) {
930 const struct mode_info *mp;
931 const struct control_info *cp;
932 const char *arg = argv[k];
933 const char *argnext = argv[k+1];
934 int param;
935
936 if (arg[0] == '-') {
937 int i;
938 mp = find_mode(arg+1);
939 if (mp) {
940 if (!(mp->flags & REV))
941 goto invalid_argument;
942 stty_state &= ~STTY_noargs;
943 continue;
944 }
945 /* It is an option - parse it */
946 i = 0;
947 while (arg[++i]) {
948 switch (arg[i]) {
949 case 'a':
950 stty_state |= STTY_verbose_output;
951 output_func = do_display;
952 display_all = 1;
953 break;
954 case 'g':
955 stty_state |= STTY_recoverable_output;
956 output_func = display_recoverable;
957 break;
958 case 'F':
959 if (file_name)
960 bb_error_msg_and_die("only one device may be specified");
961 file_name = &arg[i+1]; /* "-Fdevice" ? */
962 if (!file_name[0]) { /* nope, "-F device" */
963 int p = k+1; /* argv[p] is argnext */
964 file_name = argnext;
965 if (!file_name)
966 bb_error_msg_and_die(bb_msg_requires_arg, "-F");
967 /* remove -F param from arg[vc] */
968 --argc;
969 while (argv[p]) { argv[p] = argv[p+1]; ++p; }
970 }
971 goto end_option;
972 default:
973 goto invalid_argument;
974 }
975 }
976 end_option:
977 continue;
978 }
979
980 mp = find_mode(arg);
981 if (mp) {
982 stty_state &= ~STTY_noargs;
983 continue;
984 }
985
986 cp = find_control(arg);
987 if (cp) {
988 if (!argnext)
989 bb_error_msg_and_die(bb_msg_requires_arg, arg);
990 /* called for the side effect of xfunc death only */
991 set_control_char_or_die(cp, argnext, &mode);
992 stty_state &= ~STTY_noargs;
993 ++k;
994 continue;
995 }
996
997 param = find_param(arg);
998 if (param & param_need_arg) {
999 if (!argnext)
1000 bb_error_msg_and_die(bb_msg_requires_arg, arg);
1001 ++k;
1002 }
1003
1004 switch (param) {
1005#ifdef HAVE_C_LINE
1006 case param_line:
1007# ifndef TIOCGWINSZ
1008 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1009 break;
1010# endif /* else fall-through */
1011#endif
1012#ifdef TIOCGWINSZ
1013 case param_rows:
1014 case param_cols:
1015 case param_columns:
1016 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1017 break;
1018 case param_size:
1019#endif
1020 case param_speed:
1021 break;
1022 case param_ispeed:
1023 /* called for the side effect of xfunc death only */
1024 set_speed_or_die(input_speed, argnext, &mode);
1025 break;
1026 case param_ospeed:
1027 /* called for the side effect of xfunc death only */
1028 set_speed_or_die(output_speed, argnext, &mode);
1029 break;
1030 default:
1031 if (recover_mode(arg, &mode) == 1) break;
1032 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1033 invalid_argument:
1034 bb_error_msg_and_die("invalid argument '%s'", arg);
1035 }
1036 stty_state &= ~STTY_noargs;
1037 }
1038
1039 /* Specifying both -a and -g is an error */
1040 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1041 (STTY_verbose_output | STTY_recoverable_output))
1042 bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive");
1043 /* Specifying -a or -g with non-options is an error */
1044 if (!(stty_state & STTY_noargs) &&
1045 (stty_state & (STTY_verbose_output | STTY_recoverable_output)))
1046 bb_error_msg_and_die("modes may not be set when specifying an output style");
1047
1048 /* Now it is safe to start doing things */
1049 if (file_name) {
1050 int fd, fdflags;
1051 device_name = file_name;
1052 fd = xopen(device_name, O_RDONLY | O_NONBLOCK);
1053 if (fd != STDIN_FILENO) {
1054 dup2(fd, STDIN_FILENO);
1055 close(fd);
1056 }
1057 fdflags = fcntl(STDIN_FILENO, F_GETFL);
1058 if (fdflags < 0 ||
1059 fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
1060 perror_on_device_and_die("%s: cannot reset non-blocking mode");
1061 }
1062
1063 /* Initialize to all zeroes so there is no risk memcmp will report a
1064 spurious difference in an uninitialized portion of the structure */
1065 memset(&mode, 0, sizeof(mode));
1066 if (tcgetattr(STDIN_FILENO, &mode))
1067 perror_on_device_and_die("%s");
1068
1069 if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) {
1070 get_terminal_width_height(STDOUT_FILENO, &max_col, NULL);
1071 output_func(&mode, display_all);
1072 return EXIT_SUCCESS;
1073 }
1074
1075 /* Second pass: perform actions */
1076 k = 0;
1077 while (argv[++k]) {
1078 const struct mode_info *mp;
1079 const struct control_info *cp;
1080 const char *arg = argv[k];
1081 const char *argnext = argv[k+1];
1082 int param;
1083
1084 if (arg[0] == '-') {
1085 mp = find_mode(arg+1);
1086 if (mp) {
1087 set_mode(mp, 1 /* reversed */, &mode);
1088 stty_state |= STTY_require_set_attr;
1089 }
1090 /* It is an option - already parsed. Skip it */
1091 continue;
1092 }
1093
1094 mp = find_mode(arg);
1095 if (mp) {
1096 set_mode(mp, 0 /* non-reversed */, &mode);
1097 stty_state |= STTY_require_set_attr;
1098 continue;
1099 }
1100
1101 cp = find_control(arg);
1102 if (cp) {
1103 ++k;
1104 set_control_char_or_die(cp, argnext, &mode);
1105 stty_state |= STTY_require_set_attr;
1106 continue;
1107 }
1108
1109 param = find_param(arg);
1110 if (param & param_need_arg) {
1111 ++k;
1112 }
1113
1114 switch (param) {
1115#ifdef HAVE_C_LINE
1116 case param_line:
1117 mode.c_line = xatoul_sfx(argnext, stty_suffixes);
1118 stty_state |= STTY_require_set_attr;
1119 break;
1120#endif
1121#ifdef TIOCGWINSZ
1122 case param_cols:
1123 set_window_size(-1, xatoul_sfx(argnext, stty_suffixes));
1124 break;
1125 case param_size:
1126 display_window_size(0);
1127 break;
1128 case param_rows:
1129 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1130 break;
1131#endif
1132 case param_speed:
1133 display_speed(&mode, 0);
1134 break;
1135 case param_ispeed:
1136 set_speed_or_die(input_speed, argnext, &mode);
1137 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1138 break;
1139 case param_ospeed:
1140 set_speed_or_die(output_speed, argnext, &mode);
1141 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1142 break;
1143 default:
1144 if (recover_mode(arg, &mode) == 1)
1145 stty_state |= STTY_require_set_attr;
1146 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
1147 set_speed_or_die(both_speeds, arg, &mode);
1148 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1149 } /* else - impossible (caught in the first pass):
1150 bb_error_msg_and_die("invalid argument '%s'", arg); */
1151 }
1152 }
1153
1154 if (stty_state & STTY_require_set_attr) {
1155 struct termios new_mode;
1156
1157 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1158 perror_on_device_and_die("%s");
1159
1160 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1161 it performs *any* of the requested operations. This means it
1162 can report 'success' when it has actually failed to perform
1163 some proper subset of the requested operations. To detect
1164 this partial failure, get the current terminal attributes and
1165 compare them to the requested ones */
1166
1167 /* Initialize to all zeroes so there is no risk memcmp will report a
1168 spurious difference in an uninitialized portion of the structure */
1169 memset(&new_mode, 0, sizeof(new_mode));
1170 if (tcgetattr(STDIN_FILENO, &new_mode))
1171 perror_on_device_and_die("%s");
1172
1173 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
1174#ifdef CIBAUD
1175 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1176 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1177 sometimes (m1 != m2). The only difference is in the four bits
1178 of the c_cflag field corresponding to the baud rate. To save
1179 Sun users a little confusion, don't report an error if this
1180 happens. But suppress the error only if we haven't tried to
1181 set the baud rate explicitly -- otherwise we'd never give an
1182 error for a true failure to set the baud rate */
1183
1184 new_mode.c_cflag &= (~CIBAUD);
1185 if ((stty_state & STTY_speed_was_set)
1186 || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
1187#endif
1188 perror_on_device_and_die("%s: cannot perform all requested operations");
1189 }
1190 }
1191
1192 return EXIT_SUCCESS;
1193}
Note: See TracBrowser for help on using the repository browser.