From 1b05c950cb53a04e0d83ce3ad19815dde223d685 Mon Sep 17 00:00:00 2001 From: Ling Wang Date: Wed, 18 Sep 2024 01:43:16 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20fix:=20Fix=20shell?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix shell: use ptyprocess to make it interactive --- Cargo.lock | 287 +++++++++++------------------------------- Cargo.toml | 4 +- TODO.md | 6 +- src/consts.rs | 4 +- src/exec/cli_exec.rs | 2 +- src/term/asciicast.rs | 2 +- src/term/shell.rs | 124 ++++++++---------- src/term/tee.rs | 2 +- src/util/util.rs | 22 ++++ 9 files changed, 157 insertions(+), 296 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 21f5807..7aceabd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,21 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "android-tzdata" version = "0.1.1" @@ -50,21 +35,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -89,17 +59,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" -[[package]] -name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - [[package]] name = "cc" -version = "1.1.15" +version = "1.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" dependencies = [ "shlex", ] @@ -110,6 +74,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "chrono" version = "0.4.38" @@ -132,7 +102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys", ] [[package]] @@ -158,12 +128,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - [[package]] name = "hashbrown" version = "0.14.5" @@ -176,17 +140,11 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -207,9 +165,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -346,42 +304,44 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memoffset" -version = "0.9.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" dependencies = [ "autocfg", ] [[package]] -name = "miniz_oxide" -version = "0.7.4" +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ - "adler", + "autocfg", ] [[package]] -name = "mio" -version = "1.0.2" +name = "nix" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "hermit-abi", + "bitflags 1.3.2", + "cfg-if", "libc", - "wasi", - "windows-sys 0.52.0", + "memoffset 0.7.1", + "pin-utils", ] [[package]] name = "nix" -version = "0.26.4" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.6.0", "cfg-if", + "cfg_aliases", "libc", ] @@ -394,15 +354,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "object" -version = "0.36.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.19.0" @@ -429,17 +380,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.10", + "parking_lot_core", ] [[package]] @@ -451,29 +392,16 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec", "winapi", ] [[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.3", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" @@ -505,16 +433,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "ptyprocess" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e05aef7befb11a210468a2d77d978dde2c6381a0381e33beb575e91f57fe8cf" +dependencies = [ + "nix 0.26.4", +] + [[package]] name = "pyo3" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831e8e819a138c36e212f3af3fd9eeffed6bf1510a805af35b0edee5ffa59433" +checksum = "15ee168e30649f7f234c3d49ef5a7a6cbf5134289bc46c29ff3155fa3221c225" dependencies = [ "cfg-if", "indoc", "libc", - "memoffset", + "memoffset 0.9.1", "once_cell", "portable-atomic", "pyo3-build-config", @@ -525,9 +462,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8730e591b14492a8945cdff32f089250b05f5accecf74aeddf9e8272ce1fa8" +checksum = "e61cef80755fe9e46bb8a0b8f20752ca7676dcc07a5277d8b7768c6172e529b3" dependencies = [ "once_cell", "target-lexicon", @@ -535,9 +472,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e97e919d2df92eb88ca80a037969f44e5e70356559654962cbb3316d00300c6" +checksum = "67ce096073ec5405f5ee2b8b31f03a68e02aa10d5d4f565eca04acc41931fa1c" dependencies = [ "libc", "pyo3-build-config", @@ -545,9 +482,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb57983022ad41f9e683a599f2fd13c3664d7063a3ac5714cae4b7bee7d3f206" +checksum = "2440c6d12bc8f3ae39f1e775266fa5122fd0c8891ce7520fa6048e683ad3de28" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -557,9 +494,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.22.2" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec480c0c51ddec81019531705acac51bcdbeae563557c982aa8263bb96880372" +checksum = "1be962f0e06da8f8465729ea2cb71a416d2257dff56cbe40a70d3e62a93ae5d1" dependencies = [ "heck", "proc-macro2", @@ -616,21 +553,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "ryu" version = "1.0.18" @@ -645,18 +567,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -665,9 +587,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -696,7 +618,7 @@ dependencies = [ "io-kit-sys", "libudev", "mach2", - "nix", + "nix 0.26.4", "scopeguard", "unescaper", "winapi", @@ -708,31 +630,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "ssh2" version = "0.9.4" @@ -742,24 +645,14 @@ dependencies = [ "bitflags 1.3.2", "libc", "libssh2-sys", - "parking_lot 0.11.2", -] - -[[package]] -name = "subprocess" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2e86926081dda636c546d8c5e641661049d7562a68f5488be4a1f7f66f6086" -dependencies = [ - "libc", - "winapi", + "parking_lot", ] [[package]] name = "syn" -version = "2.0.76" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -778,14 +671,14 @@ version = "0.1.0" dependencies = [ "asciicast", "colored", + "nix 0.29.0", + "ptyprocess", "pyo3", "rand", "serde", "serde_json", "serialport", "ssh2", - "subprocess", - "tokio", "toml", ] @@ -809,35 +702,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio" -version = "1.39.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "parking_lot 0.12.3", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "toml" version = "0.8.19" @@ -861,9 +725,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" dependencies = [ "indexmap", "serde", @@ -883,9 +747,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unindent" @@ -1000,15 +864,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-targets" version = "0.48.5" diff --git a/Cargo.toml b/Cargo.toml index f856f2a..0c36930 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,10 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.125" serialport = "4.5.0" ssh2 = "0.9.4" -subprocess = "0.2.9" -tokio = { version = "1", features = ["full"] } toml = "0.8.19" colored = "2.1.0" +nix = { version = "0.29.0", features = ["fs", "process", "signal", "term"] } +ptyprocess = "0.4.1" [toolchain] channel = "nightly" diff --git a/TODO.md b/TODO.md index 5a7a48d..9950a83 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1,5 @@ -- [ ] **修 shell……** -- [ ] **想办法把那个 PyTty 缩小掉……** +- [ ] **可维护性:想办法把那个 PyTty 缩小掉……** +- [ ] Shell 控制命令的 filter - [ ] 更多的连接方式 - [x] 更完善的 SSH @@ -13,10 +13,12 @@ - [ ] 设备抽象 : mod device - [x] 更加的多态支持 : where T: Tty -> Box + - [ ] Trait Cast - [ ] 导出的 API - [x] 实现 cli-like 面向外界的哪一个巨型 wrapper - [?] 从 dyn Tty 中区分出这个巨型 wrapper,并分开实现(可以在每次开头前都试一试?) + - [ ] - [x] 执行器 - [ ] 与下一步测试软件的进一步集成 diff --git a/src/consts.rs b/src/consts.rs index 9ec39b6..0f9581c 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,4 +1,4 @@ -pub const DURATION: u64 = 25; -pub const SHELL_DURATION: u64 = 1; +pub const DURATION: u64 = 100; +pub const SHELL_DURATION: u64 = 50; pub const SHELL_PROMPT: &str = ""; // I don't know why it doesn't echo back the prompt... Add this as a workaround \ No newline at end of file diff --git a/src/exec/cli_exec.rs b/src/exec/cli_exec.rs index 72d69c8..4261e74 100644 --- a/src/exec/cli_exec.rs +++ b/src/exec/cli_exec.rs @@ -6,7 +6,7 @@ use std::{ }; use crate::{ - consts::DURATION, err, info, log, term::tty::{DynTty, InnerTty, Tty, WrapperTty}, util::{anybase::AnyBase, util::rand_string} + consts::DURATION, err, info, term::tty::{DynTty, InnerTty, Tty, WrapperTty}, util::{anybase::AnyBase, util::rand_string} }; use super::cli_api::CliTestApi; diff --git a/src/term/asciicast.rs b/src/term/asciicast.rs index 347a79e..1abbef7 100644 --- a/src/term/asciicast.rs +++ b/src/term/asciicast.rs @@ -11,7 +11,7 @@ use asciicast::{Entry, EventType, Header}; use serde_json::to_string; use crate::{ - consts::{DURATION, SHELL_PROMPT}, + consts::DURATION, info, util::anybase::AnyBase, }; diff --git a/src/term/shell.rs b/src/term/shell.rs index 99f5553..7769335 100644 --- a/src/term/shell.rs +++ b/src/term/shell.rs @@ -1,22 +1,26 @@ +use ptyprocess::{stream::Stream, PtyProcess}; +use std::io::{BufRead, BufReader, Read}; +use std::ops::DerefMut; +use std::os::fd::AsRawFd; use std::{ any::Any, - collections::HashMap, - env, error::Error, - io::{ErrorKind, Read, Write}, - process::{ChildStdin, Command, Stdio}, + io::Write, + process::Command, sync::{Arc, Mutex}, thread::{sleep, spawn, JoinHandle}, time::Duration, }; +use crate::util::util::try_read; use crate::{consts::SHELL_DURATION, err, info, log, util::anybase::AnyBase}; use super::tty::Tty; pub struct Shell { - stdin: ChildStdin, + inner: Arc>, buff: Arc>>, + proc: PtyProcess, handle: Option>, stop: Arc>, } @@ -34,78 +38,59 @@ impl Shell { info!("Spawn shell process: {}", shell); - let filtered_env: HashMap = env::vars() - .filter(|&(ref k, _)| k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH") - .collect(); - - let inner = Command::new(shell) - .envs(&filtered_env) - .envs(Into::>::into([("PS1", r"[\u@\h \W]\$")])) - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .spawn(); + let mut inner = Command::new(shell); + inner.args(&["-i"]); + let inner = PtyProcess::spawn(inner); if let Err(e) = inner { err!("Failed to spawn shell process. Reason: {}", e); return Err(Box::new(e)); } - let mut inner = inner.unwrap(); + let proc = inner.unwrap(); + let inner = proc.get_pty_stream()?; - let stdin = inner.stdin.take(); - if let None = stdin { - err!("Failed to get stdin of shell process."); - return Err(Box::::from("")); - } - let mut stdin = stdin.unwrap(); - stdin - .write_all(b"export PS1=\"[\\u@\\h \\W]\\$\"\n") - .unwrap(); - - let stdout = inner.stdout.take(); - if let None = stdout { - err!("Failed to get stdout of shell process."); - return Err(Box::::from("")); - } - let stdout = stdout.unwrap(); + info!( + "Shell process spawned, got streamed... FD: {:?}", + inner.as_raw_fd() + ); - let stderr = inner.stderr.take(); - if let None = stderr { - err!("Failed to get stderr of shell process."); - return Err(Box::::from("")); - } - let stderr = stderr.unwrap(); - let mut stdout = stdout.chain(stderr); + let inner = Arc::new(Mutex::new(inner)); let mut res = Shell { - stdin, + inner, buff: Arc::new(Mutex::new(Vec::new())), + proc, handle: None, stop: Arc::new(Mutex::new(false)), }; - let buff_clone = res.buff.clone(); - let stop_clone = res.stop.clone(); + let buff = res.buff.clone(); + let stop = res.stop.clone(); + let stream = res.inner.clone(); let handle = spawn(move || loop { sleep(Duration::from_millis(SHELL_DURATION)); { - let stop = stop_clone.lock().unwrap(); + let stop: std::sync::MutexGuard<'_, bool> = stop.lock().unwrap(); if *stop { log!("Stop shell process"); - return; } } - let mut buf = [0u8]; - let sz = stdout.read(&mut buf); - if let Err(e) = sz { - err!("Read from shell process failed. Reason: {}", e); - break; - } - if buf[0] == 0x0 { - continue; + let mut buf = Vec::new(); + { + let mut stream = stream.lock().unwrap(); + let mut reader = BufReader::new(stream.deref_mut()); + let sz = try_read(&mut reader, &mut buf); + if let Err(e) = sz { + err!("Failed to read from shell process. Reason: {}", e); + return; + } + let sz = sz.unwrap(); + if sz == 0 { + continue; + } } - let mut buff = buff_clone.lock().unwrap(); - if buf[0] != 0x0 { - buff.extend_from_slice(&buf); + { + let mut buff = buff.lock().unwrap(); + buff.extend(buf.iter()); } }); @@ -126,6 +111,7 @@ impl Shell { } *stop = true; log!("Try to stop shell process"); + self.proc.exit(false).unwrap(); // if let Some(handle) = self.handle.take() { // handle.join().unwrap(); // self.inner.wait().unwrap(); @@ -184,23 +170,19 @@ impl Tty for Shell { return Ok(res); } fn write(&mut self, data: &[u8]) -> Result<(), Box> { - loop { - sleep(Duration::from_millis(SHELL_DURATION)); - match self.stdin.write_all(data) { - Ok(_) => break, - Err(e) if e.kind() == ErrorKind::Interrupted => continue, - Err(e) => { - err!("Write to shell process failed. Reason: {}", e); - return Err(Box::new(e)); - } + let mut stream = self.inner.lock().unwrap(); + info!("Shell locked..."); + match stream.write(data) { + Ok(_) => { + stream.flush().unwrap(); + info!("Shell write: {:?}", String::from_utf8_lossy(data)); + return Ok(()); + } + Err(e) => { + err!("Write to shell process failed. Reason: {}", e); + return Err(Box::new(e)); } } - let res = self.stdin.flush(); - if let Err(e) = res { - err!("Flush to shell process failed. Reason: {}", e); - return Err(Box::::from(e)); - } - return Ok(()); } } diff --git a/src/term/tee.rs b/src/term/tee.rs index e40ee2f..979cc04 100644 --- a/src/term/tee.rs +++ b/src/term/tee.rs @@ -45,7 +45,7 @@ impl Tty for Tee { } fn write(&mut self, data: &[u8]) -> Result<(), Box> { self.inner.write(data)?; - self.file.write_all(data)?; // tee should not write to file, but for log purpose... + // self.file.write_all(data)?; // tee should not write to file, but for log purpose... Ok(()) } } diff --git a/src/util/util.rs b/src/util/util.rs index e0cc6c4..da40eb1 100644 --- a/src/util/util.rs +++ b/src/util/util.rs @@ -1,3 +1,7 @@ +use std::{ + error::Error, + io::{BufRead, ErrorKind}, +}; use rand::{distributions::Alphanumeric, thread_rng, Rng}; @@ -24,3 +28,21 @@ pub fn rand_string(len: usize) -> Vec { rnd } +pub fn try_read( + r: &mut R, + buf: &mut Vec, +) -> Result> { + loop { + let used = { + let available = match r.fill_buf() { + Ok(n) => n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(Box::new(e)), + }; + buf.extend_from_slice(available); + available.len() + }; + r.consume(used); + return Ok(used); + } +}