From 4af0789caf1080e06c756d3076930bb8077b72cf Mon Sep 17 00:00:00 2001 From: Kyle Huey Date: Thu, 27 Mar 2025 13:41:51 -0700 Subject: [PATCH] Support TCGETS2 and TCSETS2. Fixes #2430 --- src/record_syscall.cc | 19 +++++++++++++++++++ src/test/ioctl_tty.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/src/record_syscall.cc b/src/record_syscall.cc index 45ba46c90be..faf86af0e6f 100644 --- a/src/record_syscall.cc +++ b/src/record_syscall.cc @@ -103,6 +103,23 @@ using namespace std; +// The kernel header that defines this conflicts badly with glibc headers +// so we define it ourselves. +// NB: We need this struct defined so that the preprocessor macro for +// TCGETS2 will evaluate. But we use IOCTL_MASK_SIZE on it and we use +// the size from the tracee to determine how many bytes to record, so +// we don't actually depend on this being *accurate*. +struct termios2 { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[19]; + speed_t c_ispeed; + speed_t c_ospeed; +}; + namespace rr { union _semun { @@ -1943,6 +1960,7 @@ static Switchable prepare_ioctl(RecordTask* t, case IOCTL_MASK_SIZE(TUNSETIFINDEX): case IOCTL_MASK_SIZE(TUNSETVNETLE): case IOCTL_MASK_SIZE(TUNSETVNETBE): + case IOCTL_MASK_SIZE(TCSETS2): return PREVENT_SWITCH; case IOCTL_MASK_SIZE(USBDEVFS_GETDRIVER): // Reads and writes its parameter despite not having the _IOC_READ bit. @@ -2078,6 +2096,7 @@ static Switchable prepare_ioctl(RecordTask* t, case IOCTL_MASK_SIZE(OTPGETREGIONINFO): case IOCTL_MASK_SIZE(ECCGETLAYOUT): case IOCTL_MASK_SIZE(ECCGETSTATS): + case IOCTL_MASK_SIZE(TCGETS2): syscall_state.reg_parameter(3, size); return PREVENT_SWITCH; diff --git a/src/test/ioctl_tty.c b/src/test/ioctl_tty.c index 98ee07d8289..17ca3d4c8f6 100644 --- a/src/test/ioctl_tty.c +++ b/src/test/ioctl_tty.c @@ -2,10 +2,26 @@ #include "util.h" +/* We have to define termios2 ourselves. See + * https://github.com/npat-efault/picocom/blob/1acf1ddabaf3576b4023c4f6f09c5a3e4b086fb8/termios2.txt + * for the long explanation. + */ +struct termios2 { + tcflag_t c_iflag; + tcflag_t c_oflag; + tcflag_t c_cflag; + tcflag_t c_lflag; + cc_t c_line; + cc_t c_cc[19]; + speed_t c_ispeed; + speed_t c_ospeed; +}; + int main(void) { int fd; int ret; struct termios* tc; + struct termios2* tc2; struct termio* tio; pid_t* pgrp; int* navail; @@ -94,6 +110,19 @@ int main(void) { VERIFY_GUARD(nread); atomic_printf("FIONREAD returned nread=%d\n", *nread); + ALLOCATE_GUARD(tc2, 'i'); + test_assert(0 == ioctl(fd, TCGETS2, tc)); + VERIFY_GUARD(tc2); + atomic_printf("TCGETS2 returned { iflag=0x%x, oflag=0x%x, cflag=0x%x, " + "lflag=0x%x, ispeed=%d, ospeed=%d }\n", + tc2->c_iflag, tc2->c_oflag, tc2->c_cflag, tc2->c_lflag, + tc2->c_ispeed, tc2->c_ospeed); + test_assert(0 == ioctl(fd, TCSETS2, tc2)); + + // NB: leaving the TCSETS2 as the last word seems to mess up the terminal, + // so fix it. + test_assert(0 == ioctl(fd, TCSETS, tc)); + atomic_puts("EXIT-SUCCESS"); return 0; }