shitbox/utilbox/commands/swaplabel/mod.rs

82 lines
2.8 KiB
Rust

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, Default)]
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<dyn Error>> {
let mut opts = OpenOptions::new();
let device = matches
.get_one::<String>("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::<String>("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<shitbox::Path> {
Some(shitbox::Path::UsrSbin)
}
}