use proxmox::tools::time;
use proxmox_fuse::{*, requests::FuseRequest};
use super::loopdev;
-use super::fs;
-const RUN_DIR: &'static str = "/run/pbs-loopdev";
+const RUN_DIR: &str = "/run/pbs-loopdev";
const_regex! {
pub LOOPDEV_REGEX = r"^loop\d+$";
abort_chan: Receiver<()>,
) -> Result<(), Error> {
- if let None = self.session {
+ if self.session.is_none() {
panic!("internal error: fuse_loop::main called before ::map_loop");
}
let mut session = self.session.take().unwrap().fuse();
// clean leftover FUSE instances (e.g. user called 'losetup -d' or similar)
// does nothing if files are already stagnant (e.g. instance crashed etc...)
- if let Ok(_) = unmap_from_backing(&path) {
+ if unmap_from_backing(&path, None).is_ok() {
// we have reaped some leftover instance, tell the user
eprintln!(
"Cleaned up dangling mapping '{}': no loop device assigned",
Ok(backing_file.to_owned())
}
-fn unmap_from_backing(backing_file: &Path) -> Result<(), Error> {
+// call in broken state: we found the mapping, but the client is already dead,
+// only thing to do is clean up what we can
+fn emerg_cleanup (loopdev: Option<&str>, mut backing_file: PathBuf) {
+ eprintln!(
+ "warning: found mapping with dead process ({:?}), attempting cleanup",
+ &backing_file
+ );
+
+ if let Some(loopdev) = loopdev {
+ let _ = loopdev::unassign(loopdev);
+ }
+
+ // killing the backing process does not cancel the FUSE mount automatically
+ let mut command = std::process::Command::new("fusermount");
+ command.arg("-u");
+ command.arg(&backing_file);
+ let _ = crate::tools::run_command(command, None);
+
+ let _ = remove_file(&backing_file);
+ backing_file.set_extension("pid");
+ let _ = remove_file(&backing_file);
+}
+
+fn unmap_from_backing(backing_file: &Path, loopdev: Option<&str>) -> Result<(), Error> {
let mut pid_path = PathBuf::from(backing_file);
pid_path.set_extension("pid");
- let pid_str = read_to_string(&pid_path).map_err(|err|
- format_err!("error reading pidfile {:?}: {}", &pid_path, err))?;
+ let pid_str = read_to_string(&pid_path).map_err(|err| {
+ if err.kind() == std::io::ErrorKind::NotFound {
+ emerg_cleanup(loopdev, backing_file.to_owned());
+ }
+ format_err!("error reading pidfile {:?}: {}", &pid_path, err)
+ })?;
let pid = pid_str.parse::<i32>().map_err(|err|
format_err!("malformed PID ({}) in pidfile - {}", pid_str, err))?;
let pid = Pid::from_raw(pid);
// send SIGINT to trigger cleanup and exit in target process
- signal::kill(pid, Signal::SIGINT)?;
+ match signal::kill(pid, Signal::SIGINT) {
+ Ok(()) => {},
+ Err(nix::Error::Sys(nix::errno::Errno::ESRCH)) => {
+ emerg_cleanup(loopdev, backing_file.to_owned());
+ return Ok(());
+ },
+ Err(e) => return Err(e.into()),
+ }
// block until unmap is complete or timeout
let start = time::epoch_i64();
pub fn find_all_mappings() -> Result<impl Iterator<Item = (String, Option<String>)>, Error> {
// get map of all /dev/loop mappings belonging to us
let mut loopmap = HashMap::new();
- for ent in fs::scan_subdir(libc::AT_FDCWD, Path::new("/dev/"), &LOOPDEV_REGEX)? {
- match ent {
- Ok(ent) => {
- let loopdev = format!("/dev/{}", ent.file_name().to_string_lossy());
- match get_backing_file(&loopdev) {
- Ok(file) => {
- // insert filename only, strip RUN_DIR/
- loopmap.insert(file[RUN_DIR.len()+1..].to_owned(), loopdev);
- },
- Err(_) => {},
- }
- },
- Err(_) => {},
+ for ent in pbs_tools::fs::scan_subdir(libc::AT_FDCWD, Path::new("/dev/"), &LOOPDEV_REGEX)? {
+ if let Ok(ent) = ent {
+ let loopdev = format!("/dev/{}", ent.file_name().to_string_lossy());
+ if let Ok(file) = get_backing_file(&loopdev) {
+ // insert filename only, strip RUN_DIR/
+ loopmap.insert(file[RUN_DIR.len()+1..].to_owned(), loopdev);
+ }
}
}
- Ok(fs::read_subdir(libc::AT_FDCWD, Path::new(RUN_DIR))?
+ Ok(pbs_tools::fs::read_subdir(libc::AT_FDCWD, Path::new(RUN_DIR))?
.filter_map(move |ent| {
match ent {
Ok(ent) => {
}
let backing_file = get_backing_file(loopdev)?;
- unmap_from_backing(Path::new(&backing_file))
+ unmap_from_backing(Path::new(&backing_file), Some(loopdev))
}
/// Try and unmap a running proxmox-backup-client instance from the given name
pub fn unmap_name<S: AsRef<str>>(name: S) -> Result<(), Error> {
- for (mapping, _) in find_all_mappings()? {
+ for (mapping, loopdev) in find_all_mappings()? {
if mapping.ends_with(name.as_ref()) {
let mut path = PathBuf::from(RUN_DIR);
path.push(&mapping);
- return unmap_from_backing(&path);
+ return unmap_from_backing(&path, loopdev.as_deref());
}
}
Err(format_err!("no mapping for name '{}' found", name.as_ref()))