Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 31 additions & 22 deletions src/uu/sysctl/src/sysctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,15 @@ mod linux {
ret
}

pub fn print_directory_names(var: &str) -> bool {
/// Returns the variables under `var` when it names a directory, like `kernel.random`.
pub fn directory_variables(var: &str) -> Option<Vec<String>> {
let path = variable_path(var);
// Operands like /proc/sys/kernel arrive here as ".proc.sys.kernel". procps-ng fails on
// them, and variable_path would drop PROC_SYS_ROOT because the path is absolute.
if var.starts_with('.') || !path.is_dir() {
return false;
return None;
}
for name in get_sysctl_variables(&path) {
println!("{}", normalize_var(&name));
}
true
Some(get_sysctl_variables(&path))
}

pub fn normalize_var(var: &str) -> String {
Expand Down Expand Up @@ -120,7 +118,6 @@ use linux::*;
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(args)?;
let names = matches.get_flag("names");
let values = matches.get_flag("values");

let vars = if matches.get_flag("all") {
get_all_sysctl_variables()
Expand All @@ -141,29 +138,41 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
};

for var_or_assignment in vars {
if names
&& !var_or_assignment.is_empty()
&& !var_or_assignment.contains('=')
&& print_directory_names(&normalize_var(&var_or_assignment))
{
continue;
}
match handle_one_arg(&var_or_assignment, matches.get_flag("quiet")) {
Ok(None) => (),
Ok(Some((var, value))) => {
print!("{}", format_variable(&var, &value, names, values));
}
Err(e) => {
if !matches.get_flag("ignore") {
uucore::show!(e);
if !var_or_assignment.is_empty() && !var_or_assignment.contains('=') {
if let Some(dir_vars) = directory_variables(&normalize_var(&var_or_assignment)) {
for var in dir_vars {
if names {
println!("{}", normalize_var(&var));
} else {
print_one_arg(&var, &matches);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens with sysctl vm? vm.drop_caches is write-only, so i guess we print an error and exit 1.
procps-ng skips unreadable keys silently. Could be a follow-up together with -a.

}
}
continue;
}
}
print_one_arg(&var_or_assignment, &matches);
}

Ok(())
}

#[cfg(target_os = "linux")]
fn print_one_arg(var_or_assignment: &str, matches: &clap::ArgMatches) {
match handle_one_arg(var_or_assignment, matches.get_flag("quiet")) {
Ok(None) => (),
Ok(Some((var, value))) => {
let names = matches.get_flag("names");
let values = matches.get_flag("values");
print!("{}", format_variable(&var, &value, names, values));
}
Err(e) => {
if !matches.get_flag("ignore") {
uucore::show!(e);
}
}
}
}

#[cfg(not(target_os = "linux"))]
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Expand Down
18 changes: 18 additions & 0 deletions tests/by-util/test_sysctl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,24 @@ mod linux {
.stderr_is("");
}

#[test]
fn test_get_directory() {
let poolsize = std::fs::read_to_string("/proc/sys/kernel/random/poolsize").unwrap();
let poolsize = poolsize.trim_end();
new_ucmd!()
.arg("kernel.random")
.succeeds()
.stdout_contains_line(format!("kernel.random.poolsize = {poolsize}"))
.stdout_contains("kernel.random.boot_id = ")
.no_stderr();
new_ucmd!()
.args(&["-n", "kernel/random"])
.succeeds()
.stdout_contains_line(poolsize)
.stdout_does_not_contain("kernel.random")
.no_stderr();
}

#[test]
fn test_get_directory_names() {
for options in [vec!["-N"], vec!["--names"], vec!["-n", "-N"]] {
Expand Down
Loading