This commit is contained in:
mtgmonkey 2025-07-04 14:33:21 -04:00
commit 0a2ec5f358
6 changed files with 4324 additions and 0 deletions

4164
Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

7
Cargo.toml Normal file
View file

@ -0,0 +1,7 @@
[package]
name = "rust_term"
version = "0.1.0"
edition = "2024"
[dependencies]
nix = { version = "0.30.1", features = ["term", "process", "fs"], default-features = false }

47
flake.lock generated Normal file
View file

@ -0,0 +1,47 @@
{
"nodes": {
"naersk": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1745925850,
"narHash": "sha256-cyAAMal0aPrlb1NgzMxZqeN1mAJ2pJseDhm2m6Um8T0=",
"owner": "nix-community",
"repo": "naersk",
"rev": "38bc60bbc157ae266d4a0c96671c6c742ee17a5f",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "naersk",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1751011381,
"narHash": "sha256-krGXKxvkBhnrSC/kGBmg5MyupUUT5R6IBCLEzx9jhMM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "30e2e2857ba47844aa71991daa6ed1fc678bcbb7",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-unstable",
"type": "indirect"
}
},
"root": {
"inputs": {
"naersk": "naersk",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

24
flake.nix Normal file
View file

@ -0,0 +1,24 @@
{
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
naersk = {
url = "github:nix-community/naersk";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
nixpkgs,
naersk,
...
}: let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
packages.${system} = {
default = pkgs.callPackage ./package.nix {
naersk = pkgs.callPackage naersk {};
};
};
# nixosModules.${system}.default = ./module.nix;
};
}

26
package.nix Normal file
View file

@ -0,0 +1,26 @@
{
busybox-sandbox-shell,
lib,
makeWrapper,
naersk,
pkg-config,
...
}:
naersk.buildPackage rec {
name = "rust_pty";
src = ./.;
buildInputs = [
busybox-sandbox-shell
];
nativeBuildInputs = [
pkg-config
makeWrapper
];
postInstall = ''
wrapProgram "$out/bin/${meta.mainProgram}" --prefix LD_LIBRARY_PATH : "${lib.makeLibraryPath buildInputs}"
'';
meta = {
mainProgram = "rust_term";
homepage = "https://mtgmonkey.net";
};
}

56
src/main.rs Normal file
View file

@ -0,0 +1,56 @@
use nix::pty::{ForkptyResult, forkpty};
use nix::unistd::{read, write};
use std::fs::File;
use std::io::{Read, Write};
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
use std::process::Command;
fn main() {
let default_shell = "/home/mtgmonkey/.nix-profile/bin/dash".to_string();
let fd = spawn_pty_with_shell(default_shell);
set_nonblock(&fd);
let mut write_buffer = "tty\n".as_bytes().to_vec();
write(fd.as_fd(), &mut write_buffer);
loop {
let red = read_from_fd(fd.try_clone().unwrap());
match red {
Some(red) => print!("{}", String::from_utf8(red).unwrap()),
None => {
let mut write_buffer = vec![];
std::io::stdin().read_to_end(&mut write_buffer);
write(fd.as_fd(), &mut write_buffer);
}
};
}
}
fn spawn_pty_with_shell(default_shell: String) -> OwnedFd {
match (unsafe { forkpty(None, None) }) {
Ok(fork_pty_res) => match fork_pty_res {
ForkptyResult::Parent { master, .. } => master,
ForkptyResult::Child => {
Command::new(&default_shell).spawn().unwrap();
std::thread::sleep(std::time::Duration::MAX);
std::process::exit(0);
}
},
Err(e) => panic!("failed to fork {:?}", e),
}
}
fn read_from_fd(fd: OwnedFd) -> Option<Vec<u8>> {
let mut read_buffer = [0; 65536];
let mut file = File::from(fd).read(&mut read_buffer);
match file {
Ok(file) => Some(read_buffer[..file].to_vec()),
Err(_) => None,
}
}
fn set_nonblock(fd: &OwnedFd) {
let flags = nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_GETFL).unwrap();
let mut flags =
nix::fcntl::OFlag::from_bits(flags & nix::fcntl::OFlag::O_ACCMODE.bits()).unwrap();
flags.set(nix::fcntl::OFlag::O_NONBLOCK, true);
nix::fcntl::fcntl(fd, nix::fcntl::FcntlArg::F_SETFL(flags)).unwrap();
}