* Copyright (c) 1980, 1989, 1991 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1980, 1989, 1991 Regents of the University of California.\n\
static char sccsid
[] = "@(#)stty.c 5.19 (Berkeley) %G%";
#define eq(s1, s2) (strcmp((s1), (s2)) == 0)
struct modes imodes
[] = {
struct modes omodes
[] = {
"tabs", 0, OXTABS
, /* "preserve" tabs */
struct modes cmodes
[] = {
"parity", PARENB
| CS7
, PARODD
| CSIZE
,
"evenp", PARENB
| CS7
, PARODD
| CSIZE
,
"oddp", PARENB
| CS7
| PARODD
, CSIZE
,
"-parity", CS8
, PARODD
| PARENB
| CSIZE
,
"pass8", CS8
, PARODD
| PARENB
| CSIZE
,
"-evenp", CS8
, PARODD
| PARENB
| CSIZE
,
"-oddp", CS8
, PARODD
| PARENB
| CSIZE
,
struct modes lmodes
[] = {
"crtbs", ECHOE
, 0, /* crtbs not supported, close enough */
"altwerase", ALTWERASE
, 0,
"-altwerase", 0, ALTWERASE
,
"crt", ECHOE
|ECHOKE
|ECHOCTL
, ECHOK
|ECHOPRT
,
"-crt", ECHOK
, ECHOE
|ECHOKE
|ECHOCTL
,
"newcrt", ECHOE
|ECHOKE
|ECHOCTL
, ECHOK
|ECHOPRT
,
"-newcrt", ECHOK
, ECHOE
|ECHOKE
|ECHOCTL
,
"nokerninfo", NOKERNINFO
, 0,
"-nokerninfo", 0, NOKERNINFO
,
"kerninfo", 0, NOKERNINFO
,
"-kerninfo", NOKERNINFO
, 0,
* Special control characters.
* Each entry has a list of names. The first is the primary name
* and is used when printing the control character in the "name = val;"
* form. The second is an abbreviation which is guaranteed to be less
* than or equal to four characters in length and is primarily used
* when printing the values in columunar form (guarantees all will
* fit within 80 cols). The rest are optional aliases.
* All names are recognized on the command line.
{{ "erase", "era" }, VERASE
, CERASE
, },
{{ "werase", "wera" }, VWERASE
, CWERASE
, },
{{ "kill", "kill" }, VKILL
, CKILL
, },
{{ "intr", "int" }, VINTR
, CINTR
, },
{{ "quit", "quit" }, VQUIT
, CQUIT
, },
{{ "susp", "susp" }, VSUSP
, CSUSP
, },
{{ "dsusp", "dsus" }, VDSUSP
, CDSUSP
, },
{{ "eof", "eof" }, VEOF
, CEOF
, },
{{ "eol", "eol", "brk" }, VEOL
, CEOL
, },
{{ "eol2", "eol2" }, VEOL2
, CEOL
, },
{{ "stop", "stop", "xoff" }, VSTOP
, CSTOP
, },
{{ "start", "star", "xon" }, VSTART
, CSTART
, },
{{ "lnext", "lnxt" }, VLNEXT
, CLNEXT
, },
{{ "discard", "disc", "flush" }, VDISCARD
, CDISCARD
, },
{{ "reprint", "rpnt", "rprnt" }, VREPRINT
, CREPRINT
, },
{{ "status", "stat" }, VSTATUS
, CSTATUS
, },
#define OUT stdout /* informational output stream */
#define ERR stderr /* error message stream */
#define CTL 0 /* default control descriptor */
#define NORMAL 0 /* only print modes differing from defaults */
#define ALL 1 /* print all modes - POSIX standard format */
#define ALL_BSD 2 /* print all modes - using BSD shorthand for cc's */
#define GFMT 3 /* print modes in form suitable to be re-input */
if (argc
> 0 && eq(argv
[0], "-a")) {
if (argc
> 0 && eq(argv
[0], "-g")) {
if (argc
> 0 && eq(argv
[0], "-f")) {
if ((ctl
= open(argv
[0], O_RDONLY
| O_NONBLOCK
)) < 0)
if (ioctl(ctl
, TIOCGETD
, &ldisc
) < 0)
if (tcgetattr(ctl
, &t
) < 0)
if (ioctl(ctl
, TIOCGWINSZ
, &win
) < 0)
warning("TIOCGWINSZ: %s", strerror(errno
));
checkredirect(); /* conversion aid */
if (eq("everything", *argv
)) {
prmode(&t
, ldisc
, ALL_BSD
);
if (eq("tty", *argv
) || eq("old", *argv
) || eq("new", *argv
)) {
if (ioctl(0, TIOCSETD
, &nldisc
) < 0)
t
.c_cc
[VERASE
] = (u_char
)0177;
t
.c_cc
[VKILL
] = CTRL('u');
t
.c_cc
[VINTR
] = CTRL('c');
t
.c_lflag
|= ECHOE
|ECHOKE
|ECHOCTL
;
t
.c_cflag
&= ~(CSIZE
|PARENB
);
if (eq("cbreak", *argv
)) {
t
.c_iflag
| BRKINT
|IXON
|IMAXBEL
;
t
.c_lflag
|= ISIG
|IEXTEN
;
if (eq("cooked", *argv
) || eq("-raw", *argv
) ||
eq("sane", *argv
) || eq("-cbreak", *argv
)) {
t
.c_cflag
= TTYDEF_CFLAG
| (t
.c_cflag
& CLOCAL
);
t
.c_iflag
= TTYDEF_IFLAG
;
/* preserve user-preference flags in lflag */
#define LKEEP (ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
t
.c_lflag
= TTYDEF_LFLAG
| (t
.c_lflag
& LKEEP
);
t
.c_oflag
= TTYDEF_OFLAG
;
win
.ws_row
= atoi(*++argv
);
if (eq("ispeed", *argv
)) {
errexit("missing ispeed");
cfsetispeed(&t
, atoi(*++argv
));
if (eq("ospeed", *argv
)) {
errexit("missing ospeed");
cfsetospeed(&t
, atoi(*++argv
));
if (eq("cols", *argv
) || eq("columns", *argv
)) {
win
.ws_col
= atoi(*++argv
);
put("%d %d\n", win
.ws_row
, win
.ws_col
);
if (eq("extrpc", *argv
) || eq("-extproc", *argv
)) {
ioctl(ctl
, TIOCEXT
, &extproc
);
if (eq("speed", *argv
)) {
put("%d\n", cfgetospeed(&t
));
for (i
=0; imodes
[i
].name
; i
++)
if (eq(imodes
[i
].name
, *argv
)) {
t
.c_iflag
&= ~imodes
[i
].unset
;
t
.c_iflag
|= imodes
[i
].set
;
for (i
=0; omodes
[i
].name
; i
++)
if (eq(omodes
[i
].name
, *argv
)) {
t
.c_oflag
&= ~omodes
[i
].unset
;
t
.c_oflag
|= omodes
[i
].set
;
for (i
=0; cmodes
[i
].name
; i
++)
if (eq(cmodes
[i
].name
, *argv
)) {
t
.c_cflag
&= ~cmodes
[i
].unset
;
t
.c_cflag
|= cmodes
[i
].set
;
for (i
=0; lmodes
[i
].name
; i
++)
if (eq(lmodes
[i
].name
, *argv
)) {
t
.c_lflag
&= ~lmodes
[i
].unset
;
t
.c_lflag
|= lmodes
[i
].set
;
for (i
=0; *cchars
[i
].names
; i
++) {
char **cp
= cchars
[i
].names
;
if (eq(*argv
, "undef") ||
((*argv
)[1] == '?') ? 0177 :
t
.c_cc
[cchars
[i
].sub
] = **argv
;
cfsetospeed(&t
, atoi(*argv
));
cfsetispeed(&t
, atoi(*argv
));
if (strncmp(*argv
, "-gfmt", sizeof ("-gfmt") - 1) == 0) {
/* didn't match anything */
errexit("unknown option: %s", *argv
);
if (tcsetattr(ctl
, 0, &t
) < 0)
if (ioctl(ctl
, TIOCSWINSZ
, &win
) < 0)
warning("can't set window size");
register struct termios
*tp
;
#define advance(c) while (*(s) && *(s) != (c)) (s)++; if (*s) (s)++ ; \
errexit("bad gfmt operand: %s", saves)
#define chkeq(string) if (strncmp(s, (string), strlen(string))) \
errexit("bad gfmt operand: %s", saves)
errexit("missing gfmt string");
sscanf(s
, "%x", &tp
->c_iflag
);
sscanf(s
, "%x", &tp
->c_oflag
);
sscanf(s
, "%x", &tp
->c_cflag
);
sscanf(s
, "%x", &tp
->c_lflag
);
for (cnt
= 0, sep
= '='; cnt
< NCCS
; cnt
++, sep
= ',') {
sscanf(s
, "%d", &tp
->c_ispeed
);
sscanf(s
, "%d", &tp
->c_ospeed
);
int ispeed
= cfgetispeed(tp
),
ospeed
= cfgetospeed(tp
);
printf("-gfmt:iflag=%x:oflag=%x:cflag=%x:lflag=%x:cc",
for (cnt
= 0, sep
= '='; cnt
< NCCS
; cnt
++, sep
= ',')
printf("%c%o", sep
, cc
[cnt
]);
printf(":ispeed=%d:ospeed=%d:\n", ispeed
, ospeed
);
sprintf(unknown
, "#%d", ldisc
);
put("ispeed %d baud; ospeed %d baud;",
put("speed %d baud;", ispeed
);
put(" %d rows; %d columns;", win
.ws_row
, win
.ws_col
);
#define lput(n, f, d) if (fmt || on(f) != d) mdput(n+on(f))
#define on(f) ((l&f) != 0)
if (debug
) mdput("LFLAG: ");
lput("-icanon ",ICANON
, 1);
lput("-iexten ", IEXTEN
, 1);
lput("-echoe ",ECHOE
, 0);
lput("-echok ",ECHOK
, 0);
lput("-echoke ",ECHOKE
, 0);
lput("-echonl ",ECHONL
, 0);
lput("-echoctl ",ECHOCTL
, 0);
lput("-echoprt ",ECHOPRT
, 0);
lput("-altwerase ",ALTWERASE
, 0);
lput("-noflsh ",NOFLSH
, 0);
lput("-tostop ",TOSTOP
, 0);
lput("-mdmbuf ",MDMBUF
, 0);
lput("-flusho ",FLUSHO
, 0);
lput("-pendin ",PENDIN
, 0);
lput("-nokerninfo ",NOKERNINFO
, 0);
lput("-extproc ",EXTPROC
, 0);
#define on(f) ((i&f) != 0)
if (debug
) mdput("IFLAG: ");
lput("-istrip ", ISTRIP
, 0);
lput("-icrnl ", ICRNL
, 1);
lput("-inlcr ", INLCR
, 0);
lput("-igncr ", IGNCR
, 0);
lput("-ixoff ", IXOFF
, 0);
lput("-ixany ", IXANY
, 1);
lput("-imaxbel ", IMAXBEL
, 1);
lput("-ignbrk ", IGNBRK
, 0);
lput("-brkint ", BRKINT
, 1);
lput("-inpck ", INPCK
, 0);
lput("-ignpar ", IGNPAR
, 0);
lput("-parmrk ", PARMRK
, 0);
#define on(f) ((o&f) != 0)
if (debug
) mdput("OFLAG: ");
lput("-opost ", OPOST
, 1);
lput("-onlcr ", ONLCR
, 1);
lput("-oxtabs ", OXTABS
, 1);
* control flags (hardware state)
#define on(f) ((c&f) != 0)
if (debug
) mdput("CFLAG: ");
lput("-cread ", CREAD
, 1);
case CS5
: mdput("cs5 "); break;
case CS6
: mdput("cs6 "); break;
case CS7
: mdput("cs7 "); break;
case CS8
: mdput("cs8 "); break;
mdput("-parenb "+on(PARENB
));
lput("-parodd ", PARODD
, 0);
lput("-hupcl ", HUPCL
, 1);
lput("-clocal ", CLOCAL
, 0);
lput("-cstopb ", CSTOPB
, 0);
lput("-crtscts ", CRTSCTS
, 0);
* special control characters
if (debug
) mdput("CCHARS: ");
for (i
=0; *cchars
[i
].names
; i
++) {
if (fmt
|| cc
[cchars
[i
].sub
] != cchars
[i
].def
) {
sprintf(temp
, "%s = %s; ", *cchars
[i
].names
,
ccval(cc
[cchars
[i
].sub
]), fmt
);
for (i
=0; *cchars
[i
].names
; i
++)
put("%*s", strlen(*(cchars
[i
].names
+1)) + (i
>0?1:0),
for (i
=0; *cchars
[i
].names
; i
++)
put("%*s", strlen(*(cchars
[i
].names
+1)) + (i
>0?1:0),
ccval(cc
[cchars
[i
].sub
], fmt
));
* gross, but since we're changing the control descriptor
* from 1 to 0, most users will be probably be doing
* "stty > /dev/sometty" by accident. If 1 and 2 are both ttys,
* but not the same, assume that 1 was incorrectly redirected.
if (isatty(1) && isatty(2) && fstat(1, &st1
) != -1 &&
fstat(2, &st2
) != -1 && (st1
.st_rdev
!= st2
.st_rdev
))
warning("stdout appears redirected, but stdin is the control descriptor");
if (c
== _POSIX_VDISABLE
)
if ((col
+= strlen(s
)) > WRAPCOL
) {
fmt
= va_arg(ap
, char *);
(void) vfprintf(OUT
, fmt
, ap
);
fprintf(ERR
, "stty: warning: ");
fmt
= va_arg(ap
, char *);
(void) vfprintf(ERR
, fmt
, ap
);
fmt
= va_arg(ap
, char *);
(void) vfprintf(ERR
, fmt
, ap
);
fmt
= va_arg(ap
, char *);
(void) vfprintf(ERR
, fmt
, ap
);
fprintf(ERR
, ": %s\n", strerror(errno
));