use clap::{Arg, ArgAction, Command}; use mount::MntEntries; use shitbox::{args, Cmd}; use std::{ fs::File, io::{self, BufRead, BufReader}, }; #[derive(Debug, Default)] pub struct Swapoff; impl Cmd for Swapoff { fn cli(&self) -> clap::Command { Command::new("swapoff") .about("disable devices and files for paging and swapping") .author("Nathan Fisher") .version(env!("CARGO_PKG_VERSION")) .args([ Arg::new("all") .help("Disable swapping on all known swap devices and files as found in /etc/fstab.") .short('a') .long("all") .action(ArgAction::SetTrue), args::verbose(), Arg::new("device") .num_args(1..) .conflicts_with("all") .required_unless_present("all"), ]) } fn run(&self, matches: &clap::ArgMatches) -> Result<(), Box> { if matches.get_flag("all") { if let Ok(entries) = MntEntries::new("/etc/fstab") { for e in entries.filter(|x| &x.fstype == "swap") { if e.is_swapped() { let dev = e .device()? .to_str() .ok_or(io::Error::new(io::ErrorKind::Other, "utf8 error"))? .to_string(); mount::swapoff(&dev)?; if matches.get_flag("verbose") { println!("swapoff {dev}"); } } } } } else if let Some(devices) = matches.get_many::("device") { 'devloop: for d in devices { let fd = File::open("/proc/swaps")?; let reader = BufReader::new(fd); for line in reader.lines() { let line = line?; let swap = line.split_whitespace().next().ok_or(io::Error::new( io::ErrorKind::Other, "Error reading /proc/swaps", ))?; if swap == d { mount::swapoff(d)?; if matches.get_flag("verbose") { println!("swapoff {d}"); } continue 'devloop; } } let msg = format!("{d} is not swapped"); return Err(Box::new(io::Error::new(io::ErrorKind::Other, msg))); } } Ok(()) } fn path(&self) -> Option { Some(shitbox::Path::Sbin) } }