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 */
}
}
-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;
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;
}