82 lines
2.8 KiB
Rust
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)
|
|
}
|
|
}
|