From 29af667a0fc95ac4a18bae8f56abcd5d9db81228 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Tue, 7 Feb 2023 00:13:42 -0500 Subject: [PATCH] utilbox/umount - add `lazy` flag, iter through mnt entries in one pass to filter chosen entries when using `all` options --- utilbox/commands/umount/mod.rs | 101 ++++++++++++++++++++------------- 1 file changed, 63 insertions(+), 38 deletions(-) diff --git a/utilbox/commands/umount/mod.rs b/utilbox/commands/umount/mod.rs index 2e1aebf..115a9e2 100644 --- a/utilbox/commands/umount/mod.rs +++ b/utilbox/commands/umount/mod.rs @@ -1,7 +1,7 @@ -use std::io; use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint}; use mount::MntEntries; use shitbox::{args, Cmd}; +use std::io; #[derive(Debug, Default)] pub struct Umount; @@ -12,12 +12,16 @@ impl Cmd for Umount { .about("unmount filesystems") .author("Nathan Fisher") .version(env!("CARGO_PKG_VERSION")) + .before_long_help( + "umount detaches the target filesystem(s). A file system is specified \ + by giving the directory where it has been mounted. Giving the special \ + device on which the file system lives may also work, but is obsolete.", + ) .args([ Arg::new("all") .help( - "All of the filesystems described in /proc/self/mountinfo \ - are unmounted, except the proc, devfs, devpts, sysfs, rpc_pipefs \ - and nfsd filesystems.", + "All of the file systems described in /proc/mounts are \ + unmounted. The proc filesystem is not unmounted.", ) .short('a') .long("all") @@ -27,6 +31,22 @@ impl Cmd for Umount { .short('f') .long("force") .action(ArgAction::SetTrue), + Arg::new("lazy") + .help( + "Lazy unmount. Detach the filesystem from the fs hierarchy \ + now, and cleanup all references to the filesystem as soon \ + as it is not busy anymore.", + ) + .short('l') + .long("lazy") + .action(ArgAction::SetTrue), + Arg::new("nomtab") + .help( + "Unmount without writing in /etc/mtab. This is the default action. \ + This flag exists only for historical compatability.", + ) + .short('n') + .action(ArgAction::SetTrue), Arg::new("types") .help( "Indicate that the actions should only be taken on filesystems \ @@ -55,50 +75,55 @@ impl Cmd for Umount { } fn run(&self, matches: &ArgMatches) -> Result<(), Box> { - let flags = if matches.get_flag("force") { + let mut flags = if matches.get_flag("force") { libc::MNT_FORCE } else { 0 }; + if matches.get_flag("lazy") { + flags |= libc::MNT_DETACH; + } if matches.get_flag("all") { - let mut mntpts: Vec = MntEntries::new("/proc/mounts")? - .filter(|x| { - x.fstype != "proc" - && x.fstype != "sysfs" - && x.fstype != "devfs" - && x.fstype != "devpts" - && x.fstype != "rpc_pipefs" - && x.fstype != "nfsd" - && x.fstype != "swap" - }) - .collect(); - if let Some(types) = matches.get_many::("types") { - for t in types { - if t.starts_with("no") { - let t = t.strip_prefix("no").unwrap(); - mntpts.retain(|x| x.fstype != t); - } else { - mntpts.retain(|x| &x.fstype == t); - } - } - } - if let Some(spec) = matches.get_many::("spec") { - for s in spec { - for p in &mntpts { - if &p.dir == s { - mount::umount(s, flags as u32)?; - if matches.get_flag("verbose") { - println!("umount: {s} unmounted"); + let mntpts = MntEntries::new("/proc/mounts")?.filter(|x| { + let mut ret = x.fstype != "proc" + && x.fstype != "sysfs" + && x.fstype != "devfs" + && x.fstype != "devpts" + && x.fstype != "rpc_pipefs" + && x.fstype != "nfsd" + && x.fstype != "swap" + && x.fsname != "/"; + if let Some(types) = matches.get_many::("types") { + for t in types { + if t.starts_with("no") { + let t = t.strip_prefix("no").unwrap(); + if x.fstype == t { + ret = false; + } + } else { + if &x.fstype != t { + ret = false; } } } } - } else { - for p in &mntpts { - mount::umount(&p.dir, flags as u32)?; - if matches.get_flag("verbose") { - println!("umount: {} unmounted", &p.dir); + if let Some(spec) = matches.get_many::("spec") { + let mut r2 = false; + for s in spec { + if &x.dir == s || &x.fsname == s { + r2 = true; + } } + if !r2 { + ret = false; + } + } + ret + }); + for p in mntpts { + mount::umount(&p.dir, flags as u32)?; + if matches.get_flag("verbose") { + println!("umount: {} unmounted", &p.dir); } } } else {