1/* vi: set sw=4 ts=4: */ 2/* stty -- change and print terminal line settings 3 Copyright (C) 1990-1999 Free Software Foundation, Inc. 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2, or (at your option) 8 any later version. 9 10 You should have received a copy of the GNU General Public License 11 along with this program; if not, write to the Free Software Foundation, 12 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 13 14/* Usage: stty [-ag] [-F device] [setting...] 15 16 Options: 17 -a Write all current settings to stdout in human-readable form. 18 -g Write all current settings to stdout in stty-readable form. 19 -F Open and use the specified device instead of stdin 20 21 If no args are given, write to stdout the baud rate and settings that 22 have been changed from their defaults. Mode reading and changes 23 are done on the specified device, or stdin if none was specified. 24 25 David MacKenzie <djm@gnu.ai.mit.edu> 26 27 Special for busybox ported by Vladimir Oleynik <dzo@simtreas.ru> 2001 28 29 */ 30 31//#define TEST 32 33#include <termios.h> 34#include <sys/ioctl.h> 35#include <getopt.h> 36 37#include <sys/param.h> 38#include <unistd.h> 39 40#ifndef STDIN_FILENO 41# define STDIN_FILENO 0 42#endif 43 44#ifndef STDOUT_FILENO 45# define STDOUT_FILENO 1 46#endif 47 48#include <stdlib.h> 49#include <string.h> 50#include <assert.h> 51#include <ctype.h> 52#include <errno.h> 53#include <limits.h> 54#include <memory.h> 55#include <fcntl.h> 56#include "busybox.h" 57 58#define STREQ(a, b) (strcmp ((a), (b)) == 0) 59 60 61#ifndef _POSIX_VDISABLE 62# define _POSIX_VDISABLE ((unsigned char) 0) 63#endif 64 65#define Control(c) ((c) & 0x1f) 66/* Canonical values for control characters. */ 67#ifndef CINTR 68# define CINTR Control ('c') 69#endif 70#ifndef CQUIT 71# define CQUIT 28 72#endif 73#ifndef CERASE 74# define CERASE 127 75#endif 76#ifndef CKILL 77# define CKILL Control ('u') 78#endif 79#ifndef CEOF 80# define CEOF Control ('d') 81#endif 82#ifndef CEOL 83# define CEOL _POSIX_VDISABLE 84#endif 85#ifndef CSTART 86# define CSTART Control ('q') 87#endif 88#ifndef CSTOP 89# define CSTOP Control ('s') 90#endif 91#ifndef CSUSP 92# define CSUSP Control ('z') 93#endif 94#if defined(VEOL2) && !defined(CEOL2) 95# define CEOL2 _POSIX_VDISABLE 96#endif 97/* ISC renamed swtch to susp for termios, but we'll accept either name. */ 98#if defined(VSUSP) && !defined(VSWTCH) 99# define VSWTCH VSUSP 100# define CSWTCH CSUSP 101#endif 102#if defined(VSWTCH) && !defined(CSWTCH) 103# define CSWTCH _POSIX_VDISABLE 104#endif 105 106/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'. 107 So the default is to disable `swtch.' */ 108#if defined(__sparc__) && defined(__svr4__) 109# undef CSWTCH 110# define CSWTCH _POSIX_VDISABLE 111#endif 112 113#if defined(VWERSE) && !defined(VWERASE) /* AIX-3.2.5 */ 114# define VWERASE VWERSE 115#endif 116#if defined(VDSUSP) && !defined(CDSUSP) 117# define CDSUSP Control ('y') 118#endif 119#if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */ 120# define VREPRINT VRPRNT 121#endif 122#if defined(VREPRINT) && !defined(CRPRNT) 123# define CRPRNT Control ('r') 124#endif 125#if defined(VWERASE) && !defined(CWERASE) 126# define CWERASE Control ('w') 127#endif 128#if defined(VLNEXT) && !defined(CLNEXT) 129# define CLNEXT Control ('v') 130#endif 131#if defined(VDISCARD) && !defined(VFLUSHO) 132# define VFLUSHO VDISCARD 133#endif 134#if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */ 135# define VFLUSHO VFLUSH 136#endif 137#if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */ 138# define ECHOCTL CTLECH 139#endif 140#if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */ 141# define ECHOCTL TCTLECH 142#endif 143#if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */ 144# define ECHOKE CRTKIL 145#endif 146#if defined(VFLUSHO) && !defined(CFLUSHO) 147# define CFLUSHO Control ('o') 148#endif 149#if defined(VSTATUS) && !defined(CSTATUS) 150# define CSTATUS Control ('t') 151#endif 152 153/* Which speeds to set. */ 154enum speed_setting { 155 input_speed, output_speed, both_speeds 156}; 157 158/* What to output and how. */ 159enum output_type { 160 changed, all, recoverable /* Default, -a, -g. */ 161}; 162 163/* Which member(s) of `struct termios' a mode uses. */ 164enum mode_type { 165 control, input, output, local, combination 166}; 167 168 169static const char evenp [] = "evenp"; 170static const char raw [] = "raw"; 171static const char stty_min [] = "min"; 172static const char stty_time [] = "time"; 173static const char stty_swtch[] = "swtch"; 174static const char stty_eol [] = "eol"; 175static const char stty_eof [] = "eof"; 176static const char parity [] = "parity"; 177static const char stty_oddp [] = "oddp"; 178static const char stty_nl [] = "nl"; 179static const char stty_ek [] = "ek"; 180static const char stty_sane [] = "sane"; 181static const char cbreak [] = "cbreak"; 182static const char stty_pass8[] = "pass8"; 183static const char litout [] = "litout"; 184static const char cooked [] = "cooked"; 185static const char decctlq [] = "decctlq"; 186static const char stty_tabs [] = "tabs"; 187static const char stty_lcase[] = "lcase"; 188static const char stty_LCASE[] = "LCASE"; 189static const char stty_crt [] = "crt"; 190static const char stty_dec [] = "dec"; 191 192 193/* Flags for `struct mode_info'. */ 194#define SANE_SET 1 /* Set in `sane' mode. */ 195#define SANE_UNSET 2 /* Unset in `sane' mode. */ 196#define REV 4 /* Can be turned off by prepending `-'. */ 197#define OMIT 8 /* Don't display value. */ 198 199/* Each mode. */ 200struct mode_info { 201 const char *name; /* Name given on command line. */ 202 enum mode_type type; /* Which structure element to change. */ 203 char flags; /* Setting and display options. */ 204 unsigned long bits; /* Bits to set for this mode. */ 205 unsigned long mask; /* Other bits to turn off for this mode. */ 206}; 207 208static const struct mode_info mode_info[] = { 209 {"parenb", control, REV, PARENB, 0 }, 210 {"parodd", control, REV, PARODD, 0 }, 211 {"cs5", control, 0, CS5, CSIZE}, 212 {"cs6", control, 0, CS6, CSIZE}, 213 {"cs7", control, 0, CS7, CSIZE}, 214 {"cs8", control, 0, CS8, CSIZE}, 215 {"hupcl", control, REV, HUPCL, 0 }, 216 {"hup", control, REV | OMIT, HUPCL, 0 }, 217 {"cstopb", control, REV, CSTOPB, 0 }, 218 {"cread", control, SANE_SET | REV, CREAD, 0 }, 219 {"clocal", control, REV, CLOCAL, 0 }, 220#ifdef CRTSCTS 221 {"crtscts", control, REV, CRTSCTS, 0 }, 222#endif 223 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 }, 224 {"brkint", input, SANE_SET | REV, BRKINT, 0 }, 225 {"ignpar", input, REV, IGNPAR, 0 }, 226 {"parmrk", input, REV, PARMRK, 0 }, 227 {"inpck", input, REV, INPCK, 0 }, 228 {"istrip", input, REV, ISTRIP, 0 }, 229 {"inlcr", input, SANE_UNSET | REV, INLCR, 0 }, 230 {"igncr", input, SANE_UNSET | REV, IGNCR, 0 }, 231 {"icrnl", input, SANE_SET | REV, ICRNL, 0 }, 232 {"ixon", input, REV, IXON, 0 }, 233 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0 }, 234 {"tandem", input, REV | OMIT, IXOFF, 0 }, 235#ifdef IUCLC 236 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0 }, 237#endif 238#ifdef IXANY 239 {"ixany", input, SANE_UNSET | REV, IXANY, 0 }, 240#endif 241#ifdef IMAXBEL 242 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0 }, 243#endif 244 {"opost", output, SANE_SET | REV, OPOST, 0 }, 245#ifdef OLCUC 246 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0 }, 247#endif 248#ifdef OCRNL 249 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0 }, 250#endif 251#ifdef ONLCR 252 {"onlcr", output, SANE_SET | REV, ONLCR, 0 }, 253#endif 254#ifdef ONOCR 255 {"onocr", output, SANE_UNSET | REV, ONOCR, 0 }, 256#endif 257#ifdef ONLRET 258 {"onlret", output, SANE_UNSET | REV, ONLRET, 0 }, 259#endif 260#ifdef OFILL 261 {"ofill", output, SANE_UNSET | REV, OFILL, 0 }, 262#endif 263#ifdef OFDEL 264 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0 }, 265#endif 266#ifdef NLDLY 267 {"nl1", output, SANE_UNSET, NL1, NLDLY}, 268 {"nl0", output, SANE_SET, NL0, NLDLY}, 269#endif 270#ifdef CRDLY 271 {"cr3", output, SANE_UNSET, CR3, CRDLY}, 272 {"cr2", output, SANE_UNSET, CR2, CRDLY}, 273 {"cr1", output, SANE_UNSET, CR1, CRDLY}, 274 {"cr0", output, SANE_SET, CR0, CRDLY}, 275#endif 276 277#ifdef TABDLY 278 {"tab3", output, SANE_UNSET, TAB3, TABDLY}, 279 {"tab2", output, SANE_UNSET, TAB2, TABDLY}, 280 {"tab1", output, SANE_UNSET, TAB1, TABDLY}, 281 {"tab0", output, SANE_SET, TAB0, TABDLY}, 282#else 283# ifdef OXTABS 284 {"tab3", output, SANE_UNSET, OXTABS, 0 }, 285# endif 286#endif 287 288#ifdef BSDLY 289 {"bs1", output, SANE_UNSET, BS1, BSDLY}, 290 {"bs0", output, SANE_SET, BS0, BSDLY}, 291#endif 292#ifdef VTDLY 293 {"vt1", output, SANE_UNSET, VT1, VTDLY}, 294 {"vt0", output, SANE_SET, VT0, VTDLY}, 295#endif 296#ifdef FFDLY 297 {"ff1", output, SANE_UNSET, FF1, FFDLY}, 298 {"ff0", output, SANE_SET, FF0, FFDLY}, 299#endif 300 {"isig", local, SANE_SET | REV, ISIG, 0 }, 301 {"icanon", local, SANE_SET | REV, ICANON, 0 }, 302#ifdef IEXTEN 303 {"iexten", local, SANE_SET | REV, IEXTEN, 0 }, 304#endif 305 {"echo", local, SANE_SET | REV, ECHO, 0 }, 306 {"echoe", local, SANE_SET | REV, ECHOE, 0 }, 307 {"crterase", local, REV | OMIT, ECHOE, 0 }, 308 {"echok", local, SANE_SET | REV, ECHOK, 0 }, 309 {"echonl", local, SANE_UNSET | REV, ECHONL, 0 }, 310 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0 }, 311#ifdef XCASE 312 {"xcase", local, SANE_UNSET | REV, XCASE, 0 }, 313#endif 314#ifdef TOSTOP 315 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0 }, 316#endif 317#ifdef ECHOPRT 318 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 }, 319 {"prterase", local, REV | OMIT, ECHOPRT, 0 }, 320#endif 321#ifdef ECHOCTL 322 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0 }, 323 {"ctlecho", local, REV | OMIT, ECHOCTL, 0 }, 324#endif 325#ifdef ECHOKE 326 {"echoke", local, SANE_SET | REV, ECHOKE, 0 }, 327 {"crtkill", local, REV | OMIT, ECHOKE, 0 }, 328#endif 329 {evenp, combination, REV | OMIT, 0, 0 }, 330 {parity, combination, REV | OMIT, 0, 0 }, 331 {stty_oddp, combination, REV | OMIT, 0, 0 }, 332 {stty_nl, combination, REV | OMIT, 0, 0 }, 333 {stty_ek, combination, OMIT, 0, 0 }, 334 {stty_sane, combination, OMIT, 0, 0 }, 335 {cooked, combination, REV | OMIT, 0, 0 }, 336 {raw, combination, REV | OMIT, 0, 0 }, 337 {stty_pass8, combination, REV | OMIT, 0, 0 }, 338 {litout, combination, REV | OMIT, 0, 0 }, 339 {cbreak, combination, REV | OMIT, 0, 0 }, 340#ifdef IXANY 341 {decctlq, combination, REV | OMIT, 0, 0 }, 342#endif 343#if defined(TABDLY) || defined(OXTABS) 344 {stty_tabs, combination, REV | OMIT, 0, 0 }, 345#endif 346#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) 347 {stty_lcase, combination, REV | OMIT, 0, 0 }, 348 {stty_LCASE, combination, REV | OMIT, 0, 0 }, 349#endif 350 {stty_crt, combination, OMIT, 0, 0 }, 351 {stty_dec, combination, OMIT, 0, 0 }, 352}; 353 354static const int NUM_mode_info = 355 356 (sizeof(mode_info) / sizeof(struct mode_info)); 357 358/* Control character settings. */ 359struct control_info { 360 const char *name; /* Name given on command line. */ 361 unsigned char saneval; /* Value to set for `stty sane'. */ 362 int offset; /* Offset in c_cc. */ 363}; 364 365/* Control characters. */ 366 367static const struct control_info control_info[] = { 368 {"intr", CINTR, VINTR}, 369 {"quit", CQUIT, VQUIT}, 370 {"erase", CERASE, VERASE}, 371 {"kill", CKILL, VKILL}, 372 {stty_eof, CEOF, VEOF}, 373 {stty_eol, CEOL, VEOL}, 374#ifdef VEOL2 375 {"eol2", CEOL2, VEOL2}, 376#endif 377#ifdef VSWTCH 378 {stty_swtch, CSWTCH, VSWTCH}, 379#endif 380 {"start", CSTART, VSTART}, 381 {"stop", CSTOP, VSTOP}, 382 {"susp", CSUSP, VSUSP}, 383#ifdef VDSUSP 384 {"dsusp", CDSUSP, VDSUSP}, 385#endif 386#ifdef VREPRINT 387 {"rprnt", CRPRNT, VREPRINT}, 388#endif 389#ifdef VWERASE 390 {"werase", CWERASE, VWERASE}, 391#endif 392#ifdef VLNEXT 393 {"lnext", CLNEXT, VLNEXT}, 394#endif 395#ifdef VFLUSHO 396 {"flush", CFLUSHO, VFLUSHO}, 397#endif 398#ifdef VSTATUS 399 {"status", CSTATUS, VSTATUS}, 400#endif 401 /* These must be last because of the display routines. */ 402 {stty_min, 1, VMIN}, 403 {stty_time, 0, VTIME}, 404}; 405 406static const int NUM_control_info = 407 (sizeof(control_info) / sizeof(struct control_info)); 408 409 410static const char * visible(unsigned int ch); 411static unsigned long baud_to_value(speed_t speed); 412static int recover_mode(char *arg, struct termios *mode); 413static int screen_columns(void); 414static int set_mode(const struct mode_info *info, 415 int reversed, struct termios *mode); 416static speed_t string_to_baud(const char *arg); 417static tcflag_t* mode_type_flag(enum mode_type type, struct termios *mode); 418static void display_all(struct termios *mode, int fd, 419 const char *device_name); 420static void display_changed(struct termios *mode); 421static void display_recoverable(struct termios *mode); 422static void display_settings(enum output_type output_type, 423 struct termios *mode, int fd, 424 const char *device_name); 425static void display_speed(struct termios *mode, int fancy); 426static void display_window_size(int fancy, int fd, 427 const char *device_name); 428static void sane_mode(struct termios *mode); 429static void set_control_char(const struct control_info *info, 430 const char *arg, struct termios *mode); 431static void set_speed(enum speed_setting type, 432 const char *arg, struct termios *mode); 433static void set_window_size(int rows, int cols, int fd, 434 const char *device_name); 435 436/* The width of the screen, for output wrapping. */ 437static int max_col; 438 439/* Current position, to know when to wrap. */ 440static int current_col; 441 442/* Print format string MESSAGE and optional args. 443 Wrap to next line first if it won't fit. 444 Print a space first unless MESSAGE will start a new line. */ 445 446static void wrapf(const char *message, ...) 447{ 448 va_list args; 449 char buf[1024]; /* Plenty long for our needs. */ 450 int buflen; 451 452 va_start(args, message); 453 vsprintf(buf, message, args); 454 va_end(args); 455 buflen = strlen(buf); 456 if (current_col + (current_col > 0) + buflen >= max_col) { 457 putchar('\n'); 458 current_col = 0; 459 } 460 if (current_col > 0) { 461 putchar(' '); 462 current_col++; 463 } 464 fputs(buf, stdout); 465 current_col += buflen; 466} 467 468static const struct suffix_mult stty_suffixes[] = { 469 {"b", 512 }, 470 {"k", 1024}, 471 {"B", 1024}, 472 {NULL, 0 } 473}; 474 475#ifndef TEST 476extern int stty_main(int argc, char **argv) 477#else 478extern int main(int argc, char **argv) 479#endif 480{ 481 struct termios mode; 482 enum output_type output_type; 483 int optc; 484 int require_set_attr; 485 int speed_was_set; 486 int verbose_output; 487 int recoverable_output; 488 int k; 489 int noargs = 1; 490 char * file_name = NULL; 491 int fd; 492 const char *device_name; 493 494 output_type = changed; 495 verbose_output = 0; 496 recoverable_output = 0; 497 498 /* Don't print error messages for unrecognized options. */ 499 opterr = 0; 500 501 while ((optc = getopt(argc, argv, "agF:")) != -1) { 502 switch (optc) { 503 case 'a': 504 verbose_output = 1; 505 output_type = all; 506 break; 507 508 case 'g': 509 recoverable_output = 1; 510 output_type = recoverable; 511 break; 512 513 case 'F': 514 if (file_name) 515 error_msg_and_die("only one device may be specified"); 516 file_name = optarg; 517 break; 518 519 default: /* unrecognized option */ 520 noargs = 0; 521 break; 522 } 523 524 if (noargs == 0) 525 break; 526 } 527 528 if (optind < argc) 529 noargs = 0; 530 531 /* Specifying both -a and -g gets an error. */ 532 if (verbose_output && recoverable_output) 533 error_msg_and_die ("verbose and stty-readable output styles are mutually exclusive"); 534 535 /* Specifying any other arguments with -a or -g gets an error. */ 536 if (!noargs && (verbose_output || recoverable_output)) 537 error_msg_and_die ("modes may not be set when specifying an output style"); 538 539 540 if (file_name) { 541 int fdflags; 542 543 device_name = file_name; 544 fd = open(device_name, O_RDONLY | O_NONBLOCK); 545 if (fd < 0) 546 perror_msg_and_die("%s", device_name); 547 if ((fdflags = fcntl(fd, F_GETFL)) == -1 548 || fcntl(fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0) 549 perror_msg_and_die("%s: couldn't reset non-blocking mode", 550 device_name); 551 } else { 552 fd = 0; 553 device_name = "standard input"; 554 } 555 556 /* Initialize to all zeroes so there is no risk memcmp will report a 557 spurious difference in an uninitialized portion of the structure. */ 558 memset(&mode, 0, sizeof(mode)); 559 if (tcgetattr(fd, &mode)) 560 perror_msg_and_die("%s", device_name); 561 562 if (verbose_output || recoverable_output || noargs) { 563 max_col = screen_columns(); 564 current_col = 0; 565 display_settings(output_type, &mode, fd, device_name); 566 return EXIT_SUCCESS; 567 } 568 569 speed_was_set = 0; 570 require_set_attr = 0; 571 k = optind; 572 while (k < argc) { 573 int match_found = 0; 574 int reversed = 0; 575 int i; 576 577 if (argv[k][0] == '-') { 578 ++argv[k]; 579 reversed = 1; 580 } 581 for (i = 0; i < NUM_mode_info; ++i) 582 if (STREQ(argv[k], mode_info[i].name)) { 583 match_found = set_mode(&mode_info[i], reversed, &mode); 584 require_set_attr = 1; 585 break; 586 } 587 588 if (match_found == 0 && reversed) 589 error_msg_and_die("invalid argument `%s'", --argv[k]); 590 591 if (match_found == 0) 592 for (i = 0; i < NUM_control_info; ++i) 593 if (STREQ(argv[k], control_info[i].name)) { 594 if (k == argc - 1) 595 error_msg_and_die("missing argument to `%s'", argv[k]); 596 match_found = 1; 597 ++k; 598 set_control_char(&control_info[i], argv[k], &mode); 599 require_set_attr = 1; 600 break; 601 } 602 603 if (match_found == 0) { 604 if (STREQ(argv[k], "ispeed")) { 605 if (k == argc - 1) 606 error_msg_and_die("missing argument to `%s'", argv[k]); 607 ++k; 608 set_speed(input_speed, argv[k], &mode); 609 speed_was_set = 1; 610 require_set_attr = 1; 611 } else if (STREQ(argv[k], "ospeed")) { 612 if (k == argc - 1) 613 error_msg_and_die("missing argument to `%s'", argv[k]); 614 ++k; 615 set_speed(output_speed, argv[k], &mode); 616 speed_was_set = 1; 617 require_set_attr = 1; 618 } 619#ifdef TIOCGWINSZ 620 else if (STREQ(argv[k], "rows")) { 621 if (k == argc - 1) 622 error_msg_and_die("missing argument to `%s'", argv[k]); 623 ++k; 624 set_window_size((int) parse_number(argv[k], stty_suffixes), 625 -1, fd, device_name); 626 } else if (STREQ(argv[k], "cols") || STREQ(argv[k], "columns")) { 627 if (k == argc - 1) 628 error_msg_and_die("missing argument to `%s'", argv[k]); 629 ++k; 630 set_window_size(-1, 631 (int) parse_number(argv[k], stty_suffixes), 632 fd, device_name); 633 } else if (STREQ(argv[k], "size")) { 634 max_col = screen_columns(); 635 current_col = 0; 636 display_window_size(0, fd, device_name); 637 } 638#endif 639#ifdef HAVE_C_LINE 640 else if (STREQ(argv[k], "line")) { 641 if (k == argc - 1) 642 error_msg_and_die("missing argument to `%s'", argv[k]); 643 ++k; 644 mode.c_line = parse_number(argv[k], stty_suffixes); 645 require_set_attr = 1; 646 } 647#endif 648 else if (STREQ(argv[k], "speed")) { 649 max_col = screen_columns(); 650 display_speed(&mode, 0); 651 } else if (recover_mode(argv[k], &mode) == 1) 652 require_set_attr = 1; 653 else if (string_to_baud(argv[k]) != (speed_t) - 1) { 654 set_speed(both_speeds, argv[k], &mode); 655 speed_was_set = 1; 656 require_set_attr = 1; 657 } else 658 error_msg_and_die("invalid argument `%s'", argv[k]); 659 } 660 k++; 661 } 662 663 if (require_set_attr) { 664 struct termios new_mode; 665 666 if (tcsetattr(fd, TCSADRAIN, &mode)) 667 perror_msg_and_die("%s", device_name); 668 669 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if 670 it performs *any* of the requested operations. This means it 671 can report `success' when it has actually failed to perform 672 some proper subset of the requested operations. To detect 673 this partial failure, get the current terminal attributes and 674 compare them to the requested ones. */ 675 676 /* Initialize to all zeroes so there is no risk memcmp will report a 677 spurious difference in an uninitialized portion of the structure. */ 678 memset(&new_mode, 0, sizeof(new_mode)); 679 if (tcgetattr(fd, &new_mode)) 680 perror_msg_and_die("%s", device_name); 681 682 /* Normally, one shouldn't use memcmp to compare structures that 683 may have `holes' containing uninitialized data, but we have been 684 careful to initialize the storage of these two variables to all 685 zeroes. One might think it more efficient simply to compare the 686 modified fields, but that would require enumerating those fields -- 687 and not all systems have the same fields in this structure. */ 688 689 if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { 690#ifdef CIBAUD 691 /* SunOS 4.1.3 (at least) has the problem that after this sequence, 692 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); 693 sometimes (m1 != m2). The only difference is in the four bits 694 of the c_cflag field corresponding to the baud rate. To save 695 Sun users a little confusion, don't report an error if this 696 happens. But suppress the error only if we haven't tried to 697 set the baud rate explicitly -- otherwise we'd never give an 698 error for a true failure to set the baud rate. */ 699 700 new_mode.c_cflag &= (~CIBAUD); 701 if (speed_was_set || memcmp(&mode, &new_mode, sizeof(mode)) != 0) 702#endif 703 error_msg_and_die ("%s: unable to perform all requested operations", 704 device_name); 705 } 706 } 707 708 return EXIT_SUCCESS; 709} 710 711/* Return 0 if not applied because not reversible; otherwise return 1. */ 712 713static int 714set_mode(const struct mode_info *info, int reversed, struct termios *mode) 715{ 716 tcflag_t *bitsp; 717 718 if (reversed && (info->flags & REV) == 0) 719 return 0; 720 721 bitsp = mode_type_flag(info->type, mode); 722 723 if (bitsp == NULL) { 724 /* Combination mode. */ 725 if (info->name == evenp || info->name == parity) { 726 if (reversed) 727 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; 728 else 729 mode->c_cflag = 730 (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; 731 } else if (info->name == stty_oddp) { 732 if (reversed) 733 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; 734 else 735 mode->c_cflag = 736 (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; 737 } else if (info->name == stty_nl) { 738 if (reversed) { 739 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; 740 mode->c_oflag = (mode->c_oflag 741#ifdef ONLCR 742 | ONLCR 743#endif 744 ) 745#ifdef OCRNL 746 & ~OCRNL 747#endif 748#ifdef ONLRET 749 & ~ONLRET 750#endif 751 ; 752 } else { 753 mode->c_iflag = mode->c_iflag & ~ICRNL; 754#ifdef ONLCR 755 mode->c_oflag = mode->c_oflag & ~ONLCR; 756#endif 757 } 758 } else if (info->name == stty_ek) { 759 mode->c_cc[VERASE] = CERASE; 760 mode->c_cc[VKILL] = CKILL; 761 } else if (info->name == stty_sane) 762 sane_mode(mode); 763 else if (info->name == cbreak) { 764 if (reversed) 765 mode->c_lflag |= ICANON; 766 else 767 mode->c_lflag &= ~ICANON; 768 } else if (info->name == stty_pass8) { 769 if (reversed) { 770 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; 771 mode->c_iflag |= ISTRIP; 772 } else { 773 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; 774 mode->c_iflag &= ~ISTRIP; 775 } 776 } else if (info->name == litout) { 777 if (reversed) { 778 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; 779 mode->c_iflag |= ISTRIP; 780 mode->c_oflag |= OPOST; 781 } else { 782 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; 783 mode->c_iflag &= ~ISTRIP; 784 mode->c_oflag &= ~OPOST; 785 } 786 } else if (info->name == raw || info->name == cooked) { 787 if ((info->name[0] == 'r' && reversed) 788 || (info->name[0] == 'c' && !reversed)) { 789 /* Cooked mode. */ 790 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; 791 mode->c_oflag |= OPOST; 792 mode->c_lflag |= ISIG | ICANON; 793#if VMIN == VEOF 794 mode->c_cc[VEOF] = CEOF; 795#endif 796#if VTIME == VEOL 797 mode->c_cc[VEOL] = CEOL; 798#endif 799 } else { 800 /* Raw mode. */ 801 mode->c_iflag = 0; 802 mode->c_oflag &= ~OPOST; 803 mode->c_lflag &= ~(ISIG | ICANON 804#ifdef XCASE 805 | XCASE 806#endif 807 ); 808 mode->c_cc[VMIN] = 1; 809 mode->c_cc[VTIME] = 0; 810 } 811 } 812#ifdef IXANY 813 else if (info->name == decctlq) { 814 if (reversed) 815 mode->c_iflag |= IXANY; 816 else 817 mode->c_iflag &= ~IXANY; 818 } 819#endif 820#ifdef TABDLY 821 else if (info->name == stty_tabs) { 822 if (reversed) 823 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3; 824 else 825 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0; 826 } 827#else 828# ifdef OXTABS 829 else if (info->name == stty_tabs) { 830 if (reversed) 831 mode->c_oflag = mode->c_oflag | OXTABS; 832 else 833 mode->c_oflag = mode->c_oflag & ~OXTABS; 834 } 835# endif 836#endif 837#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) 838 else if (info->name == stty_lcase || info->name == stty_LCASE) { 839 if (reversed) { 840 mode->c_lflag &= ~XCASE; 841 mode->c_iflag &= ~IUCLC; 842 mode->c_oflag &= ~OLCUC; 843 } else { 844 mode->c_lflag |= XCASE; 845 mode->c_iflag |= IUCLC; 846 mode->c_oflag |= OLCUC; 847 } 848 } 849#endif 850 else if (info->name == stty_crt) 851 mode->c_lflag |= ECHOE 852#ifdef ECHOCTL 853 | ECHOCTL 854#endif 855#ifdef ECHOKE 856 | ECHOKE 857#endif 858 ; 859 else if (info->name == stty_dec) { 860 mode->c_cc[VINTR] = 3; /* ^C */ 861 mode->c_cc[VERASE] = 127; /* DEL */ 862 mode->c_cc[VKILL] = 21; /* ^U */ 863 mode->c_lflag |= ECHOE 864#ifdef ECHOCTL 865 | ECHOCTL 866#endif 867#ifdef ECHOKE 868 | ECHOKE 869#endif 870 ; 871#ifdef IXANY 872 mode->c_iflag &= ~IXANY; 873#endif 874 } 875 } else if (reversed) 876 *bitsp = *bitsp & ~info->mask & ~info->bits; 877 else 878 *bitsp = (*bitsp & ~info->mask) | info->bits; 879 880 return 1; 881} 882 883static void 884set_control_char(const struct control_info *info, const char *arg, 885 struct termios *mode) 886{ 887 unsigned char value; 888 889 if (info->name == stty_min || info->name == stty_time) 890 value = parse_number(arg, stty_suffixes); 891 else if (arg[0] == '\0' || arg[1] == '\0') 892 value = arg[0]; 893 else if (STREQ(arg, "^-") || STREQ(arg, "undef")) 894 value = _POSIX_VDISABLE; 895 else if (arg[0] == '^' && arg[1] != '\0') { /* Ignore any trailing junk. */ 896 if (arg[1] == '?') 897 value = 127; 898 else 899 value = arg[1] & ~0140; /* Non-letters get weird results. */ 900 } else 901 value = parse_number(arg, stty_suffixes); 902 mode->c_cc[info->offset] = value; 903} 904 905static void 906set_speed(enum speed_setting type, const char *arg, struct termios *mode) 907{ 908 speed_t baud; 909 910 baud = string_to_baud(arg); 911 if (type == input_speed || type == both_speeds) 912 cfsetispeed(mode, baud); 913 if (type == output_speed || type == both_speeds) 914 cfsetospeed(mode, baud); 915} 916 917#ifdef TIOCGWINSZ 918 919static int get_win_size(int fd, struct winsize *win) 920{ 921 int err = ioctl(fd, TIOCGWINSZ, (char *) win); 922 923 return err; 924} 925 926static void 927set_window_size(int rows, int cols, int fd, const char *device_name) 928{ 929 struct winsize win; 930 931 if (get_win_size(fd, &win)) { 932 if (errno != EINVAL) 933 perror_msg_and_die("%s", device_name); 934 memset(&win, 0, sizeof(win)); 935 } 936 937 if (rows >= 0) 938 win.ws_row = rows; 939 if (cols >= 0) 940 win.ws_col = cols; 941 942# ifdef TIOCSSIZE 943 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote: 944 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel. 945 This comment from sys/ttold.h describes Sun's twisted logic - a better 946 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0). 947 At any rate, the problem is gone in Solaris 2.x. */ 948 949 if (win.ws_row == 0 || win.ws_col == 0) { 950 struct ttysize ttysz; 951 952 ttysz.ts_lines = win.ws_row; 953 ttysz.ts_cols = win.ws_col; 954 955 win.ws_row = 1; 956 win.ws_col = 1; 957 958 if (ioctl(fd, TIOCSWINSZ, (char *) &win)) 959 perror_msg_and_die("%s", device_name); 960 961 if (ioctl(fd, TIOCSSIZE, (char *) &ttysz)) 962 perror_msg_and_die("%s", device_name); 963 return; 964 } 965# endif 966 967 if (ioctl(fd, TIOCSWINSZ, (char *) &win)) 968 perror_msg_and_die("%s", device_name); 969} 970 971static void display_window_size(int fancy, int fd, const char *device_name) 972{ 973 struct winsize win; 974 975 if (get_win_size(fd, &win)) { 976 if (errno != EINVAL) 977 perror_msg_and_die("%s", device_name); 978 if (!fancy) 979 perror_msg_and_die("%s: no size information for this device", 980 device_name); 981 } else { 982 wrapf(fancy ? "rows %d; columns %d;" : "%d %d\n", 983 win.ws_row, win.ws_col); 984 if (!fancy) 985 current_col = 0; 986 } 987} 988#endif 989 990static int screen_columns(void) 991{ 992#ifdef TIOCGWINSZ 993 struct winsize win; 994 995 /* With Solaris 2.[123], this ioctl fails and errno is set to 996 EINVAL for telnet (but not rlogin) sessions. 997 On ISC 3.0, it fails for the console and the serial port 998 (but it works for ptys). 999 It can also fail on any system when stdout isn't a tty. 1000 In case of any failure, just use the default. */ 1001 if (get_win_size(STDOUT_FILENO, &win) == 0 && win.ws_col > 0) 1002 return win.ws_col; 1003#endif 1004 1005 if (getenv("COLUMNS")) 1006 return atoi(getenv("COLUMNS")); 1007 return 80; 1008} 1009 1010static tcflag_t *mode_type_flag(enum mode_type type, struct termios *mode) 1011{ 1012 switch (type) { 1013 case control: 1014 return &mode->c_cflag; 1015 1016 case input: 1017 return &mode->c_iflag; 1018 1019 case output: 1020 return &mode->c_oflag; 1021 1022 case local: 1023 return &mode->c_lflag; 1024 1025 default: /* combination: */ 1026 return NULL; 1027 } 1028} 1029 1030static void 1031display_settings(enum output_type output_type, struct termios *mode, 1032 int fd, const char *device_name) 1033{ 1034 switch (output_type) { 1035 case changed: 1036 display_changed(mode); 1037 break; 1038 1039 case all: 1040 display_all(mode, fd, device_name); 1041 break; 1042 1043 case recoverable: 1044 display_recoverable(mode); 1045 break; 1046 } 1047} 1048 1049static void display_changed(struct termios *mode) 1050{ 1051 int i; 1052 int empty_line; 1053 tcflag_t *bitsp; 1054 unsigned long mask; 1055 enum mode_type prev_type = control; 1056 1057 display_speed(mode, 1); 1058#ifdef HAVE_C_LINE 1059 wrapf("line = %d;", mode->c_line); 1060#endif 1061 putchar('\n'); 1062 current_col = 0; 1063 1064 empty_line = 1; 1065 for (i = 0; control_info[i].name != stty_min; ++i) { 1066 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval) 1067 continue; 1068 /* If swtch is the same as susp, don't print both. */ 1069#if VSWTCH == VSUSP 1070 if (control_info[i].name == stty_swtch) 1071 continue; 1072#endif 1073 /* If eof uses the same slot as min, only print whichever applies. */ 1074#if VEOF == VMIN 1075 if ((mode->c_lflag & ICANON) == 0 1076 && (control_info[i].name == stty_eof 1077 || control_info[i].name == stty_eol)) continue; 1078#endif 1079 1080 empty_line = 0; 1081 wrapf("%s = %s;", control_info[i].name, 1082 visible(mode->c_cc[control_info[i].offset])); 1083 } 1084 if ((mode->c_lflag & ICANON) == 0) { 1085 wrapf("min = %d; time = %d;\n", (int) mode->c_cc[VMIN], 1086 (int) mode->c_cc[VTIME]); 1087 } else if (empty_line == 0) 1088 putchar('\n'); 1089 current_col = 0; 1090 1091 empty_line = 1; 1092 for (i = 0; i < NUM_mode_info; ++i) { 1093 if (mode_info[i].flags & OMIT) 1094 continue; 1095 if (mode_info[i].type != prev_type) { 1096 if (empty_line == 0) { 1097 putchar('\n'); 1098 current_col = 0; 1099 empty_line = 1; 1100 } 1101 prev_type = mode_info[i].type; 1102 } 1103 1104 bitsp = mode_type_flag(mode_info[i].type, mode); 1105 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; 1106 if ((*bitsp & mask) == mode_info[i].bits) { 1107 if (mode_info[i].flags & SANE_UNSET) { 1108 wrapf("%s", mode_info[i].name); 1109 empty_line = 0; 1110 } 1111 } 1112 else if ((mode_info[i].flags & (SANE_SET | REV)) == 1113 (SANE_SET | REV)) { 1114 wrapf("-%s", mode_info[i].name); 1115 empty_line = 0; 1116 } 1117 } 1118 if (empty_line == 0) 1119 putchar('\n'); 1120 current_col = 0; 1121} 1122 1123static void 1124display_all(struct termios *mode, int fd, const char *device_name) 1125{ 1126 int i; 1127 tcflag_t *bitsp; 1128 unsigned long mask; 1129 enum mode_type prev_type = control; 1130 1131 display_speed(mode, 1); 1132#ifdef TIOCGWINSZ 1133 display_window_size(1, fd, device_name); 1134#endif 1135#ifdef HAVE_C_LINE 1136 wrapf("line = %d;", mode->c_line); 1137#endif 1138 putchar('\n'); 1139 current_col = 0; 1140 1141 for (i = 0; control_info[i].name != stty_min; ++i) { 1142 /* If swtch is the same as susp, don't print both. */ 1143#if VSWTCH == VSUSP 1144 if (control_info[i].name == stty_swtch) 1145 continue; 1146#endif 1147 /* If eof uses the same slot as min, only print whichever applies. */ 1148#if VEOF == VMIN 1149 if ((mode->c_lflag & ICANON) == 0 1150 && (control_info[i].name == stty_eof 1151 || control_info[i].name == stty_eol)) continue; 1152#endif 1153 wrapf("%s = %s;", control_info[i].name, 1154 visible(mode->c_cc[control_info[i].offset])); 1155 } 1156#if VEOF == VMIN 1157 if ((mode->c_lflag & ICANON) == 0) 1158#endif 1159 wrapf("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]); 1160 if (current_col != 0) 1161 putchar('\n'); 1162 current_col = 0; 1163 1164 for (i = 0; i < NUM_mode_info; ++i) { 1165 if (mode_info[i].flags & OMIT) 1166 continue; 1167 if (mode_info[i].type != prev_type) { 1168 putchar('\n'); 1169 current_col = 0; 1170 prev_type = mode_info[i].type; 1171 } 1172 1173 bitsp = mode_type_flag(mode_info[i].type, mode); 1174 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; 1175 if ((*bitsp & mask) == mode_info[i].bits) 1176 wrapf("%s", mode_info[i].name); 1177 else if (mode_info[i].flags & REV) 1178 wrapf("-%s", mode_info[i].name); 1179 } 1180 putchar('\n'); 1181 current_col = 0; 1182} 1183 1184static void display_speed(struct termios *mode, int fancy) 1185{ 1186 if (cfgetispeed(mode) == 0 || cfgetispeed(mode) == cfgetospeed(mode)) 1187 wrapf(fancy ? "speed %lu baud;" : "%lu\n", 1188 baud_to_value(cfgetospeed(mode))); 1189 else 1190 wrapf(fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", 1191 baud_to_value(cfgetispeed(mode)), 1192 baud_to_value(cfgetospeed(mode))); 1193 if (!fancy) 1194 current_col = 0; 1195} 1196 1197static void display_recoverable(struct termios *mode) 1198{ 1199 int i; 1200 1201 printf("%lx:%lx:%lx:%lx", 1202 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, 1203 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); 1204 for (i = 0; i < NCCS; ++i) 1205 printf(":%x", (unsigned int) mode->c_cc[i]); 1206 putchar('\n'); 1207} 1208 1209static int recover_mode(char *arg, struct termios *mode) 1210{ 1211 int i, n; 1212 unsigned int chr; 1213 unsigned long iflag, oflag, cflag, lflag; 1214 1215 /* Scan into temporaries since it is too much trouble to figure out 1216 the right format for `tcflag_t'. */ 1217 if (sscanf(arg, "%lx:%lx:%lx:%lx%n", 1218 &iflag, &oflag, &cflag, &lflag, &n) != 4) 1219 return 0; 1220 mode->c_iflag = iflag; 1221 mode->c_oflag = oflag; 1222 mode->c_cflag = cflag; 1223 mode->c_lflag = lflag; 1224 arg += n; 1225 for (i = 0; i < NCCS; ++i) { 1226 if (sscanf(arg, ":%x%n", &chr, &n) != 1) 1227 return 0; 1228 mode->c_cc[i] = chr; 1229 arg += n; 1230 } 1231 1232 /* Fail if there are too many fields. */ 1233 if (*arg != '\0') 1234 return 0; 1235 1236 return 1; 1237} 1238 1239struct speed_map { 1240 speed_t speed; /* Internal form. */ 1241 unsigned long value; /* Numeric value. */ 1242}; 1243 1244static const struct speed_map speeds[] = { 1245 {B0, 0}, 1246 {B50, 50}, 1247 {B75, 75}, 1248 {B110, 110}, 1249 {B134, 134}, 1250 {B150, 150}, 1251 {B200, 200}, 1252 {B300, 300}, 1253 {B600, 600}, 1254 {B1200, 1200}, 1255 {B1800, 1800}, 1256 {B2400, 2400}, 1257 {B4800, 4800}, 1258 {B9600, 9600}, 1259 {B19200, 19200}, 1260 {B38400, 38400}, 1261#ifdef B57600 1262 {B57600, 57600}, 1263#endif 1264#ifdef B115200 1265 {B115200, 115200}, 1266#endif 1267#ifdef B230400 1268 {B230400, 230400}, 1269#endif 1270#ifdef B460800 1271 {B460800, 460800}, 1272#endif 1273}; 1274 1275static const int NUM_SPEEDS = (sizeof(speeds) / sizeof(struct speed_map)); 1276 1277static speed_t string_to_baud(const char *arg) 1278{ 1279 int i; 1280 1281 for (i = 0; i < NUM_SPEEDS; ++i) 1282 if (parse_number(arg, 0) == speeds[i].value) 1283 return speeds[i].speed; 1284 return (speed_t) - 1; 1285} 1286 1287static unsigned long baud_to_value(speed_t speed) 1288{ 1289 int i; 1290 1291 for (i = 0; i < NUM_SPEEDS; ++i) 1292 if (speed == speeds[i].speed) 1293 return speeds[i].value; 1294 return 0; 1295} 1296 1297static void sane_mode(struct termios *mode) 1298{ 1299 int i; 1300 tcflag_t *bitsp; 1301 1302 for (i = 0; i < NUM_control_info; ++i) { 1303#if VMIN == VEOF 1304 if (control_info[i].name == stty_min) 1305 break; 1306#endif 1307 mode->c_cc[control_info[i].offset] = control_info[i].saneval; 1308 } 1309 1310 for (i = 0; i < NUM_mode_info; ++i) { 1311 if (mode_info[i].flags & SANE_SET) { 1312 bitsp = mode_type_flag(mode_info[i].type, mode); 1313 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits; 1314 } else if (mode_info[i].flags & SANE_UNSET) { 1315 bitsp = mode_type_flag(mode_info[i].type, mode); 1316 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits; 1317 } 1318 } 1319} 1320 1321/* Return a string that is the printable representation of character CH. */ 1322/* Adapted from `cat' by Torbjorn Granlund. */ 1323 1324static const char *visible(unsigned int ch) 1325{ 1326 static char buf[10]; 1327 char *bpout = buf; 1328 1329 if (ch == _POSIX_VDISABLE) 1330 return "<undef>"; 1331 1332 if (ch >= 32) { 1333 if (ch < 127) 1334 *bpout++ = ch; 1335 else if (ch == 127) { 1336 *bpout++ = '^'; 1337 *bpout++ = '?'; 1338 } else { 1339 *bpout++ = 'M', *bpout++ = '-'; 1340 if (ch >= 128 + 32) { 1341 if (ch < 128 + 127) 1342 *bpout++ = ch - 128; 1343 else { 1344 *bpout++ = '^'; 1345 *bpout++ = '?'; 1346 } 1347 } else { 1348 *bpout++ = '^'; 1349 *bpout++ = ch - 128 + 64; 1350 } 1351 } 1352 } else { 1353 *bpout++ = '^'; 1354 *bpout++ = ch + 64; 1355 } 1356 *bpout = '\0'; 1357 return (const char *) buf; 1358} 1359 1360#ifdef TEST 1361 1362const char *applet_name = "stty"; 1363 1364#endif 1365 1366/* 1367Local Variables: 1368c-file-style: "linux" 1369c-basic-offset: 4 1370tab-width: 4 1371End: 1372*/ 1373