improve ping behaviour

This commit is contained in:
Empire 2024-09-06 20:12:17 +02:00
parent d71e515050
commit fa04e70d44
3 changed files with 1011 additions and 112 deletions

1002
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,8 @@ anyhow = "1.0.86"
dns-lookup = "2.0.4" dns-lookup = "2.0.4"
mountinfo = "0.2.0" mountinfo = "0.2.0"
ping = "0.5.2" ping = "0.5.2"
sys-mount = "3.0.1" sys-mount = {version="3.0.1", default-features = false}
notify-rust = "4"
[[bin]] [[bin]]
name = "automount" name = "automount"

View File

@ -1,64 +1,96 @@
use anyhow::Result; use anyhow::Result;
use dns_lookup::lookup_host; use dns_lookup::lookup_host;
use mountinfo::{MountInfo, ReadWrite, MountPoint}; use mountinfo::{MountInfo, ReadWrite, MountPoint};
use notify_rust::Notification;
use ping::{dgramsock, rawsock::ping}; use ping::{dgramsock, rawsock::ping};
use std::{ffi::OsStr, fs, path::PathBuf, sync::mpsc::{self, Receiver, Sender}, thread, time::Duration}; use std::{ffi::OsStr, fs, net::IpAddr, path::PathBuf, sync::mpsc::{self, Receiver, Sender}, thread::{self, sleep}, time::Duration};
use sys_mount::{unmount, UnmountFlags}; use sys_mount::{unmount, UnmountFlags};
fn main() { fn main() {
let mtab = MountInfo::new().unwrap();
let mounting_points = mtab.mounting_points; loop {
let relevant_mounts = mounting_points.iter().filter(|&mount_point| { let mtab = MountInfo::new().unwrap();
match &mount_point.fstype { let mounting_points = mtab.mounting_points;
mountinfo::FsType::Other(fsstring) => match fsstring.as_str() { let relevant_mounts = mounting_points.iter().filter(|&mount_point| {
"cifs" => { match &mount_point.fstype {
true mountinfo::FsType::Other(fsstring) => match fsstring.as_str() {
"cifs" => {
true
},
_ => false
}, },
_ => false _ => false
}, }
_ => false });
for mount_point in relevant_mounts {
let path = mount_point.path.to_owned();
let fstype = match &mount_point.fstype {
mountinfo::FsType::Other(fsstring) => fsstring,
_ => ""
};
let what = &mount_point.what;
//println!("Processing {fstype} @ {path:?} from {what}");
process_mount(fstype, what, path);
} }
}); sleep(Duration::from_secs(5));
println!("Scanning for hanging mounts");
for mount_point in relevant_mounts {
let path = mount_point.path.to_owned();
let fstype = match &mount_point.fstype {
mountinfo::FsType::Other(fsstring) => fsstring,
_ => ""
};
let what = &mount_point.what;
println!("Processing {fstype} @ {path:?} from {what}");
process_mount(fstype, what, path);
} }
}
fn ping_unreachable(host: &IpAddr, repeat:u8 ) -> bool{
for _attempt in 0..repeat {
match ping::ping(host.to_owned(),Some(Duration::from_millis(100)),Some(10),None, None, None) {
Ok(_) => {
return false
},
Err(_) => {
},
}
}
println!("All ping failed with error -> unmount");
return true;
} }
fn process_mount(fstype: &str, what: &String, path: PathBuf) { fn process_mount(fstype: &str, what: &String, path: PathBuf) {
let mut higher_timeout = false;
let mut failed_initial_check = false;
match fstype { match fstype {
"cifs" => { "cifs" => {
let path_parts = what.replace("//","/"); let path_parts = what.replace("//","/");
let host = path_parts.split("/").nth(1).unwrap(); let host = path_parts.split("/").nth(1).unwrap();
println!("Checking ping to host {host}");
let ips = lookup_host(host).unwrap(); let ips = lookup_host(host).unwrap();
let ip = ips.first().unwrap(); let ip = ips.first().unwrap();
println!("Using ip {ip:?}"); failed_initial_check = ping_unreachable(&ip, 5);
match ping::ping(ip.to_owned(),Some(Duration::from_millis(100)),Some(10),None, None, None) { higher_timeout = true;
Ok(_) => {
println!("Ping ok, proceeding")
},
Err(err) => {
println!("Ping failed with errror {err:?} -> unmount");
remove_mount(path.as_os_str());
},
}
}, },
_ => {} _ => {}
} }
if failed_initial_check {
let path_utf8 = path.as_os_str().to_string_lossy();
let body = format!("Unmounted {} due to fail online check", path_utf8);
let timeout = Duration::from_millis(500); let _ = Notification::new()
println!("Checking file access timeout {timeout:?}"); .summary("Autounmount")
.body(body.as_str())
.icon("firefox")
.show();
remove_mount(path.as_os_str());
return;
}
let timeout = if higher_timeout {
Duration::from_millis(10000)
} else {
Duration::from_millis(1000)
};
let (sender, receiver) = mpsc::channel(); let (sender, receiver) = mpsc::channel();
let path_copy = path.clone(); let path_copy = path.clone();
thread::spawn(move || { thread::spawn(move || {
@ -79,15 +111,25 @@ fn process_mount(fstype: &str, what: &String, path: PathBuf) {
let read_successful = receiver.recv_timeout(timeout); let read_successful = receiver.recv_timeout(timeout);
match read_successful { match read_successful {
Ok(_) => { Ok(_) => {
println!("passed, mount still valid")
}, },
Err(err) => { Err(err) => {
println!("Listing failed with errror {err:?} -> unmount"); println!("Listing failed with errror {err:?} -> unmount");
let path_utf8 = path.as_os_str().to_string_lossy();
let body = format!("Unmounted {} due to fs operation check timeout out after {}s", path_utf8, timeout.as_secs());
let _ = Notification::new()
.summary("Autounmount")
.body(body.as_str())
.icon("firefox")
.show();
remove_mount(path.as_os_str()); remove_mount(path.as_os_str());
}, },
} }
} }
fn remove_mount(path: &OsStr){ fn remove_mount(path: &OsStr){
//unmount(path, UnmountFlags::FORCE | UnmountFlags::DETACH).unwrap() unmount(path, UnmountFlags::FORCE | UnmountFlags::DETACH).unwrap()
} }