DF-2344 / tioc0.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | /* * tioc0.c -- live probe of the TIOCSETA*-with-c_ospeed==0 routes on a * harness-created stock /dev/ttyU* (real ucom cdevsw, real tty.c). * * Modes: * firstopen <dev> just open(2) the device (the DF-2343 first-open * trigger: usb_serial.c:839-842 feeds the * never-initialized sc_it_in.c_ospeed==0 to * ucom_pre_param). Stock kernel: panic. * tioc <dev> open, then push TIOCSETA variants with * c_ospeed == 0 and report each errno. Expect * EINVAL (tty.c:1033-1041 / usb_serial.c:1670) * and NO panic. * * Build: cc -O -Wall -o tioc0 tioc0.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <err.h> #include <termios.h> #include <sys/ioctl.h> static void show(const char *what, const struct termios *t) { printf(" %-28s ispeed=%u ospeed=%u cflag=0x%x\n", what, t->c_ispeed, t->c_ospeed, t->c_cflag); } static int push(int fd, const char *what, struct termios *t) { int rc; errno = 0; rc = ioctl(fd, TIOCSETA, t); printf(" TIOCSETA %-24s -> rc=%d errno=%d (%s)\n", what, rc, errno, errno ? strerror(errno) : "OK"); return (rc); } int main(int argc, char **argv) { struct termios t0, t; int fd; if (argc < 3) errx(1, "usage: %s firstopen|tioc <device>", argv[0]); if (strcmp(argv[1], "firstopen") == 0) { printf("tioc0: opening %s (uid=%d) -- sc_it_* untouched, " "c_ospeed==0 flows to ucom_pre_param on first open\n", argv[2], getuid()); fflush(stdout); fd = open(argv[2], O_RDWR | O_NONBLOCK); if (fd < 0) err(1, "open %s", argv[2]); printf("tioc0: open returned fd=%d -- NO PANIC\n", fd); if (tcgetattr(fd, &t) == 0) show("post-open termios", &t); close(fd); return (0); } if (strcmp(argv[1], "tioc") != 0) errx(1, "bad mode %s", argv[1]); printf("tioc0: opening %s (uid=%d), then TIOCSETA " "c_ospeed==0 variants\n", argv[2], getuid()); fflush(stdout); fd = open(argv[2], O_RDWR | O_NONBLOCK); if (fd < 0) err(1, "open %s", argv[2]); if (tcgetattr(fd, &t0) != 0) err(1, "tcgetattr"); show("current", &t0); /* sanity: a sane speed must be accepted (proves t_param runs) */ t = t0; t.c_ispeed = 19200; t.c_ospeed = 19200; push(fd, "sane 19200", &t); /* variant A: both speeds 0 (classic hangup-style termios) */ t = t0; t.c_ispeed = 0; t.c_ospeed = 0; push(fd, "ispeed=0 ospeed=0", &t); /* variant B: ispeed sane, ospeed 0 (mismatch) */ t = t0; t.c_ispeed = 19200; t.c_ospeed = 0; push(fd, "ispeed=19200 ospeed=0", &t); /* variant C: CIGNORE set, ospeed 0 (skips t_param entirely) */ t = t0; t.c_cflag |= CIGNORE; t.c_ispeed = 0; t.c_ospeed = 0; push(fd, "CIGNORE ispeed=0 ospeed=0", &t); if (tcgetattr(fd, &t) == 0) show("after variants", &t); printf("tioc0: still alive, no panic\n"); close(fd); return (0); } |