Initial commit

This commit is contained in:
Arne Keller 2021-03-26 11:24:43 +01:00
commit da3eabaf8f
4 changed files with 174 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

69
Cargo.lock generated Normal file
View File

@ -0,0 +1,69 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "ascii_table"
version = "3.0.2"
source = "git+https://gitlab.com/arnekeller/ascii-table.git?rev=7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b#7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "df"
version = "0.1.0"
dependencies = [
"ascii_table",
"libc",
"procinfo",
]
[[package]]
name = "libc"
version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
[[package]]
name = "nom"
version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf51a729ecf40266a2368ad335a5fdde43471f545a967109cd62146ecf8b66ff"
[[package]]
name = "procinfo"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ab1427f3d2635891f842892dda177883dca0639e05fe66796a62c9d2f23b49c"
dependencies = [
"byteorder",
"libc",
"nom",
"rustc_version",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"

13
Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "df"
version = "0.1.0"
authors = ["Arne Keller <arne.keller@posteo.de>"]
license = "GPL-3.0-or-later"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
ascii_table = { git = "https://gitlab.com/arnekeller/ascii-table.git", rev = "7fffb5d93b8c63283fc1359ee3c6dbfcf12ed90b" }
libc = "0.2.91"
procinfo = "0.4.2"

91
src/main.rs Normal file
View File

@ -0,0 +1,91 @@
use libc::{c_char, statvfs64, strerror_r};
use procinfo::pid::mountinfo_self;
use ascii_table::{Align, AsciiTable, Column};
use std::{array::IntoIter, ffi::CString, fs, mem::MaybeUninit};
use std::os::unix::ffi::OsStrExt;
const IGNORED_FS: &'static [&'static str] = &["proc", "sysfs", "securityfs", "bpf", "cgroup", "cgroup2", "fusectl", "efivarfs", "debugfs"];
const IGNORED_FS2: &'static [(&'static str, &'static str)] = &[];//("fuse", "portal")];
fn main() {
let mut rows = Vec::new();
let mut devices = Vec::new();
for mount in mountinfo_self().unwrap() {
if IGNORED_FS.contains(&&*mount.fs_type.0) {
continue;
}
if let Some(second) = mount.fs_type.1.as_ref() {
if IGNORED_FS2.contains(&(&mount.fs_type.0, second)) {
continue;
}
}
// skip multiple FS on the same partition
let device = (mount.major, mount.minor);
if devices.contains(&device) {
continue;
}
devices.push(device);
let mut data = MaybeUninit::<statvfs64>::uninit();
let path = CString::new(mount.mount_point.as_os_str().as_bytes()).unwrap();
let mut res = unsafe { statvfs64(path.as_ptr(), data.as_mut_ptr()) };
if res != 0 {
if res < 0 {
res = unsafe { *libc::__errno_location() };
}
let mut error_buffer = vec![0 as c_char; 256];
let error: String = unsafe {
let result = strerror_r(res, error_buffer.as_mut_ptr(), error_buffer.len());
if result != 0 {
eprintln!("fail {}", result);
res.to_string().into()
} else {
error_buffer.into_iter().take_while(|&x| x != 0).map(|x| x as u8 as char).collect()
}
};
eprintln!("df: {}: {}", mount.mount_point.display(), error);
continue;
}
let data = unsafe { data.assume_init() };
if data.f_blocks == 0 {
continue; // metadata is useless
}
let typ = match mount.mount_src.as_deref() {
Some(path) if path.starts_with('/') => {
fs::canonicalize(path).unwrap().display().to_string()
},
_ => mount.fs_type.0
};
rows.push((typ, data.f_blocks, data.f_bfree, mount.mount_point));
}
let mut ascii_table = AsciiTable::default();
ascii_table.draw_lines = false;
for (i, &(header, align)) in [
("Filesystem", Align::Left),
("Blocks", Align::Right),
("Used", Align::Right),
("Free", Align::Right),
("Use%", Align::Right),
("Mounted on", Align::Left)
].iter().enumerate() {
let mut column = Column::default();
column.header = header.to_owned();
column.align = align;
ascii_table.columns.insert(i, column);
}
ascii_table.print(rows.into_iter().map(
|(typ, blocks, free, path)| IntoIter::new(
[
typ,
blocks.to_string(),
(blocks-free).to_string(),
free.to_string(),
format!("{:.0}%", ((blocks-free) as f64 * 100.0 / blocks as f64).ceil()),
path.display().to_string()
]
)
));
}