use clap::{Arg, ArgMatches, Command}; use lazy_static::lazy_static; use shitbox::Cmd; use std::{ error::Error, ffi::CString, fs::OpenOptions, io::{self, Read, Seek, SeekFrom, Write}, }; const SWAP_MAGIC1: &str = "SWAPSPACE2"; const SWAP_MAGIC2: &str = "SWAP_SPACE"; const SWAP_MAGIC_LENGTH: u64 = 10; const SWAP_LABEL_LENGTH: u64 = 16; const SWAP_LABEL_OFFSET: u64 = 1024 + 4 + 4 + 4 + 16; lazy_static! { static ref SWAP_MAGIC_OFFSET: u64 = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as u64 - SWAP_MAGIC_LENGTH }; } #[derive(Debug)] pub struct Swaplabel; impl Cmd for Swaplabel { fn cli(&self) -> Command { Command::new("swaplabel") .about("set the label of a swap filesystem") .author("Nathan Fisher") .version(env!("CARGO_PKG_VERSION")) .args([ Arg::new("label") .help("set the label") .short('L') .visible_short_alias('l') .long("label") .num_args(1) .required(false), Arg::new("device").num_args(1).required(true), ]) } fn run(&self, matches: &ArgMatches) -> Result<(), Box> { let mut opts = OpenOptions::new(); let device = matches .get_one::("device") .ok_or(io::Error::new(io::ErrorKind::Other, "no device given"))?; let mut fd = opts.read(true).write(true).open(device)?; fd.seek(SeekFrom::Start(*SWAP_MAGIC_OFFSET))?; let mut magic = [0; SWAP_MAGIC_LENGTH as usize]; fd.read_exact(&mut magic)?; let m: String = magic.iter().map(|x| *x as char).collect(); if m.as_str() != SWAP_MAGIC1 && m.as_str() != SWAP_MAGIC2 { let msg = format!("{device} is not a swap file or partition"); println!("Magic String: {m}"); return Err(io::Error::new(io::ErrorKind::Other, msg).into()); } fd.seek(SeekFrom::Start(SWAP_LABEL_OFFSET))?; if let Some(label) = matches.get_one::("label") { if label.len() + 1 > SWAP_LABEL_LENGTH as usize { return Err(io::Error::new(io::ErrorKind::Other, "label is too long").into()); } let label = CString::new(label.as_str())?; fd.write_all(label.as_bytes())?; } else { let mut label = [0; SWAP_LABEL_LENGTH as usize]; fd.read_exact(&mut label)?; let label: String = label .iter() .map(|x| *x as char) .take_while(|x| *x != '\0') .collect(); println!("label: {label}"); } Ok(()) } fn path(&self) -> Option { Some(shitbox::Path::UsrSbin) } }