From f8abc100cc84c370f7c595846c74ab46456faccb Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 12 Jan 2007 21:02:04 +0000 Subject: [PATCH] stty: rearrange functions, avoiding the need in forward declarations. No other code chages. --- coreutils/stty.c | 818 +++++++++++++++++++++++------------------------ 1 file changed, 403 insertions(+), 415 deletions(-) diff --git a/coreutils/stty.c b/coreutils/stty.c index b48941429..93919b33a 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c @@ -637,296 +637,141 @@ static int find_param(const char *name) return 0; } - -static int recover_mode(const char *arg, struct termios *mode); -static void set_mode(const struct mode_info *info, - int reversed, struct termios *mode); -static void display_all(const struct termios *mode); -static void display_changed(const struct termios *mode); -static void display_recoverable(const struct termios *mode); -static void display_speed(const struct termios *mode, int fancy); -static void sane_mode(struct termios *mode); -static void set_control_char_or_die(const struct control_info *info, - const char *arg, struct termios *mode); - -int stty_main(int argc, char **argv) +static int recover_mode(const char *arg, struct termios *mode) { - struct termios mode; - void (*output_func)(const struct termios *); - const char *file_name = NULL; - int require_set_attr; - int speed_was_set; - int verbose_output; - int recoverable_output; - int noargs; - int k; - - output_func = display_changed; - noargs = 1; - speed_was_set = 0; - require_set_attr = 0; - verbose_output = 0; - recoverable_output = 0; - - /* First pass: only parse/verify command line params */ - k = 0; - while (argv[++k]) { - const struct mode_info *mp; - const struct control_info *cp; - const char *arg = argv[k]; - const char *argnext = argv[k+1]; - int param; - - if (arg[0] == '-') { - int i; - mp = find_mode(arg+1); - if (mp) { - if (!(mp->flags & REV)) - bb_error_msg_and_die("invalid argument '%s'", arg); - noargs = 0; - continue; - } - /* It is an option - parse it */ - i = 0; - while (arg[++i]) { - switch (arg[i]) { - case 'a': - verbose_output = 1; - output_func = display_all; - break; - case 'g': - recoverable_output = 1; - output_func = display_recoverable; - break; - case 'F': - if (file_name) - bb_error_msg_and_die("only one device may be specified"); - file_name = &arg[i+1]; /* "-Fdevice" ? */ - if (!file_name[0]) { /* nope, "-F device" */ - int p = k+1; /* argv[p] is argnext */ - file_name = argnext; - if (!file_name) - bb_error_msg_and_die(bb_msg_requires_arg, "-F"); - /* remove -F param from arg[vc] */ - --argc; - while (argv[p]) { argv[p] = argv[p+1]; ++p; } - } - goto end_option; - default: - bb_error_msg_and_die("invalid argument '%s'", arg); - } - } -end_option: - continue; - } - - mp = find_mode(arg); - if (mp) { - noargs = 0; - continue; - } - - cp = find_control(arg); - if (cp) { - if (!argnext) - bb_error_msg_and_die(bb_msg_requires_arg, arg); - /* called for the side effect of xfunc death only */ - set_control_char_or_die(cp, argnext, &mode); - noargs = 0; - ++k; - continue; - } - - param = find_param(arg); - if (param & param_need_arg) { - if (!argnext) - bb_error_msg_and_die(bb_msg_requires_arg, arg); - ++k; - } - - switch (param) { -#ifdef HAVE_C_LINE - case param_line: -# ifndef TIOCGWINSZ - xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); - break; -# endif /* else fall-through */ -#endif -#ifdef TIOCGWINSZ - case param_rows: - case param_cols: - xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); - break; - case param_size: -#endif - case param_speed: - break; - case param_ispeed: - /* called for the side effect of xfunc death only */ - set_speed_or_die(input_speed, argnext, &mode); - break; - case param_ospeed: - /* called for the side effect of xfunc death only */ - set_speed_or_die(output_speed, argnext, &mode); - break; - default: - if (recover_mode(arg, &mode) == 1) break; - if (string_to_baud_or_die(arg) != (speed_t) -1) break; - bb_error_msg_and_die("invalid argument '%s'", arg); - } - noargs = 0; - } - - /* Specifying both -a and -g is an error */ - if (verbose_output && recoverable_output) - bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive"); - /* Specifying -a or -g with non-options is an error */ - if (!noargs && (verbose_output || recoverable_output)) - bb_error_msg_and_die("modes may not be set when specifying an output style"); + int i, n; + unsigned int chr; + unsigned long iflag, oflag, cflag, lflag; - /* Now it is safe to start doing things */ - if (file_name) { - int fd, fdflags; - device_name = file_name; - fd = xopen(device_name, O_RDONLY | O_NONBLOCK); - if (fd != STDIN_FILENO) { - dup2(fd, STDIN_FILENO); - close(fd); - } - fdflags = fcntl(STDIN_FILENO, F_GETFL); - if (fdflags == -1 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0) - perror_on_device_and_die("%s: cannot reset non-blocking mode"); + /* Scan into temporaries since it is too much trouble to figure out + the right format for 'tcflag_t' */ + if (sscanf(arg, "%lx:%lx:%lx:%lx%n", + &iflag, &oflag, &cflag, &lflag, &n) != 4) + return 0; + mode->c_iflag = iflag; + mode->c_oflag = oflag; + mode->c_cflag = cflag; + mode->c_lflag = lflag; + arg += n; + for (i = 0; i < NCCS; ++i) { + if (sscanf(arg, ":%x%n", &chr, &n) != 1) + return 0; + mode->c_cc[i] = chr; + arg += n; } - /* Initialize to all zeroes so there is no risk memcmp will report a - spurious difference in an uninitialized portion of the structure */ - memset(&mode, 0, sizeof(mode)); - if (tcgetattr(STDIN_FILENO, &mode)) - perror_on_device_and_die("%s"); - - if (verbose_output || recoverable_output || noargs) { - max_col = screen_columns_or_die(); - output_func(&mode); - return EXIT_SUCCESS; - } + /* Fail if there are too many fields */ + if (*arg != '\0') + return 0; - /* Second pass: perform actions */ - k = 0; - while (argv[++k]) { - const struct mode_info *mp; - const struct control_info *cp; - const char *arg = argv[k]; - const char *argnext = argv[k+1]; - int param; + return 1; +} - if (arg[0] == '-') { - mp = find_mode(arg+1); - if (mp) { - set_mode(mp, 1 /* reversed */, &mode); - } - /* It is an option - already parsed. Skip it */ - continue; - } +static void display_recoverable(const struct termios *mode) +{ + int i; + printf("%lx:%lx:%lx:%lx", + (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, + (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); + for (i = 0; i < NCCS; ++i) + printf(":%x", (unsigned int) mode->c_cc[i]); + putchar('\n'); +} - mp = find_mode(arg); - if (mp) { - set_mode(mp, 0 /* non-reversed */, &mode); - continue; - } +static void display_speed(const struct termios *mode, int fancy) +{ + //01234567 8 9 + const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;"; + unsigned long ispeed, ospeed; - cp = find_control(arg); - if (cp) { - ++k; - set_control_char_or_die(cp, argnext, &mode); - continue; - } + ospeed = ispeed = cfgetispeed(mode); + if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) { + ispeed = ospeed; /* in case ispeed was 0 */ + //0123 4 5 6 7 8 9 + fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;"; + } + if (fancy) fmt_str += 9; + wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); +} - param = find_param(arg); - if (param & param_need_arg) { - ++k; - } +static void display_all(const struct termios *mode) +{ + int i; + tcflag_t *bitsp; + unsigned long mask; + int prev_type = control; - switch (param) { + display_speed(mode, 1); + display_window_size(1); #ifdef HAVE_C_LINE - case param_line: - mode.c_line = xatoul_sfx(argnext, stty_suffixes); - require_set_attr = 1; - break; + wrapf("line = %d;\n", mode->c_line); +#else + wrapf("\n"); #endif -#ifdef TIOCGWINSZ - case param_cols: - set_window_size(-1, xatoul_sfx(argnext, stty_suffixes)); - break; - case param_size: - display_window_size(0); - break; - case param_rows: - set_window_size(xatoul_sfx(argnext, stty_suffixes), -1); - break; + + for (i = 0; control_info[i].name != stty_min; ++i) { + /* If swtch is the same as susp, don't print both */ +#if VSWTCH == VSUSP + if (control_info[i].name == stty_swtch) + continue; #endif - case param_speed: - display_speed(&mode, 0); - break; - case param_ispeed: - set_speed_or_die(input_speed, argnext, &mode); - speed_was_set = 1; - require_set_attr = 1; - break; - case param_ospeed: - set_speed_or_die(output_speed, argnext, &mode); - speed_was_set = 1; - require_set_attr = 1; - break; - default: - if (recover_mode(arg, &mode) == 1) - require_set_attr = 1; - else /* true: if (string_to_baud_or_die(arg) != (speed_t) -1) */ { - set_speed_or_die(both_speeds, arg, &mode); - speed_was_set = 1; - require_set_attr = 1; - } /* else - impossible (caught in the first pass): - bb_error_msg_and_die("invalid argument '%s'", arg); */ - } + /* If eof uses the same slot as min, only print whichever applies */ +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0 + && (control_info[i].name == stty_eof + || control_info[i].name == stty_eol)) continue; +#endif + wrapf("%s = %s;", control_info[i].name, + visible(mode->c_cc[control_info[i].offset])); } +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0) +#endif + wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); + if (current_col) wrapf("\n"); - if (require_set_attr) { - struct termios new_mode; - - if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) - perror_on_device_and_die("%s"); - - /* POSIX (according to Zlotnick's book) tcsetattr returns zero if - it performs *any* of the requested operations. This means it - can report 'success' when it has actually failed to perform - some proper subset of the requested operations. To detect - this partial failure, get the current terminal attributes and - compare them to the requested ones */ + for (i = 0; i < NUM_mode_info; ++i) { + if (mode_info[i].flags & OMIT) + continue; + if (mode_info[i].type != prev_type) { + wrapf("\n"); + prev_type = mode_info[i].type; + } - /* Initialize to all zeroes so there is no risk memcmp will report a - spurious difference in an uninitialized portion of the structure */ - memset(&new_mode, 0, sizeof(new_mode)); - if (tcgetattr(STDIN_FILENO, &new_mode)) - perror_on_device_and_die("%s"); + bitsp = mode_type_flag(mode_info[i].type, mode); + mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; + if ((*bitsp & mask) == mode_info[i].bits) + wrapf("%s", mode_info[i].name); + else if (mode_info[i].flags & REV) + wrapf("-%s", mode_info[i].name); + } + if (current_col) wrapf("\n"); +} - if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { -#ifdef CIBAUD - /* SunOS 4.1.3 (at least) has the problem that after this sequence, - tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); - sometimes (m1 != m2). The only difference is in the four bits - of the c_cflag field corresponding to the baud rate. To save - Sun users a little confusion, don't report an error if this - happens. But suppress the error only if we haven't tried to - set the baud rate explicitly -- otherwise we'd never give an - error for a true failure to set the baud rate */ +static void sane_mode(struct termios *mode) +{ + int i; + tcflag_t *bitsp; - new_mode.c_cflag &= (~CIBAUD); - if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) + for (i = 0; i < NUM_control_info; ++i) { +#if VMIN == VEOF + if (control_info[i].name == stty_min) + break; #endif - perror_on_device_and_die("%s: cannot perform all requested operations"); - } + mode->c_cc[control_info[i].offset] = control_info[i].saneval; } - return EXIT_SUCCESS; + for (i = 0; i < NUM_mode_info; ++i) { + if (mode_info[i].flags & SANE_SET) { + bitsp = mode_type_flag(mode_info[i].type, mode); + *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask)) + | mode_info[i].bits; + } else if (mode_info[i].flags & SANE_UNSET) { + bitsp = mode_type_flag(mode_info[i].type, mode); + *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask) + & ~mode_info[i].bits; + } + } } /* Save set_mode from #ifdef forest plague */ @@ -1091,26 +936,6 @@ static void set_mode(const struct mode_info *info, int reversed, } } -static void set_control_char_or_die(const struct control_info *info, - const char *arg, struct termios *mode) -{ - unsigned char value; - - if (info->name == stty_min || info->name == stty_time) - value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); - else if (arg[0] == '\0' || arg[1] == '\0') - value = arg[0]; - else if (streq(arg, "^-") || streq(arg, "undef")) - value = _POSIX_VDISABLE; - else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */ - value = arg[1] & 0x1f; /* Non-letters get weird results */ - if (arg[1] == '?') - value = 127; - } else - value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); - mode->c_cc[info->offset] = value; -} - static void display_changed(const struct termios *mode) { int i; @@ -1156,152 +981,315 @@ static void display_changed(const struct termios *mode) prev_type = mode_info[i].type; } - bitsp = mode_type_flag(mode_info[i].type, mode); - mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; - if ((*bitsp & mask) == mode_info[i].bits) { - if (mode_info[i].flags & SANE_UNSET) { - wrapf("%s", mode_info[i].name); - } - } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) { - wrapf("-%s", mode_info[i].name); + bitsp = mode_type_flag(mode_info[i].type, mode); + mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; + if ((*bitsp & mask) == mode_info[i].bits) { + if (mode_info[i].flags & SANE_UNSET) { + wrapf("%s", mode_info[i].name); + } + } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) { + wrapf("-%s", mode_info[i].name); + } + } + if (current_col) wrapf("\n"); +} + +static void set_control_char_or_die(const struct control_info *info, + const char *arg, struct termios *mode) +{ + unsigned char value; + + if (info->name == stty_min || info->name == stty_time) + value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); + else if (arg[0] == '\0' || arg[1] == '\0') + value = arg[0]; + else if (streq(arg, "^-") || streq(arg, "undef")) + value = _POSIX_VDISABLE; + else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */ + value = arg[1] & 0x1f; /* Non-letters get weird results */ + if (arg[1] == '?') + value = 127; + } else + value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); + mode->c_cc[info->offset] = value; +} + +int stty_main(int argc, char **argv) +{ + struct termios mode; + void (*output_func)(const struct termios *); + const char *file_name = NULL; + int require_set_attr; + int speed_was_set; + int verbose_output; + int recoverable_output; + int noargs; + int k; + + output_func = display_changed; + noargs = 1; + speed_was_set = 0; + require_set_attr = 0; + verbose_output = 0; + recoverable_output = 0; + + /* First pass: only parse/verify command line params */ + k = 0; + while (argv[++k]) { + const struct mode_info *mp; + const struct control_info *cp; + const char *arg = argv[k]; + const char *argnext = argv[k+1]; + int param; + + if (arg[0] == '-') { + int i; + mp = find_mode(arg+1); + if (mp) { + if (!(mp->flags & REV)) + bb_error_msg_and_die("invalid argument '%s'", arg); + noargs = 0; + continue; + } + /* It is an option - parse it */ + i = 0; + while (arg[++i]) { + switch (arg[i]) { + case 'a': + verbose_output = 1; + output_func = display_all; + break; + case 'g': + recoverable_output = 1; + output_func = display_recoverable; + break; + case 'F': + if (file_name) + bb_error_msg_and_die("only one device may be specified"); + file_name = &arg[i+1]; /* "-Fdevice" ? */ + if (!file_name[0]) { /* nope, "-F device" */ + int p = k+1; /* argv[p] is argnext */ + file_name = argnext; + if (!file_name) + bb_error_msg_and_die(bb_msg_requires_arg, "-F"); + /* remove -F param from arg[vc] */ + --argc; + while (argv[p]) { argv[p] = argv[p+1]; ++p; } + } + goto end_option; + default: + bb_error_msg_and_die("invalid argument '%s'", arg); + } + } +end_option: + continue; + } + + mp = find_mode(arg); + if (mp) { + noargs = 0; + continue; + } + + cp = find_control(arg); + if (cp) { + if (!argnext) + bb_error_msg_and_die(bb_msg_requires_arg, arg); + /* called for the side effect of xfunc death only */ + set_control_char_or_die(cp, argnext, &mode); + noargs = 0; + ++k; + continue; + } + + param = find_param(arg); + if (param & param_need_arg) { + if (!argnext) + bb_error_msg_and_die(bb_msg_requires_arg, arg); + ++k; + } + + switch (param) { +#ifdef HAVE_C_LINE + case param_line: +# ifndef TIOCGWINSZ + xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); + break; +# endif /* else fall-through */ +#endif +#ifdef TIOCGWINSZ + case param_rows: + case param_cols: + xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); + break; + case param_size: +#endif + case param_speed: + break; + case param_ispeed: + /* called for the side effect of xfunc death only */ + set_speed_or_die(input_speed, argnext, &mode); + break; + case param_ospeed: + /* called for the side effect of xfunc death only */ + set_speed_or_die(output_speed, argnext, &mode); + break; + default: + if (recover_mode(arg, &mode) == 1) break; + if (string_to_baud_or_die(arg) != (speed_t) -1) break; + bb_error_msg_and_die("invalid argument '%s'", arg); + } + noargs = 0; + } + + /* Specifying both -a and -g is an error */ + if (verbose_output && recoverable_output) + bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive"); + /* Specifying -a or -g with non-options is an error */ + if (!noargs && (verbose_output || recoverable_output)) + bb_error_msg_and_die("modes may not be set when specifying an output style"); + + /* Now it is safe to start doing things */ + if (file_name) { + int fd, fdflags; + device_name = file_name; + fd = xopen(device_name, O_RDONLY | O_NONBLOCK); + if (fd != STDIN_FILENO) { + dup2(fd, STDIN_FILENO); + close(fd); } + fdflags = fcntl(STDIN_FILENO, F_GETFL); + if (fdflags == -1 || fcntl(STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0) + perror_on_device_and_die("%s: cannot reset non-blocking mode"); } - if (current_col) wrapf("\n"); -} -static void display_all(const struct termios *mode) -{ - int i; - tcflag_t *bitsp; - unsigned long mask; - int prev_type = control; + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure */ + memset(&mode, 0, sizeof(mode)); + if (tcgetattr(STDIN_FILENO, &mode)) + perror_on_device_and_die("%s"); - display_speed(mode, 1); - display_window_size(1); -#ifdef HAVE_C_LINE - wrapf("line = %d;\n", mode->c_line); -#else - wrapf("\n"); -#endif + if (verbose_output || recoverable_output || noargs) { + max_col = screen_columns_or_die(); + output_func(&mode); + return EXIT_SUCCESS; + } - for (i = 0; control_info[i].name != stty_min; ++i) { - /* If swtch is the same as susp, don't print both */ -#if VSWTCH == VSUSP - if (control_info[i].name == stty_swtch) + /* Second pass: perform actions */ + k = 0; + while (argv[++k]) { + const struct mode_info *mp; + const struct control_info *cp; + const char *arg = argv[k]; + const char *argnext = argv[k+1]; + int param; + + if (arg[0] == '-') { + mp = find_mode(arg+1); + if (mp) { + set_mode(mp, 1 /* reversed */, &mode); + } + /* It is an option - already parsed. Skip it */ continue; -#endif - /* If eof uses the same slot as min, only print whichever applies */ -#if VEOF == VMIN - if ((mode->c_lflag & ICANON) == 0 - && (control_info[i].name == stty_eof - || control_info[i].name == stty_eol)) continue; -#endif - wrapf("%s = %s;", control_info[i].name, - visible(mode->c_cc[control_info[i].offset])); - } -#if VEOF == VMIN - if ((mode->c_lflag & ICANON) == 0) -#endif - wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); - if (current_col) wrapf("\n"); + } - for (i = 0; i < NUM_mode_info; ++i) { - if (mode_info[i].flags & OMIT) + mp = find_mode(arg); + if (mp) { + set_mode(mp, 0 /* non-reversed */, &mode); continue; - if (mode_info[i].type != prev_type) { - wrapf("\n"); - prev_type = mode_info[i].type; } - bitsp = mode_type_flag(mode_info[i].type, mode); - mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; - if ((*bitsp & mask) == mode_info[i].bits) - wrapf("%s", mode_info[i].name); - else if (mode_info[i].flags & REV) - wrapf("-%s", mode_info[i].name); - } - if (current_col) wrapf("\n"); -} + cp = find_control(arg); + if (cp) { + ++k; + set_control_char_or_die(cp, argnext, &mode); + continue; + } -static void display_speed(const struct termios *mode, int fancy) -{ - //01234567 8 9 - const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;"; - unsigned long ispeed, ospeed; + param = find_param(arg); + if (param & param_need_arg) { + ++k; + } - ospeed = ispeed = cfgetispeed(mode); - if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) { - ispeed = ospeed; /* in case ispeed was 0 */ - //0123 4 5 6 7 8 9 - fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;"; + switch (param) { +#ifdef HAVE_C_LINE + case param_line: + mode.c_line = xatoul_sfx(argnext, stty_suffixes); + require_set_attr = 1; + break; +#endif +#ifdef TIOCGWINSZ + case param_cols: + set_window_size(-1, xatoul_sfx(argnext, stty_suffixes)); + break; + case param_size: + display_window_size(0); + break; + case param_rows: + set_window_size(xatoul_sfx(argnext, stty_suffixes), -1); + break; +#endif + case param_speed: + display_speed(&mode, 0); + break; + case param_ispeed: + set_speed_or_die(input_speed, argnext, &mode); + speed_was_set = 1; + require_set_attr = 1; + break; + case param_ospeed: + set_speed_or_die(output_speed, argnext, &mode); + speed_was_set = 1; + require_set_attr = 1; + break; + default: + if (recover_mode(arg, &mode) == 1) + require_set_attr = 1; + else /* true: if (string_to_baud_or_die(arg) != (speed_t) -1) */ { + set_speed_or_die(both_speeds, arg, &mode); + speed_was_set = 1; + require_set_attr = 1; + } /* else - impossible (caught in the first pass): + bb_error_msg_and_die("invalid argument '%s'", arg); */ + } } - if (fancy) fmt_str += 9; - wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); -} - -static void display_recoverable(const struct termios *mode) -{ - int i; - printf("%lx:%lx:%lx:%lx", - (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, - (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); - for (i = 0; i < NCCS; ++i) - printf(":%x", (unsigned int) mode->c_cc[i]); - putchar('\n'); -} -static int recover_mode(const char *arg, struct termios *mode) -{ - int i, n; - unsigned int chr; - unsigned long iflag, oflag, cflag, lflag; + if (require_set_attr) { + struct termios new_mode; - /* Scan into temporaries since it is too much trouble to figure out - the right format for 'tcflag_t' */ - if (sscanf(arg, "%lx:%lx:%lx:%lx%n", - &iflag, &oflag, &cflag, &lflag, &n) != 4) - return 0; - mode->c_iflag = iflag; - mode->c_oflag = oflag; - mode->c_cflag = cflag; - mode->c_lflag = lflag; - arg += n; - for (i = 0; i < NCCS; ++i) { - if (sscanf(arg, ":%x%n", &chr, &n) != 1) - return 0; - mode->c_cc[i] = chr; - arg += n; - } + if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) + perror_on_device_and_die("%s"); - /* Fail if there are too many fields */ - if (*arg != '\0') - return 0; + /* POSIX (according to Zlotnick's book) tcsetattr returns zero if + it performs *any* of the requested operations. This means it + can report 'success' when it has actually failed to perform + some proper subset of the requested operations. To detect + this partial failure, get the current terminal attributes and + compare them to the requested ones */ - return 1; -} + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure */ + memset(&new_mode, 0, sizeof(new_mode)); + if (tcgetattr(STDIN_FILENO, &new_mode)) + perror_on_device_and_die("%s"); -static void sane_mode(struct termios *mode) -{ - int i; - tcflag_t *bitsp; + if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { +#ifdef CIBAUD + /* SunOS 4.1.3 (at least) has the problem that after this sequence, + tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); + sometimes (m1 != m2). The only difference is in the four bits + of the c_cflag field corresponding to the baud rate. To save + Sun users a little confusion, don't report an error if this + happens. But suppress the error only if we haven't tried to + set the baud rate explicitly -- otherwise we'd never give an + error for a true failure to set the baud rate */ - for (i = 0; i < NUM_control_info; ++i) { -#if VMIN == VEOF - if (control_info[i].name == stty_min) - break; + new_mode.c_cflag &= (~CIBAUD); + if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) #endif - mode->c_cc[control_info[i].offset] = control_info[i].saneval; - } - - for (i = 0; i < NUM_mode_info; ++i) { - if (mode_info[i].flags & SANE_SET) { - bitsp = mode_type_flag(mode_info[i].type, mode); - *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask)) - | mode_info[i].bits; - } else if (mode_info[i].flags & SANE_UNSET) { - bitsp = mode_type_flag(mode_info[i].type, mode); - *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask) - & ~mode_info[i].bits; + perror_on_device_and_die("%s: cannot perform all requested operations"); } } + + return EXIT_SUCCESS; } -- 2.25.1