mirror of
https://github.com/SL-RU/mmtui.git
synced 2025-03-04 08:24:43 +01:00
works
This commit is contained in:
parent
ed9ca59452
commit
7f2ac0f3f3
5 changed files with 336 additions and 49 deletions
167
Cargo.lock
generated
167
Cargo.lock
generated
|
@ -202,6 +202,26 @@ dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bindgen"
|
||||||
|
version = "0.69.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cexpr",
|
||||||
|
"clang-sys",
|
||||||
|
"itertools 0.12.1",
|
||||||
|
"lazy_static",
|
||||||
|
"lazycell",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"regex",
|
||||||
|
"rustc-hash",
|
||||||
|
"shlex",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
@ -272,6 +292,15 @@ dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cexpr"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||||
|
dependencies = [
|
||||||
|
"nom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -284,6 +313,17 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clang-sys"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4"
|
||||||
|
dependencies = [
|
||||||
|
"glob",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compact_str"
|
name = "compact_str"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -330,6 +370,7 @@ checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
|
"futures-core",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rustix",
|
"rustix",
|
||||||
|
@ -596,6 +637,12 @@ version = "0.31.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "glob"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
|
@ -661,6 +708,15 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.13.0"
|
version = "0.13.0"
|
||||||
|
@ -682,12 +738,28 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazycell"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.168"
|
version = "0.2.168"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.4.14"
|
version = "0.4.14"
|
||||||
|
@ -723,6 +795,17 @@ version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "loopdev-3"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "90a97d7a5124296ee9124a815acdc3dc4a91f577b72812b3f1f99bb959b46e8d"
|
||||||
|
dependencies = [
|
||||||
|
"bindgen",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lru"
|
name = "lru"
|
||||||
version = "0.12.5"
|
version = "0.12.5"
|
||||||
|
@ -756,6 +839,12 @@ dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
|
@ -783,7 +872,9 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
|
"sys-mount",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-stream",
|
||||||
"udisks2",
|
"udisks2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -800,6 +891,16 @@ dependencies = [
|
||||||
"memoffset",
|
"memoffset",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc"
|
name = "objc"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -1015,7 +1116,7 @@ dependencies = [
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"indoc",
|
"indoc",
|
||||||
"instability",
|
"instability",
|
||||||
"itertools",
|
"itertools 0.13.0",
|
||||||
"lru",
|
"lru",
|
||||||
"paste",
|
"paste",
|
||||||
"strum",
|
"strum",
|
||||||
|
@ -1068,6 +1169,12 @@ version = "0.1.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.42"
|
version = "0.38.42"
|
||||||
|
@ -1192,6 +1299,17 @@ version = "1.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smart-default"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.8"
|
version = "0.5.8"
|
||||||
|
@ -1247,6 +1365,20 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sys-mount"
|
||||||
|
version = "3.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6acb8bb63826062d5a44b68298cf2e25b84bc151bc0c31c35a83b61f818682a"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"libc",
|
||||||
|
"loopdev-3",
|
||||||
|
"smart-default",
|
||||||
|
"thiserror",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "temp-dir"
|
name = "temp-dir"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
|
@ -1266,6 +1398,26 @@ dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "1.0.69"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.42.0"
|
version = "1.42.0"
|
||||||
|
@ -1295,6 +1447,17 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-stream"
|
||||||
|
version = "0.1.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
|
@ -1391,7 +1554,7 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools 0.13.0",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"unicode-width 0.1.14",
|
"unicode-width 0.1.14",
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,7 +4,9 @@ version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm = "0.28.1"
|
crossterm = { version = "0.28.1", features = ["event-stream"]}
|
||||||
ratatui = "0.29.0"
|
ratatui = "0.29.0"
|
||||||
|
sys-mount = "3.0.1"
|
||||||
tokio = {version = "1.42.0", features = ["full"]}
|
tokio = {version = "1.42.0", features = ["full"]}
|
||||||
|
tokio-stream = "0.1.17"
|
||||||
udisks2 = "0.2.0"
|
udisks2 = "0.2.0"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
os::unix::ffi::{OsStrExt, OsStringExt},
|
os::unix::ffi::{OsStrExt, OsStringExt},
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
|
@ -6,19 +7,20 @@ use std::{
|
||||||
|
|
||||||
use crate::mountpoints;
|
use crate::mountpoints;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub id: String,
|
pub object_path: String,
|
||||||
pub dev: String,
|
pub dev: String,
|
||||||
pub label: String,
|
pub label: String,
|
||||||
pub mount: Option<String>,
|
pub mount: Option<String>,
|
||||||
pub fstype: String,
|
pub fstype: String,
|
||||||
|
pub mounted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Drive {
|
pub struct Drive {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub path: String,
|
pub object_path: String,
|
||||||
pub model: String,
|
pub model: String,
|
||||||
pub ejectable: bool,
|
pub ejectable: bool,
|
||||||
pub blocks: Vec<Block>,
|
pub blocks: Vec<Block>,
|
||||||
|
@ -44,14 +46,14 @@ pub async fn collect_drives_from_udisk() -> udisks2::Result<Vec<Drive>> {
|
||||||
let path = path.to_string();
|
let path = path.to_string();
|
||||||
if let Ok(drv) = i.drive().await {
|
if let Ok(drv) = i.drive().await {
|
||||||
let drv = Drive {
|
let drv = Drive {
|
||||||
path,
|
object_path: path,
|
||||||
id: drv.id().await?,
|
id: drv.id().await?,
|
||||||
model: drv.model().await?,
|
model: drv.model().await?,
|
||||||
ejectable: drv.ejectable().await?,
|
ejectable: drv.ejectable().await?,
|
||||||
blocks: Vec::new(),
|
blocks: Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(d) = drives.iter_mut().find(|i| i.path == drv.path) {
|
if let Some(d) = drives.iter_mut().find(|i| i.object_path == drv.object_path) {
|
||||||
d.model = drv.model;
|
d.model = drv.model;
|
||||||
d.ejectable = drv.ejectable;
|
d.ejectable = drv.ejectable;
|
||||||
d.id = drv.id;
|
d.id = drv.id;
|
||||||
|
@ -61,7 +63,7 @@ pub async fn collect_drives_from_udisk() -> udisks2::Result<Vec<Drive>> {
|
||||||
} else if let Ok(blk) = i.block().await {
|
} else if let Ok(blk) = i.block().await {
|
||||||
let drv_path = blk.drive().await?.to_string();
|
let drv_path = blk.drive().await?.to_string();
|
||||||
let block = Block {
|
let block = Block {
|
||||||
id: blk.id().await?,
|
object_path: path,
|
||||||
dev: String::from_utf8_lossy(&blk.device().await?)
|
dev: String::from_utf8_lossy(&blk.device().await?)
|
||||||
.chars()
|
.chars()
|
||||||
.filter(|c| c != &'\0')
|
.filter(|c| c != &'\0')
|
||||||
|
@ -69,13 +71,14 @@ pub async fn collect_drives_from_udisk() -> udisks2::Result<Vec<Drive>> {
|
||||||
label: blk.id_label().await?,
|
label: blk.id_label().await?,
|
||||||
mount: None,
|
mount: None,
|
||||||
fstype: blk.id_type().await?,
|
fstype: blk.id_type().await?,
|
||||||
|
mounted: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(d) = drives.iter_mut().find(|i| i.path == drv_path) {
|
if let Some(d) = drives.iter_mut().find(|i| i.object_path == drv_path) {
|
||||||
d.blocks.push(block);
|
d.blocks.push(block);
|
||||||
} else {
|
} else {
|
||||||
drives.push(Drive {
|
drives.push(Drive {
|
||||||
path: drv_path,
|
object_path: drv_path,
|
||||||
id: String::new(),
|
id: String::new(),
|
||||||
model: String::new(),
|
model: String::new(),
|
||||||
ejectable: false,
|
ejectable: false,
|
||||||
|
@ -94,7 +97,7 @@ pub async fn collect_all() -> udisks2::Result<Vec<Drive>> {
|
||||||
|
|
||||||
let mut fstab = Drive {
|
let mut fstab = Drive {
|
||||||
id: "fstab".to_owned(),
|
id: "fstab".to_owned(),
|
||||||
path: "fstab".to_owned(),
|
object_path: "fstab".to_owned(),
|
||||||
model: "fstab".to_owned(),
|
model: "fstab".to_owned(),
|
||||||
ejectable: false,
|
ejectable: false,
|
||||||
blocks: Vec::new(),
|
blocks: Vec::new(),
|
||||||
|
@ -107,22 +110,55 @@ pub async fn collect_all() -> udisks2::Result<Vec<Drive>> {
|
||||||
.and_then(|d| d.blocks.iter_mut().find(|b| b.dev == i.dev));
|
.and_then(|d| d.blocks.iter_mut().find(|b| b.dev == i.dev));
|
||||||
if let Some(block) = block {
|
if let Some(block) = block {
|
||||||
block.mount = i.path;
|
block.mount = i.path;
|
||||||
|
block.mounted = i.mounted;
|
||||||
} else {
|
} else {
|
||||||
fstab.blocks.push(Block {
|
fstab.blocks.push(Block {
|
||||||
id: i.dev.clone(),
|
object_path: String::new(),
|
||||||
dev: i.dev,
|
dev: i.dev,
|
||||||
label: String::new(),
|
label: String::new(),
|
||||||
mount: i.path,
|
mount: i.path,
|
||||||
fstype: i.fs,
|
fstype: i.fs,
|
||||||
|
mounted: i.mounted,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drives.push(fstab);
|
drives.push(fstab);
|
||||||
drives.sort_by_cached_key(|b| b.path.clone());
|
drives.sort_by_cached_key(|b| b.object_path.clone());
|
||||||
for i in &mut drives {
|
for i in &mut drives {
|
||||||
i.blocks.sort_by_cached_key(|b| b.dev.clone());
|
i.blocks.sort_by_cached_key(|b| b.dev.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(drives);
|
Ok(drives)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn mount(block: &Block) -> udisks2::Result<()> {
|
||||||
|
let mut drives: Vec<Drive> = Vec::new();
|
||||||
|
let client = udisks2::Client::new().await?;
|
||||||
|
|
||||||
|
client
|
||||||
|
.object(block.object_path.clone())?
|
||||||
|
.filesystem()
|
||||||
|
.await?
|
||||||
|
.mount(HashMap::new())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// client.part
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn unmount(block: &Block) -> udisks2::Result<()> {
|
||||||
|
let mut drives: Vec<Drive> = Vec::new();
|
||||||
|
let client = udisks2::Client::new().await?;
|
||||||
|
|
||||||
|
client
|
||||||
|
.object(block.object_path.clone())?
|
||||||
|
.filesystem()
|
||||||
|
.await?
|
||||||
|
.unmount(HashMap::new())
|
||||||
|
.await?;
|
||||||
|
// client.part
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
113
src/main.rs
113
src/main.rs
|
@ -3,48 +3,109 @@ mod mountpoints;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
ffi::{OsStr, OsString},
|
ffi::{OsStr, OsString},
|
||||||
|
io::stderr,
|
||||||
os::unix::ffi::{OsStrExt, OsStringExt},
|
os::unix::ffi::{OsStrExt, OsStringExt},
|
||||||
sync::{Arc, Mutex},
|
sync::Arc,
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crossterm::event::{self, Event, KeyCode, KeyEventKind};
|
use crossterm::{
|
||||||
|
event::{Event, EventStream, KeyCode, KeyEventKind},
|
||||||
|
execute,
|
||||||
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
|
};
|
||||||
|
use drives::Drive;
|
||||||
use mountpoints::MountPoint;
|
use mountpoints::MountPoint;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Alignment, Constraint, Layout},
|
layout::{Alignment, Constraint, Layout},
|
||||||
|
prelude::CrosstermBackend,
|
||||||
style::Color,
|
style::Color,
|
||||||
text::{Line, Text},
|
text::{Line, Text},
|
||||||
widgets::{
|
widgets::{
|
||||||
Block, BorderType, Padding, Paragraph, Row, StatefulWidget, Table, TableState, Widget, Wrap,
|
Block, BorderType, Padding, Paragraph, Row, StatefulWidget, Table, TableState, Widget, Wrap,
|
||||||
},
|
},
|
||||||
Frame,
|
Frame, Terminal,
|
||||||
};
|
};
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
|
enum Command {
|
||||||
|
None,
|
||||||
|
Mount(String),
|
||||||
|
Umount(String),
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> udisks2::Result<()> {
|
async fn main() -> udisks2::Result<()> {
|
||||||
let mut terminal = ratatui::init();
|
enable_raw_mode().unwrap();
|
||||||
|
execute!(stderr(), EnterAlternateScreen).unwrap();
|
||||||
|
let mut terminal = Terminal::new(CrosstermBackend::new(stderr())).unwrap();
|
||||||
let mut ts = TableState::new();
|
let mut ts = TableState::new();
|
||||||
|
|
||||||
|
let period = Duration::from_secs_f32(1.0 / 10.0);
|
||||||
|
let mut interval = tokio::time::interval(period);
|
||||||
|
let mut events = EventStream::new();
|
||||||
|
|
||||||
|
let state: Arc<Mutex<Vec<drives::Drive>>> = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
let s = state.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
loop {
|
||||||
|
let drv = drives::collect_all().await.unwrap();
|
||||||
|
s.lock().await.clone_from(&drv);
|
||||||
|
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut output = String::new();
|
||||||
|
let mut last_status = String::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let drv = drives::collect_all().await?;
|
let drv = state.lock().await.clone();
|
||||||
|
let mut selected: Option<drives::Block> = None;
|
||||||
terminal
|
terminal
|
||||||
.draw(|f| draw(f, &mut ts, &drv))
|
.draw(|f| draw(f, &mut ts, &drv, &mut selected, &last_status))
|
||||||
.expect("failed to draw frame");
|
.expect("failed to draw frame");
|
||||||
|
|
||||||
if let Event::Key(key) = event::read().unwrap() {
|
tokio::select! {
|
||||||
if key.kind == KeyEventKind::Press {
|
_ = interval.tick() => { },
|
||||||
match key.code {
|
Some(Ok(event)) = events.next() => {
|
||||||
KeyCode::Up => ts.select_previous(),
|
if let Event::Key(key) = event {
|
||||||
KeyCode::Down => ts.select_next(),
|
if key.kind == KeyEventKind::Press {
|
||||||
KeyCode::Esc => break,
|
match key.code {
|
||||||
_ => {}
|
KeyCode::Up | KeyCode::Char('k') => ts.select_previous(),
|
||||||
|
KeyCode::Down | KeyCode::Char('j') => ts.select_next(),
|
||||||
|
KeyCode::Char('m') => if let Some(b) = &selected {
|
||||||
|
last_status = format!("{:?}", drives::mount(b).await);
|
||||||
|
}
|
||||||
|
KeyCode::Char('u') => if let Some(b) = &selected {
|
||||||
|
last_status = format!("{:?}", drives::unmount(b).await);
|
||||||
|
}
|
||||||
|
KeyCode::Esc | KeyCode::Char('q') => break,
|
||||||
|
KeyCode::Enter => {
|
||||||
|
output = selected.unwrap().mount.unwrap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ratatui::restore();
|
|
||||||
|
disable_raw_mode().unwrap();
|
||||||
|
execute!(stderr(), LeaveAlternateScreen).unwrap();
|
||||||
|
println!("{output}");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(frame: &mut Frame, state: &mut TableState, drv: &[drives::Drive]) {
|
fn draw(
|
||||||
|
frame: &mut Frame,
|
||||||
|
state: &mut TableState,
|
||||||
|
drv: &[drives::Drive],
|
||||||
|
selected: &mut Option<drives::Block>,
|
||||||
|
last_status: &str,
|
||||||
|
) {
|
||||||
let text = Text::raw("Hello World!");
|
let text = Text::raw("Hello World!");
|
||||||
frame.render_widget(text, frame.area());
|
frame.render_widget(text, frame.area());
|
||||||
|
|
||||||
|
@ -61,12 +122,22 @@ fn draw(frame: &mut Frame, state: &mut TableState, drv: &[drives::Drive]) {
|
||||||
.border_style(Color::Yellow);
|
.border_style(Color::Yellow);
|
||||||
block.clone().render(layout[0], frame.buffer_mut());
|
block.clone().render(layout[0], frame.buffer_mut());
|
||||||
|
|
||||||
let rows = drv.iter().flat_map(|d| &d.blocks).map(|i| {
|
let rows: Vec<drives::Block> = drv.iter().flat_map(|d| d.blocks.clone()).collect();
|
||||||
|
|
||||||
|
state
|
||||||
|
.selected()
|
||||||
|
.and_then(|n| rows.get(n).cloned())
|
||||||
|
.clone_into(selected);
|
||||||
|
|
||||||
|
let rows = rows.iter().map(|i| {
|
||||||
Row::new(vec![
|
Row::new(vec![
|
||||||
i.dev.clone(),
|
i.dev.clone(),
|
||||||
i.label.clone(),
|
i.label.clone(),
|
||||||
i.mount.clone().unwrap_or_default(),
|
i.mount.clone().unwrap_or_default(),
|
||||||
"M".to_owned(),
|
match i.mounted {
|
||||||
|
true => "M".to_owned(),
|
||||||
|
false => "O".to_owned(),
|
||||||
|
},
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
let widths = [
|
let widths = [
|
||||||
|
@ -81,8 +152,10 @@ fn draw(frame: &mut Frame, state: &mut TableState, drv: &[drives::Drive]) {
|
||||||
|
|
||||||
StatefulWidget::render(table, block.inner(frame.area()), frame.buffer_mut(), state);
|
StatefulWidget::render(table, block.inner(frame.area()), frame.buffer_mut(), state);
|
||||||
frame.render_widget(
|
frame.render_widget(
|
||||||
Paragraph::new("j - UP, k - DOWN, l - Goto mountpoint\nm - Mount, u - Unmount, e - Eject")
|
Paragraph::new(format!(
|
||||||
.wrap(Wrap { trim: true }),
|
"j - UP, k - DOWN, l - Goto mountpoint, m - Mount, u - Unmount, e - Eject\n{selected:?} {last_status:?}"
|
||||||
|
))
|
||||||
|
.wrap(Wrap { trim: true }),
|
||||||
layout[1],
|
layout[1],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,22 @@ pub struct MountPoint {
|
||||||
pub dev: String,
|
pub dev: String,
|
||||||
pub path: Option<String>,
|
pub path: Option<String>,
|
||||||
pub fs: String,
|
pub fs: String,
|
||||||
|
pub mounted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MountPoint {
|
impl MountPoint {
|
||||||
pub fn collect_from_file(path: &str) -> Vec<MountPoint> {
|
pub fn collect_from_file(path: &str) -> Vec<MountPoint> {
|
||||||
|
const FSTYPE_IGNORE: [&str; 8] = [
|
||||||
|
"tmpfs",
|
||||||
|
"swap",
|
||||||
|
"devtmpfs",
|
||||||
|
"devpts",
|
||||||
|
"hugetlbfs",
|
||||||
|
"mqueue",
|
||||||
|
"fuse.portal",
|
||||||
|
"fuse.gvfsd-fuse",
|
||||||
|
];
|
||||||
|
const PATH_IGNORE: [&str; 3] = ["/tmp", "/sys", "/proc"];
|
||||||
std::io::BufReader::new(std::fs::File::open(PathBuf::from(path)).unwrap())
|
std::io::BufReader::new(std::fs::File::open(PathBuf::from(path)).unwrap())
|
||||||
.lines()
|
.lines()
|
||||||
.map_while(Result::ok)
|
.map_while(Result::ok)
|
||||||
|
@ -21,17 +33,16 @@ impl MountPoint {
|
||||||
.into(),
|
.into(),
|
||||||
path: Some(parts.next()?.to_string()),
|
path: Some(parts.next()?.to_string()),
|
||||||
fs: parts.next()?.into(),
|
fs: parts.next()?.into(),
|
||||||
|
mounted: false,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
.filter(|p| !FSTYPE_IGNORE.contains(&p.fs.as_str()))
|
||||||
.filter(|p| {
|
.filter(|p| {
|
||||||
p.fs != "tmpfs" && p.fs != "swap"
|
if let Some(p) = &p.path {
|
||||||
&& p.path.clone().is_some_and(|p| {
|
!PATH_IGNORE.iter().any(|ignore| p.starts_with(ignore))
|
||||||
!p.starts_with("/sys")
|
} else {
|
||||||
&& !p.starts_with("/tmp")
|
false
|
||||||
&& !p.starts_with("/run")
|
}
|
||||||
&& !p.starts_with("/proc")
|
|
||||||
&& !p.starts_with("/dev")
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -44,12 +55,14 @@ impl MountPoint {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|p| !mnt.iter().any(|f| f.path == p.path))
|
.filter(|p| !mnt.iter().any(|f| f.path == p.path))
|
||||||
.map(|p| MountPoint {
|
.map(|p| MountPoint {
|
||||||
dev: p.dev,
|
mounted: false,
|
||||||
path: None,
|
..p
|
||||||
fs: p.fs,
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
mnt.into_iter().chain(fstab).collect()
|
mnt.into_iter()
|
||||||
|
.map(|m| MountPoint { mounted: true, ..m })
|
||||||
|
.chain(fstab)
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue