10f66f451Sopenharmony_ci/* stty.c - Get/set terminal configuration. 20f66f451Sopenharmony_ci * 30f66f451Sopenharmony_ci * Copyright 2017 The Android Open Source Project. 40f66f451Sopenharmony_ci * 50f66f451Sopenharmony_ci * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/stty.html 60f66f451Sopenharmony_ci 70f66f451Sopenharmony_ciUSE_STTY(NEWTOY(stty, "?aF:g[!ag]", TOYFLAG_BIN)) 80f66f451Sopenharmony_ci 90f66f451Sopenharmony_ciconfig STTY 100f66f451Sopenharmony_ci bool "stty" 110f66f451Sopenharmony_ci default n 120f66f451Sopenharmony_ci help 130f66f451Sopenharmony_ci usage: stty [-ag] [-F device] SETTING... 140f66f451Sopenharmony_ci 150f66f451Sopenharmony_ci Get/set terminal configuration. 160f66f451Sopenharmony_ci 170f66f451Sopenharmony_ci -F Open device instead of stdin 180f66f451Sopenharmony_ci -a Show all current settings (default differences from "sane") 190f66f451Sopenharmony_ci -g Show all current settings usable as input to stty 200f66f451Sopenharmony_ci 210f66f451Sopenharmony_ci Special characters (syntax ^c or undef): intr quit erase kill eof eol eol2 220f66f451Sopenharmony_ci swtch start stop susp rprnt werase lnext discard 230f66f451Sopenharmony_ci 240f66f451Sopenharmony_ci Control/input/output/local settings as shown by -a, '-' prefix to disable 250f66f451Sopenharmony_ci 260f66f451Sopenharmony_ci Combo settings: cooked/raw, evenp/oddp/parity, nl, ek, sane 270f66f451Sopenharmony_ci 280f66f451Sopenharmony_ci N set input and output speed (ispeed N or ospeed N for just one) 290f66f451Sopenharmony_ci cols N set number of columns 300f66f451Sopenharmony_ci rows N set number of rows 310f66f451Sopenharmony_ci line N set line discipline 320f66f451Sopenharmony_ci min N set minimum chars per read 330f66f451Sopenharmony_ci time N set read timeout 340f66f451Sopenharmony_ci speed show speed only 350f66f451Sopenharmony_ci size show size only 360f66f451Sopenharmony_ci*/ 370f66f451Sopenharmony_ci 380f66f451Sopenharmony_ci#define FOR_stty 390f66f451Sopenharmony_ci#include "toys.h" 400f66f451Sopenharmony_ci 410f66f451Sopenharmony_ci#include <linux/tty.h> 420f66f451Sopenharmony_ci 430f66f451Sopenharmony_ciGLOBALS( 440f66f451Sopenharmony_ci char *device; 450f66f451Sopenharmony_ci 460f66f451Sopenharmony_ci int fd, col; 470f66f451Sopenharmony_ci unsigned output_cols; 480f66f451Sopenharmony_ci) 490f66f451Sopenharmony_ci 500f66f451Sopenharmony_cistatic const int bauds[] = { 510f66f451Sopenharmony_ci 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 520f66f451Sopenharmony_ci 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 530f66f451Sopenharmony_ci 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000 540f66f451Sopenharmony_ci}; 550f66f451Sopenharmony_ci 560f66f451Sopenharmony_cistatic int baud(speed_t speed) 570f66f451Sopenharmony_ci{ 580f66f451Sopenharmony_ci if (speed&CBAUDEX) speed=(speed&~CBAUDEX)+15; 590f66f451Sopenharmony_ci return bauds[speed]; 600f66f451Sopenharmony_ci} 610f66f451Sopenharmony_ci 620f66f451Sopenharmony_cistatic speed_t speed(int baud) 630f66f451Sopenharmony_ci{ 640f66f451Sopenharmony_ci int i; 650f66f451Sopenharmony_ci 660f66f451Sopenharmony_ci for (i=0;i<ARRAY_LEN(bauds);i++) if (bauds[i] == baud) break; 670f66f451Sopenharmony_ci if (i == ARRAY_LEN(bauds)) error_exit("unknown speed: %d", baud); 680f66f451Sopenharmony_ci return i+4081*(i>16); 690f66f451Sopenharmony_ci} 700f66f451Sopenharmony_ci 710f66f451Sopenharmony_cistruct flag { 720f66f451Sopenharmony_ci char *name; 730f66f451Sopenharmony_ci int value; 740f66f451Sopenharmony_ci int mask; 750f66f451Sopenharmony_ci}; 760f66f451Sopenharmony_ci 770f66f451Sopenharmony_cistatic const struct flag chars[] = { 780f66f451Sopenharmony_ci { "intr", VINTR }, { "quit", VQUIT }, { "erase", VERASE }, { "kill", VKILL }, 790f66f451Sopenharmony_ci { "eof", VEOF }, { "eol", VEOL }, { "eol2", VEOL2 }, { "swtch", VSWTC }, 800f66f451Sopenharmony_ci { "start", VSTART }, { "stop", VSTOP }, { "susp", VSUSP }, 810f66f451Sopenharmony_ci { "rprnt", VREPRINT }, { "werase", VWERASE }, { "lnext", VLNEXT }, 820f66f451Sopenharmony_ci { "discard", VDISCARD }, { "min", VMIN }, { "time", VTIME }, 830f66f451Sopenharmony_ci}; 840f66f451Sopenharmony_ci 850f66f451Sopenharmony_cistatic const struct flag cflags[] = { 860f66f451Sopenharmony_ci { "parenb", PARENB }, { "parodd", PARODD }, { "cmspar", CMSPAR }, 870f66f451Sopenharmony_ci { "cs5", CS5, CSIZE }, { "cs6", CS6, CSIZE }, { "cs7", CS7, CSIZE }, 880f66f451Sopenharmony_ci { "cs8", CS8, CSIZE }, { "hupcl", HUPCL }, { "cstopb", CSTOPB }, 890f66f451Sopenharmony_ci { "cread", CREAD }, { "clocal", CLOCAL }, { "crtscts", CRTSCTS }, 900f66f451Sopenharmony_ci}; 910f66f451Sopenharmony_ci 920f66f451Sopenharmony_cistatic const struct flag iflags[] = { 930f66f451Sopenharmony_ci { "ignbrk", IGNBRK }, { "brkint", BRKINT }, { "ignpar", IGNPAR }, 940f66f451Sopenharmony_ci { "parmrk", PARMRK }, { "inpck", INPCK }, { "istrip", ISTRIP }, 950f66f451Sopenharmony_ci { "inlcr", INLCR }, { "igncr", IGNCR }, { "icrnl", ICRNL }, { "ixon", IXON }, 960f66f451Sopenharmony_ci { "ixoff", IXOFF }, { "iuclc", IUCLC }, { "ixany", IXANY }, 970f66f451Sopenharmony_ci { "imaxbel", IMAXBEL }, { "iutf8", IUTF8 }, 980f66f451Sopenharmony_ci}; 990f66f451Sopenharmony_ci 1000f66f451Sopenharmony_cistatic const struct flag oflags[] = { 1010f66f451Sopenharmony_ci { "opost", OPOST }, { "olcuc", OLCUC }, { "ocrnl", OCRNL }, 1020f66f451Sopenharmony_ci { "onlcr", ONLCR }, { "onocr", ONOCR }, { "onlret", ONLRET }, 1030f66f451Sopenharmony_ci { "ofill", OFILL }, { "ofdel", OFDEL }, { "nl0", NL0, NLDLY }, 1040f66f451Sopenharmony_ci { "nl1", NL1, NLDLY }, { "cr0", CR0, CRDLY }, { "cr1", CR1, CRDLY }, 1050f66f451Sopenharmony_ci { "cr2", CR2, CRDLY }, { "cr3", CR3, CRDLY }, { "tab0", TAB0, TABDLY }, 1060f66f451Sopenharmony_ci { "tab1", TAB1, TABDLY }, { "tab2", TAB2, TABDLY }, { "tab3", TAB3, TABDLY }, 1070f66f451Sopenharmony_ci { "bs0", BS0, BSDLY }, { "bs1", BS1, BSDLY }, { "vt0", VT0, VTDLY }, 1080f66f451Sopenharmony_ci { "vt1", VT1, VTDLY }, { "ff0", FF0, FFDLY }, { "ff1", FF1, FFDLY }, 1090f66f451Sopenharmony_ci}; 1100f66f451Sopenharmony_ci 1110f66f451Sopenharmony_cistatic const struct flag lflags[] = { 1120f66f451Sopenharmony_ci { "isig", ISIG }, { "icanon", ICANON }, { "iexten", IEXTEN }, 1130f66f451Sopenharmony_ci { "echo", ECHO }, { "echoe", ECHOE }, { "echok", ECHOK }, 1140f66f451Sopenharmony_ci { "echonl", ECHONL }, { "noflsh", NOFLSH }, { "xcase", XCASE }, 1150f66f451Sopenharmony_ci { "tostop", TOSTOP }, { "echoprt", ECHOPRT }, { "echoctl", ECHOCTL }, 1160f66f451Sopenharmony_ci { "echoke", ECHOKE }, { "flusho", FLUSHO }, { "extproc", EXTPROC }, 1170f66f451Sopenharmony_ci}; 1180f66f451Sopenharmony_ci 1190f66f451Sopenharmony_cistatic const struct synonym { 1200f66f451Sopenharmony_ci char *from; 1210f66f451Sopenharmony_ci char *to; 1220f66f451Sopenharmony_ci} synonyms[] = { 1230f66f451Sopenharmony_ci { "cbreak", "-icanon" }, { "-cbreak", "icanon" }, { "-cooked", "raw" }, 1240f66f451Sopenharmony_ci { "crterase", "echoe" }, { "-crterase", "-echoe" }, { "crtkill", "echoke" }, 1250f66f451Sopenharmony_ci { "-crtkill", "-echoke" }, { "ctlecho", "echoctl" }, { "-tandem", "-ixoff" }, 1260f66f451Sopenharmony_ci { "-ctlecho", "-echoctl" }, { "hup", "hupcl" }, { "-hup", "-hupcl" }, 1270f66f451Sopenharmony_ci { "prterase", "echoprt" }, { "-prterase", "-echoprt" }, { "-raw", "cooked" }, 1280f66f451Sopenharmony_ci { "tabs", "tab0" }, { "-tabs", "tab3" }, { "tandem", "ixoff" }, 1290f66f451Sopenharmony_ci}; 1300f66f451Sopenharmony_ci 1310f66f451Sopenharmony_cistatic void out(const char *fmt, ...) 1320f66f451Sopenharmony_ci{ 1330f66f451Sopenharmony_ci va_list va; 1340f66f451Sopenharmony_ci int len; 1350f66f451Sopenharmony_ci char *prefix = " "; 1360f66f451Sopenharmony_ci 1370f66f451Sopenharmony_ci va_start(va, fmt); 1380f66f451Sopenharmony_ci len = vsnprintf(toybuf, sizeof(toybuf), fmt, va); 1390f66f451Sopenharmony_ci va_end(va); 1400f66f451Sopenharmony_ci 1410f66f451Sopenharmony_ci if (TT.output_cols == 0) { 1420f66f451Sopenharmony_ci TT.output_cols = 80; 1430f66f451Sopenharmony_ci terminal_size(&TT.output_cols, NULL); 1440f66f451Sopenharmony_ci } 1450f66f451Sopenharmony_ci 1460f66f451Sopenharmony_ci if (TT.col == 0 || *fmt == '\n') prefix = ""; 1470f66f451Sopenharmony_ci else if (TT.col + 1 + len >= TT.output_cols) { 1480f66f451Sopenharmony_ci prefix = "\n"; 1490f66f451Sopenharmony_ci TT.col = 0; 1500f66f451Sopenharmony_ci } 1510f66f451Sopenharmony_ci xprintf("%s%s", prefix, toybuf); 1520f66f451Sopenharmony_ci 1530f66f451Sopenharmony_ci if (toybuf[len-1] == '\n') TT.col = 0; 1540f66f451Sopenharmony_ci else TT.col += strlen(prefix) + len; 1550f66f451Sopenharmony_ci} 1560f66f451Sopenharmony_ci 1570f66f451Sopenharmony_cistatic void show_flags(tcflag_t actual, tcflag_t sane, 1580f66f451Sopenharmony_ci const struct flag *flags, int len) 1590f66f451Sopenharmony_ci{ 1600f66f451Sopenharmony_ci int i, j, value, mask; 1610f66f451Sopenharmony_ci 1620f66f451Sopenharmony_ci // Implement -a by ensuring that sane != actual so we'll show everything. 1630f66f451Sopenharmony_ci if (toys.optflags&FLAG_a) sane = ~actual; 1640f66f451Sopenharmony_ci 1650f66f451Sopenharmony_ci for (i=j=0;i<len;i++) { 1660f66f451Sopenharmony_ci value = flags[i].value; 1670f66f451Sopenharmony_ci if ((mask = flags[i].mask)) { 1680f66f451Sopenharmony_ci if ((actual&mask)==value && (sane&mask)!=value) { 1690f66f451Sopenharmony_ci out("%s", flags[i].name); 1700f66f451Sopenharmony_ci j++; 1710f66f451Sopenharmony_ci } 1720f66f451Sopenharmony_ci } else { 1730f66f451Sopenharmony_ci if ((actual&value) != (sane&value)) { 1740f66f451Sopenharmony_ci out("%s%s", actual&value?"":"-", flags[i].name); 1750f66f451Sopenharmony_ci j++; 1760f66f451Sopenharmony_ci } 1770f66f451Sopenharmony_ci } 1780f66f451Sopenharmony_ci } 1790f66f451Sopenharmony_ci if (j) out("\n"); 1800f66f451Sopenharmony_ci} 1810f66f451Sopenharmony_ci 1820f66f451Sopenharmony_cistatic void show_size(int verbose) 1830f66f451Sopenharmony_ci{ 1840f66f451Sopenharmony_ci struct winsize ws; 1850f66f451Sopenharmony_ci 1860f66f451Sopenharmony_ci if (ioctl(TT.fd, TIOCGWINSZ, &ws)) perror_exit("TIOCGWINSZ %s", TT.device); 1870f66f451Sopenharmony_ci out(verbose ? "rows %d; columns %d;" : "%d %d\n", ws.ws_row, ws.ws_col); 1880f66f451Sopenharmony_ci} 1890f66f451Sopenharmony_ci 1900f66f451Sopenharmony_cistatic void show_speed(struct termios *t, int verbose) 1910f66f451Sopenharmony_ci{ 1920f66f451Sopenharmony_ci int ispeed = baud(cfgetispeed(t)), ospeed = baud(cfgetospeed(t)); 1930f66f451Sopenharmony_ci char *fmt = verbose ? "ispeed %d baud; ospeed %d baud;" : "%d %d\n"; 1940f66f451Sopenharmony_ci 1950f66f451Sopenharmony_ci if (ispeed == ospeed) fmt += (verbose ? 17 : 3); 1960f66f451Sopenharmony_ci out(fmt, ispeed, ospeed); 1970f66f451Sopenharmony_ci} 1980f66f451Sopenharmony_ci 1990f66f451Sopenharmony_cistatic int get_arg(int *i, long long low, long long high) 2000f66f451Sopenharmony_ci{ 2010f66f451Sopenharmony_ci (*i)++; 2020f66f451Sopenharmony_ci if (!toys.optargs[*i]) error_exit("missing arg"); 2030f66f451Sopenharmony_ci return atolx_range(toys.optargs[*i], low, high); 2040f66f451Sopenharmony_ci} 2050f66f451Sopenharmony_ci 2060f66f451Sopenharmony_cistatic int set_flag(tcflag_t *f, const struct flag *flags, int len, 2070f66f451Sopenharmony_ci char *name, int on) 2080f66f451Sopenharmony_ci{ 2090f66f451Sopenharmony_ci int i; 2100f66f451Sopenharmony_ci 2110f66f451Sopenharmony_ci for (i=0;i<len;i++) { 2120f66f451Sopenharmony_ci if (!strcmp(flags[i].name, name)) { 2130f66f451Sopenharmony_ci if (on) { 2140f66f451Sopenharmony_ci *f &= ~flags[i].mask; 2150f66f451Sopenharmony_ci *f |= flags[i].value; 2160f66f451Sopenharmony_ci } else { 2170f66f451Sopenharmony_ci if (flags[i].mask) error_exit("%s isn't a boolean", name); 2180f66f451Sopenharmony_ci *f &= ~flags[i].value; 2190f66f451Sopenharmony_ci } 2200f66f451Sopenharmony_ci return 1; 2210f66f451Sopenharmony_ci } 2220f66f451Sopenharmony_ci } 2230f66f451Sopenharmony_ci return 0; 2240f66f451Sopenharmony_ci} 2250f66f451Sopenharmony_ci 2260f66f451Sopenharmony_cistatic void set_option(struct termios *new, char *option) 2270f66f451Sopenharmony_ci{ 2280f66f451Sopenharmony_ci int on = (*option != '-'); 2290f66f451Sopenharmony_ci 2300f66f451Sopenharmony_ci if (!on) option++; 2310f66f451Sopenharmony_ci if (!set_flag(&new->c_cflag, cflags, ARRAY_LEN(cflags), option, on) && 2320f66f451Sopenharmony_ci !set_flag(&new->c_iflag, iflags, ARRAY_LEN(iflags), option, on) && 2330f66f451Sopenharmony_ci !set_flag(&new->c_oflag, oflags, ARRAY_LEN(oflags), option, on) && 2340f66f451Sopenharmony_ci !set_flag(&new->c_lflag, lflags, ARRAY_LEN(lflags), option, on)) 2350f66f451Sopenharmony_ci error_exit("unknown option: %s", option); 2360f66f451Sopenharmony_ci} 2370f66f451Sopenharmony_ci 2380f66f451Sopenharmony_cistatic void set_options(struct termios* new, ...) 2390f66f451Sopenharmony_ci{ 2400f66f451Sopenharmony_ci va_list va; 2410f66f451Sopenharmony_ci char *option; 2420f66f451Sopenharmony_ci 2430f66f451Sopenharmony_ci va_start(va, new); 2440f66f451Sopenharmony_ci while ((option = va_arg(va, char *))) set_option(new, option); 2450f66f451Sopenharmony_ci va_end(va); 2460f66f451Sopenharmony_ci} 2470f66f451Sopenharmony_ci 2480f66f451Sopenharmony_cistatic void set_size(int is_rows, unsigned short value) 2490f66f451Sopenharmony_ci{ 2500f66f451Sopenharmony_ci struct winsize ws; 2510f66f451Sopenharmony_ci 2520f66f451Sopenharmony_ci if (ioctl(TT.fd, TIOCGWINSZ, &ws)) perror_exit("TIOCGWINSZ %s", TT.device); 2530f66f451Sopenharmony_ci if (is_rows) ws.ws_row = value; 2540f66f451Sopenharmony_ci else ws.ws_col = value; 2550f66f451Sopenharmony_ci if (ioctl(TT.fd, TIOCSWINSZ, &ws)) perror_exit("TIOCSWINSZ %s", TT.device); 2560f66f451Sopenharmony_ci} 2570f66f451Sopenharmony_ci 2580f66f451Sopenharmony_cistatic int set_special_character(struct termios *new, int *i, char *char_name) 2590f66f451Sopenharmony_ci{ 2600f66f451Sopenharmony_ci int j; 2610f66f451Sopenharmony_ci 2620f66f451Sopenharmony_ci // The -2 is to ignore VMIN and VTIME, which are just unsigned integers. 2630f66f451Sopenharmony_ci for (j=0;j<ARRAY_LEN(chars)-2;j++) { 2640f66f451Sopenharmony_ci if (!strcmp(chars[j].name, char_name)) { 2650f66f451Sopenharmony_ci char *arg = toys.optargs[++(*i)]; 2660f66f451Sopenharmony_ci cc_t ch; 2670f66f451Sopenharmony_ci 2680f66f451Sopenharmony_ci if (!arg) error_exit("missing arg"); 2690f66f451Sopenharmony_ci if (!strcmp(arg, "^-") || !strcmp(arg, "undef")) ch = _POSIX_VDISABLE; 2700f66f451Sopenharmony_ci else if (!strcmp(arg, "^?")) ch = 0x7f; 2710f66f451Sopenharmony_ci else if (arg[0] == '^' && arg[2] == 0) ch = (toupper(arg[1])-'@'); 2720f66f451Sopenharmony_ci else if (!arg[1]) ch = arg[0]; 2730f66f451Sopenharmony_ci else error_exit("invalid arg: %s", arg); 2740f66f451Sopenharmony_ci xprintf("setting %s to %s (%02x)\n", char_name, arg, ch); 2750f66f451Sopenharmony_ci new->c_cc[chars[j].value] = ch; 2760f66f451Sopenharmony_ci return 1; 2770f66f451Sopenharmony_ci } 2780f66f451Sopenharmony_ci } 2790f66f451Sopenharmony_ci return 0; 2800f66f451Sopenharmony_ci} 2810f66f451Sopenharmony_ci 2820f66f451Sopenharmony_cistatic void make_sane(struct termios *t) 2830f66f451Sopenharmony_ci{ 2840f66f451Sopenharmony_ci // POSIX has no opinion about what "sane" means. From "man stty". 2850f66f451Sopenharmony_ci // "cs8" is missing from the man page, but needed to get identical results. 2860f66f451Sopenharmony_ci set_options(t, "cread", "-ignbrk", "brkint", "-inlcr", "-igncr", "icrnl", 2870f66f451Sopenharmony_ci "icanon", "iexten", "echo", "echoe", "echok", "-echonl", "-noflsh", 2880f66f451Sopenharmony_ci "-ixoff", "-iutf8", "-iuclc", "-ixany", "imaxbel", "-xcase", "-olcuc", 2890f66f451Sopenharmony_ci "-ocrnl", "opost", "-ofill", "onlcr", "-onocr", "-onlret", "nl0", "cr0", 2900f66f451Sopenharmony_ci "tab0", "bs0", "vt0", "ff0", "isig", "-tostop", "-ofdel", "-echoprt", 2910f66f451Sopenharmony_ci "echoctl", "echoke", "-extproc", "-flusho", "cs8", NULL); 2920f66f451Sopenharmony_ci memset(t->c_cc, 0, NCCS); 2930f66f451Sopenharmony_ci t->c_cc[VINTR] = 0x3; 2940f66f451Sopenharmony_ci t->c_cc[VQUIT] = 0x1c; 2950f66f451Sopenharmony_ci t->c_cc[VERASE] = 0x7f; 2960f66f451Sopenharmony_ci t->c_cc[VKILL] = 0x15; 2970f66f451Sopenharmony_ci t->c_cc[VEOF] = 0x4; 2980f66f451Sopenharmony_ci t->c_cc[VTIME] = 0; 2990f66f451Sopenharmony_ci t->c_cc[VMIN] = 1; 3000f66f451Sopenharmony_ci t->c_cc[VSWTC] = 0; 3010f66f451Sopenharmony_ci t->c_cc[VSTART] = 0x11; 3020f66f451Sopenharmony_ci t->c_cc[VSTOP] = 0x13; 3030f66f451Sopenharmony_ci t->c_cc[VSUSP] = 0x1a; 3040f66f451Sopenharmony_ci t->c_cc[VEOL] = 0; 3050f66f451Sopenharmony_ci t->c_cc[VREPRINT] = 0x12; 3060f66f451Sopenharmony_ci t->c_cc[VDISCARD] = 0xf; 3070f66f451Sopenharmony_ci t->c_cc[VWERASE] = 0x17; 3080f66f451Sopenharmony_ci t->c_cc[VLNEXT] = 0x16; 3090f66f451Sopenharmony_ci t->c_cc[VEOL2] = 0; 3100f66f451Sopenharmony_ci} 3110f66f451Sopenharmony_ci 3120f66f451Sopenharmony_cistatic void xtcgetattr(struct termios *t) 3130f66f451Sopenharmony_ci{ 3140f66f451Sopenharmony_ci if (tcgetattr(TT.fd, t)) perror_exit("tcgetattr %s", TT.device); 3150f66f451Sopenharmony_ci} 3160f66f451Sopenharmony_ci 3170f66f451Sopenharmony_cistatic void do_stty() 3180f66f451Sopenharmony_ci{ 3190f66f451Sopenharmony_ci struct termios old, sane; 3200f66f451Sopenharmony_ci int i, j, n; 3210f66f451Sopenharmony_ci 3220f66f451Sopenharmony_ci xtcgetattr(&old); 3230f66f451Sopenharmony_ci 3240f66f451Sopenharmony_ci if (*toys.optargs) { 3250f66f451Sopenharmony_ci struct termios new = old; 3260f66f451Sopenharmony_ci 3270f66f451Sopenharmony_ci for (i=0; toys.optargs[i]; i++) { 3280f66f451Sopenharmony_ci char *arg = toys.optargs[i]; 3290f66f451Sopenharmony_ci 3300f66f451Sopenharmony_ci if (!strcmp(arg, "size")) show_size(0); 3310f66f451Sopenharmony_ci else if (!strcmp(arg, "speed")) show_speed(&old, 0); 3320f66f451Sopenharmony_ci else if (!strcmp(arg, "line")) new.c_line = get_arg(&i, N_TTY, NR_LDISCS); 3330f66f451Sopenharmony_ci else if (!strcmp(arg, "min")) new.c_cc[VMIN] = get_arg(&i, 0, 255); 3340f66f451Sopenharmony_ci else if (!strcmp(arg, "time")) new.c_cc[VTIME] = get_arg(&i, 0, 255); 3350f66f451Sopenharmony_ci else if (atoi(arg) > 0) { 3360f66f451Sopenharmony_ci int new_speed = speed(atolx_range(arg, 0, 4000000)); 3370f66f451Sopenharmony_ci 3380f66f451Sopenharmony_ci cfsetispeed(&new, new_speed); 3390f66f451Sopenharmony_ci cfsetospeed(&new, new_speed); 3400f66f451Sopenharmony_ci } else if (!strcmp(arg, "ispeed")) 3410f66f451Sopenharmony_ci cfsetispeed(&new, speed(get_arg(&i, 0, 4000000))); 3420f66f451Sopenharmony_ci else if (!strcmp(arg, "ospeed")) 3430f66f451Sopenharmony_ci cfsetospeed(&new, speed(get_arg(&i, 0, 4000000))); 3440f66f451Sopenharmony_ci else if (!strcmp(arg, "rows")) set_size(1, get_arg(&i, 0, USHRT_MAX)); 3450f66f451Sopenharmony_ci else if (!strcmp(arg, "cols") || !strcmp(arg, "columns")) 3460f66f451Sopenharmony_ci set_size(0, get_arg(&i, 0, USHRT_MAX)); 3470f66f451Sopenharmony_ci else if (sscanf(arg, "%x:%x:%x:%x:%n", &new.c_iflag, &new.c_oflag, 3480f66f451Sopenharmony_ci &new.c_cflag, &new.c_lflag, &n) == 4) 3490f66f451Sopenharmony_ci { 3500f66f451Sopenharmony_ci int value; 3510f66f451Sopenharmony_ci 3520f66f451Sopenharmony_ci arg += n; 3530f66f451Sopenharmony_ci for (j=0;j<NCCS;j++) { 3540f66f451Sopenharmony_ci if (sscanf(arg, "%x%n", &value, &n) != 1) error_exit("bad -g string"); 3550f66f451Sopenharmony_ci new.c_cc[j] = value; 3560f66f451Sopenharmony_ci arg += n+1; 3570f66f451Sopenharmony_ci } 3580f66f451Sopenharmony_ci } else if (set_special_character(&new, &i, arg)); 3590f66f451Sopenharmony_ci // Already done as a side effect. 3600f66f451Sopenharmony_ci else if (!strcmp(arg, "cooked")) 3610f66f451Sopenharmony_ci set_options(&new, "brkint", "ignpar", "istrip", "icrnl", "ixon", 3620f66f451Sopenharmony_ci "opost", "isig", "icanon", NULL); 3630f66f451Sopenharmony_ci else if (!strcmp(arg, "evenp") || !strcmp(arg, "parity")) 3640f66f451Sopenharmony_ci set_options(&new, "parenb", "cs7", "-parodd", NULL); 3650f66f451Sopenharmony_ci else if (!strcmp(arg, "oddp")) 3660f66f451Sopenharmony_ci set_options(&new, "parenb", "cs7", "parodd", NULL); 3670f66f451Sopenharmony_ci else if (!strcmp(arg, "-parity") || !strcmp(arg, "-evenp") || 3680f66f451Sopenharmony_ci !strcmp(arg, "-oddp")) { 3690f66f451Sopenharmony_ci set_options(&new, "-parenb", "cs8", NULL); 3700f66f451Sopenharmony_ci } else if (!strcmp(arg, "raw")) { 3710f66f451Sopenharmony_ci // POSIX and "man stty" differ wildly. This is "man stty". 3720f66f451Sopenharmony_ci set_options(&new, "-ignbrk", "-brkint", "-ignpar", "-parmrk", "-inpck", 3730f66f451Sopenharmony_ci "-istrip", "-inlcr", "-igncr", "-icrnl", "-ixon", "-ixoff", "-iuclc", 3740f66f451Sopenharmony_ci "-ixany", "-imaxbel", "-opost", "-isig", "-icanon", "-xcase", NULL); 3750f66f451Sopenharmony_ci new.c_cc[VMIN] = 1; 3760f66f451Sopenharmony_ci new.c_cc[VTIME] = 0; 3770f66f451Sopenharmony_ci } else if (!strcmp(arg, "nl")) 3780f66f451Sopenharmony_ci set_options(&new, "-icrnl", "-ocrnl", NULL); 3790f66f451Sopenharmony_ci else if (!strcmp(arg, "-nl")) 3800f66f451Sopenharmony_ci set_options(&new, "icrnl", "ocrnl", "-inlcr", "-igncr", NULL); 3810f66f451Sopenharmony_ci else if (!strcmp(arg, "ek")) { 3820f66f451Sopenharmony_ci new.c_cc[VERASE] = 0x7f; 3830f66f451Sopenharmony_ci new.c_cc[VKILL] = 0x15; 3840f66f451Sopenharmony_ci } else if (!strcmp(arg, "sane")) make_sane(&new); 3850f66f451Sopenharmony_ci else { 3860f66f451Sopenharmony_ci // Translate historical cruft into canonical forms. 3870f66f451Sopenharmony_ci for (j=0;j<ARRAY_LEN(synonyms);j++) { 3880f66f451Sopenharmony_ci if (!strcmp(synonyms[j].from, arg)) { 3890f66f451Sopenharmony_ci arg = synonyms[j].to; 3900f66f451Sopenharmony_ci break; 3910f66f451Sopenharmony_ci } 3920f66f451Sopenharmony_ci } 3930f66f451Sopenharmony_ci set_option(&new, arg); 3940f66f451Sopenharmony_ci } 3950f66f451Sopenharmony_ci } 3960f66f451Sopenharmony_ci tcsetattr(TT.fd, TCSAFLUSH, &new); 3970f66f451Sopenharmony_ci xtcgetattr(&old); 3980f66f451Sopenharmony_ci if (memcmp(&old, &new, sizeof(old))) 3990f66f451Sopenharmony_ci error_exit("unable to perform all requested operations on %s", TT.device); 4000f66f451Sopenharmony_ci 4010f66f451Sopenharmony_ci return; 4020f66f451Sopenharmony_ci } 4030f66f451Sopenharmony_ci 4040f66f451Sopenharmony_ci if (toys.optflags&FLAG_g) { 4050f66f451Sopenharmony_ci xprintf("%x:%x:%x:%x:", old.c_iflag, old.c_oflag, old.c_cflag, old.c_lflag); 4060f66f451Sopenharmony_ci for (i=0;i<NCCS;i++) xprintf("%x%c", old.c_cc[i], i==NCCS-1?'\n':':'); 4070f66f451Sopenharmony_ci return; 4080f66f451Sopenharmony_ci } 4090f66f451Sopenharmony_ci 4100f66f451Sopenharmony_ci // Without arguments, "stty" only shows the speed, the line discipline, 4110f66f451Sopenharmony_ci // special characters and any flags that differ from the "sane" settings. 4120f66f451Sopenharmony_ci make_sane(&sane); 4130f66f451Sopenharmony_ci show_speed(&old, 1); 4140f66f451Sopenharmony_ci if (toys.optflags&FLAG_a) show_size(1); 4150f66f451Sopenharmony_ci out("line = %d;\n", old.c_line); 4160f66f451Sopenharmony_ci 4170f66f451Sopenharmony_ci for (i=j=0;i<ARRAY_LEN(chars);i++) { 4180f66f451Sopenharmony_ci char vis[16] = {}; 4190f66f451Sopenharmony_ci cc_t ch = old.c_cc[chars[i].value]; 4200f66f451Sopenharmony_ci 4210f66f451Sopenharmony_ci if (ch == sane.c_cc[chars[i].value] && (toys.optflags&FLAG_a)==0) 4220f66f451Sopenharmony_ci continue; 4230f66f451Sopenharmony_ci 4240f66f451Sopenharmony_ci if (chars[i].value == VMIN || chars[i].value == VTIME) { 4250f66f451Sopenharmony_ci snprintf(vis, sizeof(vis), "%u", ch); 4260f66f451Sopenharmony_ci } else if (ch == _POSIX_VDISABLE) { 4270f66f451Sopenharmony_ci strcat(vis, "<undef>"); 4280f66f451Sopenharmony_ci } else { 4290f66f451Sopenharmony_ci if (ch > 0x7f) { 4300f66f451Sopenharmony_ci strcat(vis, "M-"); 4310f66f451Sopenharmony_ci ch -= 128; 4320f66f451Sopenharmony_ci } 4330f66f451Sopenharmony_ci if (ch < ' ') sprintf(vis+strlen(vis), "^%c", (ch+'@')); 4340f66f451Sopenharmony_ci else if (ch == 0x7f) strcat(vis, "^?"); 4350f66f451Sopenharmony_ci else sprintf(vis+strlen(vis), "%c", ch); 4360f66f451Sopenharmony_ci } 4370f66f451Sopenharmony_ci out("%s = %s;", chars[i].name, vis); 4380f66f451Sopenharmony_ci j++; 4390f66f451Sopenharmony_ci } 4400f66f451Sopenharmony_ci if (j) out("\n"); 4410f66f451Sopenharmony_ci 4420f66f451Sopenharmony_ci show_flags(old.c_cflag, sane.c_cflag, cflags, ARRAY_LEN(cflags)); 4430f66f451Sopenharmony_ci show_flags(old.c_iflag, sane.c_iflag, iflags, ARRAY_LEN(iflags)); 4440f66f451Sopenharmony_ci show_flags(old.c_oflag, sane.c_oflag, oflags, ARRAY_LEN(oflags)); 4450f66f451Sopenharmony_ci show_flags(old.c_lflag, sane.c_lflag, lflags, ARRAY_LEN(lflags)); 4460f66f451Sopenharmony_ci} 4470f66f451Sopenharmony_ci 4480f66f451Sopenharmony_civoid stty_main(void) 4490f66f451Sopenharmony_ci{ 4500f66f451Sopenharmony_ci if (toys.optflags&(FLAG_a|FLAG_g) && *toys.optargs) 4510f66f451Sopenharmony_ci error_exit("can't make settings with -a/-g"); 4520f66f451Sopenharmony_ci 4530f66f451Sopenharmony_ci if (!TT.device) TT.device = "standard input"; 4540f66f451Sopenharmony_ci else TT.fd=xopen(TT.device, (O_RDWR*!!*toys.optargs)|O_NOCTTY|O_NONBLOCK); 4550f66f451Sopenharmony_ci 4560f66f451Sopenharmony_ci do_stty(); 4570f66f451Sopenharmony_ci 4580f66f451Sopenharmony_ci if (CFG_TOYBOX_FREE && TT.device) close(TT.fd); 4590f66f451Sopenharmony_ci} 460