Add `df` applet; Finalize some bootstrap details;

This commit is contained in:
Nathan Fisher 2023-02-17 19:01:30 -05:00
parent 888cc3272b
commit 5a7c2008b5
11 changed files with 204 additions and 24 deletions

41
Cargo.lock generated
View File

@ -78,9 +78,9 @@ version = "0.1.0"
[[package]]
name = "blake2b_simd"
version = "1.0.0"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127"
checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc"
dependencies = [
"arrayref",
"arrayvec",
@ -169,9 +169,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.1.4"
version = "4.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3"
dependencies = [
"bitflags",
"clap_lex",
@ -182,11 +182,11 @@ dependencies = [
[[package]]
name = "clap_complete"
version = "4.1.1"
version = "4.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6540eedc41f8a5a76cf3d8d458057dcdf817be4158a55b5f861f7a5483de75"
checksum = "bd125be87bf4c255ebc50de0b7f4d2a6201e8ac3dc86e39c0ad081dc5e7236fe"
dependencies = [
"clap 4.1.4",
"clap 4.1.6",
]
[[package]]
@ -195,7 +195,7 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fa41f5e6aa83bd151b70fd0ceaee703d68cd669522795dc812df9edad1252c"
dependencies = [
"clap 4.1.4",
"clap 4.1.6",
"clap_complete",
]
@ -210,19 +210,19 @@ dependencies = [
[[package]]
name = "clap_mangen"
version = "0.2.7"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb258c6232b4d728d13d6072656627924c16707aae6267cd5a1ea05abff9a25c"
checksum = "48283ce8d5cd9513633949a674a0442bcb507ab61ed6533863437052ddbb494b"
dependencies = [
"clap 4.1.4",
"clap 4.1.6",
"roff",
]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
checksum = "f3ad85c1f65dc7b37604eb0e89748faf0b9653065f2a8ef69f96a687ec1e9279"
[[package]]
name = "cpufeatures"
@ -333,9 +333,9 @@ dependencies = [
[[package]]
name = "hermit-abi"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "humantime"
@ -359,7 +359,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
dependencies = [
"hermit-abi 0.3.0",
"hermit-abi 0.3.1",
"io-lifetimes",
"rustix",
"windows-sys",
@ -578,7 +578,7 @@ dependencies = [
"atty",
"bitflags-mini",
"blake2b_simd",
"clap 4.1.4",
"clap 4.1.6",
"clap_complete",
"clap_complete_nushell",
"clap_mangen",
@ -593,6 +593,7 @@ dependencies = [
"sc",
"sha1",
"sha2",
"size-display",
"termcolor",
"textwrap 0.16.0",
"unistd",
@ -606,6 +607,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
[[package]]
name = "size-display"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9df415f09e1c4d4f58cd0cd08b2f5385bc07cf1878e7a7846abc2225fa00e1e1"
[[package]]
name = "smawk"
version = "0.3.1"

View File

@ -37,6 +37,7 @@ md5 = { version = "0.10", package = "md-5" }
sc = { workspace = true }
sha1 = "0.10"
sha2 = "0.10"
size-display = "0.1"
termcolor = "1.1"
textwrap = { version = "0.16", default-features = false, features = ["smawk"] }
walkdir = "2.3"

View File

@ -27,6 +27,7 @@ code between applets, making for an overall smaller binary.
- chroot
- clear
- cut
- df
- dirname
- echo
- false

View File

@ -395,4 +395,3 @@ fn links(prefix: &str, usr: bool, cmd: &ArgMatches) -> Result<(), Box<dyn Error>
})?;
Ok(())
}

150
corebox/commands/df/mod.rs Normal file
View File

@ -0,0 +1,150 @@
use clap::{Arg, ArgAction, ArgMatches, Command};
use mount::MntEntries;
use shitbox::Cmd;
use size_display::Size;
use std::{error::Error, fmt, io, path::PathBuf};
#[derive(Debug, Default)]
pub struct Df;
impl Cmd for Df {
fn cli(&self) -> Command {
Command::new("df")
.about("report free disk space")
.author("Nathan Fisher")
.version(env!("CARGO_PKG_VERSION"))
.disable_help_flag(true)
.args([
Arg::new("kilobytes")
.help("Use 1024-byte units, instead of the default 512-byte units, when writing space figures.")
.short('k')
.long("kilobytes")
.action(ArgAction::SetTrue),
Arg::new("human")
.help("print sizes in powers of 1024 (e.g., 1023M)")
.short('h')
.long("human-readable")
.conflicts_with("kilobytes")
.action(ArgAction::SetTrue),
Arg::new("file")
.value_name("FILE")
.num_args(1..)
])
}
fn run(&self, matches: &ArgMatches) -> Result<(), Box<dyn Error>> {
let units = if matches.get_flag("kilobytes") {
Units::Kilo
} else if matches.get_flag("human") {
Units::Natural
} else {
Units::Posix
};
println!("Filesystem {units} Used Avail Capacity Mounted on");
if let Some(files) = matches.get_many::<String>("file") {
for f in files {
let entry = MntEntries::new("/proc/mounts")?
.filter(|e| e.dir.as_str() == f)
.next()
.ok_or(io::Error::new(io::ErrorKind::Other, "no such filesystem"))?;
print_stats(&entry.fsname, &entry.dir, units)?;
}
} else {
let entries = MntEntries::new("/proc/mounts")?.filter(|x| {
x.fstype != "proc"
&& x.fstype != "sysfs"
&& x.fstype != "securityfs"
&& x.fstype != "cgroup2"
&& x.fstype != "pstore"
&& x.fstype != "bpf"
&& x.fstype != "autofs"
&& x.fstype != "hugetlbfs"
&& x.fstype != "tracefs"
&& x.fstype != "debugfs"
&& x.fstype != "configfs"
&& x.fstype != "devpts"
&& x.fstype != "efivarfs"
&& x.fstype != "ramfs"
&& x.fstype != "binfmt_misc"
&& x.fstype != "fuse.gvfsd-fuse"
&& x.fstype != "fuse.portal"
&& x.fstype != "mqueue"
&& x.fstype != "fusectl"
});
for e in entries {
print_stats(&e.fsname, &e.dir, units)?;
}
}
Ok(())
}
fn path(&self) -> Option<shitbox::Path> {
Some(shitbox::Path::UsrBin)
}
}
#[derive(Clone, Copy, PartialEq)]
enum Units {
Posix,
Kilo,
Natural,
}
impl fmt::Display for Units {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Posix => write!(f, "512-blocks"),
Self::Kilo => write!(f, " 1K-blocks"),
Self::Natural => write!(f, " Size"),
}
}
}
fn print_stats(fs: &str, mntpt: &str, units: Units) -> Result<(), Box<dyn Error>> {
let p = PathBuf::from(mntpt);
if p.exists() {
let st = shitbox::stat::statfs(mntpt)?;
let bs = match units {
Units::Posix => st.f_frsize / 512,
Units::Kilo => st.f_frsize / 1024,
Units::Natural => st.f_frsize,
};
let total = st.f_blocks * bs as u64;
let avail = st.f_bfree * bs as u64;
let used = total - avail;
let mut capacity = if total > 0 { (used * 100) / total } else { 0 };
if used * 100 != capacity * (used + avail) {
capacity += 1;
}
if units == Units::Natural {
print_human(fs, mntpt, total, avail, used, capacity);
return Ok(());
}
println!("{fs:<12} {total:>9} {used:>9} {avail:>9} {capacity:>7}% {mntpt}");
Ok(())
} else {
Err(io::Error::new(io::ErrorKind::Other, "fs does not exist").into())
}
}
fn print_human(fs: &str, mntpt: &str, total: u64, avail: u64, used: u64, capacity: u64) {
// Unfortunately these strings must be printed separately due to the way the
// library formats size display, as 0 will be a shorter string due to having
// no suffix, throwing off column alignment
print!("{fs:<12}");
if total > 0 {
print!("{:>9.1}", Size(total));
} else {
print!("{total:>10}");
}
if used > 0 {
print!("{:>9.1}", Size(used));
} else {
print!("{used:>10}");
}
if avail > 0 {
println!("{:9.1} {capacity:>7}% {mntpt}", Size(avail));
} else {
println!("{avail:>10} {capacity:>7}% {mntpt}");
}
}

View File

@ -14,6 +14,7 @@ mod cp;
mod cut;
mod date;
mod dd;
mod df;
mod dirname;
mod echo;
mod expand;
@ -66,6 +67,7 @@ pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
"chroot" => Some(Box::new(chroot::Chroot::default())),
"corebox" => Some(Box::new(corebox::Corebox::default())),
"cut" => Some(Box::new(cut::Cut::default())),
"df" => Some(Box::new(df::Df::default())),
"dirname" => Some(Box::new(dirname::Dirname::default())),
"echo" => Some(Box::new(echo::Echo::default())),
"factor" => Some(Box::new(factor::Factor::default())),
@ -102,7 +104,7 @@ pub fn get(name: &str) -> Option<Box<dyn Cmd>> {
}
}
pub static COMMANDS: [&str; 42] = [
pub static COMMANDS: [&str; 43] = [
"base32",
"base64",
"basename",
@ -113,6 +115,7 @@ pub static COMMANDS: [&str; 42] = [
"chroot",
"corebox",
"cut",
"df",
"dirname",
"echo",
"false",

View File

@ -395,4 +395,3 @@ fn links(prefix: &str, usr: bool, cmd: &ArgMatches) -> Result<(), Box<dyn Error>
})?;
Ok(())
}

View File

@ -1,6 +1,6 @@
use errno::Errno;
use sc::*;
use std::{ffi::CString, error::Error};
use std::{error::Error, ffi::CString};
mod mntent;
mod mntentries;

View File

@ -6,11 +6,12 @@ use blkid::{
tag::{PartitionTag, SuperblockTag, TagType},
};
use std::{
error::Error,
fmt::{self, Write},
fs::File,
io::{self, BufRead, BufReader},
path::PathBuf,
str::FromStr, error::Error,
str::FromStr,
};
/// The information for a mount broken out into a struct

View File

@ -1,6 +1,12 @@
use errno::Errno;
use sc::*;
use std::{ffi::CString, error::Error};
use std::{
error::Error,
ffi::{c_long, CString},
fs::File,
mem,
os::fd::AsRawFd,
};
#[inline(always)]
pub fn mknod(path: &str, mode: u32, dev: u64) -> Result<(), Box<dyn Error>> {
@ -37,3 +43,17 @@ pub fn mkfifo(path: &str, mode: u32) -> Result<(), Box<dyn Error>> {
Err(Errno::from(ret).into())
}
}
#[inline(always)]
pub fn statfs(dir: &str) -> Result<libc::statvfs, Box<dyn Error>> {
let mut buf = mem::MaybeUninit::<libc::statvfs>::uninit();
let fd = File::open(dir)?;
let ret = unsafe { libc::fstatvfs(fd.as_raw_fd(), buf.as_mut_ptr()) };
if ret == 0 {
let buf = unsafe { buf.assume_init() };
Ok(buf)
} else {
let e = unsafe { *libc::__errno_location() };
Err(Errno::from(e as c_long).into())
}
}

View File

@ -395,4 +395,3 @@ fn links(prefix: &str, usr: bool, cmd: &ArgMatches) -> Result<(), Box<dyn Error>
})?;
Ok(())
}