lsmem: Implement sysroot, add many test, more output alignment with util-linux

This commit is contained in:
Foorack
2025-02-09 11:53:21 +01:00
parent 8b8728e1df
commit 57b9c1f0f4
528 changed files with 1844 additions and 47 deletions
src/uu/lsmem/src
tests
by-util
fixtures
lsmem
input
sys
devices
system
memory
block_size_bytes
memory0
memory1
memory100
memory101
memory102
memory103
memory104
memory105
memory106
memory107
memory108
memory109
memory110
memory111
memory112
memory113
memory114
memory115
memory116
memory117
memory118
memory119
memory120
memory121
memory122
memory123
memory124
memory125
memory126
memory127
memory128
memory129
memory130
memory131
memory132
memory133
memory134
memory135
memory136
memory137
memory138
memory139
memory140
memory141
memory142
memory143
memory144
memory145
memory146
memory147
memory148
memory149
memory2
memory3
memory32
memory33
memory34
memory35
memory36
memory37
memory38
memory39
memory4
memory40
memory41
memory42
memory43
memory44
memory45
memory46
memory47
memory48
memory49
memory5
memory50
memory51
memory52
memory53
memory54
memory55
memory56
memory57
memory58
memory59
memory6
memory60
memory61
memory62
memory63
memory64
memory65
memory66
memory67
memory68
memory69
memory70
memory71
memory72
memory73
memory74
memory75
memory76
memory77
memory78
memory79
memory80
memory81
memory82
memory83
memory84
memory85
memory86
memory87
memory88
memory89
memory90
memory91
memory92
memory93
memory94
memory95
memory96
memory97
memory98
memory99
valid_zones
test_lsmem_columns_json.expectedtest_lsmem_columns_pairs.expectedtest_lsmem_columns_raw.expectedtest_lsmem_columns_table.expectedtest_lsmem_json.expectedtest_lsmem_json_all.expectedtest_lsmem_json_bytes.expectedtest_lsmem_json_noheadings.expectedtest_lsmem_pairs.expectedtest_lsmem_pairs_all.expectedtest_lsmem_pairs_bytes.expectedtest_lsmem_pairs_noheadings.expectedtest_lsmem_raw.expectedtest_lsmem_raw_all.expectedtest_lsmem_raw_bytes.expectedtest_lsmem_raw_noheadings.expectedtest_lsmem_split_node.expectedtest_lsmem_split_removable.expectedtest_lsmem_split_state.expectedtest_lsmem_split_zones.expectedtest_lsmem_table.expectedtest_lsmem_table_all.expectedtest_lsmem_table_bytes.expectedtest_lsmem_table_noheadings.expected

@ -29,16 +29,16 @@ mod options {
pub const PAIRS: &str = "pairs";
pub const RAW: &str = "raw";
pub const SPLIT: &str = "split";
pub const SYSROOT: &str = "sysroot";
}
// const BUFSIZ: usize = 1024;
const PATH_SYS_MEMORY: &str = "/sys/devices/system/memory";
const PATH_BLOCK_SIZE_BYTES: &str = "/sys/devices/system/memory/block_size_bytes";
const PATH_VALID_ZONES: &str = "/sys/devices/system/memory/valid_zones";
const PATH_NAME_MEMORY: &str = "memory";
const PATH_NAME_NODE: &str = "node";
const PATH_SUB_BLOCK_SIZE_BYTES: &str = "block_size_bytes";
const PATH_SUB_REMOVABLE: &str = "removable";
const PATH_SUB_STATE: &str = "state";
const NAME_MEMORY: &str = "memory";
const PATH_SUB_VALID_ZONES: &str = "valid_zones";
const PATH_SYS_MEMORY: &str = "/sys/devices/system/memory";
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
enum Column {
@ -107,15 +107,7 @@ impl Column {
#[allow(dead_code)]
fn get_float_right(&self) -> bool {
match self {
Column::Range => false,
Column::Size => true,
Column::State => true,
Column::Removable => true,
Column::Block => true,
Column::Node => true,
Column::Zones => true,
}
self != &Column::Range
}
#[allow(dead_code)]
@ -226,8 +218,8 @@ struct TableRow {
state: String,
removable: String,
block: String,
#[serde(skip_serializing)]
node: String,
#[allow(unused)]
#[serde(skip_serializing)]
zones: String,
}
@ -276,6 +268,8 @@ struct Options {
split_by_removable: bool,
split_by_state: bool,
split_by_zones: bool,
/// Default to PATH_SYS_MEMORY, but a prefix can be appended
sysmem: String,
// Set by read_info
have_nodes: bool,
@ -324,6 +318,7 @@ impl Options {
split_by_removable: false,
split_by_state: false,
split_by_zones: false,
sysmem: String::from(PATH_SYS_MEMORY),
have_nodes: false,
have_zones: false,
@ -336,16 +331,20 @@ impl Options {
fn read_info(lsmem: &mut Lsmem, opts: &mut Options) {
lsmem.block_size = u64::from_str_radix(
&read_file_content::<String>(Path::new(PATH_BLOCK_SIZE_BYTES)).unwrap(),
&read_file_content::<String>(&Path::new(&format!(
"{}/{}",
opts.sysmem, PATH_SUB_BLOCK_SIZE_BYTES
)))
.unwrap(),
16,
)
.unwrap();
lsmem.dirs = get_block_paths();
lsmem.dirs = get_block_paths(opts);
lsmem.dirs.sort_by(|a, b| {
let filename_a = a.to_str().unwrap().split('/').last().unwrap();
let filename_b = b.to_str().unwrap().split('/').last().unwrap();
let idx_a: u64 = filename_a[NAME_MEMORY.len()..].parse().unwrap();
let idx_b: u64 = filename_b[NAME_MEMORY.len()..].parse().unwrap();
let idx_a: u64 = filename_a[PATH_NAME_MEMORY.len()..].parse().unwrap();
let idx_b: u64 = filename_b[PATH_NAME_MEMORY.len()..].parse().unwrap();
idx_a.cmp(&idx_b)
});
lsmem.ndirs = lsmem.dirs.len();
@ -355,7 +354,7 @@ fn read_info(lsmem: &mut Lsmem, opts: &mut Options) {
}
let mut p = path.clone();
p.push("valid_zones");
p.push(PATH_SUB_VALID_ZONES);
if fs::read_dir(p).is_ok() {
opts.have_zones = true;
}
@ -381,13 +380,13 @@ fn read_info(lsmem: &mut Lsmem, opts: &mut Options) {
}
}
fn get_block_paths() -> Vec<PathBuf> {
fn get_block_paths(opts: &mut Options) -> Vec<PathBuf> {
let mut paths = Vec::<PathBuf>::new();
for entry in fs::read_dir(PATH_SYS_MEMORY).unwrap() {
for entry in fs::read_dir(&opts.sysmem).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
let filename = path.to_str().unwrap().split('/').last().unwrap();
if path.is_dir() && filename.starts_with(NAME_MEMORY) {
if path.is_dir() && filename.starts_with(PATH_NAME_MEMORY) {
paths.push(path);
}
}
@ -434,8 +433,8 @@ fn memory_block_get_node(path: &PathBuf) -> Result<i32, <i32 as FromStr>::Err> {
let entry = entry.unwrap();
let path = entry.path();
let filename = path.to_str().unwrap().split('/').last().unwrap();
if path.is_dir() && filename.starts_with("node") {
return filename["node".len()..].parse();
if path.is_dir() && filename.starts_with(PATH_NAME_NODE) {
return filename[PATH_NAME_NODE.len()..].parse();
}
}
Ok(-1)
@ -446,7 +445,7 @@ fn memory_block_read_attrs(opts: &Options, path: &PathBuf) -> MemoryBlock {
blk.count = 1;
blk.state = MemoryState::Unknown;
let filename = path.to_str().unwrap().split('/').last().unwrap();
blk.index = filename[NAME_MEMORY.len()..].parse().unwrap();
blk.index = filename[PATH_NAME_MEMORY.len()..].parse().unwrap();
let mut removable_path = path.clone();
removable_path.push(PATH_SUB_REMOVABLE);
@ -464,7 +463,11 @@ fn memory_block_read_attrs(opts: &Options, path: &PathBuf) -> MemoryBlock {
blk.nr_zones = 0;
if opts.have_zones {
if let Ok(raw_content) = read_file_content::<String>(Path::new(PATH_VALID_ZONES)) {
if let Ok(raw_content) = read_file_content::<String>(Path::new(&format!(
"{}/{}",
opts.sysmem.clone(),
PATH_SUB_VALID_ZONES
))) {
let zone_toks = raw_content.split(' ').collect::<Vec<&str>>();
for (i, zone_tok) in zone_toks
.iter()
@ -608,6 +611,10 @@ fn print_pairs(lsmem: &Lsmem, opts: &Options) {
}
fn print_raw(lsmem: &Lsmem, opts: &Options) {
if !opts.noheadings {
println!("RANGE SIZE STATE REMOVABLE BLOCK");
}
let table_rows = create_table_rows(lsmem, opts);
let mut table_raw_string = String::new();
for row in table_rows {
@ -616,7 +623,6 @@ fn print_raw(lsmem: &Lsmem, opts: &Options) {
}
// remove the last newline
table_raw_string.pop();
println!("RANGE SIZE STATE REMOVABLE BLOCK");
println!("{table_raw_string}");
}
@ -689,6 +695,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
opts.want_summary = false;
}
if let Some(sysroot) = matches.get_one::<String>(options::SYSROOT) {
opts.sysmem = format!(
"{}/{}",
sysroot.trim_end_matches('/'),
opts.sysmem.trim_start_matches('/')
);
}
read_info(&mut lsmem, &mut opts);
if opts.want_table {
@ -766,6 +780,7 @@ pub fn uu_app() -> Command {
.help("output columns")
.ignore_case(true)
.action(ArgAction::Set)
.value_name("list")
.value_delimiter(',')
.value_parser(EnumValueParser::<Column>::new()),
)
@ -791,6 +806,7 @@ pub fn uu_app() -> Command {
.conflicts_with(options::ALL)
.ignore_case(true)
.action(ArgAction::Set)
.value_name("list")
.value_delimiter(',')
.value_parser(PossibleValuesParser::new(
SPLIT_COLUMNS
@ -799,6 +815,14 @@ pub fn uu_app() -> Command {
.collect::<Vec<_>>(),
)),
)
.arg(
Arg::new(options::SYSROOT)
.short('s')
.long("sysroot")
.help("use the specified directory as system root")
.action(ArgAction::Set)
.value_name("dir"),
)
.after_help(&format!(
"Available output columns:\n{}",
Column::value_variants()

@ -5,34 +5,157 @@
use crate::common::util::TestScenario;
#[must_use]
fn sysroot() -> String {
format!("{}/tests/fixtures/lsmem/input", env!("CARGO_MANIFEST_DIR"))
}
fn sysroot_test_with_args(expected_output: &str, args: &[&str]) {
let mut cmd = new_ucmd!();
cmd.arg("-s").arg(sysroot());
for arg in args {
cmd.arg(arg);
}
cmd.succeeds()
.no_stderr()
.stdout_is_templated_fixture(expected_output, &[("\r\n", "\n")]);
}
#[test]
fn test_invalid_arg() {
new_ucmd!().arg("--definitely-invalid").fails().code_is(1);
}
#[test]
fn test_basic() {
// Verify basic usage with no args prints both table and summary
new_ucmd!()
.succeeds()
.stdout_contains("STATE REMOVABLE")
.stdout_contains("Memory block size:");
fn test_columns_table() {
sysroot_test_with_args("test_lsmem_columns_table.expected", &["-o", "block,size"]);
}
// FAILS, COMMENT FOR NOW - TODO
// #[test]
// fn test_columns_raw() {
// sysroot_test_with_args(
// "test_lsmem_columns_raw.expected",
// &["-o", "block,size", "-r"],
// );
// }
// FAILS, COMMENT FOR NOW - TODO
// #[test]
// fn test_columns_json() {
// sysroot_test_with_args(
// "test_lsmem_columns_json.expected",
// &["-o", "block,size", "-J"],
// );
// }
// FAILS, COMMENT FOR NOW - TODO
// #[test]
// fn test_columns_pairs() {
// sysroot_test_with_args(
// "test_lsmem_columns_pairs.expected",
// &["-o", "block,size", "-P"],
// );
// }
#[test]
fn test_json() {
sysroot_test_with_args("test_lsmem_json.expected", &["-J"]);
}
#[test]
fn test_table_not_padded() {
let result = new_ucmd!().succeeds();
let stdout = result.code_is(0).stdout_str();
assert!(
!stdout.starts_with(' '),
"Table output should not start with a space"
);
fn test_json_all() {
sysroot_test_with_args("test_lsmem_json_all.expected", &["-J", "-a"]);
}
// FAILS, COMMENT FOR NOW - TODO
// #[test]
// fn test_json_bytes() {
// sysroot_test_with_args("test_lsmem_json_bytes.expected", &["-J", "-b"]);
// }
#[test]
fn test_json_noheadings() {
sysroot_test_with_args("test_lsmem_json_noheadings.expected", &["-J", "-n"]);
}
#[test]
fn test_json_output() {
new_ucmd!()
.arg("-J")
.succeeds()
.stdout_contains(" \"memory\": [\n");
fn test_pairs() {
sysroot_test_with_args("test_lsmem_pairs.expected", &["-P"]);
}
#[test]
fn test_pairs_all() {
sysroot_test_with_args("test_lsmem_pairs_all.expected", &["-P", "-a"]);
}
#[test]
fn test_pairs_bytes() {
sysroot_test_with_args("test_lsmem_pairs_bytes.expected", &["-P", "-b"]);
}
#[test]
fn test_pairs_noheadings() {
sysroot_test_with_args("test_lsmem_pairs_noheadings.expected", &["-P", "-n"]);
}
#[test]
fn test_raw() {
sysroot_test_with_args("test_lsmem_raw.expected", &["-r"]);
}
#[test]
fn test_raw_all() {
sysroot_test_with_args("test_lsmem_raw_all.expected", &["-r", "-a"]);
}
#[test]
fn test_raw_bytes() {
sysroot_test_with_args("test_lsmem_raw_bytes.expected", &["-r", "-b"]);
}
#[test]
fn test_raw_noheadings() {
sysroot_test_with_args("test_lsmem_raw_noheadings.expected", &["-r", "-n"]);
}
#[test]
fn test_split_node() {
sysroot_test_with_args("test_lsmem_split_node.expected", &["-S", "node"]);
}
#[test]
fn test_split_removable() {
sysroot_test_with_args("test_lsmem_split_removable.expected", &["-S", "removable"]);
}
#[test]
fn test_split_state() {
sysroot_test_with_args("test_lsmem_split_state.expected", &["-S", "state"]);
}
// FAILS, COMMENT FOR NOW - TODO
// #[test]
// fn test_split_zones() {
// sysroot_test_with_args("test_lsmem_split_zones.expected", &["-S", "zones"]);
// }
#[test]
fn test_table() {
sysroot_test_with_args("test_lsmem_table.expected", &[]);
}
#[test]
fn test_table_all() {
sysroot_test_with_args("test_lsmem_table_all.expected", &["-a"]);
}
#[test]
fn test_table_bytes() {
sysroot_test_with_args("test_lsmem_table_bytes.expected", &["-b"]);
}
#[test]
fn test_table_noheadings() {
sysroot_test_with_args("test_lsmem_table_noheadings.expected", &["-n"]);
}

@ -0,0 +1 @@
8000000

@ -0,0 +1 @@
online

@ -0,0 +1 @@
online

Some files were not shown because too many files have changed in this diff Show More