ioctl: Forward standard termios calls to real pty#279
Conversation
will look later. |
1acf0bc to
b833d01
Compare
|
Man, what a mess. This should work now! |
There was a problem hiding this comment.
Pull request overview
This PR improves ioctl handling for emulated TTY devices by forwarding standard termios ioctls (e.g., TCGETS/TCSETS/TIOCGWINSZ) to the underlying PTY when no explicit emulation handler exists, fixing failures with Rust coreutils’ stty.
Changes:
- Add a termios-ioctl fallback path in the default ioctl handler to execute the ioctl on the real (PTY-backed) fd when appropriate.
- Introduce a small C helper (
ioctl_termios.*) to identify termios ioctls and expose constants in a Vala-friendly way. - Add a Vala test ensuring a basic termios ioctl (TCGETS) succeeds on an emulated TTY device.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test-umockdev-vala.vala | Adds regression test for TCGETS on PTY-backed emulated TTY. |
| src/umockdev-ioctl.vala | Adds fallback to run real ioctl for termios requests when emulation yields ENOTTY. |
| src/ioctl_termios.vapi | Vala bindings for termios ioctl helper functions. |
| src/ioctl_termios.h | Declares helper functions for identifying termios ioctls / getting TCGETS. |
| src/ioctl_termios.c | Implements termios ioctl detection with arch-conditional TC*2 handling. |
| meson.build | Wires new helper sources into library/program builds and the Vala test build. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Handle ioctls TCGETS{,2} and friends on emulated TTY devices by
forwarding them to the underlying PTY. Our ioctl handler previously
always returned `ENOTTY` for these, unless there was an explicit
handler.
This fixes tests with uutils (Rust coreutils)' `stty` implementation,
the current Ubuntu development series just switched to that [1].
GNU coreutils avoids that problem:
1. Opens (emulated) /dev/ttyUSB1 as fd 3
2. dup2(3,0) = 0
3. close(3)
4. ioctl(0, TCGETS2, ...) = 0
i.e. it bypasses the emulation and does the ioctl on the real underlying
PTY.
Rust coreutils does *not* do the dup() step, but calls TCGETS2 on the
/dev/ttyUSB1 directly, so it previously got ENOTTY and failed.
This is unfortunately rather messy: The most obvious solution of using
the Linux::Termios::TC* constants does not work, as Vala cannot evaluate
the incomplete `struct termios2`; and the TC*2 variants don't exist on
ppc64le, but Vala does not have conditional compilation. So add a little
C helper library for these.
[1] https://launchpad.net/ubuntu/+source/rust-coreutils/0.6.0-0ubuntu1
Per POSIX, errno is only meaningful after a syscall fails. Successful syscalls preserve the previous errno value. Remove assertions that check errno == 0 after successful ioctl calls. This prepares the tests for the next change where we actually fix the emulated ioctls to behave that way.
Per POSIX, errno is only modified on syscall failure and is preserved on success. Make our emulated ioctl()s conformant to that. In the preload (client side), only set errno when ioctl/read/write fails. In umockdev-ioctl.vala (server side), clean up the errno handling: - Pre-set default errno (ENOENT for type 'E', ENOTTY otherwise) before calling tree.execute(), so ioctl handlers can override it - Capture errno after tree.execute() to preserve handler-set errors (e.g., ENODATA for USBDEVFS_GETDRIVER) - For termios ioctls forwarded to real PTY: preserve errno from the real ioctl(2) call - For successful tree.execute(): send errno=0 to preload, which now correctly ignores it This ensures umockdev's ioctl emulation matches real kernel behavior: - Successful calls preserve errno (applications can detect success by checking return value, not errno) - Failed calls set appropriate error codes - termios ioctls forwarded to real PTY inherit the real errno
b833d01 to
a868760
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Handle ioctls TCGETS{,2} and friends on emulated TTY devices by forwarding them to the underlying PTY. Our ioctl handler previously always returned
ENOTTYfor these, unless there was an explicit handler.This fixes tests with uutils (Rust coreutils)'
sttyimplementation, the current Ubuntu development series just switched to that [1].GNU coreutils avoids that problem:
i.e. it bypasses the emulation and does the ioctl on the real underlying PTY.
Rust coreutils does not do the dup() step, but calls TCGETS2 on the /dev/ttyUSB1 directly, so it previously got ENOTTY and failed.
This is unfortunately rather messy: The most obvious solution of using the Linux::Termios::TC* constants does not work, as Vala cannot evaluate the incomplete
struct termios2; and the TC*2 variants don't exist on ppc64le, but Vala does not have conditional compilation. So add a little C helper library for these.[1] https://launchpad.net/ubuntu/+source/rust-coreutils/0.6.0-0ubuntu1
Fixes the ubuntu/devel failure which started a few days ago.