TIOCGPTPEER PTY Fallback for Restricted Android Kernels#20
Merged
bajrangCoder merged 6 commits intobajrangCoder:mainfrom Mar 10, 2026
Merged
TIOCGPTPEER PTY Fallback for Restricted Android Kernels#20bajrangCoder merged 6 commits intobajrangCoder:mainfrom
bajrangCoder merged 6 commits intobajrangCoder:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a Linux TIOCGPTPEER-based PTY creation/spawn fallback for environments where openpty() fails (e.g., SELinux denying /dev/pts/N), and updates portable-pty to the crates.io release to reduce dependency bloat and fetch time.
Changes:
- Introduces
src/terminal/pty_fallback.rsimplementing a PTY + spawn fallback using/dev/ptmx+TIOCGPTPEER. - Refactors
create_terminalto try standardportable-ptyfirst, then fall back on failure with shared session setup. - Updates dependencies (
portable-pty = 0.9.0) and addsanyhow+libc.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/terminal/pty_fallback.rs | New Linux-only PTY fallback implementation using TIOCGPTPEER and Command spawn. |
| src/terminal/mod.rs | Wires the new pty_fallback module into the terminal module. |
| src/terminal/handlers.rs | Refactors terminal creation to use a two-stage (standard → fallback) PTY creation path. |
| Cargo.toml | Adds anyhow + libc, switches portable-pty to crates.io. |
| Cargo.lock | Lockfile update reflecting new dependency source and resolver updates. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
added 2 commits
March 4, 2026 18:04
Add pty_fallback.rs implementing TIOCGPTPEER ioctl to obtain slave PTY fd directly from master fd, bypassing /dev/pts directory access blocked by SELinux in proot environments (e.g. HarmonyOS + Zhuo Yi Tong). Refactor create_terminal in handlers.rs: extract session setup into a shared path after a two-step PTY creation (standard openpty first, then TIOCGPTPEER fallback on failure). Add dependencies: anyhow (error handling), libc (POSIX syscalls).
- Set FD_CLOEXEC on dup'd fds in OwnedFd::try_clone() to prevent fd leaks - Retry read/write on EINTR for robust PTY I/O - Replace close_fds_above_stderr() with async-signal-safe implementation (close_range syscall + getrlimit loop, no heap allocation in pre_exec) - Wrap slave_fd in OwnedFd RAII to ensure cleanup on all error paths - Separate openpty from spawn_command in handlers.rs to avoid unnecessary fallback when spawn fails (e.g. missing program) - Log non-fatal TIOCSWINSZ failure instead of ignoring silently - Add #[cfg] rejection comment in mod.rs (Linux-only by design)
bajrangCoder
reviewed
Mar 8, 2026
Kill and wait the spawned child when shared terminal session setup fails after spawn so partially initialized sessions do not leak background processes. Also tighten the pre-exec file descriptor cleanup fallback by using RLIMIT-derived bounds when available and a high conservative upper bound when they are not, preventing descriptors above 1023 from surviving when close_range cannot be used.
bajrangCoder
approved these changes
Mar 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The standard
openpty()call might fail because SELinux blocksopen("/dev/pts/N")under certain environments. This PR adds aTIOCGPTPEERioctl fallback path so the terminal can create PTY sessions on these restricted kernels. It also switchesportable-ptyfrom a pinned wezterm git revision to the crates.io release.Changes
1. New file:
src/terminal/pty_fallback.rs(+351 lines)Why:
portable_pty::native_pty_system().openpty()callsopen("/dev/pts/N")internally, which might be denied by SELinux in proot environments. TheTIOCGPTPEERioctl obtains the slave fd directly from the master fd, completely bypassing/dev/ptsdirectory access.Implementation:
OwnedFd— lightweight RAII fd wrapper implementingRead/Write, maps EIO to EOFFallbackMasterPty— implements theportable_pty::MasterPtytrait (resize / get_size / try_clone_reader / take_writer)FallbackMasterWriter— sends EOT on drop to match portable-pty behaviourclose_fds_above_stderr()— closes leaked fds after forkfallback_open_and_spawn()— public entry point:/dev/ptmx→grantpt→unlockpt→TIOCGPTPEER→ set winsize → fork + setsid + TIOCSCTTY → exec child2. Refactored
src/terminal/handlers.rs(create_terminal)Why: The original code performed all session setup (reader/writer/scrollback/exit waiter) inside a deeply nested
match openpty { Ok(pair) => match spawn { Ok(child) => ... } }block. Adding a fallback path would make this nesting unmanageable.What changed:
fallback_open_and_spawnon failure(Box<dyn MasterPty + Send>, Box<dyn Child + Send + Sync>)native_pty_system()initialization moved closer to its usage point3. New dependencies:
anyhow+libc(Cargo.toml)anyhowpty_fallback.rs(bail!macro)libcioctl/grantpt/setsidand other POSIX APIs4.
portable-ptysource changeWhy: The previous dependency pulled from a pinned revision of the entire wezterm monorepo, resulting in slow fetches and a bloated Cargo.lock. The crates.io 0.9.0 release provides the same API surface with faster builds and fewer transitive dependencies.