diff --git a/Cargo.toml b/Cargo.toml index 7236713..0cbc565 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ hashbrown = "0.9.0" log = "0.4" env_logger = "0.8" clap = "3.0" +nix = { version = "0.29.0", features = ["process", "feature"]} +signal-hook = "0.3.17" [build-dependencies] tonic-build = "0.11" diff --git a/README.md b/README.md index 4a527a4..908f087 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ # lws_client -lws的客户端。运行在linux服务器上。使用fuser \ No newline at end of file +lws的客户端。运行在linux服务器上。使用fuser + + +如果要编译libfue3.0 的版本 +需要将如下的命令撤销,还原回来原来的路径,将优先链接libfuse3 +```bash +mv /usr/local/lib/x86_64-linux-gnu/ /usr/local/lib/x86_64-linux-gnu_fuse3 +``` \ No newline at end of file diff --git a/src/client.rs b/src/client.rs index 46f3181..50a1f9f 100755 --- a/src/client.rs +++ b/src/client.rs @@ -1,49 +1,15 @@ use clap::{App, Arg}; use lws_client::LwsVfsIns; -use std::thread; +use std::{process, thread}; +use std::process::Command; extern crate log; - +use nix::unistd::{fork, ForkResult, getpid, getppid}; +use signal_hook::consts::{SIGCHLD, SIGINT}; +use signal_hook::iterator::Signals; use std::env; const DEFAULT_PORT: u16 = 33444; const DEFAULT_CACHE_LIFE: u32 = 10_000; -// use std::process::{Command,Stdio}; -// fn get_ssh_clinet() -> String { -// // Run `who` command -// let who = Command::new("who") -// .stdout(Stdio::piped()) -// .spawn().unwrap(); - -// // Run `grep $(whoami)` command -// let whoami = Command::new("whoami") -// .stdout(Stdio::piped()) -// .output().unwrap(); -// let user = String::from_utf8_lossy(&whoami.stdout).trim().to_string(); - -// let grep = Command::new("grep") -// .arg(&user) -// .stdin(Stdio::from(who.stdout.unwrap())) -// .stdout(Stdio::piped()) -// .spawn().unwrap(); - -// // Run `awk '{print $5}'` command -// let awk = Command::new("awk") -// .arg("{print $5}") -// .stdin(Stdio::from(grep.stdout.unwrap())) -// .stdout(Stdio::piped()) -// .spawn().unwrap(); - -// // Collect the output -// let output = awk.wait_with_output().unwrap(); -// let output = String::from_utf8_lossy(&output.stdout).to_string(); -// println!("output: {}",output); -// let mut iter = output.split("("); -// iter.next(); -// let output = iter.next().unwrap().split(")").collect::>()[0].to_string(); -// println!("output: {}",output); -// output -// } - fn get_ssh_clinet() -> String { // 获取特定环境变量的值 let client = env::var("SSH_CLIENT").expect("only support auto get ssh connection"); @@ -123,6 +89,43 @@ fn param_parser() -> (String, String, u32) { (server, mount_point, cache_life) } +fn umount_point(mount: &String) { + log::info!("fusermount -u {}", mount); + let output = Command::new("fusermount") + .arg("-u") + .arg(mount) + .output() + .expect("umount command execaute failed"); + if output.status.success(){ + log::info!("{}", format!("umount {} success", mount)); + } else { + if let Some(code) = output.status.code() { + let stdout = String::from_utf8_lossy(&output.stdout).to_string(); + let stderr:String = String::from_utf8_lossy(&output.stderr).to_string(); + // 不存在的话就不需要umount了 + if stderr.contains("not found") { + log::info!("{}", format!("not need umount {}", mount)); + return; + } + log::error!("{}", format!("umount {} fail: {}", mount, code)); + log::error!("{} {}", stdout, stderr); + } else { + log::error!("{}", format!("umount {} interrupted", mount)); + } + } + +} +fn set_cleanup(mount: &String) { + // 捕获 SIGCHLD 信号 + log::info!("waiting for SIGCHLD SIGINT signal"); + let mut signals = Signals::new(&[SIGCHLD, SIGINT]).expect("Error creating signals"); + for _ in signals.forever() { + log::info!("Catch SIGCHLD||SIGINT, exit...."); + umount_point(&mount); + break; + } +} + #[tokio::main] async fn main() -> Result<(), Box> { env_logger::init(); @@ -134,6 +137,9 @@ async fn main() -> Result<(), Box> { return Err(e); } }; + // 尝试卸载此前的挂载点 + umount_point(&mount_point); + child_process(&mount_point); log::info!("lws client instance created"); match lws_ins.hello().await { Err(e) => { @@ -160,4 +166,25 @@ async fn main() -> Result<(), Box> { ))) } } + +} + +fn child_process(mount: &String) { + match unsafe{fork()} { + Ok(ForkResult::Parent { child: _ }) => { + // no thing + } + Ok(ForkResult::Child) => { + let pid = getpid(); + let ppid = getppid(); + log::info!("parent: {}, child: {}", ppid, pid); + set_cleanup(mount); + } + Err(err) => { + log::error!("fork fail: {}", err); + process::exit(1); + } + } + + } diff --git a/src/lib.rs b/src/lib.rs index ab9e3cd..5b526e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,7 @@ use lws_client::{ use serde_json::{self, Value}; use std::error::Error; use std::ffi::OsStr; -use std::io::{Error as IoError, ErrorKind, Read as IoRead}; +use std::io::{Error as IoError, ErrorKind}; use std::thread::{self}; use std::{env, vec}; use tokio::runtime::{Builder, Runtime}; @@ -237,12 +237,12 @@ impl VirFs { //self.match_path(&mut vname) } - pub fn match_path<'a>(&self, name_list: &mut impl Iterator) -> Option<&VirFs> { + pub fn _match_path<'a>(&self, name_list: &mut impl Iterator) -> Option<&VirFs> { if let Some(current) = name_list.next() { match self.sub.get(current) { Some(v) => { // try match sub dir - if let Some(sub) = v.match_path(name_list) { + if let Some(sub) = v._match_path(name_list) { Some(sub) // sub dirs not match } else { @@ -312,7 +312,7 @@ impl FileAttrCacheCtx { } pub struct FileAttrCacheManager { - handle: thread::JoinHandle<()>, + _handle: thread::JoinHandle<()>, tx: mpsc::Sender, } @@ -323,7 +323,7 @@ impl FileAttrCacheManager { let handle = thread::spawn(move || { Self::cache_manager(cache_ctx, cache_life); }); - FileAttrCacheManager { handle, tx } + FileAttrCacheManager { _handle:handle, tx } } fn cache_manager(mut ctx: FileAttrCacheCtx, cache_life: u32) { @@ -431,6 +431,7 @@ pub struct LwsVfsIns { cache: FileAttrCacheManager, } +/// 将返回值转换为 Result<(), i32> 类型,给rpc使用 macro_rules! ret2result { ($ret:expr) => { match $ret { @@ -439,6 +440,7 @@ macro_rules! ret2result { } }; } + fn mode_to_filetype(mode: libc::mode_t) -> FileType { match mode & libc::S_IFMT { libc::S_IFDIR => FileType::Directory,