* NEWS: Mention these SELinux changes.
[coreutils/ericb.git] / src / stty.c
blobce0cb0caef82e114fbbd6e7d53cb254fcc6ea994
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2005, 2007 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
20 Options:
21 -a, --all Write all current settings to stdout in human-readable form.
22 -g, --save Write all current settings to stdout in stty-readable form.
23 -F, --file Open and use the specified device instead of stdin
25 If no args are given, write to stdout the baud rate and settings that
26 have been changed from their defaults. Mode reading and changes
27 are done on the specified device, or stdin if none was specified.
29 David MacKenzie <djm@gnu.ai.mit.edu> */
31 #include <config.h>
33 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
34 # define _XOPEN_SOURCE
35 #endif
37 #include <stdio.h>
38 #include <sys/types.h>
40 #if HAVE_TERMIOS_H
41 # include <termios.h>
42 #endif
43 #if HAVE_STROPTS_H
44 # include <stropts.h>
45 #endif
46 #ifdef HAVE_SYS_IOCTL_H
47 # include <sys/ioctl.h>
48 #endif
50 #ifdef WINSIZE_IN_PTEM
51 # include <sys/stream.h>
52 # include <sys/ptem.h>
53 #endif
54 #ifdef GWINSZ_IN_SYS_PTY
55 # include <sys/tty.h>
56 # include <sys/pty.h>
57 #endif
58 #include <getopt.h>
59 #include <stdarg.h>
61 #include "system.h"
62 #include "error.h"
63 #include "fd-reopen.h"
64 #include "quote.h"
65 #include "xstrtol.h"
67 /* The official name of this program (e.g., no `g' prefix). */
68 #define PROGRAM_NAME "stty"
70 #define AUTHORS "David MacKenzie"
72 #ifndef _POSIX_VDISABLE
73 # define _POSIX_VDISABLE 0
74 #endif
76 #define Control(c) ((c) & 0x1f)
77 /* Canonical values for control characters. */
78 #ifndef CINTR
79 # define CINTR Control ('c')
80 #endif
81 #ifndef CQUIT
82 # define CQUIT 28
83 #endif
84 #ifndef CERASE
85 # define CERASE 127
86 #endif
87 #ifndef CKILL
88 # define CKILL Control ('u')
89 #endif
90 #ifndef CEOF
91 # define CEOF Control ('d')
92 #endif
93 #ifndef CEOL
94 # define CEOL _POSIX_VDISABLE
95 #endif
96 #ifndef CSTART
97 # define CSTART Control ('q')
98 #endif
99 #ifndef CSTOP
100 # define CSTOP Control ('s')
101 #endif
102 #ifndef CSUSP
103 # define CSUSP Control ('z')
104 #endif
105 #if defined VEOL2 && !defined CEOL2
106 # define CEOL2 _POSIX_VDISABLE
107 #endif
108 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
109 character is initialized by CSWTCH, if present. */
110 #if defined VSWTC && !defined VSWTCH
111 # define VSWTCH VSWTC
112 #endif
113 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
114 #if defined VSUSP && !defined VSWTCH
115 # define VSWTCH VSUSP
116 # if defined CSUSP && !defined CSWTCH
117 # define CSWTCH CSUSP
118 # endif
119 #endif
120 #if defined VSWTCH && !defined CSWTCH
121 # define CSWTCH _POSIX_VDISABLE
122 #endif
124 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
125 So the default is to disable `swtch.' */
126 #if defined __sparc__ && defined __svr4__
127 # undef CSWTCH
128 # define CSWTCH _POSIX_VDISABLE
129 #endif
131 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
132 # define VWERASE VWERSE
133 #endif
134 #if defined VDSUSP && !defined CDSUSP
135 # define CDSUSP Control ('y')
136 #endif
137 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
138 # define VREPRINT VRPRNT
139 #endif
140 #if defined VREPRINT && !defined CRPRNT
141 # define CRPRNT Control ('r')
142 #endif
143 #if defined CREPRINT && !defined CRPRNT
144 # define CRPRNT Control ('r')
145 #endif
146 #if defined VWERASE && !defined CWERASE
147 # define CWERASE Control ('w')
148 #endif
149 #if defined VLNEXT && !defined CLNEXT
150 # define CLNEXT Control ('v')
151 #endif
152 #if defined VDISCARD && !defined VFLUSHO
153 # define VFLUSHO VDISCARD
154 #endif
155 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
156 # define VFLUSHO VFLUSH
157 #endif
158 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
159 # define ECHOCTL CTLECH
160 #endif
161 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
162 # define ECHOCTL TCTLECH
163 #endif
164 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
165 # define ECHOKE CRTKIL
166 #endif
167 #if defined VFLUSHO && !defined CFLUSHO
168 # define CFLUSHO Control ('o')
169 #endif
170 #if defined VSTATUS && !defined CSTATUS
171 # define CSTATUS Control ('t')
172 #endif
174 /* Which speeds to set. */
175 enum speed_setting
177 input_speed, output_speed, both_speeds
180 /* What to output and how. */
181 enum output_type
183 changed, all, recoverable /* Default, -a, -g. */
186 /* Which member(s) of `struct termios' a mode uses. */
187 enum mode_type
189 control, input, output, local, combination
192 /* Flags for `struct mode_info'. */
193 #define SANE_SET 1 /* Set in `sane' mode. */
194 #define SANE_UNSET 2 /* Unset in `sane' mode. */
195 #define REV 4 /* Can be turned off by prepending `-'. */
196 #define OMIT 8 /* Don't display value. */
198 /* Each mode. */
199 struct 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. */
208 static struct mode_info mode_info[] =
210 {"parenb", control, REV, PARENB, 0},
211 {"parodd", control, REV, PARODD, 0},
212 {"cs5", control, 0, CS5, CSIZE},
213 {"cs6", control, 0, CS6, CSIZE},
214 {"cs7", control, 0, CS7, CSIZE},
215 {"cs8", control, 0, CS8, CSIZE},
216 {"hupcl", control, REV, HUPCL, 0},
217 {"hup", control, REV | OMIT, HUPCL, 0},
218 {"cstopb", control, REV, CSTOPB, 0},
219 {"cread", control, SANE_SET | REV, CREAD, 0},
220 {"clocal", control, REV, CLOCAL, 0},
221 #ifdef CRTSCTS
222 {"crtscts", control, REV, CRTSCTS, 0},
223 #endif
225 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
226 {"brkint", input, SANE_SET | REV, BRKINT, 0},
227 {"ignpar", input, REV, IGNPAR, 0},
228 {"parmrk", input, REV, PARMRK, 0},
229 {"inpck", input, REV, INPCK, 0},
230 {"istrip", input, REV, ISTRIP, 0},
231 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
232 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
233 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
234 {"ixon", input, REV, IXON, 0},
235 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
236 {"tandem", input, REV | OMIT, IXOFF, 0},
237 #ifdef IUCLC
238 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
239 #endif
240 #ifdef IXANY
241 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
242 #endif
243 #ifdef IMAXBEL
244 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
245 #endif
246 #ifdef IUTF8
247 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
248 #endif
250 {"opost", output, SANE_SET | REV, OPOST, 0},
251 #ifdef OLCUC
252 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
253 #endif
254 #ifdef OCRNL
255 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
256 #endif
257 #ifdef ONLCR
258 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
259 #endif
260 #ifdef ONOCR
261 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
262 #endif
263 #ifdef ONLRET
264 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
265 #endif
266 #ifdef OFILL
267 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
268 #endif
269 #ifdef OFDEL
270 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
271 #endif
272 #ifdef NLDLY
273 {"nl1", output, SANE_UNSET, NL1, NLDLY},
274 {"nl0", output, SANE_SET, NL0, NLDLY},
275 #endif
276 #ifdef CRDLY
277 {"cr3", output, SANE_UNSET, CR3, CRDLY},
278 {"cr2", output, SANE_UNSET, CR2, CRDLY},
279 {"cr1", output, SANE_UNSET, CR1, CRDLY},
280 {"cr0", output, SANE_SET, CR0, CRDLY},
281 #endif
282 #ifdef TABDLY
283 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
284 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
285 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
286 {"tab0", output, SANE_SET, TAB0, TABDLY},
287 #else
288 # ifdef OXTABS
289 {"tab3", output, SANE_UNSET, OXTABS, 0},
290 # endif
291 #endif
292 #ifdef BSDLY
293 {"bs1", output, SANE_UNSET, BS1, BSDLY},
294 {"bs0", output, SANE_SET, BS0, BSDLY},
295 #endif
296 #ifdef VTDLY
297 {"vt1", output, SANE_UNSET, VT1, VTDLY},
298 {"vt0", output, SANE_SET, VT0, VTDLY},
299 #endif
300 #ifdef FFDLY
301 {"ff1", output, SANE_UNSET, FF1, FFDLY},
302 {"ff0", output, SANE_SET, FF0, FFDLY},
303 #endif
305 {"isig", local, SANE_SET | REV, ISIG, 0},
306 {"icanon", local, SANE_SET | REV, ICANON, 0},
307 #ifdef IEXTEN
308 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
309 #endif
310 {"echo", local, SANE_SET | REV, ECHO, 0},
311 {"echoe", local, SANE_SET | REV, ECHOE, 0},
312 {"crterase", local, REV | OMIT, ECHOE, 0},
313 {"echok", local, SANE_SET | REV, ECHOK, 0},
314 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
315 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
316 #ifdef XCASE
317 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
318 #endif
319 #ifdef TOSTOP
320 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
321 #endif
322 #ifdef ECHOPRT
323 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
324 {"prterase", local, REV | OMIT, ECHOPRT, 0},
325 #endif
326 #ifdef ECHOCTL
327 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
328 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
329 #endif
330 #ifdef ECHOKE
331 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
332 {"crtkill", local, REV | OMIT, ECHOKE, 0},
333 #endif
335 {"evenp", combination, REV | OMIT, 0, 0},
336 {"parity", combination, REV | OMIT, 0, 0},
337 {"oddp", combination, REV | OMIT, 0, 0},
338 {"nl", combination, REV | OMIT, 0, 0},
339 {"ek", combination, OMIT, 0, 0},
340 {"sane", combination, OMIT, 0, 0},
341 {"cooked", combination, REV | OMIT, 0, 0},
342 {"raw", combination, REV | OMIT, 0, 0},
343 {"pass8", combination, REV | OMIT, 0, 0},
344 {"litout", combination, REV | OMIT, 0, 0},
345 {"cbreak", combination, REV | OMIT, 0, 0},
346 #ifdef IXANY
347 {"decctlq", combination, REV | OMIT, 0, 0},
348 #endif
349 #if defined TABDLY || defined OXTABS
350 {"tabs", combination, REV | OMIT, 0, 0},
351 #endif
352 #if defined XCASE && defined IUCLC && defined OLCUC
353 {"lcase", combination, REV | OMIT, 0, 0},
354 {"LCASE", combination, REV | OMIT, 0, 0},
355 #endif
356 {"crt", combination, OMIT, 0, 0},
357 {"dec", combination, OMIT, 0, 0},
359 {NULL, control, 0, 0, 0}
362 /* Control character settings. */
363 struct control_info
365 const char *name; /* Name given on command line. */
366 cc_t saneval; /* Value to set for `stty sane'. */
367 size_t offset; /* Offset in c_cc. */
370 /* Control characters. */
372 static struct control_info control_info[] =
374 {"intr", CINTR, VINTR},
375 {"quit", CQUIT, VQUIT},
376 {"erase", CERASE, VERASE},
377 {"kill", CKILL, VKILL},
378 {"eof", CEOF, VEOF},
379 {"eol", CEOL, VEOL},
380 #ifdef VEOL2
381 {"eol2", CEOL2, VEOL2},
382 #endif
383 #ifdef VSWTCH
384 {"swtch", CSWTCH, VSWTCH},
385 #endif
386 {"start", CSTART, VSTART},
387 {"stop", CSTOP, VSTOP},
388 {"susp", CSUSP, VSUSP},
389 #ifdef VDSUSP
390 {"dsusp", CDSUSP, VDSUSP},
391 #endif
392 #ifdef VREPRINT
393 {"rprnt", CRPRNT, VREPRINT},
394 #else
395 # ifdef CREPRINT /* HPUX 10.20 needs this */
396 {"rprnt", CRPRNT, CREPRINT},
397 # endif
398 #endif
399 #ifdef VWERASE
400 {"werase", CWERASE, VWERASE},
401 #endif
402 #ifdef VLNEXT
403 {"lnext", CLNEXT, VLNEXT},
404 #endif
405 #ifdef VFLUSHO
406 {"flush", CFLUSHO, VFLUSHO},
407 #endif
408 #ifdef VSTATUS
409 {"status", CSTATUS, VSTATUS},
410 #endif
412 /* These must be last because of the display routines. */
413 {"min", 1, VMIN},
414 {"time", 0, VTIME},
415 {NULL, 0, 0}
418 static char const *visible (cc_t ch);
419 static unsigned long int baud_to_value (speed_t speed);
420 static bool recover_mode (char const *arg, struct termios *mode);
421 static int screen_columns (void);
422 static bool set_mode (struct mode_info *info, bool reversed,
423 struct termios *mode);
424 static unsigned long int integer_arg (const char *s, unsigned long int max);
425 static speed_t string_to_baud (const char *arg);
426 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
427 static void display_all (struct termios *mode, char const *device_name);
428 static void display_changed (struct termios *mode);
429 static void display_recoverable (struct termios *mode);
430 static void display_settings (enum output_type output_type,
431 struct termios *mode,
432 const char *device_name);
433 static void display_speed (struct termios *mode, bool fancy);
434 static void display_window_size (bool fancy, char const *device_name);
435 static void sane_mode (struct termios *mode);
436 static void set_control_char (struct control_info *info,
437 const char *arg,
438 struct termios *mode);
439 static void set_speed (enum speed_setting type, const char *arg,
440 struct termios *mode);
441 static void set_window_size (int rows, int cols, char const *device_name);
443 /* The width of the screen, for output wrapping. */
444 static int max_col;
446 /* Current position, to know when to wrap. */
447 static int current_col;
449 static struct option longopts[] =
451 {"all", no_argument, NULL, 'a'},
452 {"save", no_argument, NULL, 'g'},
453 {"file", required_argument, NULL, 'F'},
454 {GETOPT_HELP_OPTION_DECL},
455 {GETOPT_VERSION_OPTION_DECL},
456 {NULL, 0, NULL, 0}
459 /* The name this program was run with. */
460 char *program_name;
462 static void wrapf (const char *message, ...)
463 __attribute__ ((__format__ (__printf__, 1, 2)));
465 /* Print format string MESSAGE and optional args.
466 Wrap to next line first if it won't fit.
467 Print a space first unless MESSAGE will start a new line. */
469 static void
470 wrapf (const char *message,...)
472 va_list args;
473 char *buf;
474 int buflen;
476 va_start (args, message);
477 buflen = vasprintf (&buf, message, args);
478 va_end (args);
480 if (buflen < 0)
481 xalloc_die ();
483 if (0 < current_col)
485 if (max_col - current_col < buflen)
487 putchar ('\n');
488 current_col = 0;
490 else
492 putchar (' ');
493 current_col++;
497 fputs (buf, stdout);
498 free (buf);
499 current_col += buflen;
502 void
503 usage (int status)
505 if (status != EXIT_SUCCESS)
506 fprintf (stderr, _("Try `%s --help' for more information.\n"),
507 program_name);
508 else
510 printf (_("\
511 Usage: %s [-F DEVICE] [--file=DEVICE] [SETTING]...\n\
512 or: %s [-F DEVICE] [--file=DEVICE] [-a|--all]\n\
513 or: %s [-F DEVICE] [--file=DEVICE] [-g|--save]\n\
515 program_name, program_name, program_name);
516 fputs (_("\
517 Print or change terminal characteristics.\n\
519 -a, --all print all current settings in human-readable form\n\
520 -g, --save print all current settings in a stty-readable form\n\
521 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
522 "), stdout);
523 fputs (HELP_OPTION_DESCRIPTION, stdout);
524 fputs (VERSION_OPTION_DESCRIPTION, stdout);
525 fputs (_("\
527 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
528 settings. The underlying system defines which settings are available.\n\
529 "), stdout);
530 fputs (_("\
532 Special characters:\n\
533 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
534 eof CHAR CHAR will send an end of file (terminate the input)\n\
535 eol CHAR CHAR will end the line\n\
536 "), stdout);
537 fputs (_("\
538 * eol2 CHAR alternate CHAR for ending the line\n\
539 erase CHAR CHAR will erase the last character typed\n\
540 intr CHAR CHAR will send an interrupt signal\n\
541 kill CHAR CHAR will erase the current line\n\
542 "), stdout);
543 fputs (_("\
544 * lnext CHAR CHAR will enter the next character quoted\n\
545 quit CHAR CHAR will send a quit signal\n\
546 * rprnt CHAR CHAR will redraw the current line\n\
547 start CHAR CHAR will restart the output after stopping it\n\
548 "), stdout);
549 fputs (_("\
550 stop CHAR CHAR will stop the output\n\
551 susp CHAR CHAR will send a terminal stop signal\n\
552 * swtch CHAR CHAR will switch to a different shell layer\n\
553 * werase CHAR CHAR will erase the last word typed\n\
554 "), stdout);
555 fputs (_("\
557 Special settings:\n\
558 N set the input and output speeds to N bauds\n\
559 * cols N tell the kernel that the terminal has N columns\n\
560 * columns N same as cols N\n\
561 "), stdout);
562 fputs (_("\
563 ispeed N set the input speed to N\n\
564 * line N use line discipline N\n\
565 min N with -icanon, set N characters minimum for a completed read\n\
566 ospeed N set the output speed to N\n\
567 "), stdout);
568 fputs (_("\
569 * rows N tell the kernel that the terminal has N rows\n\
570 * size print the number of rows and columns according to the kernel\n\
571 speed print the terminal speed\n\
572 time N with -icanon, set read timeout of N tenths of a second\n\
573 "), stdout);
574 fputs (_("\
576 Control settings:\n\
577 [-]clocal disable modem control signals\n\
578 [-]cread allow input to be received\n\
579 * [-]crtscts enable RTS/CTS handshaking\n\
580 csN set character size to N bits, N in [5..8]\n\
581 "), stdout);
582 fputs (_("\
583 [-]cstopb use two stop bits per character (one with `-')\n\
584 [-]hup send a hangup signal when the last process closes the tty\n\
585 [-]hupcl same as [-]hup\n\
586 [-]parenb generate parity bit in output and expect parity bit in input\n\
587 [-]parodd set odd parity (even with `-')\n\
588 "), stdout);
589 fputs (_("\
591 Input settings:\n\
592 [-]brkint breaks cause an interrupt signal\n\
593 [-]icrnl translate carriage return to newline\n\
594 [-]ignbrk ignore break characters\n\
595 [-]igncr ignore carriage return\n\
596 "), stdout);
597 fputs (_("\
598 [-]ignpar ignore characters with parity errors\n\
599 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
600 [-]inlcr translate newline to carriage return\n\
601 [-]inpck enable input parity checking\n\
602 [-]istrip clear high (8th) bit of input characters\n\
603 "), stdout);
604 fputs (_("\
605 * [-]iutf8 assume input characters are UTF-8 encoded\n\
606 "), stdout);
607 fputs (_("\
608 * [-]iuclc translate uppercase characters to lowercase\n\
609 * [-]ixany let any character restart output, not only start character\n\
610 [-]ixoff enable sending of start/stop characters\n\
611 [-]ixon enable XON/XOFF flow control\n\
612 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
613 [-]tandem same as [-]ixoff\n\
614 "), stdout);
615 fputs (_("\
617 Output settings:\n\
618 * bsN backspace delay style, N in [0..1]\n\
619 * crN carriage return delay style, N in [0..3]\n\
620 * ffN form feed delay style, N in [0..1]\n\
621 * nlN newline delay style, N in [0..1]\n\
622 "), stdout);
623 fputs (_("\
624 * [-]ocrnl translate carriage return to newline\n\
625 * [-]ofdel use delete characters for fill instead of null characters\n\
626 * [-]ofill use fill (padding) characters instead of timing for delays\n\
627 * [-]olcuc translate lowercase characters to uppercase\n\
628 * [-]onlcr translate newline to carriage return-newline\n\
629 * [-]onlret newline performs a carriage return\n\
630 "), stdout);
631 fputs (_("\
632 * [-]onocr do not print carriage returns in the first column\n\
633 [-]opost postprocess output\n\
634 * tabN horizontal tab delay style, N in [0..3]\n\
635 * tabs same as tab0\n\
636 * -tabs same as tab3\n\
637 * vtN vertical tab delay style, N in [0..1]\n\
638 "), stdout);
639 fputs (_("\
641 Local settings:\n\
642 [-]crterase echo erase characters as backspace-space-backspace\n\
643 * crtkill kill all line by obeying the echoprt and echoe settings\n\
644 * -crtkill kill all line by obeying the echoctl and echok settings\n\
645 "), stdout);
646 fputs (_("\
647 * [-]ctlecho echo control characters in hat notation (`^c')\n\
648 [-]echo echo input characters\n\
649 * [-]echoctl same as [-]ctlecho\n\
650 [-]echoe same as [-]crterase\n\
651 [-]echok echo a newline after a kill character\n\
652 "), stdout);
653 fputs (_("\
654 * [-]echoke same as [-]crtkill\n\
655 [-]echonl echo newline even if not echoing other characters\n\
656 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
657 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
658 [-]iexten enable non-POSIX special characters\n\
659 "), stdout);
660 fputs (_("\
661 [-]isig enable interrupt, quit, and suspend special characters\n\
662 [-]noflsh disable flushing after interrupt and quit special characters\n\
663 * [-]prterase same as [-]echoprt\n\
664 * [-]tostop stop background jobs that try to write to the terminal\n\
665 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
666 "), stdout);
667 fputs (_("\
669 Combination settings:\n\
670 * [-]LCASE same as [-]lcase\n\
671 cbreak same as -icanon\n\
672 -cbreak same as icanon\n\
673 "), stdout);
674 fputs (_("\
675 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
676 icanon, eof and eol characters to their default values\n\
677 -cooked same as raw\n\
678 crt same as echoe echoctl echoke\n\
679 "), stdout);
680 fputs (_("\
681 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
682 kill ^u\n\
683 * [-]decctlq same as [-]ixany\n\
684 ek erase and kill characters to their default values\n\
685 evenp same as parenb -parodd cs7\n\
686 "), stdout);
687 fputs (_("\
688 -evenp same as -parenb cs8\n\
689 * [-]lcase same as xcase iuclc olcuc\n\
690 litout same as -parenb -istrip -opost cs8\n\
691 -litout same as parenb istrip opost cs7\n\
692 nl same as -icrnl -onlcr\n\
693 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
694 "), stdout);
695 fputs (_("\
696 oddp same as parenb parodd cs7\n\
697 -oddp same as -parenb cs8\n\
698 [-]parity same as [-]evenp\n\
699 pass8 same as -parenb -istrip cs8\n\
700 -pass8 same as parenb istrip cs7\n\
701 "), stdout);
702 fputs (_("\
703 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
704 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
705 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
706 -raw same as cooked\n\
707 "), stdout);
708 fputs (_("\
709 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
710 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
711 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
712 isig icanon iexten echo echoe echok -echonl -noflsh\n\
713 -xcase -tostop -echoprt echoctl echoke, all special\n\
714 characters to their default values.\n\
715 "), stdout);
716 fputs (_("\
718 Handle the tty line connected to standard input. Without arguments,\n\
719 prints baud rate, line discipline, and deviations from stty sane. In\n\
720 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
721 127; special values ^- or undef used to disable special characters.\n\
722 "), stdout);
723 emit_bug_reporting_address ();
725 exit (status);
729 main (int argc, char **argv)
731 /* Initialize to all zeroes so there is no risk memcmp will report a
732 spurious difference in an uninitialized portion of the structure. */
733 struct termios mode = { 0, };
735 enum output_type output_type;
736 int optc;
737 int argi = 0;
738 int opti = 1;
739 bool require_set_attr;
740 bool speed_was_set;
741 bool verbose_output;
742 bool recoverable_output;
743 int k;
744 bool noargs = true;
745 char *file_name = NULL;
746 const char *device_name;
748 initialize_main (&argc, &argv);
749 program_name = argv[0];
750 setlocale (LC_ALL, "");
751 bindtextdomain (PACKAGE, LOCALEDIR);
752 textdomain (PACKAGE);
754 atexit (close_stdout);
756 output_type = changed;
757 verbose_output = false;
758 recoverable_output = false;
760 /* Don't print error messages for unrecognized options. */
761 opterr = 0;
763 /* If any new options are ever added to stty, the short options MUST
764 NOT allow any ambiguity with the stty settings. For example, the
765 stty setting "-gagFork" would not be feasible, since it will be
766 parsed as "-g -a -g -F ork". If you change anything about how
767 stty parses options, be sure it still works with combinations of
768 short and long options, --, POSIXLY_CORRECT, etc. */
770 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
771 longopts, NULL))
772 != -1)
774 switch (optc)
776 case 'a':
777 verbose_output = true;
778 output_type = all;
779 break;
781 case 'g':
782 recoverable_output = true;
783 output_type = recoverable;
784 break;
786 case 'F':
787 if (file_name)
788 error (EXIT_FAILURE, 0, _("only one device may be specified"));
789 file_name = optarg;
790 break;
792 case_GETOPT_HELP_CHAR;
794 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
796 default:
797 noargs = false;
799 /* Skip the argument containing this unrecognized option;
800 the 2nd pass will analyze it. */
801 argi += opti;
803 /* Restart getopt_long from the first unskipped argument. */
804 opti = 1;
805 optind = 0;
807 break;
810 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
811 while (opti < optind)
812 argv[argi + opti++] = NULL;
815 /* Specifying both -a and -g gets an error. */
816 if (verbose_output & recoverable_output)
817 error (EXIT_FAILURE, 0,
818 _("the options for verbose and stty-readable output styles are\n"
819 "mutually exclusive"));
821 /* Specifying any other arguments with -a or -g gets an error. */
822 if (!noargs & (verbose_output | recoverable_output))
823 error (EXIT_FAILURE, 0,
824 _("when specifying an output style, modes may not be set"));
826 /* FIXME: it'd be better not to open the file until we've verified
827 that all arguments are valid. Otherwise, we could end up doing
828 only some of the requested operations and then failing, probably
829 leaving things in an undesirable state. */
831 if (file_name)
833 int fdflags;
834 device_name = file_name;
835 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
836 error (EXIT_FAILURE, errno, "%s", device_name);
837 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
838 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
839 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
840 device_name);
842 else
843 device_name = _("standard input");
845 if (tcgetattr (STDIN_FILENO, &mode))
846 error (EXIT_FAILURE, errno, "%s", device_name);
848 if (verbose_output | recoverable_output | noargs)
850 max_col = screen_columns ();
851 current_col = 0;
852 display_settings (output_type, &mode, device_name);
853 exit (EXIT_SUCCESS);
856 speed_was_set = false;
857 require_set_attr = false;
858 for (k = 1; k < argc; k++)
860 char const *arg = argv[k];
861 bool match_found = false;
862 bool reversed = false;
863 int i;
865 if (! arg)
866 continue;
868 if (arg[0] == '-')
870 ++arg;
871 reversed = true;
873 for (i = 0; mode_info[i].name != NULL; ++i)
875 if (STREQ (arg, mode_info[i].name))
877 match_found = set_mode (&mode_info[i], reversed, &mode);
878 require_set_attr = true;
879 break;
882 if (!match_found & reversed)
884 error (0, 0, _("invalid argument %s"), quote (arg - 1));
885 usage (EXIT_FAILURE);
887 if (!match_found)
889 for (i = 0; control_info[i].name != NULL; ++i)
891 if (STREQ (arg, control_info[i].name))
893 if (k == argc - 1)
895 error (0, 0, _("missing argument to %s"), quote (arg));
896 usage (EXIT_FAILURE);
898 match_found = true;
899 ++k;
900 set_control_char (&control_info[i], argv[k], &mode);
901 require_set_attr = true;
902 break;
906 if (!match_found)
908 if (STREQ (arg, "ispeed"))
910 if (k == argc - 1)
912 error (0, 0, _("missing argument to %s"), quote (arg));
913 usage (EXIT_FAILURE);
915 ++k;
916 set_speed (input_speed, argv[k], &mode);
917 speed_was_set = true;
918 require_set_attr = true;
920 else if (STREQ (arg, "ospeed"))
922 if (k == argc - 1)
924 error (0, 0, _("missing argument to %s"), quote (arg));
925 usage (EXIT_FAILURE);
927 ++k;
928 set_speed (output_speed, argv[k], &mode);
929 speed_was_set = true;
930 require_set_attr = true;
932 #ifdef TIOCGWINSZ
933 else if (STREQ (arg, "rows"))
935 if (k == argc - 1)
937 error (0, 0, _("missing argument to %s"), quote (arg));
938 usage (EXIT_FAILURE);
940 ++k;
941 set_window_size (integer_arg (argv[k], INT_MAX), -1,
942 device_name);
944 else if (STREQ (arg, "cols")
945 || STREQ (arg, "columns"))
947 if (k == argc - 1)
949 error (0, 0, _("missing argument to %s"), quote (arg));
950 usage (EXIT_FAILURE);
952 ++k;
953 set_window_size (-1, integer_arg (argv[k], INT_MAX),
954 device_name);
956 else if (STREQ (arg, "size"))
958 max_col = screen_columns ();
959 current_col = 0;
960 display_window_size (false, device_name);
962 #endif
963 #ifdef HAVE_C_LINE
964 else if (STREQ (arg, "line"))
966 unsigned long int value;
967 if (k == argc - 1)
969 error (0, 0, _("missing argument to %s"), quote (arg));
970 usage (EXIT_FAILURE);
972 ++k;
973 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
974 if (mode.c_line != value)
975 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
976 require_set_attr = true;
978 #endif
979 else if (STREQ (arg, "speed"))
981 max_col = screen_columns ();
982 display_speed (&mode, false);
984 else if (string_to_baud (arg) != (speed_t) -1)
986 set_speed (both_speeds, arg, &mode);
987 speed_was_set = true;
988 require_set_attr = true;
990 else
992 if (! recover_mode (arg, &mode))
994 error (0, 0, _("invalid argument %s"), quote (arg));
995 usage (EXIT_FAILURE);
997 require_set_attr = true;
1002 if (require_set_attr)
1004 /* Initialize to all zeroes so there is no risk memcmp will report a
1005 spurious difference in an uninitialized portion of the structure. */
1006 struct termios new_mode = { 0, };
1008 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1009 error (EXIT_FAILURE, errno, "%s", device_name);
1011 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1012 it performs *any* of the requested operations. This means it
1013 can report `success' when it has actually failed to perform
1014 some proper subset of the requested operations. To detect
1015 this partial failure, get the current terminal attributes and
1016 compare them to the requested ones. */
1018 if (tcgetattr (STDIN_FILENO, &new_mode))
1019 error (EXIT_FAILURE, errno, "%s", device_name);
1021 /* Normally, one shouldn't use memcmp to compare structures that
1022 may have `holes' containing uninitialized data, but we have been
1023 careful to initialize the storage of these two variables to all
1024 zeroes. One might think it more efficient simply to compare the
1025 modified fields, but that would require enumerating those fields --
1026 and not all systems have the same fields in this structure. */
1028 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1030 #ifdef CIBAUD
1031 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1032 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1033 sometimes (m1 != m2). The only difference is in the four bits
1034 of the c_cflag field corresponding to the baud rate. To save
1035 Sun users a little confusion, don't report an error if this
1036 happens. But suppress the error only if we haven't tried to
1037 set the baud rate explicitly -- otherwise we'd never give an
1038 error for a true failure to set the baud rate. */
1040 new_mode.c_cflag &= (~CIBAUD);
1041 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1042 #endif
1044 error (EXIT_FAILURE, 0,
1045 _("%s: unable to perform all requested operations"),
1046 device_name);
1047 #ifdef TESTING
1049 size_t i;
1050 printf (_("new_mode: mode\n"));
1051 for (i = 0; i < sizeof (new_mode); i++)
1052 printf ("0x%02x: 0x%02x\n",
1053 *(((unsigned char *) &new_mode) + i),
1054 *(((unsigned char *) &mode) + i));
1056 #endif
1061 exit (EXIT_SUCCESS);
1064 /* Return false if not applied because not reversible; otherwise
1065 return true. */
1067 static bool
1068 set_mode (struct mode_info *info, bool reversed, struct termios *mode)
1070 tcflag_t *bitsp;
1072 if (reversed && (info->flags & REV) == 0)
1073 return false;
1075 bitsp = mode_type_flag (info->type, mode);
1077 if (bitsp == NULL)
1079 /* Combination mode. */
1080 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1082 if (reversed)
1083 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1084 else
1085 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1087 else if (STREQ (info->name, "oddp"))
1089 if (reversed)
1090 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1091 else
1092 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1094 else if (STREQ (info->name, "nl"))
1096 if (reversed)
1098 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1099 mode->c_oflag = (mode->c_oflag
1100 #ifdef ONLCR
1101 | ONLCR
1102 #endif
1104 #ifdef OCRNL
1105 & ~OCRNL
1106 #endif
1107 #ifdef ONLRET
1108 & ~ONLRET
1109 #endif
1112 else
1114 mode->c_iflag = mode->c_iflag & ~ICRNL;
1115 #ifdef ONLCR
1116 mode->c_oflag = mode->c_oflag & ~ONLCR;
1117 #endif
1120 else if (STREQ (info->name, "ek"))
1122 mode->c_cc[VERASE] = CERASE;
1123 mode->c_cc[VKILL] = CKILL;
1125 else if (STREQ (info->name, "sane"))
1126 sane_mode (mode);
1127 else if (STREQ (info->name, "cbreak"))
1129 if (reversed)
1130 mode->c_lflag |= ICANON;
1131 else
1132 mode->c_lflag &= ~ICANON;
1134 else if (STREQ (info->name, "pass8"))
1136 if (reversed)
1138 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1139 mode->c_iflag |= ISTRIP;
1141 else
1143 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1144 mode->c_iflag &= ~ISTRIP;
1147 else if (STREQ (info->name, "litout"))
1149 if (reversed)
1151 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1152 mode->c_iflag |= ISTRIP;
1153 mode->c_oflag |= OPOST;
1155 else
1157 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1158 mode->c_iflag &= ~ISTRIP;
1159 mode->c_oflag &= ~OPOST;
1162 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1164 if ((info->name[0] == 'r' && reversed)
1165 || (info->name[0] == 'c' && !reversed))
1167 /* Cooked mode. */
1168 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1169 mode->c_oflag |= OPOST;
1170 mode->c_lflag |= ISIG | ICANON;
1171 #if VMIN == VEOF
1172 mode->c_cc[VEOF] = CEOF;
1173 #endif
1174 #if VTIME == VEOL
1175 mode->c_cc[VEOL] = CEOL;
1176 #endif
1178 else
1180 /* Raw mode. */
1181 mode->c_iflag = 0;
1182 mode->c_oflag &= ~OPOST;
1183 mode->c_lflag &= ~(ISIG | ICANON
1184 #ifdef XCASE
1185 | XCASE
1186 #endif
1188 mode->c_cc[VMIN] = 1;
1189 mode->c_cc[VTIME] = 0;
1192 #ifdef IXANY
1193 else if (STREQ (info->name, "decctlq"))
1195 if (reversed)
1196 mode->c_iflag |= IXANY;
1197 else
1198 mode->c_iflag &= ~IXANY;
1200 #endif
1201 #ifdef TABDLY
1202 else if (STREQ (info->name, "tabs"))
1204 if (reversed)
1205 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1206 else
1207 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1209 #else
1210 # ifdef OXTABS
1211 else if (STREQ (info->name, "tabs"))
1213 if (reversed)
1214 mode->c_oflag = mode->c_oflag | OXTABS;
1215 else
1216 mode->c_oflag = mode->c_oflag & ~OXTABS;
1218 # endif
1219 #endif
1220 #if defined XCASE && defined IUCLC && defined OLCUC
1221 else if (STREQ (info->name, "lcase")
1222 || STREQ (info->name, "LCASE"))
1224 if (reversed)
1226 mode->c_lflag &= ~XCASE;
1227 mode->c_iflag &= ~IUCLC;
1228 mode->c_oflag &= ~OLCUC;
1230 else
1232 mode->c_lflag |= XCASE;
1233 mode->c_iflag |= IUCLC;
1234 mode->c_oflag |= OLCUC;
1237 #endif
1238 else if (STREQ (info->name, "crt"))
1239 mode->c_lflag |= ECHOE
1240 #ifdef ECHOCTL
1241 | ECHOCTL
1242 #endif
1243 #ifdef ECHOKE
1244 | ECHOKE
1245 #endif
1247 else if (STREQ (info->name, "dec"))
1249 mode->c_cc[VINTR] = 3; /* ^C */
1250 mode->c_cc[VERASE] = 127; /* DEL */
1251 mode->c_cc[VKILL] = 21; /* ^U */
1252 mode->c_lflag |= ECHOE
1253 #ifdef ECHOCTL
1254 | ECHOCTL
1255 #endif
1256 #ifdef ECHOKE
1257 | ECHOKE
1258 #endif
1260 #ifdef IXANY
1261 mode->c_iflag &= ~IXANY;
1262 #endif
1265 else if (reversed)
1266 *bitsp = *bitsp & ~info->mask & ~info->bits;
1267 else
1268 *bitsp = (*bitsp & ~info->mask) | info->bits;
1270 return true;
1273 static void
1274 set_control_char (struct control_info *info, const char *arg,
1275 struct termios *mode)
1277 unsigned long int value;
1279 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1280 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1281 else if (arg[0] == '\0' || arg[1] == '\0')
1282 value = to_uchar (arg[0]);
1283 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1284 value = _POSIX_VDISABLE;
1285 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1287 if (arg[1] == '?')
1288 value = 127;
1289 else
1290 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1292 else
1293 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1294 mode->c_cc[info->offset] = value;
1297 static void
1298 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1300 speed_t baud;
1302 baud = string_to_baud (arg);
1303 if (type == input_speed || type == both_speeds)
1304 cfsetispeed (mode, baud);
1305 if (type == output_speed || type == both_speeds)
1306 cfsetospeed (mode, baud);
1309 #ifdef TIOCGWINSZ
1311 static int
1312 get_win_size (int fd, struct winsize *win)
1314 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1315 return err;
1318 static void
1319 set_window_size (int rows, int cols, char const *device_name)
1321 struct winsize win;
1323 if (get_win_size (STDIN_FILENO, &win))
1325 if (errno != EINVAL)
1326 error (EXIT_FAILURE, errno, "%s", device_name);
1327 memset (&win, 0, sizeof (win));
1330 if (rows >= 0)
1331 win.ws_row = rows;
1332 if (cols >= 0)
1333 win.ws_col = cols;
1335 # ifdef TIOCSSIZE
1336 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1337 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1338 This comment from sys/ttold.h describes Sun's twisted logic - a better
1339 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1340 At any rate, the problem is gone in Solaris 2.x.
1342 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1343 but they can be disambiguated by checking whether a "struct ttysize"
1344 structure's "ts_lines" field is greater than 64K or not. If so,
1345 it's almost certainly a "struct winsize" instead.
1347 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1348 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1349 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1350 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1351 "stty cols 0 rows 0" would do the right thing. On a little-endian
1352 machine like the sun386i, the problem is the same, but for ws_col == 0.
1354 The workaround is to do the ioctl once with row and col = 1 to set the
1355 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1357 if (win.ws_row == 0 || win.ws_col == 0)
1359 struct ttysize ttysz;
1361 ttysz.ts_lines = win.ws_row;
1362 ttysz.ts_cols = win.ws_col;
1364 win.ws_row = 1;
1365 win.ws_col = 1;
1367 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1368 error (EXIT_FAILURE, errno, "%s", device_name);
1370 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1371 error (EXIT_FAILURE, errno, "%s", device_name);
1372 return;
1374 # endif
1376 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1377 error (EXIT_FAILURE, errno, "%s", device_name);
1380 static void
1381 display_window_size (bool fancy, char const *device_name)
1383 struct winsize win;
1385 if (get_win_size (STDIN_FILENO, &win))
1387 if (errno != EINVAL)
1388 error (EXIT_FAILURE, errno, "%s", device_name);
1389 if (!fancy)
1390 error (EXIT_FAILURE, 0,
1391 _("%s: no size information for this device"), device_name);
1393 else
1395 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1396 win.ws_row, win.ws_col);
1397 if (!fancy)
1398 current_col = 0;
1401 #endif
1403 static int
1404 screen_columns (void)
1406 #ifdef TIOCGWINSZ
1407 struct winsize win;
1409 /* With Solaris 2.[123], this ioctl fails and errno is set to
1410 EINVAL for telnet (but not rlogin) sessions.
1411 On ISC 3.0, it fails for the console and the serial port
1412 (but it works for ptys).
1413 It can also fail on any system when stdout isn't a tty.
1414 In case of any failure, just use the default. */
1415 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1416 return win.ws_col;
1417 #endif
1419 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1420 char *col_string = getenv ("COLUMNS");
1421 long int n_columns;
1422 if (!(col_string != NULL
1423 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1424 && 0 < n_columns
1425 && n_columns <= INT_MAX))
1426 n_columns = 80;
1427 return n_columns;
1431 static tcflag_t *
1432 mode_type_flag (enum mode_type type, struct termios *mode)
1434 switch (type)
1436 case control:
1437 return &mode->c_cflag;
1439 case input:
1440 return &mode->c_iflag;
1442 case output:
1443 return &mode->c_oflag;
1445 case local:
1446 return &mode->c_lflag;
1448 case combination:
1449 return NULL;
1451 default:
1452 abort ();
1456 static void
1457 display_settings (enum output_type output_type, struct termios *mode,
1458 char const *device_name)
1460 switch (output_type)
1462 case changed:
1463 display_changed (mode);
1464 break;
1466 case all:
1467 display_all (mode, device_name);
1468 break;
1470 case recoverable:
1471 display_recoverable (mode);
1472 break;
1476 static void
1477 display_changed (struct termios *mode)
1479 int i;
1480 bool empty_line;
1481 tcflag_t *bitsp;
1482 unsigned long mask;
1483 enum mode_type prev_type = control;
1485 display_speed (mode, true);
1486 #ifdef HAVE_C_LINE
1487 wrapf ("line = %d;", mode->c_line);
1488 #endif
1489 putchar ('\n');
1490 current_col = 0;
1492 empty_line = true;
1493 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1495 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1496 continue;
1497 /* If swtch is the same as susp, don't print both. */
1498 #if VSWTCH == VSUSP
1499 if (STREQ (control_info[i].name, "swtch"))
1500 continue;
1501 #endif
1502 /* If eof uses the same slot as min, only print whichever applies. */
1503 #if VEOF == VMIN
1504 if ((mode->c_lflag & ICANON) == 0
1505 && (STREQ (control_info[i].name, "eof")
1506 || STREQ (control_info[i].name, "eol")))
1507 continue;
1508 #endif
1510 empty_line = false;
1511 wrapf ("%s = %s;", control_info[i].name,
1512 visible (mode->c_cc[control_info[i].offset]));
1514 if ((mode->c_lflag & ICANON) == 0)
1516 wrapf ("min = %lu; time = %lu;\n",
1517 (unsigned long int) mode->c_cc[VMIN],
1518 (unsigned long int) mode->c_cc[VTIME]);
1520 else if (!empty_line)
1521 putchar ('\n');
1522 current_col = 0;
1524 empty_line = true;
1525 for (i = 0; mode_info[i].name != NULL; ++i)
1527 if (mode_info[i].flags & OMIT)
1528 continue;
1529 if (mode_info[i].type != prev_type)
1531 if (!empty_line)
1533 putchar ('\n');
1534 current_col = 0;
1535 empty_line = true;
1537 prev_type = mode_info[i].type;
1540 bitsp = mode_type_flag (mode_info[i].type, mode);
1541 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1542 if ((*bitsp & mask) == mode_info[i].bits)
1544 if (mode_info[i].flags & SANE_UNSET)
1546 wrapf ("%s", mode_info[i].name);
1547 empty_line = false;
1550 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1552 wrapf ("-%s", mode_info[i].name);
1553 empty_line = false;
1556 if (!empty_line)
1557 putchar ('\n');
1558 current_col = 0;
1561 static void
1562 display_all (struct termios *mode, char const *device_name)
1564 int i;
1565 tcflag_t *bitsp;
1566 unsigned long mask;
1567 enum mode_type prev_type = control;
1569 display_speed (mode, true);
1570 #ifdef TIOCGWINSZ
1571 display_window_size (true, device_name);
1572 #endif
1573 #ifdef HAVE_C_LINE
1574 wrapf ("line = %d;", mode->c_line);
1575 #endif
1576 putchar ('\n');
1577 current_col = 0;
1579 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1581 /* If swtch is the same as susp, don't print both. */
1582 #if VSWTCH == VSUSP
1583 if (STREQ (control_info[i].name, "swtch"))
1584 continue;
1585 #endif
1586 /* If eof uses the same slot as min, only print whichever applies. */
1587 #if VEOF == VMIN
1588 if ((mode->c_lflag & ICANON) == 0
1589 && (STREQ (control_info[i].name, "eof")
1590 || STREQ (control_info[i].name, "eol")))
1591 continue;
1592 #endif
1593 wrapf ("%s = %s;", control_info[i].name,
1594 visible (mode->c_cc[control_info[i].offset]));
1596 #if VEOF == VMIN
1597 if ((mode->c_lflag & ICANON) == 0)
1598 #endif
1599 wrapf ("min = %lu; time = %lu;",
1600 (unsigned long int) mode->c_cc[VMIN],
1601 (unsigned long int) mode->c_cc[VTIME]);
1602 if (current_col != 0)
1603 putchar ('\n');
1604 current_col = 0;
1606 for (i = 0; mode_info[i].name != NULL; ++i)
1608 if (mode_info[i].flags & OMIT)
1609 continue;
1610 if (mode_info[i].type != prev_type)
1612 putchar ('\n');
1613 current_col = 0;
1614 prev_type = mode_info[i].type;
1617 bitsp = mode_type_flag (mode_info[i].type, mode);
1618 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1619 if ((*bitsp & mask) == mode_info[i].bits)
1620 wrapf ("%s", mode_info[i].name);
1621 else if (mode_info[i].flags & REV)
1622 wrapf ("-%s", mode_info[i].name);
1624 putchar ('\n');
1625 current_col = 0;
1628 static void
1629 display_speed (struct termios *mode, bool fancy)
1631 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1632 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1633 baud_to_value (cfgetospeed (mode)));
1634 else
1635 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1636 baud_to_value (cfgetispeed (mode)),
1637 baud_to_value (cfgetospeed (mode)));
1638 if (!fancy)
1639 current_col = 0;
1642 static void
1643 display_recoverable (struct termios *mode)
1645 size_t i;
1647 printf ("%lx:%lx:%lx:%lx",
1648 (unsigned long int) mode->c_iflag,
1649 (unsigned long int) mode->c_oflag,
1650 (unsigned long int) mode->c_cflag,
1651 (unsigned long int) mode->c_lflag);
1652 for (i = 0; i < NCCS; ++i)
1653 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1654 putchar ('\n');
1657 static bool
1658 recover_mode (char const *arg, struct termios *mode)
1660 size_t i;
1661 int n;
1662 unsigned long int chr;
1663 unsigned long int iflag, oflag, cflag, lflag;
1665 /* Scan into temporaries since it is too much trouble to figure out
1666 the right format for `tcflag_t'. */
1667 if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1668 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1669 return false;
1670 mode->c_iflag = iflag;
1671 mode->c_oflag = oflag;
1672 mode->c_cflag = cflag;
1673 mode->c_lflag = lflag;
1674 if (mode->c_iflag != iflag
1675 || mode->c_oflag != oflag
1676 || mode->c_cflag != cflag
1677 || mode->c_lflag != lflag)
1678 return false;
1679 arg += n;
1680 for (i = 0; i < NCCS; ++i)
1682 if (sscanf (arg, ":%lx%n", &chr, &n) != 1)
1683 return false;
1684 mode->c_cc[i] = chr;
1685 if (mode->c_cc[i] != chr)
1686 return false;
1687 arg += n;
1690 /* Fail if there are too many fields. */
1691 if (*arg != '\0')
1692 return false;
1694 return true;
1697 struct speed_map
1699 const char *string; /* ASCII representation. */
1700 speed_t speed; /* Internal form. */
1701 unsigned long int value; /* Numeric value. */
1704 static struct speed_map speeds[] =
1706 {"0", B0, 0},
1707 {"50", B50, 50},
1708 {"75", B75, 75},
1709 {"110", B110, 110},
1710 {"134", B134, 134},
1711 {"134.5", B134, 134},
1712 {"150", B150, 150},
1713 {"200", B200, 200},
1714 {"300", B300, 300},
1715 {"600", B600, 600},
1716 {"1200", B1200, 1200},
1717 {"1800", B1800, 1800},
1718 {"2400", B2400, 2400},
1719 {"4800", B4800, 4800},
1720 {"9600", B9600, 9600},
1721 {"19200", B19200, 19200},
1722 {"38400", B38400, 38400},
1723 {"exta", B19200, 19200},
1724 {"extb", B38400, 38400},
1725 #ifdef B57600
1726 {"57600", B57600, 57600},
1727 #endif
1728 #ifdef B115200
1729 {"115200", B115200, 115200},
1730 #endif
1731 #ifdef B230400
1732 {"230400", B230400, 230400},
1733 #endif
1734 #ifdef B460800
1735 {"460800", B460800, 460800},
1736 #endif
1737 #ifdef B500000
1738 {"500000", B500000, 500000},
1739 #endif
1740 #ifdef B576000
1741 {"576000", B576000, 576000},
1742 #endif
1743 #ifdef B921600
1744 {"921600", B921600, 921600},
1745 #endif
1746 #ifdef B1000000
1747 {"1000000", B1000000, 1000000},
1748 #endif
1749 #ifdef B1152000
1750 {"1152000", B1152000, 1152000},
1751 #endif
1752 #ifdef B1500000
1753 {"1500000", B1500000, 1500000},
1754 #endif
1755 #ifdef B2000000
1756 {"2000000", B2000000, 2000000},
1757 #endif
1758 #ifdef B2500000
1759 {"2500000", B2500000, 2500000},
1760 #endif
1761 #ifdef B3000000
1762 {"3000000", B3000000, 3000000},
1763 #endif
1764 #ifdef B3500000
1765 {"3500000", B3500000, 3500000},
1766 #endif
1767 #ifdef B4000000
1768 {"4000000", B4000000, 4000000},
1769 #endif
1770 {NULL, 0, 0}
1773 static speed_t
1774 string_to_baud (const char *arg)
1776 int i;
1778 for (i = 0; speeds[i].string != NULL; ++i)
1779 if (STREQ (arg, speeds[i].string))
1780 return speeds[i].speed;
1781 return (speed_t) -1;
1784 static unsigned long int
1785 baud_to_value (speed_t speed)
1787 int i;
1789 for (i = 0; speeds[i].string != NULL; ++i)
1790 if (speed == speeds[i].speed)
1791 return speeds[i].value;
1792 return 0;
1795 static void
1796 sane_mode (struct termios *mode)
1798 int i;
1799 tcflag_t *bitsp;
1801 for (i = 0; control_info[i].name; ++i)
1803 #if VMIN == VEOF
1804 if (STREQ (control_info[i].name, "min"))
1805 break;
1806 #endif
1807 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1810 for (i = 0; mode_info[i].name != NULL; ++i)
1812 if (mode_info[i].flags & SANE_SET)
1814 bitsp = mode_type_flag (mode_info[i].type, mode);
1815 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1817 else if (mode_info[i].flags & SANE_UNSET)
1819 bitsp = mode_type_flag (mode_info[i].type, mode);
1820 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1825 /* Return a string that is the printable representation of character CH. */
1826 /* Adapted from `cat' by Torbjorn Granlund. */
1828 static const char *
1829 visible (cc_t ch)
1831 static char buf[10];
1832 char *bpout = buf;
1834 if (ch == _POSIX_VDISABLE)
1835 return "<undef>";
1837 if (ch >= 32)
1839 if (ch < 127)
1840 *bpout++ = ch;
1841 else if (ch == 127)
1843 *bpout++ = '^';
1844 *bpout++ = '?';
1846 else
1848 *bpout++ = 'M',
1849 *bpout++ = '-';
1850 if (ch >= 128 + 32)
1852 if (ch < 128 + 127)
1853 *bpout++ = ch - 128;
1854 else
1856 *bpout++ = '^';
1857 *bpout++ = '?';
1860 else
1862 *bpout++ = '^';
1863 *bpout++ = ch - 128 + 64;
1867 else
1869 *bpout++ = '^';
1870 *bpout++ = ch + 64;
1872 *bpout = '\0';
1873 return (const char *) buf;
1876 /* Parse string S as an integer, using decimal radix by default,
1877 but allowing octal and hex numbers as in C. Reject values
1878 larger than MAXVAL. */
1880 static unsigned long int
1881 integer_arg (const char *s, unsigned long int maxval)
1883 unsigned long int value;
1884 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK
1885 || maxval < value)
1887 error (0, 0, _("invalid integer argument %s"), quote (s));
1888 usage (EXIT_FAILURE);
1890 return value;