diff --git a/Cargo.lock b/Cargo.lock index d36f0a84..fce8cb78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1881,6 +1881,7 @@ dependencies = [ "chrono", "clap", "terminal_size", + "uu_slabtop", "uucore", ] diff --git a/src/uu/slabtop/src/parse.rs b/src/uu/slabtop/src/parse.rs index 07303798..eb016463 100644 --- a/src/uu/slabtop/src/parse.rs +++ b/src/uu/slabtop/src/parse.rs @@ -3,25 +3,35 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use std::{ - cmp::Ordering, - fs, - io::{Error, ErrorKind}, -}; +use std::io::Error; +use std::{cmp::Ordering, fs, io::ErrorKind}; +use uucore::error::{UError, UResult, USimpleError}; #[derive(Debug, Default)] -pub(crate) struct SlabInfo { - pub(crate) meta: Vec, - pub(crate) data: Vec<(String, Vec)>, +pub struct SlabInfo { + pub meta: Vec, + pub data: Vec<(String, Vec)>, } impl SlabInfo { // parse slabinfo from /proc/slabinfo // need root permission - pub fn new() -> Result { - let content = fs::read_to_string("/proc/slabinfo")?; + pub fn new() -> UResult { + let error_wrapper = |e: Error| { + USimpleError::new( + 1, + format!( + "Unable to create slabinfo structure: {}", + Box::::from(e) // We need Display impl of UError + ), + ) + }; + + let content = fs::read_to_string("/proc/slabinfo").map_err(error_wrapper)?; - Self::parse(&content).ok_or(ErrorKind::Unsupported.into()) + Self::parse(&content) + .ok_or(ErrorKind::Unsupported.into()) + .map_err(error_wrapper) } pub fn parse(content: &str) -> Option { diff --git a/src/uu/slabtop/src/slabtop.rs b/src/uu/slabtop/src/slabtop.rs index 3fc01653..1dc5c91f 100644 --- a/src/uu/slabtop/src/slabtop.rs +++ b/src/uu/slabtop/src/slabtop.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -use crate::parse::SlabInfo; +pub use crate::parse::SlabInfo; use clap::{arg, crate_version, ArgAction, Command}; use uucore::{error::UResult, format_usage, help_about, help_section, help_usage}; @@ -25,6 +25,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let slabinfo = SlabInfo::new()?.sort(*sort_flag, false); + println!("{slabinfo:?}"); + if matches.get_flag("once") { output_header(&slabinfo); println!(); diff --git a/src/uu/vmstat/Cargo.toml b/src/uu/vmstat/Cargo.toml index 6538ed46..f9122619 100644 --- a/src/uu/vmstat/Cargo.toml +++ b/src/uu/vmstat/Cargo.toml @@ -17,6 +17,8 @@ clap = { workspace = true } terminal_size = { workspace = true } uucore = { workspace = true, features = ["custom-tz-fmt"] } +uu_slabtop = {path = "../slabtop"} + [lib] path = "src/vmstat.rs" diff --git a/src/uu/vmstat/src/vmstat.rs b/src/uu/vmstat/src/vmstat.rs index 93996afa..8b943f0b 100644 --- a/src/uu/vmstat/src/vmstat.rs +++ b/src/uu/vmstat/src/vmstat.rs @@ -38,6 +38,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let one_header = matches.get_flag("one-header"); let no_first = matches.get_flag("no-first"); + let term_height = terminal_size::terminal_size() + .map(|size| size.1 .0) + .unwrap_or(0); + + if matches.get_flag("slabs") { + return print_slabs(one_header, term_height); + } let delay = matches.get_one::("delay"); let count = matches.get_one::("count"); @@ -57,14 +64,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { line_count += 1; } - let term_height = terminal_size::terminal_size() - .map(|size| size.1 .0) - .unwrap_or(0); - while count.is_none() || line_count < count.unwrap() { std::thread::sleep(std::time::Duration::from_secs(delay)); let proc_data_now = ProcData::new(); - if !one_header && term_height > 0 && ((line_count + 3) % term_height as u64 == 0) { + if needs_header(one_header, term_height, line_count) { print_header(&pickers); } print_data(&pickers, &proc_data_now, Some(&proc_data), &matches); @@ -76,6 +79,41 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(()) } +#[cfg(target_os = "linux")] +fn print_slabs(one_header: bool, term_height: u16) -> UResult<()> { + let mut slab_data = uu_slabtop::SlabInfo::new()?.data; + + slab_data.sort_by_key(|k| k.0.to_lowercase()); + + print_slab_header(); + + for (line_count, slab_item) in slab_data.into_iter().enumerate() { + if needs_header(one_header, term_height, line_count as u64) { + print_slab_header(); + } + + println!( + "{:<24} {:>6} {:>6} {:>6} {:>6}", + slab_item.0, slab_item.1[0], slab_item.1[1], slab_item.1[2], slab_item.1[3] + ); + } + + Ok(()) +} + +#[cfg(target_os = "linux")] +fn needs_header(one_header: bool, term_height: u16, line_count: u64) -> bool { + !one_header && term_height > 0 && ((line_count + 3) % term_height as u64 == 0) +} + +#[cfg(target_os = "linux")] +fn print_slab_header() { + println!( + "{:<24} {:>6} {:>6} {:>6} {:>6}", + "Cache", "Num", "Total", "Size", "Pages" + ); +} + #[cfg(target_os = "linux")] fn print_header(pickers: &[Picker]) { let mut section: Vec<&str> = vec![]; @@ -126,7 +164,7 @@ pub fn uu_app() -> Command { .value_parser(value_parser!(u64)), arg!(-a --active "Display active and inactive memory"), // arg!(-f --forks "switch displays the number of forks since boot"), - // arg!(-m --slabs "Display slabinfo"), + arg!(-m --slabs "Display slabinfo"), arg!(-n --"one-header" "Display the header only once rather than periodically"), // arg!(-s --stats "Displays a table of various event counters and memory statistics"), // arg!(-d --disk "Report disk statistics"),