/* * 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. */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1980, 1989, 1991 Regents of the University of California.\n\ All rights reserved.\n"; #endif not lint #ifndef lint static char sccsid[] = "@(#)stty.c 5.19 (Berkeley) 02/06/91"; #endif not lint /* * set teletype modes */ #include #include #include #include #define KERNEL #include #undef KERNEL #include #include #include #include #include #define eq(s1, s2) (strcmp((s1), (s2)) == 0) #define WRAPCOL 65 struct modes { char *name; long set; long unset; }; struct modes imodes[] = { "ignbrk", IGNBRK, 0, "-ignbrk", 0, IGNBRK, "brkint", BRKINT, 0, "-brkint", 0, BRKINT, "ignpar", IGNPAR, 0, "-ignpar", 0, IGNPAR, "parmrk", PARMRK, 0, "-parmrk", 0, PARMRK, "inpck", INPCK, 0, "-inpck", 0, INPCK, "istrip", ISTRIP, 0, "-istrip", 0, ISTRIP, "inlcr", INLCR, 0, "-inlcr", 0, INLCR, "igncr", IGNCR, 0, "-igncr", 0, IGNCR, "icrnl", ICRNL, 0, "-icrnl", 0, ICRNL, "ixon", IXON, 0, "-ixon", 0, IXON, "flow", IXON, 0, "-flow", 0, IXON, "ixoff", IXOFF, 0, "-ixoff", 0, IXOFF, "tandem", IXOFF, 0, "-tandem", 0, IXOFF, "ixany", IXANY, 0, "-ixany", 0, IXANY, "decctlq", 0, IXANY, "-decctlq", IXANY, 0, "imaxbel", IMAXBEL, 0, "-imaxbel", 0, IMAXBEL, 0 }; struct modes omodes[] = { "opost", OPOST, 0, "-opost", 0, OPOST, "-litout", OPOST, 0, "litout", 0, OPOST, "onlcr", ONLCR, 0, "-onlcr", 0, ONLCR, "tabs", 0, OXTABS, /* "preserve" tabs */ "-tabs", OXTABS, 0, "xtabs", OXTABS, 0, "-xtabs", 0, OXTABS, "oxtabs", OXTABS, 0, "-oxtabs", 0, OXTABS, 0 }; struct modes cmodes[] = { "cs5", CS5, CSIZE, "cs6", CS6, CSIZE, "cs7", CS7, CSIZE, "cs8", CS8, CSIZE, "cstopb", CSTOPB, 0, "-cstopb", 0, CSTOPB, "cread", CREAD, 0, "-cread", 0, CREAD, "parenb", PARENB, 0, "-parenb", 0, PARENB, "parodd", PARODD, 0, "-parodd", 0, PARODD, "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, "hupcl", HUPCL, 0, "-hupcl", 0, HUPCL, "hup", HUPCL, 0, "-hup", 0, HUPCL, "clocal", CLOCAL, 0, "-clocal", 0, CLOCAL, "crtscts", CRTSCTS, 0, "-crtscts", 0, CRTSCTS, 0 }; struct modes lmodes[] = { "echo", ECHO, 0, "-echo", 0, ECHO, "echoe", ECHOE, 0, "-echoe", 0, ECHOE, "crterase", ECHOE, 0, "-crterase", 0, ECHOE, "crtbs", ECHOE, 0, /* crtbs not supported, close enough */ "-crtbs", 0, ECHOE, "echok", ECHOK, 0, "-echok", 0, ECHOK, "echoke", ECHOKE, 0, "-echoke", 0, ECHOKE, "crtkill", ECHOKE, 0, "-crtkill", 0, ECHOKE, "altwerase", ALTWERASE, 0, "-altwerase", 0, ALTWERASE, "iexten", IEXTEN, 0, "-iexten", 0, IEXTEN, "echonl", ECHONL, 0, "-echonl", 0, ECHONL, "echoctl", ECHOCTL, 0, "-echoctl", 0, ECHOCTL, "ctlecho", ECHOCTL, 0, "-ctlecho", 0, ECHOCTL, "echoprt", ECHOPRT, 0, "-echoprt", 0, ECHOPRT, "prterase", ECHOPRT, 0, "-prterase", 0, ECHOPRT, "isig", ISIG, 0, "-isig", 0, ISIG, "icanon", ICANON, 0, "-icanon", 0, ICANON, "noflsh", NOFLSH, 0, "-noflsh", 0, NOFLSH, "tostop", TOSTOP, 0, "-tostop", 0, TOSTOP, "mdmbuf", MDMBUF, 0, "-mdmbuf", 0, MDMBUF, "flusho", FLUSHO, 0, "-flusho", 0, FLUSHO, "pendin", PENDIN, 0, "-pendin", 0, PENDIN, "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, 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. */ #define MAXNAMES 3 struct { char *names[MAXNAMES+1]; int sub; u_char def; } cchars[] = { {{ "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, }, 0 }; struct winsize win; int ldisc; int debug = 0; int trace, dotrace; int extproc; #define OUT stdout /* informational output stream */ #define ERR stderr /* error message stream */ #define CTL 0 /* default control descriptor */ int ctl = CTL; extern errno; #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 */ main(argc, argv) char *argv[]; { struct termios t; int i, fmt = NORMAL; extern char *optarg; extern int optind; int ch; argc--, argv++; if (argc > 0 && eq(argv[0], "-a")) { fmt = ALL; argc--, argv++; } if (argc > 0 && eq(argv[0], "-g")) { fmt = GFMT; argc--, argv++; } if (argc > 0 && eq(argv[0], "-f")) { argc--, argv++; if ((ctl = open(argv[0], O_RDONLY | O_NONBLOCK)) < 0) syserrexit(*argv); argc--, argv++; } if (ioctl(ctl, TIOCGETD, &ldisc) < 0) syserrexit("TIOCGETD"); if (tcgetattr(ctl, &t) < 0) syserrexit("tcgetattr"); if (ioctl(ctl, TIOCGWINSZ, &win) < 0) warning("TIOCGWINSZ: %s", strerror(errno)); checkredirect(); /* conversion aid */ if (argc == 0 || fmt) { prmode(&t, ldisc, fmt); exit(0); } while (*argv) { if (eq("everything", *argv)) { prmode(&t, ldisc, ALL_BSD); exit(0); } if (eq("all", *argv)) { prmode(&t, ldisc, ALL); exit(0); } if (eq("tty", *argv) || eq("old", *argv) || eq("new", *argv)) { int nldisc = TTYDISC; if (ioctl(0, TIOCSETD, &nldisc) < 0) syserrexit("TIOCSETD"); goto next; } if (eq("nl", *argv)) { t.c_iflag &= ~ICRNL; t.c_oflag &= ~ONLCR; goto next; } if (eq("-nl", *argv)) { t.c_iflag |= ICRNL; t.c_oflag |= ONLCR; goto next; } if (eq("dec", *argv)){ t.c_cc[VERASE] = (u_char)0177; t.c_cc[VKILL] = CTRL('u'); t.c_cc[VINTR] = CTRL('c'); t.c_lflag &= ~ECHOPRT; t.c_lflag |= ECHOE|ECHOKE|ECHOCTL; t.c_iflag &= ~IXANY; goto next; } if (eq("raw", *argv)) { cfmakeraw(&t); t.c_cflag &= ~(CSIZE|PARENB); t.c_cflag |= CS8; goto next; } if (eq("cbreak", *argv)) { t.c_iflag | BRKINT|IXON|IMAXBEL; t.c_oflag |= OPOST; t.c_lflag |= ISIG|IEXTEN; t.c_lflag &= ~ICANON; } 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; t.c_iflag |= ICRNL; /* 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; goto next; } if (eq("rows", *argv)) { if (*(argv+1) == 0) goto setit; win.ws_row = atoi(*++argv); goto next; } if (eq("ispeed", *argv)) { int code; if (*(argv+1) == 0) errexit("missing ispeed"); cfsetispeed(&t, atoi(*++argv)); goto next; } if (eq("ospeed", *argv)) { if (*(argv+1) == 0) errexit("missing ospeed"); cfsetospeed(&t, atoi(*++argv)); goto next; } if (eq("cols", *argv) || eq("columns", *argv)) { if (*(argv+1) == 0) goto setit; win.ws_col = atoi(*++argv); goto next; } if (eq("size", *argv)) { put("%d %d\n", win.ws_row, win.ws_col); exit(0); } if (eq("extrpc", *argv) || eq("-extproc", *argv)) { if (**argv == '-') extproc = 0; else extproc = 1; ioctl(ctl, TIOCEXT, &extproc); } if (eq("speed", *argv)) { put("%d\n", cfgetospeed(&t)); exit(0); } 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; goto next; } 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; goto next; } 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; goto next; } 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; goto next; } for (i=0; *cchars[i].names; i++) { char **cp = cchars[i].names; while (*cp) { if (eq(*cp, *argv)) { if (*++argv == 0) goto setit; if (eq(*argv, "undef") || eq(*argv, "disable")) t.c_cc[cchars[i].sub] = _POSIX_VDISABLE; else if (**argv == '^') t.c_cc[cchars[i].sub] = ((*argv)[1] == '?') ? 0177 : ((*argv)[1] == '-') ? _POSIX_VDISABLE : (*argv)[1] & 037; else t.c_cc[cchars[i].sub] = **argv; goto next; } cp++; } } if (isdigit(**argv)) { cfsetospeed(&t, atoi(*argv)); cfsetispeed(&t, atoi(*argv)); goto next; } if (strncmp(*argv, "-gfmt", sizeof ("-gfmt") - 1) == 0) { gfmtset(&t, *argv); goto next; } /* didn't match anything */ errexit("unknown option: %s", *argv); exit(1); next: argv++; } setit: if (tcsetattr(ctl, 0, &t) < 0) syserrexit("tcsetattr"); if (ioctl(ctl, TIOCSWINSZ, &win) < 0) warning("can't set window size"); exit(0); } gfmtset(tp, s) register struct termios *tp; char *s; { register int cnt; char sep; char *saves = s; int cval; #define advance(c) while (*(s) && *(s) != (c)) (s)++; if (*s) (s)++ ; \ else \ errexit("bad gfmt operand: %s", saves) #define chkeq(string) if (strncmp(s, (string), strlen(string))) \ errexit("bad gfmt operand: %s", saves) if (s == NULL) errexit("missing gfmt string"); advance(':'); chkeq("iflag="); advance('='); sscanf(s, "%x", &tp->c_iflag); advance(':'); chkeq("oflag"); advance('='); sscanf(s, "%x", &tp->c_oflag); advance(':'); chkeq("cflag"); advance('='); sscanf(s, "%x", &tp->c_cflag); advance(':'); chkeq("lflag"); advance('='); sscanf(s, "%x", &tp->c_lflag); advance(':'); chkeq("cc="); for (cnt = 0, sep = '='; cnt < NCCS; cnt++, sep = ',') { advance(sep); sscanf(s, "%o", &cval); tp->c_cc[cnt] = cval; } advance(':'); chkeq("ispeed="); advance('='); sscanf(s, "%d", &tp->c_ispeed); advance(':'); chkeq("ospeed="); advance('='); sscanf(s, "%d", &tp->c_ospeed); } prmode(tp, ldisc, fmt) struct termios *tp; { long i = tp->c_iflag, o = tp->c_oflag, c = tp->c_cflag, l = tp->c_lflag; u_char *cc = tp->c_cc; int ispeed = cfgetispeed(tp), ospeed = cfgetospeed(tp); char unknown[32], *ld; char *ccval(); if (fmt == GFMT) { int cnt; char sep; printf("-gfmt:iflag=%x:oflag=%x:cflag=%x:lflag=%x:cc", i, o, c, l); for (cnt = 0, sep = '='; cnt < NCCS; cnt++, sep = ',') printf("%c%o", sep, cc[cnt]); printf(":ispeed=%d:ospeed=%d:\n", ispeed, ospeed); return; } /* * line discipline */ if (ldisc != TTYDISC) { switch(ldisc) { case TABLDISC: ld = "tablet"; break; case SLIPDISC: ld = "slip"; break; default: sprintf(unknown, "#%d", ldisc); ld = unknown; break; } put("%s disc; ", ld); } /* * line speed */ if (ispeed != ospeed) put("ispeed %d baud; ospeed %d baud;", ispeed, ospeed); else put("speed %d baud;", ispeed); if (fmt) put(" %d rows; %d columns;", win.ws_row, win.ws_col); put("\n"); #define lput(n, f, d) if (fmt || on(f) != d) mdput(n+on(f)) /* * "local" flags */ #define on(f) ((l&f) != 0) if (debug) mdput("LFLAG: "); lput("-icanon ",ICANON, 1); lput("-isig ", ISIG, 1); lput("-iexten ", IEXTEN, 1); lput("-echo ",ECHO, 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); /* * input flags */ #undef on #define on(f) ((i&f) != 0) mdput(0); if (debug) mdput("IFLAG: "); lput("-istrip ", ISTRIP, 0); lput("-icrnl ", ICRNL, 1); lput("-inlcr ", INLCR, 0); lput("-igncr ", IGNCR, 0); lput("-ixon ", IXON, 1); 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); #undef on /* * output flags */ #define on(f) ((o&f) != 0) mdput(0); if (debug) mdput("OFLAG: "); lput("-opost ", OPOST, 1); lput("-onlcr ", ONLCR, 1); lput("-oxtabs ", OXTABS, 1); #undef on /* * control flags (hardware state) */ #define on(f) ((c&f) != 0) mdput(0); if (debug) mdput("CFLAG: "); lput("-cread ", CREAD, 1); switch(c&CSIZE) { 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); mdput(0); #undef on /* * special control characters */ if (debug) mdput("CCHARS: "); if (fmt != 2) { for (i=0; *cchars[i].names; i++) { char temp[64]; if (fmt || cc[cchars[i].sub] != cchars[i].def) { sprintf(temp, "%s = %s; ", *cchars[i].names, ccval(cc[cchars[i].sub]), fmt); mdput(temp); } } mdput(0); } else { for (i=0; *cchars[i].names; i++) put("%*s", strlen(*(cchars[i].names+1)) + (i>0?1:0), *(cchars[i].names+1)); printf("\n"); for (i=0; *cchars[i].names; i++) put("%*s", strlen(*(cchars[i].names+1)) + (i>0?1:0), ccval(cc[cchars[i].sub], fmt)); printf("\n"); } } /* * 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. */ checkredirect() { struct stat st1, st2; 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"); } char * ccval(c, fmt) unsigned char c; { static char buf[128]; char *bp; *buf = 0, bp = buf; if (c == _POSIX_VDISABLE) if (fmt == 2) return(""); else return(""); if (c & 0200) { strcat(buf, "M-"); *bp++ = 'M'; *bp++ = '-'; c &= 0177; } if (c == 0177) { *bp++ = '^'; *bp++ = '?'; } else if (c < 040) { *bp++ = '^'; *bp++ = c + '@'; } else *bp++ = c; *bp = 0; return(buf); } mdput(s) char *s; { static int col = 0; if (s == (char *)0) { if (col) { put("\n"); col = 0; } return; } if ((col += strlen(s)) > WRAPCOL) { put("\n"); col = strlen(s); } put(s); } #include put(va_alist) va_dcl { char *fmt; va_list ap; va_start(ap); fmt = va_arg(ap, char *); (void) vfprintf(OUT, fmt, ap); va_end(ap); } warning(va_alist) va_dcl { char *fmt; va_list ap; fprintf(ERR, "stty: warning: "); va_start(ap); fmt = va_arg(ap, char *); (void) vfprintf(ERR, fmt, ap); va_end(ap); fprintf(ERR, "\n"); } errexit(va_alist) va_dcl { char *fmt; va_list ap; fprintf(ERR, "stty: "); va_start(ap); fmt = va_arg(ap, char *); (void) vfprintf(ERR, fmt, ap); va_end(ap); fprintf(ERR, "\n"); exit(1); } syserrexit(va_alist) va_dcl { char *fmt; va_list ap; fprintf(ERR, "stty: "); va_start(ap); fmt = va_arg(ap, char *); (void) vfprintf(ERR, fmt, ap); va_end(ap); fprintf(ERR, ": %s\n", strerror(errno)); exit(1); }