Add swaplabel applet

This commit is contained in:
Nathan Fisher 2023-02-07 10:34:09 -05:00
parent 29af667a0f
commit 565e2c52d4
7 changed files with 104 additions and 9 deletions

1
Cargo.lock generated
View File

@ -579,6 +579,7 @@ dependencies = [
"clap_mangen", "clap_mangen",
"data-encoding", "data-encoding",
"digest", "digest",
"lazy_static",
"libc", "libc",
"md-5", "md-5",
"mount", "mount",

View File

@ -30,7 +30,8 @@ clap_complete = "4.1"
clap_complete_nushell = "0.1" clap_complete_nushell = "0.1"
clap_mangen = "0.2" clap_mangen = "0.2"
data-encoding = "2.3" data-encoding = "2.3"
digest = "0.10.6" digest = "0.10"
lazy_static = "1.4"
libc = { workspace = true } libc = { workspace = true }
md5 = { version = "0.10", package = "md-5" } md5 = { version = "0.10", package = "md-5" }
sc = { workspace = true } sc = { workspace = true }

View File

@ -17,10 +17,10 @@ worth. Like Busybox it is a multi-call binary which is therefore able to share
code between applets, making for an overall smaller binary. code between applets, making for an overall smaller binary.
## Provided Commands ## Provided Commands
- b2sum
- base32 - base32
- base64 - base64
- basename - basename
- bootstrap
- chgrp - chgrp
- chmod - chmod
- chown - chown
@ -37,6 +37,7 @@ code between applets, making for an overall smaller binary.
- hostid - hostid
- hostname - hostname
- link - link
- ln
- logname - logname
- md5sum - md5sum
- mkfifo - mkfifo
@ -57,10 +58,11 @@ code between applets, making for an overall smaller binary.
- sha256sum - sha256sum
- sha384sum - sha384sum
- sha512sum - sha512sum
- shitbox
- sleep - sleep
- swaplabel
- sync - sync
- true - true
- umount
- unlink - unlink
- wc - wc
- which - which
@ -75,9 +77,8 @@ for the project include:
- Network servers - Network servers
- Kernel module handling utilities - Kernel module handling utilities
- Anything requiring suid or sgid bits such as `su` or `sudo` - Anything requiring suid or sgid bits such as `su` or `sudo`
The code aims to be portable across **Unix** variants, ie Linux and BSD, but not The code is not intended to be portable across different architectures, only
MacOS or Windows. Development occurs on Linux, so if your OS is more exotic then Linux is supported.
YMMV.
## Installation ## Installation
Building is done using the official Rust toolchain. It is recommended that you Building is done using the official Rust toolchain. It is recommended that you
@ -86,11 +87,16 @@ versions are not supported.
```Sh ```Sh
cargo build --release cargo build --release
``` ```
This produces three binaries: corebox, hashbox and utilbox. Most of the commands
ordinarily provided by GNU coreutils are applets of `corebox`, with the exception
of cryptographic hash related commands which are split out into `hashbox`. Linux
swpecific commands ordinarily provided by the util-linux package are in `utilbox`.
The `bootstrap` applet provides facility for installing the binary, creating all The `bootstrap` applet provides facility for installing the binary, creating all
required symlinks and installing some nice to haves such as **Unix man pages** required symlinks and installing some nice to haves such as **Unix man pages**
and **shell completions** [see below]. and **shell completions** [see below].
```Sh ```Sh
target/release/shitbox help bootstrap target/release/corebox help bootstrap
``` ```
### Supported shells for completions ### Supported shells for completions
- Bash - Bash

View File

@ -4,9 +4,12 @@ mod blkid;
mod clear; mod clear;
mod mount; mod mount;
mod mountpoint; mod mountpoint;
mod swaplabel;
mod swapoff;
mod swapon;
mod umount; mod umount;
mod utilbox; mod utilbox;
///
/// Parses a string into a command to run /// Parses a string into a command to run
#[must_use] #[must_use]
#[allow(clippy::box_default)] #[allow(clippy::box_default)]
@ -14,10 +17,11 @@ pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
match name { match name {
"clear" => Some(Box::new(clear::Clear::default())), "clear" => Some(Box::new(clear::Clear::default())),
"mountpoint" => Some(Box::new(mountpoint::Mountpoint::default())), "mountpoint" => Some(Box::new(mountpoint::Mountpoint::default())),
"swaplabel" => Some(Box::new(swaplabel::Swaplabel::default())),
"umount" => Some(Box::new(umount::Umount::default())), "umount" => Some(Box::new(umount::Umount::default())),
"utilbox" => Some(Box::new(utilbox::Utilbox::default())), "utilbox" => Some(Box::new(utilbox::Utilbox::default())),
_ => None, _ => None,
} }
} }
pub static COMMANDS: [&str; 4] = ["clear", "mountpoint", "umount", "utilbox"]; pub static COMMANDS: [&str; 5] = ["clear", "mountpoint", "swaplabel", "umount", "utilbox"];

View File

@ -0,0 +1,81 @@
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: &'static str = "SWAPSPACE2";
const SWAP_MAGIC2: &'static 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(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)
}
}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@