Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (13 years ago)
Author:
Bruno Cornec
Message:
  • 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:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/coreutils/stty.c

    r821 r1770  
    2222   */
    2323
    24 //#define TEST
    25 
    26 #include "busybox.h"
    27 #include <stddef.h>
    28 #include <termios.h>
    29 #include <sys/ioctl.h>
    30 
    31 #include <sys/param.h>
    32 #include <unistd.h>
    33 
    34 #ifndef STDIN_FILENO
    35 # define STDIN_FILENO 0
    36 #endif
    37 
    38 #ifndef STDOUT_FILENO
    39 # define STDOUT_FILENO 1
    40 #endif
    41 
    42 #include <stdlib.h>
    43 #include <string.h>
    44 #include <assert.h>
    45 #include <ctype.h>
    46 #include <errno.h>
    47 #include <limits.h>
    48 #include <fcntl.h>
    49 
    50 #define STREQ(a, b) (strcmp ((a), (b)) == 0)
    51 
     24#include "libbb.h"
    5225
    5326#ifndef _POSIX_VDISABLE
     
    5629
    5730#define Control(c) ((c) & 0x1f)
    58 /* Canonical values for control characters. */
     31/* Canonical values for control characters */
    5932#ifndef CINTR
    60 # define CINTR Control ('c')
     33# define CINTR Control('c')
    6134#endif
    6235#ifndef CQUIT
     
    6740#endif
    6841#ifndef CKILL
    69 # define CKILL Control ('u')
     42# define CKILL Control('u')
    7043#endif
    7144#ifndef CEOF
    72 # define CEOF Control ('d')
     45# define CEOF Control('d')
    7346#endif
    7447#ifndef CEOL
     
    7649#endif
    7750#ifndef CSTART
    78 # define CSTART Control ('q')
     51# define CSTART Control('q')
    7952#endif
    8053#ifndef CSTOP
    81 # define CSTOP Control ('s')
     54# define CSTOP Control('s')
    8255#endif
    8356#ifndef CSUSP
    84 # define CSUSP Control ('z')
     57# define CSUSP Control('z')
    8558#endif
    8659#if defined(VEOL2) && !defined(CEOL2)
    8760# define CEOL2 _POSIX_VDISABLE
    8861#endif
    89 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
     62/* ISC renamed swtch to susp for termios, but we'll accept either name */
    9063#if defined(VSUSP) && !defined(VSWTCH)
    9164# define VSWTCH VSUSP
     
    9669#endif
    9770
    98 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
    99    So the default is to disable `swtch.'  */
    100 #if defined (__sparc__) && defined (__svr4__)
     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__)
    10174# undef CSWTCH
    10275# define CSWTCH _POSIX_VDISABLE
    10376#endif
    10477
    105 #if defined(VWERSE) && !defined (VWERASE)       /* AIX-3.2.5 */
     78#if defined(VWERSE) && !defined(VWERASE)       /* AIX-3.2.5 */
    10679# define VWERASE VWERSE
    10780#endif
    108 #if defined(VDSUSP) && !defined (CDSUSP)
    109 # define CDSUSP Control ('y')
     81#if defined(VDSUSP) && !defined(CDSUSP)
     82# define CDSUSP Control('y')
    11083#endif
    11184#if !defined(VREPRINT) && defined(VRPRNT)       /* Irix 4.0.5 */
     
    11386#endif
    11487#if defined(VREPRINT) && !defined(CRPRNT)
    115 # define CRPRNT Control ('r')
     88# define CRPRNT Control('r')
    11689#endif
    11790#if defined(VWERASE) && !defined(CWERASE)
    118 # define CWERASE Control ('w')
     91# define CWERASE Control('w')
    11992#endif
    12093#if defined(VLNEXT) && !defined(CLNEXT)
    121 # define CLNEXT Control ('v')
     94# define CLNEXT Control('v')
    12295#endif
    12396#if defined(VDISCARD) && !defined(VFLUSHO)
     
    137110#endif
    138111#if defined(VFLUSHO) && !defined(CFLUSHO)
    139 # define CFLUSHO Control ('o')
     112# define CFLUSHO Control('o')
    140113#endif
    141114#if defined(VSTATUS) && !defined(CSTATUS)
    142 # define CSTATUS Control ('t')
    143 #endif
    144 
    145 /* Which speeds to set. */
     115# define CSTATUS Control('t')
     116#endif
     117
     118/* Which speeds to set */
    146119enum speed_setting {
    147120    input_speed, output_speed, both_speeds
    148121};
    149122
    150 /* Which member(s) of `struct termios' a mode uses. */
    151 enum mode_type {
     123/* Which member(s) of 'struct termios' a mode uses */
     124enum {
    152125    /* Do NOT change the order or values, as mode_type_flag()
    153      * depends on them. */
     126     * depends on them */
    154127    control, input, output, local, combination
    155128};
    156129
    157 
    158 static const char evenp     [] = "evenp";
    159 static const char raw       [] = "raw";
    160 static const char stty_min  [] = "min";
    161 static const char stty_time [] = "time";
    162 static const char stty_swtch[] = "swtch";
    163 static const char stty_eol  [] = "eol";
    164 static const char stty_eof  [] = "eof";
    165 static const char parity    [] = "parity";
    166 static const char stty_oddp [] = "oddp";
    167 static const char stty_nl   [] = "nl";
    168 static const char stty_ek   [] = "ek";
    169 static const char stty_sane [] = "sane";
    170 static const char cbreak    [] = "cbreak";
    171 static const char stty_pass8[] = "pass8";
    172 static const char litout    [] = "litout";
    173 static const char cooked    [] = "cooked";
    174 static const char decctlq   [] = "decctlq";
    175 static const char stty_tabs [] = "tabs";
    176 static const char stty_lcase[] = "lcase";
    177 static const char stty_LCASE[] = "LCASE";
    178 static const char stty_crt  [] = "crt";
    179 static const char stty_dec  [] = "dec";
    180 
    181 
    182 /* Flags for `struct mode_info'. */
    183 #define SANE_SET 1              /* Set in `sane' mode.                  */
    184 #define SANE_UNSET 2            /* Unset in `sane' mode.                */
    185 #define REV 4                   /* Can be turned off by prepending `-'. */
    186 #define OMIT 8                  /* Don't display value.                 */
    187 
    188 /* Each mode.  */
     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 */
    189160struct mode_info {
    190     const char *name;       /* Name given on command line.           */
    191     /* enum mode_type type; */
    192     char type;              /* Which structure element to change.    */
    193     char flags;             /* Setting and display options.          */
    194     unsigned short mask;     /* Other bits to turn off for this mode. */
    195     unsigned long bits;     /* Bits to set for this mode.            */
     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            */
    196167};
    197168
     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
    198173#define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B }
    199174
    200 static const struct  mode_info mode_info[] = {
     175static const struct mode_info mode_info[] = {
    201176    MI_ENTRY("parenb",   control,     REV,               PARENB,     0 ),
    202177    MI_ENTRY("parodd",   control,     REV,               PARODD,     0 ),
     
    333308    MI_ENTRY(decctlq,    combination, REV        | OMIT, 0,          0 ),
    334309#endif
    335 #if defined (TABDLY) || defined (OXTABS)
     310#if defined(TABDLY) || defined(OXTABS)
    336311    MI_ENTRY(stty_tabs,  combination, REV        | OMIT, 0,          0 ),
    337312#endif
     
    345320
    346321enum {
    347     NUM_mode_info =
    348     (sizeof(mode_info) / sizeof(struct mode_info))
     322    NUM_mode_info = ARRAY_SIZE(mode_info)
    349323};
    350324
    351 /* Control character settings. */
     325/* Control character settings */
    352326struct control_info {
    353     const char *name;                       /* Name given on command line. */
    354     unsigned char saneval;          /* Value to set for `stty sane'. */
    355     unsigned char offset;                           /* Offset in c_cc. */
     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 */
    356330};
    357331
    358 /* Control characters. */
    359 
    360 static const struct  control_info control_info[] = {
     332/* Control characters */
     333
     334static const struct control_info control_info[] = {
    361335    {"intr",     CINTR,   VINTR},
    362336    {"quit",     CQUIT,   VQUIT},
     
    392366    {"status",   CSTATUS, VSTATUS},
    393367#endif
    394     /* These must be last because of the display routines. */
     368    /* These must be last because of the display routines */
    395369    {stty_min,   1,       VMIN},
    396370    {stty_time,  0,       VTIME},
     
    398372
    399373enum {
    400     NUM_control_info =
    401     (sizeof(control_info) / sizeof(struct control_info))
     374    NUM_control_info = ARRAY_SIZE(control_info)
    402375};
    403376
    404 #define EMT(t) ((enum mode_type)(t))
    405 
    406 static const char *  visible(unsigned int ch);
    407 static int           recover_mode(char *arg, struct termios *mode);
    408 static int           screen_columns(void);
    409 static int           set_mode(const struct mode_info *info,
    410                     int reversed, struct termios *mode);
    411 static speed_t       string_to_baud(const char *arg);
    412 static tcflag_t*     mode_type_flag(enum mode_type type, struct termios *mode);
    413 static void          display_all(struct termios *mode);
    414 static void          display_changed(struct termios *mode);
    415 static void          display_recoverable(struct termios *mode);
    416 static void          display_speed(struct termios *mode, int fancy);
    417 static void          display_window_size(int fancy);
    418 static void          sane_mode(struct termios *mode);
    419 static void          set_control_char(const struct control_info *info,
    420                     const char *arg, struct termios *mode);
    421 static void          set_speed(enum speed_setting type,
    422                     const char *arg, struct termios *mode);
    423 static void          set_window_size(int rows, int cols);
    424 
    425 static const char *device_name;
    426 
    427 static ATTRIBUTE_NORETURN void perror_on_device(const char *fmt)
     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)
    428449{
    429450    bb_perror_msg_and_die(fmt, device_name);
    430451}
    431452
    432 
    433 /* The width of the screen, for output wrapping. */
    434 static int max_col;
    435 
    436 /* Current position, to know when to wrap. */
    437 static int current_col;
     453static void perror_on_device(const char *fmt)
     454{
     455    bb_perror_msg(fmt, device_name);
     456}
    438457
    439458/* Print format string MESSAGE and optional args.
    440459   Wrap to next line first if it won't fit.
    441    Print a space first unless MESSAGE will start a new line. */
    442 
     460   Print a space first unless MESSAGE will start a new line */
    443461static void wrapf(const char *message, ...)
    444462{
     463    char buf[128];
    445464    va_list args;
    446     char buf[1024];                 /* Plenty long for our needs. */
    447465    int buflen;
    448466
    449467    va_start(args, message);
    450     vsprintf(buf, message, args);
     468    buflen = vsnprintf(buf, sizeof(buf), message, args);
    451469    va_end(args);
    452     buflen = strlen(buf);
    453     if (current_col + (current_col > 0) + buflen >= max_col) {
    454         putchar('\n');
    455         current_col = 0;
    456     }
    457     if (current_col > 0) {
    458         putchar(' ');
    459         current_col++;
     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        }
    460483    }
    461484    fputs(buf, stdout);
    462     current_col += buflen;
    463 }
    464 
    465 static const struct suffix_mult stty_suffixes[] = {
    466     {"b",  512 },
    467     {"k",  1024},
    468     {"B",  1024},
    469     {NULL, 0   }
    470 };
    471 
    472 #ifndef TEST
    473 int stty_main(int argc, char **argv)
    474 #else
    475 int main(int argc, char **argv)
    476 #endif
    477 {
    478     struct termios mode;
    479     void (*output_func)(struct termios *);
    480     int    optc;
    481     int    require_set_attr;
    482     int    speed_was_set;
    483     int    verbose_output;
    484     int    recoverable_output;
    485     int    k;
    486     int    noargs = 1;
    487     char * file_name = NULL;
    488 
    489     output_func = display_changed;
    490     verbose_output = 0;
    491     recoverable_output = 0;
    492 
    493     /* Don't print error messages for unrecognized options.  */
    494     opterr = 0;
    495 
    496     while ((optc = getopt(argc, argv, "agF:")) != -1) {
    497         switch (optc) {
    498         case 'a':
    499             verbose_output = 1;
    500             output_func = display_all;
    501             break;
    502 
    503         case 'g':
    504             recoverable_output = 1;
    505             output_func = display_recoverable;
    506             break;
    507 
    508         case 'F':
    509             if (file_name)
    510                 bb_error_msg_and_die("only one device may be specified");
    511             file_name = optarg;
    512             break;
    513 
    514         default:                /* unrecognized option */
    515             noargs = 0;
    516             break;
    517         }
    518 
    519         if (noargs == 0)
    520             break;
    521     }
    522 
    523     if (optind < argc)
    524         noargs = 0;
    525 
    526     /* Specifying both -a and -g gets an error.  */
    527     if (verbose_output & recoverable_output)
    528         bb_error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive");
    529 
    530     /* Specifying any other arguments with -a or -g gets an error.  */
    531     if (~noargs & (verbose_output | recoverable_output))
    532         bb_error_msg_and_die ("modes may not be set when specifying an output style");
    533 
    534     /* FIXME: it'd be better not to open the file until we've verified
    535        that all arguments are valid.  Otherwise, we could end up doing
    536        only some of the requested operations and then failing, probably
    537        leaving things in an undesirable state.  */
    538 
    539     if (file_name) {
    540         int fdflags;
    541 
    542         device_name = file_name;
    543         fclose(stdin);
    544         bb_xopen(device_name, O_RDONLY | O_NONBLOCK);
    545         if ((fdflags = fcntl(STDIN_FILENO, F_GETFL)) == -1
    546             || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
    547             perror_on_device("%s: couldn't reset non-blocking mode");
    548     } else {
    549         device_name = bb_msg_standard_input;
    550     }
    551 
    552     /* Initialize to all zeroes so there is no risk memcmp will report a
    553        spurious difference in an uninitialized portion of the structure.  */
    554     memset(&mode, 0, sizeof(mode));
    555     if (tcgetattr(STDIN_FILENO, &mode))
    556         perror_on_device("%s");
    557 
    558     if (verbose_output | recoverable_output | noargs) {
    559         max_col = screen_columns();
    560         current_col = 0;
    561         output_func(&mode);
    562         return EXIT_SUCCESS;
    563     }
    564 
    565     speed_was_set = 0;
    566     require_set_attr = 0;
    567     k = 0;
    568     while (++k < argc) {
    569         int match_found = 0;
    570         int reversed = 0;
    571         int i;
    572 
    573         if (argv[k][0] == '-') {
    574             char *find_dev_opt;
    575 
    576             ++argv[k];
    577 
    578      /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc.
    579     Find the options that have been parsed.  This is really
    580     gross, but it's needed because stty SETTINGS look like options to
    581     getopt(), so we need to work around things in a really horrible
    582     way.  If any new options are ever added to stty, the short option
    583     MUST NOT be a letter which is the first letter of one of the
    584     possible stty settings.
    585      */
    586             find_dev_opt = strchr(argv[k], 'F'); /* find -*F* */
    587             if(find_dev_opt) {
    588                 if(find_dev_opt[1]==0)  /* -*F   /dev/foo */
    589                     k++;            /* skip  /dev/foo */
    590                 continue;   /* else -*F/dev/foo - no skip */
    591             }
    592             if(argv[k][0]=='a' || argv[k][0]=='g')
    593                 continue;
    594             /* Is not options - is reverse params */
    595             reversed = 1;
    596         }
    597         for (i = 0; i < NUM_mode_info; ++i)
    598             if (STREQ(argv[k], mode_info[i].name)) {
    599                 match_found = set_mode(&mode_info[i], reversed, &mode);
    600                 require_set_attr = 1;
    601                 break;
    602             }
    603 
    604         if (match_found == 0 && reversed)
    605             bb_error_msg_and_die("invalid argument `%s'", --argv[k]);
    606 
    607         if (match_found == 0)
    608             for (i = 0; i < NUM_control_info; ++i)
    609                 if (STREQ(argv[k], control_info[i].name)) {
    610                     if (k == argc - 1)
    611                         bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
    612                     match_found = 1;
    613                     ++k;
    614                     set_control_char(&control_info[i], argv[k], &mode);
    615                     require_set_attr = 1;
    616                     break;
    617                 }
    618 
    619         if (match_found == 0) {
    620             if (STREQ(argv[k], "ispeed")) {
    621                 if (k == argc - 1)
    622                     bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
    623                 ++k;
    624                 set_speed(input_speed, argv[k], &mode);
    625                 speed_was_set = 1;
    626                 require_set_attr = 1;
    627             } else if (STREQ(argv[k], "ospeed")) {
    628                 if (k == argc - 1)
    629                     bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
    630                 ++k;
    631                 set_speed(output_speed, argv[k], &mode);
    632                 speed_was_set = 1;
    633                 require_set_attr = 1;
    634             }
    635 #ifdef TIOCGWINSZ
    636             else if (STREQ(argv[k], "rows")) {
    637                 if (k == argc - 1)
    638                     bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
    639                 ++k;
    640                 set_window_size((int) bb_xparse_number(argv[k], stty_suffixes),
    641                                 -1);
    642             } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) {
    643                 if (k == argc - 1)
    644                     bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
    645                 ++k;
    646                 set_window_size(-1,
    647                         (int) bb_xparse_number(argv[k], stty_suffixes));
    648             } else if (STREQ(argv[k], "size")) {
    649                 max_col = screen_columns();
    650                 current_col = 0;
    651                 display_window_size(0);
    652             }
    653 #endif
    654 #ifdef HAVE_C_LINE
    655             else if (STREQ(argv[k], "line")) {
    656                 if (k == argc - 1)
    657                     bb_error_msg_and_die(bb_msg_requires_arg, argv[k]);
    658                 ++k;
    659                 mode.c_line = bb_xparse_number(argv[k], stty_suffixes);
    660                 require_set_attr = 1;
    661             }
    662 #endif
    663             else if (STREQ(argv[k], "speed")) {
    664                 max_col = screen_columns();
    665                 display_speed(&mode, 0);
    666             } else if (recover_mode(argv[k], &mode) == 1)
    667                 require_set_attr = 1;
    668             else if (string_to_baud(argv[k]) != (speed_t) - 1) {
    669                 set_speed(both_speeds, argv[k], &mode);
    670                 speed_was_set = 1;
    671                 require_set_attr = 1;
    672             } else
    673                 bb_error_msg_and_die("invalid argument `%s'", argv[k]);
    674         }
    675     }
    676 
    677     if (require_set_attr) {
    678         struct termios new_mode;
    679 
    680         if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
    681             perror_on_device("%s");
    682 
    683         /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
    684            it performs *any* of the requested operations.  This means it
    685            can report `success' when it has actually failed to perform
    686            some proper subset of the requested operations.  To detect
    687            this partial failure, get the current terminal attributes and
    688            compare them to the requested ones.  */
    689 
    690         /* Initialize to all zeroes so there is no risk memcmp will report a
    691            spurious difference in an uninitialized portion of the structure.  */
    692         memset(&new_mode, 0, sizeof(new_mode));
    693         if (tcgetattr(STDIN_FILENO, &new_mode))
    694             perror_on_device("%s");
    695 
    696         /* Normally, one shouldn't use memcmp to compare structures that
    697            may have `holes' containing uninitialized data, but we have been
    698            careful to initialize the storage of these two variables to all
    699            zeroes.  One might think it more efficient simply to compare the
    700            modified fields, but that would require enumerating those fields --
    701            and not all systems have the same fields in this structure.  */
    702 
    703         if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) {
    704 #ifdef CIBAUD
    705             /* SunOS 4.1.3 (at least) has the problem that after this sequence,
    706                tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
    707                sometimes (m1 != m2).  The only difference is in the four bits
    708                of the c_cflag field corresponding to the baud rate.  To save
    709                Sun users a little confusion, don't report an error if this
    710                happens.  But suppress the error only if we haven't tried to
    711                set the baud rate explicitly -- otherwise we'd never give an
    712                error for a true failure to set the baud rate.  */
    713 
    714             new_mode.c_cflag &= (~CIBAUD);
    715             if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0)
    716 #endif
    717                 perror_on_device ("%s: unable to perform all requested operations");
    718         }
    719     }
    720 
    721     return EXIT_SUCCESS;
    722 }
    723 
    724 /* Return 0 if not applied because not reversible; otherwise return 1.  */
    725 
    726 static int
    727 set_mode(const struct mode_info *info, int reversed, struct termios *mode)
    728 {
    729     tcflag_t *bitsp;
    730 
    731     if (reversed && (info->flags & REV) == 0)
    732         return 0;
    733 
    734     bitsp = mode_type_flag(EMT(info->type), mode);
    735 
    736     if (bitsp == NULL) {
    737         /* Combination mode. */
    738         if (info->name == evenp || info->name == parity) {
    739             if (reversed)
    740                 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
    741             else
    742                 mode->c_cflag =
    743                     (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
    744         } else if (info->name == stty_oddp) {
    745             if (reversed)
    746                 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
    747             else
    748                 mode->c_cflag =
    749                     (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
    750         } else if (info->name == stty_nl) {
    751             if (reversed) {
    752                 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
    753                 mode->c_oflag = (mode->c_oflag
    754 #ifdef ONLCR
    755                                  | ONLCR
    756 #endif
    757                     )
    758 #ifdef OCRNL
    759                     & ~OCRNL
    760 #endif
    761 #ifdef ONLRET
    762                     & ~ONLRET
    763 #endif
    764                     ;
    765             } else {
    766                 mode->c_iflag = mode->c_iflag & ~ICRNL;
    767 #ifdef ONLCR
    768                 mode->c_oflag = mode->c_oflag & ~ONLCR;
    769 #endif
    770             }
    771         } else if (info->name == stty_ek) {
    772             mode->c_cc[VERASE] = CERASE;
    773             mode->c_cc[VKILL] = CKILL;
    774         } else if (info->name == stty_sane)
    775             sane_mode(mode);
    776         else if (info->name == cbreak) {
    777             if (reversed)
    778                 mode->c_lflag |= ICANON;
    779             else
    780                 mode->c_lflag &= ~ICANON;
    781         } else if (info->name == stty_pass8) {
    782             if (reversed) {
    783                 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
    784                 mode->c_iflag |= ISTRIP;
    785             } else {
    786                 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
    787                 mode->c_iflag &= ~ISTRIP;
    788             }
    789         } else if (info->name == litout) {
    790             if (reversed) {
    791                 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
    792                 mode->c_iflag |= ISTRIP;
    793                 mode->c_oflag |= OPOST;
    794             } else {
    795                 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
    796                 mode->c_iflag &= ~ISTRIP;
    797                 mode->c_oflag &= ~OPOST;
    798             }
    799         } else if (info->name == raw || info->name == cooked) {
    800             if ((info->name[0] == 'r' && reversed)
    801                 || (info->name[0] == 'c' && !reversed)) {
    802                 /* Cooked mode. */
    803                 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
    804                 mode->c_oflag |= OPOST;
    805                 mode->c_lflag |= ISIG | ICANON;
    806 #if VMIN == VEOF
    807                 mode->c_cc[VEOF] = CEOF;
    808 #endif
    809 #if VTIME == VEOL
    810                 mode->c_cc[VEOL] = CEOL;
    811 #endif
    812             } else {
    813                 /* Raw mode. */
    814                 mode->c_iflag = 0;
    815                 mode->c_oflag &= ~OPOST;
    816                 mode->c_lflag &= ~(ISIG | ICANON
    817 #ifdef XCASE
    818                                    | XCASE
    819 #endif
    820                     );
    821                 mode->c_cc[VMIN] = 1;
    822                 mode->c_cc[VTIME] = 0;
    823             }
    824         }
    825 #ifdef IXANY
    826         else if (info->name == decctlq) {
    827             if (reversed)
    828                 mode->c_iflag |= IXANY;
    829             else
    830                 mode->c_iflag &= ~IXANY;
    831         }
    832 #endif
    833 #ifdef TABDLY
    834         else if (info->name == stty_tabs) {
    835             if (reversed)
    836                 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
    837             else
    838                 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
    839         }
    840 #else
    841 # ifdef OXTABS
    842         else if (info->name == stty_tabs) {
    843             if (reversed)
    844                 mode->c_oflag = mode->c_oflag | OXTABS;
    845             else
    846                 mode->c_oflag = mode->c_oflag & ~OXTABS;
    847         }
    848 # endif
    849 #endif
    850 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
    851         else if (info->name == stty_lcase || info->name == stty_LCASE) {
    852             if (reversed) {
    853                 mode->c_lflag &= ~XCASE;
    854                 mode->c_iflag &= ~IUCLC;
    855                 mode->c_oflag &= ~OLCUC;
    856             } else {
    857                 mode->c_lflag |= XCASE;
    858                 mode->c_iflag |= IUCLC;
    859                 mode->c_oflag |= OLCUC;
    860             }
    861         }
    862 #endif
    863         else if (info->name == stty_crt)
    864             mode->c_lflag |= ECHOE
    865 #ifdef ECHOCTL
    866                 | ECHOCTL
    867 #endif
    868 #ifdef ECHOKE
    869                 | ECHOKE
    870 #endif
    871                 ;
    872         else if (info->name == stty_dec) {
    873             mode->c_cc[VINTR] = 3;  /* ^C */
    874             mode->c_cc[VERASE] = 127;       /* DEL */
    875             mode->c_cc[VKILL] = 21; /* ^U */
    876             mode->c_lflag |= ECHOE
    877 #ifdef ECHOCTL
    878                 | ECHOCTL
    879 #endif
    880 #ifdef ECHOKE
    881                 | ECHOKE
    882 #endif
    883                 ;
    884 #ifdef IXANY
    885             mode->c_iflag &= ~IXANY;
    886 #endif
    887         }
    888     } else if (reversed)
    889         *bitsp = *bitsp & ~((unsigned long)info->mask) & ~info->bits;
    890     else
    891         *bitsp = (*bitsp & ~((unsigned long)info->mask)) | info->bits;
    892 
    893     return 1;
    894 }
    895 
    896 static void
    897 set_control_char(const struct control_info *info, const char *arg,
    898                  struct termios *mode)
    899 {
    900     unsigned char value;
    901 
    902     if (info->name == stty_min || info->name == stty_time)
    903         value = bb_xparse_number(arg, stty_suffixes);
    904     else if (arg[0] == '\0' || arg[1] == '\0')
    905         value = arg[0];
    906     else if (STREQ(arg, "^-") || STREQ(arg, "undef"))
    907         value = _POSIX_VDISABLE;
    908     else if (arg[0] == '^' && arg[1] != '\0') {     /* Ignore any trailing junk. */
    909         if (arg[1] == '?')
    910             value = 127;
    911         else
    912             value = arg[1] & ~0140; /* Non-letters get weird results. */
    913     } else
    914         value = bb_xparse_number(arg, stty_suffixes);
    915     mode->c_cc[info->offset] = value;
    916 }
    917 
    918 static void
    919 set_speed(enum speed_setting type, const char *arg, struct termios *mode)
    920 {
    921     speed_t baud;
    922 
    923     baud = string_to_baud(arg);
    924 
    925     if (type != output_speed) {     /* either input or both */
    926         cfsetispeed(mode, baud);
    927     }
    928     if (type != input_speed) {      /* either output or both */
    929         cfsetospeed(mode, baud);
    930     }
    931 }
    932 
    933 #ifdef TIOCGWINSZ
    934 
    935 static int get_win_size(int fd, struct winsize *win)
    936 {
    937     int err = ioctl(fd, TIOCGWINSZ, (char *) win);
    938 
    939     return err;
    940 }
    941 
    942 static void
    943 set_window_size(int rows, int cols)
    944 {
    945     struct winsize win;
    946 
    947     if (get_win_size(STDIN_FILENO, &win)) {
    948         if (errno != EINVAL)
    949             perror_on_device("%s");
     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        }
    950498        memset(&win, 0, sizeof(win));
    951499    }
     
    956504        win.ws_col = cols;
    957505
    958 # ifdef TIOCSSIZE
    959     /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
    960        The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
    961        This comment from sys/ttold.h describes Sun's twisted logic - a better
    962        test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
    963        At any rate, the problem is gone in Solaris 2.x. */
    964 
    965     if (win.ws_row == 0 || win.ws_col == 0) {
    966         struct ttysize ttysz;
    967 
    968         ttysz.ts_lines = win.ws_row;
    969         ttysz.ts_cols = win.ws_col;
    970 
    971         win.ws_row = win.ws_col = 1;
    972 
    973         if ((ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win) != 0)
    974             || (ioctl(STDIN_FILENO, TIOCSSIZE, (char *) &ttysz) != 0)) {
    975             perror_on_device("%s");
    976         }
    977         return;
    978     }
    979 # endif
    980 
    981506    if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win))
     507bail:
    982508        perror_on_device("%s");
    983509}
    984510
    985 static void display_window_size(int fancy)
    986 {
    987     const char *fmt_str = "%s" "\0" "%s: no size information for this device";
    988     struct winsize win;
    989 
    990     if (get_win_size(STDIN_FILENO, &win)) {
     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)) {
    991517        if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) {
    992518            perror_on_device(fmt_str);
     
    994520    } else {
    995521        wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n",
    996               win.ws_row, win.ws_col);
    997         if (!fancy)
    998             current_col = 0;
    999     }
    1000 }
    1001 #endif
    1002 
    1003 static int screen_columns(void)
    1004 {
    1005     int columns;
    1006     const char *s;
    1007 
    1008 #ifdef TIOCGWINSZ
    1009     struct winsize win;
    1010 
    1011     /* With Solaris 2.[123], this ioctl fails and errno is set to
    1012        EINVAL for telnet (but not rlogin) sessions.
    1013        On ISC 3.0, it fails for the console and the serial port
    1014        (but it works for ptys).
    1015        It can also fail on any system when stdout isn't a tty.
    1016        In case of any failure, just use the default.  */
    1017     if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
    1018         return win.ws_col;
    1019 #endif
    1020 
    1021     columns = 80;
    1022     if ((s = getenv("COLUMNS"))) {
    1023         columns = atoi(s);
    1024     }
    1025     return columns;
    1026 }
    1027 
    1028 static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode)
    1029 {
    1030     static const unsigned char tcflag_offsets[] = {
    1031         offsetof(struct termios, c_cflag), /* control */
    1032         offsetof(struct termios, c_iflag), /* input */
    1033         offsetof(struct termios, c_oflag), /* output */
    1034         offsetof(struct termios, c_lflag) /* local */
    1035     };
    1036 
    1037     if (((unsigned int) type) <= local) {
    1038         return (tcflag_t *)(((char *) mode) + tcflag_offsets[(int)type]);
    1039     }
    1040     return NULL;
    1041 }
    1042 
    1043 static void display_changed(struct termios *mode)
     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)
    1044534{
    1045535    int i;
    1046     int empty_line;
    1047     tcflag_t *bitsp;
    1048     unsigned long mask;
    1049     enum mode_type prev_type = control;
    1050 
    1051     display_speed(mode, 1);
    1052 #ifdef HAVE_C_LINE
    1053     wrapf("line = %d;", mode->c_line);
    1054 #endif
    1055     putchar('\n');
    1056     current_col = 0;
    1057 
    1058     empty_line = 1;
    1059     for (i = 0; control_info[i].name != stty_min; ++i) {
    1060         if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
    1061             continue;
    1062         /* If swtch is the same as susp, don't print both.  */
    1063 #if VSWTCH == VSUSP
    1064         if (control_info[i].name == stty_swtch)
    1065             continue;
    1066 #endif
    1067         /* If eof uses the same slot as min, only print whichever applies.  */
    1068 #if VEOF == VMIN
    1069         if ((mode->c_lflag & ICANON) == 0
    1070             && (control_info[i].name == stty_eof
    1071                 || control_info[i].name == stty_eol)) continue;
    1072 #endif
    1073 
    1074         empty_line = 0;
    1075         wrapf("%s = %s;", control_info[i].name,
    1076               visible(mode->c_cc[control_info[i].offset]));
    1077     }
    1078     if ((mode->c_lflag & ICANON) == 0) {
    1079         wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
    1080               (int) mode->c_cc[VTIME]);
    1081     } else if (empty_line == 0)
    1082         putchar('\n');
    1083     current_col = 0;
    1084 
    1085     empty_line = 1;
    1086     for (i = 0; i < NUM_mode_info; ++i) {
    1087         if (mode_info[i].flags & OMIT)
    1088             continue;
    1089         if (EMT(mode_info[i].type) != prev_type) {
    1090             if (empty_line == 0) {
    1091                 putchar('\n');
    1092                 current_col = 0;
    1093                 empty_line = 1;
    1094             }
    1095             prev_type = EMT(mode_info[i].type);
    1096         }
    1097 
    1098         bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
    1099         mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
    1100         if ((*bitsp & mask) == mode_info[i].bits) {
    1101             if (mode_info[i].flags & SANE_UNSET) {
    1102                 wrapf("%s", mode_info[i].name);
    1103                 empty_line = 0;
    1104             }
    1105         }
    1106             else if ((mode_info[i].flags & (SANE_SET | REV)) ==
    1107                      (SANE_SET | REV)) {
    1108             wrapf("-%s", mode_info[i].name);
    1109             empty_line = 0;
    1110         }
    1111     }
    1112     if (empty_line == 0)
    1113         putchar('\n');
    1114     current_col = 0;
    1115 }
    1116 
    1117 static void
    1118 display_all(struct termios *mode)
     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)
    1119543{
    1120544    int i;
    1121     tcflag_t *bitsp;
    1122     unsigned long mask;
    1123     enum mode_type prev_type = control;
    1124 
    1125     display_speed(mode, 1);
    1126 #ifdef TIOCGWINSZ
    1127     display_window_size(1);
    1128 #endif
    1129 #ifdef HAVE_C_LINE
    1130     wrapf("line = %d;", mode->c_line);
    1131 #endif
    1132     putchar('\n');
    1133     current_col = 0;
    1134 
    1135     for (i = 0; control_info[i].name != stty_min; ++i) {
    1136         /* If swtch is the same as susp, don't print both.  */
    1137 #if VSWTCH == VSUSP
    1138         if (control_info[i].name == stty_swtch)
    1139             continue;
    1140 #endif
    1141         /* If eof uses the same slot as min, only print whichever applies.  */
    1142 #if VEOF == VMIN
    1143         if ((mode->c_lflag & ICANON) == 0
    1144             && (control_info[i].name == stty_eof
    1145                 || control_info[i].name == stty_eol)) continue;
    1146 #endif
    1147         wrapf("%s = %s;", control_info[i].name,
    1148               visible(mode->c_cc[control_info[i].offset]));
    1149     }
    1150 #if VEOF == VMIN
    1151     if ((mode->c_lflag & ICANON) == 0)
    1152 #endif
    1153         wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
    1154     if (current_col != 0)
    1155         putchar('\n');
    1156     current_col = 0;
    1157 
    1158     for (i = 0; i < NUM_mode_info; ++i) {
    1159         if (mode_info[i].flags & OMIT)
    1160             continue;
    1161         if (EMT(mode_info[i].type) != prev_type) {
    1162             putchar('\n');
    1163             current_col = 0;
    1164             prev_type = EMT(mode_info[i].type);
    1165         }
    1166 
    1167         bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
    1168         mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
    1169         if ((*bitsp & mask) == mode_info[i].bits)
    1170             wrapf("%s", mode_info[i].name);
    1171         else if (mode_info[i].flags & REV)
    1172             wrapf("-%s", mode_info[i].name);
    1173     }
    1174     putchar('\n');
    1175     current_col = 0;
    1176 }
    1177 
    1178 static void display_speed(struct termios *mode, int fancy)
    1179 {
    1180     unsigned long ispeed, ospeed;
    1181     const char *fmt_str =
    1182         "%lu %lu\n\0"        "ispeed %lu baud; ospeed %lu baud;\0"
    1183         "%lu\n\0" "\0\0\0\0" "speed %lu baud;";
    1184 
    1185     ospeed = ispeed = cfgetispeed(mode);
    1186     if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) {
    1187         ispeed = ospeed;                /* in case ispeed was 0 */
    1188         fmt_str += 43;
    1189     }
    1190     if (fancy) {
    1191         fmt_str += 9;
    1192     }
    1193     wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
    1194     if (!fancy)
    1195         current_col = 0;
    1196 }
    1197 
    1198 static void display_recoverable(struct termios *mode)
    1199 {
    1200     int i;
    1201 
    1202     printf("%lx:%lx:%lx:%lx",
    1203            (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
    1204            (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
    1205     for (i = 0; i < NCCS; ++i)
    1206         printf(":%x", (unsigned int) mode->c_cc[i]);
    1207     putchar('\n');
    1208 }
    1209 
    1210 static int recover_mode(char *arg, struct termios *mode)
     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)
    1211583{
    1212584    int i, n;
    1213     unsigned int chr;
     585    unsigned chr;
    1214586    unsigned long iflag, oflag, cflag, lflag;
    1215587
    1216588    /* Scan into temporaries since it is too much trouble to figure out
    1217        the right format for `tcflag_t'. */
     589       the right format for 'tcflag_t' */
    1218590    if (sscanf(arg, "%lx:%lx:%lx:%lx%n",
    1219591               &iflag, &oflag, &cflag, &lflag, &n) != 4)
     
    1231603    }
    1232604
    1233     /* Fail if there are too many fields. */
     605    /* Fail if there are too many fields */
    1234606    if (*arg != '\0')
    1235607        return 0;
     
    1238610}
    1239611
    1240 static speed_t string_to_baud(const char *arg)
    1241 {
    1242     return tty_value_to_baud(bb_xparse_number(arg, 0));
     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");
    1243699}
    1244700
     
    1258714    for (i = 0; i < NUM_mode_info; ++i) {
    1259715        if (mode_info[i].flags & SANE_SET) {
    1260             bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
     716            bitsp = mode_type_flag(mode_info[i].type, mode);
    1261717            *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask))
    1262718                | mode_info[i].bits;
    1263719        } else if (mode_info[i].flags & SANE_UNSET) {
    1264             bitsp = mode_type_flag(EMT(mode_info[i].type), mode);
     720            bitsp = mode_type_flag(mode_info[i].type, mode);
    1265721            *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask)
    1266722                & ~mode_info[i].bits;
     
    1269725}
    1270726
    1271 /* Return a string that is the printable representation of character CH.  */
    1272 /* Adapted from `cat' by Torbjorn Granlund.  */
    1273 
    1274 static const char *visible(unsigned int ch)
    1275 {
    1276     static char buf[10];
    1277     char *bpout = buf;
    1278 
    1279     if (ch == _POSIX_VDISABLE) {
    1280         return "<undef>";
    1281     }
    1282 
    1283     if (ch >= 128) {
    1284         ch -= 128;
    1285         *bpout++ = 'M';
    1286         *bpout++ = '-';
    1287     }
    1288 
    1289     if (ch < 32) {
    1290         *bpout++ = '^';
    1291         *bpout++ = ch + 64;
    1292     } else if (ch < 127) {
    1293         *bpout++ = ch;
    1294     } else {
    1295         *bpout++ = '^';
    1296         *bpout++ = '?';
    1297     }
    1298 
    1299     *bpout = '\0';
    1300     return (const char *) buf;
    1301 }
    1302 
    1303 #ifdef TEST
    1304 
    1305 const char *bb_applet_name = "stty";
    1306 
    1307 #endif
     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 TracChangeset for help on using the changeset viewer.