Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/coreutils/stty.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/coreutils/stty.c
r821 r1770 22 22 */ 23 23 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" 52 25 53 26 #ifndef _POSIX_VDISABLE … … 56 29 57 30 #define Control(c) ((c) & 0x1f) 58 /* Canonical values for control characters .*/31 /* Canonical values for control characters */ 59 32 #ifndef CINTR 60 # define CINTR Control 33 # define CINTR Control('c') 61 34 #endif 62 35 #ifndef CQUIT … … 67 40 #endif 68 41 #ifndef CKILL 69 # define CKILL Control 42 # define CKILL Control('u') 70 43 #endif 71 44 #ifndef CEOF 72 # define CEOF Control 45 # define CEOF Control('d') 73 46 #endif 74 47 #ifndef CEOL … … 76 49 #endif 77 50 #ifndef CSTART 78 # define CSTART Control 51 # define CSTART Control('q') 79 52 #endif 80 53 #ifndef CSTOP 81 # define CSTOP Control 54 # define CSTOP Control('s') 82 55 #endif 83 56 #ifndef CSUSP 84 # define CSUSP Control 57 # define CSUSP Control('z') 85 58 #endif 86 59 #if defined(VEOL2) && !defined(CEOL2) 87 60 # define CEOL2 _POSIX_VDISABLE 88 61 #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 */ 90 63 #if defined(VSUSP) && !defined(VSWTCH) 91 64 # define VSWTCH VSUSP … … 96 69 #endif 97 70 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__) 101 74 # undef CSWTCH 102 75 # define CSWTCH _POSIX_VDISABLE 103 76 #endif 104 77 105 #if defined(VWERSE) && !defined 78 #if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */ 106 79 # define VWERASE VWERSE 107 80 #endif 108 #if defined(VDSUSP) && !defined 109 # define CDSUSP Control 81 #if defined(VDSUSP) && !defined(CDSUSP) 82 # define CDSUSP Control('y') 110 83 #endif 111 84 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */ … … 113 86 #endif 114 87 #if defined(VREPRINT) && !defined(CRPRNT) 115 # define CRPRNT Control 88 # define CRPRNT Control('r') 116 89 #endif 117 90 #if defined(VWERASE) && !defined(CWERASE) 118 # define CWERASE Control 91 # define CWERASE Control('w') 119 92 #endif 120 93 #if defined(VLNEXT) && !defined(CLNEXT) 121 # define CLNEXT Control 94 # define CLNEXT Control('v') 122 95 #endif 123 96 #if defined(VDISCARD) && !defined(VFLUSHO) … … 137 110 #endif 138 111 #if defined(VFLUSHO) && !defined(CFLUSHO) 139 # define CFLUSHO Control 112 # define CFLUSHO Control('o') 140 113 #endif 141 114 #if defined(VSTATUS) && !defined(CSTATUS) 142 # define CSTATUS Control 143 #endif 144 145 /* Which speeds to set .*/115 # define CSTATUS Control('t') 116 #endif 117 118 /* Which speeds to set */ 146 119 enum speed_setting { 147 120 input_speed, output_speed, both_speeds 148 121 }; 149 122 150 /* Which member(s) of `struct termios' a mode uses.*/151 enum mode_type{123 /* Which member(s) of 'struct termios' a mode uses */ 124 enum { 152 125 /* Do NOT change the order or values, as mode_type_flag() 153 * depends on them .*/126 * depends on them */ 154 127 control, input, output, local, combination 155 128 }; 156 129 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. */ 130 static const char evenp [] ALIGN1 = "evenp"; 131 static const char raw [] ALIGN1 = "raw"; 132 static const char stty_min [] ALIGN1 = "min"; 133 static const char stty_time [] ALIGN1 = "time"; 134 static const char stty_swtch[] ALIGN1 = "swtch"; 135 static const char stty_eol [] ALIGN1 = "eol"; 136 static const char stty_eof [] ALIGN1 = "eof"; 137 static const char parity [] ALIGN1 = "parity"; 138 static const char stty_oddp [] ALIGN1 = "oddp"; 139 static const char stty_nl [] ALIGN1 = "nl"; 140 static const char stty_ek [] ALIGN1 = "ek"; 141 static const char stty_sane [] ALIGN1 = "sane"; 142 static const char cbreak [] ALIGN1 = "cbreak"; 143 static const char stty_pass8[] ALIGN1 = "pass8"; 144 static const char litout [] ALIGN1 = "litout"; 145 static const char cooked [] ALIGN1 = "cooked"; 146 static const char decctlq [] ALIGN1 = "decctlq"; 147 static const char stty_tabs [] ALIGN1 = "tabs"; 148 static const char stty_lcase[] ALIGN1 = "lcase"; 149 static const char stty_LCASE[] ALIGN1 = "LCASE"; 150 static const char stty_crt [] ALIGN1 = "crt"; 151 static 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 */ 189 160 struct mode_info { 190 const char * name; /* Name given on command line.*/191 /* enum mode_type type;*/192 c har 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 */ 196 167 }; 197 168 169 /* We can optimize it further by using name[8] instead of char *name */ 170 /* but beware of "if (info->name == evenp)" checks! */ 171 /* Need to replace them with "if (info == &mode_info[EVENP_INDX])" */ 172 198 173 #define MI_ENTRY(N,T,F,B,M) { N, T, F, M, B } 199 174 200 static const struct 175 static const struct mode_info mode_info[] = { 201 176 MI_ENTRY("parenb", control, REV, PARENB, 0 ), 202 177 MI_ENTRY("parodd", control, REV, PARODD, 0 ), … … 333 308 MI_ENTRY(decctlq, combination, REV | OMIT, 0, 0 ), 334 309 #endif 335 #if defined (TABDLY) || defined(OXTABS)310 #if defined(TABDLY) || defined(OXTABS) 336 311 MI_ENTRY(stty_tabs, combination, REV | OMIT, 0, 0 ), 337 312 #endif … … 345 320 346 321 enum { 347 NUM_mode_info = 348 (sizeof(mode_info) / sizeof(struct mode_info)) 322 NUM_mode_info = ARRAY_SIZE(mode_info) 349 323 }; 350 324 351 /* Control character settings .*/325 /* Control character settings */ 352 326 struct 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 */ 356 330 }; 357 331 358 /* Control characters .*/359 360 static const struct 332 /* Control characters */ 333 334 static const struct control_info control_info[] = { 361 335 {"intr", CINTR, VINTR}, 362 336 {"quit", CQUIT, VQUIT}, … … 392 366 {"status", CSTATUS, VSTATUS}, 393 367 #endif 394 /* These must be last because of the display routines .*/368 /* These must be last because of the display routines */ 395 369 {stty_min, 1, VMIN}, 396 370 {stty_time, 0, VTIME}, … … 398 372 399 373 enum { 400 NUM_control_info = 401 (sizeof(control_info) / sizeof(struct control_info)) 374 NUM_control_info = ARRAY_SIZE(control_info) 402 375 }; 403 376 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 */ 378 unsigned max_col = 80; /* default */ 379 380 struct 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 387 static 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 */ 391 static 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 418 static 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 433 static 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 448 static ATTRIBUTE_NORETURN void perror_on_device_and_die(const char *fmt) 428 449 { 429 450 bb_perror_msg_and_die(fmt, device_name); 430 451 } 431 452 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; 453 static void perror_on_device(const char *fmt) 454 { 455 bb_perror_msg(fmt, device_name); 456 } 438 457 439 458 /* Print format string MESSAGE and optional args. 440 459 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 */ 443 461 static void wrapf(const char *message, ...) 444 462 { 463 char buf[128]; 445 464 va_list args; 446 char buf[1024]; /* Plenty long for our needs. */447 465 int buflen; 448 466 449 467 va_start(args, message); 450 vsprintf(buf, message, args);468 buflen = vsnprintf(buf, sizeof(buf), message, args); 451 469 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 } 460 483 } 461 484 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 490 static 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 } 950 498 memset(&win, 0, sizeof(win)); 951 499 } … … 956 504 win.ws_col = cols; 957 505 958 # ifdef TIOCSSIZE959 /* 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 better962 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 # endif980 981 506 if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win)) 507 bail: 982 508 perror_on_device("%s"); 983 509 } 984 510 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)) {511 static 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)) { 991 517 if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) { 992 518 perror_on_device(fmt_str); … … 994 520 } else { 995 521 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 526 static const struct suffix_mult stty_suffixes[] = { 527 { "b", 512 }, 528 { "k", 1024 }, 529 { "B", 1024 }, 530 { } 531 }; 532 533 static const struct mode_info *find_mode(const char *name) 1044 534 { 1045 535 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 542 static const struct control_info *find_control(const char *name) 1119 543 { 1120 544 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 551 enum { 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 563 static 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 582 static int recover_mode(const char *arg, struct termios *mode) 1211 583 { 1212 584 int i, n; 1213 unsigned intchr;585 unsigned chr; 1214 586 unsigned long iflag, oflag, cflag, lflag; 1215 587 1216 588 /* 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' */ 1218 590 if (sscanf(arg, "%lx:%lx:%lx:%lx%n", 1219 591 &iflag, &oflag, &cflag, &lflag, &n) != 4) … … 1231 603 } 1232 604 1233 /* Fail if there are too many fields .*/605 /* Fail if there are too many fields */ 1234 606 if (*arg != '\0') 1235 607 return 0; … … 1238 610 } 1239 611 1240 static speed_t string_to_baud(const char *arg) 1241 { 1242 return tty_value_to_baud(bb_xparse_number(arg, 0)); 612 static 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 624 static 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 640 static 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"); 1243 699 } 1244 700 … … 1258 714 for (i = 0; i < NUM_mode_info; ++i) { 1259 715 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); 1261 717 *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask)) 1262 718 | mode_info[i].bits; 1263 719 } 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); 1265 721 *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask) 1266 722 & ~mode_info[i].bits; … … 1269 725 } 1270 726 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 762 static 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 889 static 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) 914 int stty_main(int argc, char **argv); 915 int 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.