DF-3902 / sio_ioctl_test.c
/* * sio.c pass-2 live ioctl-glue verification (guest console is sio0). * Exercises: control-device (ttyid/ttyld) TIOCGETA/TIOCSETA/TIOCGWINSZ, * termios lock-merge on the live console, TIOCMGET, TIOCTIMESTAMP zero-init. * Read-mostly; restores any state it changes. */ #include <sys/ioctl.h> #include <termios.h> #include <sys/time.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> static void dump_speed(const char *tag, struct termios *t) { printf("%s: ispeed=%u ospeed=%u cflag=0x%x\n", tag, (unsigned)t->c_ispeed, (unsigned)t->c_ospeed, (unsigned)t->c_cflag); } int main(int argc, char **argv) { struct termios t, t0; struct timeval tv; int fd, m, rc; /* 1. TIOCTIMESTAMP / TIOCDCDTIMESTAMP on the console: must be * all-zero on first use (attach-time bzero) — no stale kernel data. */ fd = open("/dev/ttyd0", O_RDONLY | O_NONBLOCK); if (fd < 0) { printf("FAIL open ttyd0: %s\n", strerror(errno)); return 1; } memset(&tv, 0xAA, sizeof(tv)); rc = ioctl(fd, TIOCTIMESTAMP, &tv); printf("TIOCTIMESTAMP rc=%d sec=%lld usec=%ld (expect 0/0 or runtime vals, not 0xAA garbage)\n", rc, (long long)tv.tv_sec, tv.tv_usec); memset(&tv, 0xAA, sizeof(tv)); rc = ioctl(fd, TIOCDCDTIMESTAMP, &tv); printf("TIOCDCDTIMESTAMP rc=%d sec=%lld usec=%ld\n", rc, (long long)tv.tv_sec, tv.tv_usec); /* 2. TIOCMGET: commctl DMGET */ rc = ioctl(fd, TIOCMGET, &m); printf("TIOCMGET rc=%d bits=0x%x (LE|DTR|RTS expected)\n", rc, m); /* 3. lock-merge on the console: lt_in.c_ispeed locked at boot, * so a TIOCSETA speed change must NOT take effect. */ rc = ioctl(fd, TIOCGETA, &t0); dump_speed("ttyd0 TIOCGETA before", &t0); t = t0; t.c_ispeed = t.c_ospeed = 57600; rc = ioctl(fd, TIOCSETA, &t); printf("TIOCSETA(57600) rc=%d\n", rc); rc = ioctl(fd, TIOCGETA, &t); dump_speed("ttyd0 TIOCGETA after (speed must be unchanged: lock holds)", &t); if (t.c_ispeed == 57600) printf("WARNING: speed lock did NOT hold\n"); else printf("OK: console speed lock enforced by sio.c merge (2077-2099)\n"); close(fd); /* 4. control device ttyid0: TIOCGETA/TIOCSETA + TIOCGWINSZ */ fd = open("/dev/ttyid0", O_RDONLY); if (fd < 0) { printf("FAIL open ttyid0: %s\n", strerror(errno)); return 1; } rc = ioctl(fd, TIOCGETA, &t0); dump_speed("ttyid0 TIOCGETA (it_in)", &t0); memset(&tv, 0xAA, sizeof(tv)); { struct winsize wz; memset(&wz, 0xAA, sizeof(wz)); rc = ioctl(fd, TIOCGWINSZ, &wz); printf("ttyid0 TIOCGWINSZ rc=%d row=%d col=%d (expect zeros)\n", rc, wz.ws_row, wz.ws_col); } t = t0; t.c_ispeed = t.c_ospeed = 57600; rc = ioctl(fd, TIOCSETA, &t); printf("ttyid0 TIOCSETA rc=%d (root: expect 0; unpriv: expect EPERM)\n", rc); ioctl(fd, TIOCGETA, &t); dump_speed("ttyid0 after SETA", &t); /* restore */ rc = ioctl(fd, TIOCSETA, &t0); printf("ttyid0 restore rc=%d\n", rc); close(fd); /* 5. TIOCMSDTRWAIT: priv-gated; round-trip as root */ fd = open("/dev/ttyd0", O_RDONLY | O_NONBLOCK); { int dw = 0, dw2 = 300; /* centiseconds */ rc = ioctl(fd, TIOCMGDTRWAIT, &dw); printf("TIOCMGDTRWAIT rc=%d dtr_wait=%d cs\n", rc, dw); rc = ioctl(fd, TIOCMSDTRWAIT, &dw2); printf("TIOCMSDTRWAIT(300) rc=%d\n", rc); rc = ioctl(fd, TIOCMGDTRWAIT, &dw); printf(" readback=%d\n", dw); rc = ioctl(fd, TIOCMSDTRWAIT, &dw); /* restore */ } close(fd); printf("DONE\n"); return 0; } |