mirror of
https://github.com/orhun/systeroid
synced 2024-07-21 10:25:00 +00:00
feat(sysctl): support changing the value of parameters
This commit is contained in:
parent
e4507feb5c
commit
ad024dc5c2
|
@ -14,22 +14,25 @@ macro_rules! map {
|
|||
/// General configuration.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Config {
|
||||
/// Sysctl configuration.
|
||||
pub sysctl: SysctlConfig,
|
||||
/// Color configuration.
|
||||
pub color: ColorConfig,
|
||||
}
|
||||
|
||||
/// Sysctl configuration.
|
||||
#[derive(Debug)]
|
||||
pub struct SysctlConfig {
|
||||
pub struct ColorConfig {
|
||||
/// Whether if the colors are disabled.
|
||||
pub no_color: bool,
|
||||
/// Sections and the corresponding colors.
|
||||
pub section_colors: HashMap<Section, Color>,
|
||||
/// Default color for the output
|
||||
pub default_color: Color,
|
||||
}
|
||||
|
||||
impl Default for SysctlConfig {
|
||||
impl Default for ColorConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
no_color: false,
|
||||
section_colors: map! {
|
||||
Section::Abi => Color::Red,
|
||||
Section::Fs => Color::Green,
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use crate::config::SysctlConfig;
|
||||
use crate::config::ColorConfig;
|
||||
use crate::error::Result;
|
||||
use crate::parsers::parse_kernel_docs;
|
||||
use colored::*;
|
||||
use rayon::prelude::*;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use std::result::Result as StdResult;
|
||||
use sysctl::{CtlFlags, CtlIter, Sysctl as SysctlImpl};
|
||||
use sysctl::{Ctl, CtlFlags, CtlIter, Sysctl as SysctlImpl};
|
||||
use systeroid_parser::document::Document;
|
||||
|
||||
/// Sections of the sysctl documentation.
|
||||
|
@ -91,7 +92,7 @@ pub struct Parameter {
|
|||
|
||||
impl Parameter {
|
||||
/// Returns the parameter name with corresponding section colors.
|
||||
pub fn colored_name(&self, config: &SysctlConfig) -> String {
|
||||
pub fn colored_name(&self, config: &ColorConfig) -> String {
|
||||
let fields = self.name.split('.').collect::<Vec<&str>>();
|
||||
fields
|
||||
.iter()
|
||||
|
@ -113,6 +114,48 @@ impl Parameter {
|
|||
result
|
||||
})
|
||||
}
|
||||
|
||||
/// Prints the kernel parameter to given output.
|
||||
pub fn display<W: Write>(&self, config: &ColorConfig, output: &mut W) -> Result<()> {
|
||||
if !config.no_color {
|
||||
writeln!(
|
||||
output,
|
||||
"{} {} {}",
|
||||
self.colored_name(config),
|
||||
"=".color(config.default_color),
|
||||
self.value.bold(),
|
||||
)?;
|
||||
} else {
|
||||
writeln!(output, "{} = {}", self.name, self.value)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Sets a new value for the kernel parameter.
|
||||
pub fn update<W: Write>(
|
||||
&mut self,
|
||||
new_value: &str,
|
||||
config: &ColorConfig,
|
||||
output: &mut W,
|
||||
) -> Result<()> {
|
||||
let ctl = Ctl::new(&self.name)?;
|
||||
let new_value = ctl.set_value_string(new_value)?;
|
||||
self.value = new_value;
|
||||
self.display(config, output)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a Ctl> for Parameter {
|
||||
type Error = crate::error::Error;
|
||||
fn try_from(ctl: &'a Ctl) -> Result<Self> {
|
||||
Ok(Parameter {
|
||||
name: ctl.name()?,
|
||||
value: ctl.value_string()?,
|
||||
description: ctl.description().ok(),
|
||||
section: Section::from(ctl.name()?),
|
||||
document: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Sysctl wrapper for managing the kernel parameters.
|
||||
|
@ -120,28 +163,27 @@ impl Parameter {
|
|||
pub struct Sysctl {
|
||||
/// Available kernel parameters.
|
||||
pub parameters: Vec<Parameter>,
|
||||
/// Configuration.
|
||||
pub config: SysctlConfig,
|
||||
}
|
||||
|
||||
impl Sysctl {
|
||||
/// Constructs a new instance by fetching the available kernel parameters.
|
||||
pub fn init(config: SysctlConfig) -> Result<Self> {
|
||||
pub fn init() -> Result<Self> {
|
||||
let mut parameters = Vec::new();
|
||||
for ctl in CtlIter::root().filter_map(StdResult::ok).filter(|ctl| {
|
||||
ctl.flags()
|
||||
.map(|flags| !flags.contains(CtlFlags::SKIP))
|
||||
.unwrap_or(false)
|
||||
}) {
|
||||
parameters.push(Parameter {
|
||||
name: ctl.name()?,
|
||||
value: ctl.value_string()?,
|
||||
description: ctl.description().ok(),
|
||||
section: Section::from(ctl.name()?),
|
||||
document: None,
|
||||
});
|
||||
match Parameter::try_from(&ctl) {
|
||||
Ok(parameter) => {
|
||||
parameters.push(parameter);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{} ({})", e, ctl.name()?);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Self { parameters, config })
|
||||
Ok(Self { parameters })
|
||||
}
|
||||
|
||||
/// Updates the descriptions of the kernel parameters.
|
||||
|
@ -174,31 +216,4 @@ impl Sysctl {
|
|||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Prints the available kernel parameters to the given output.
|
||||
pub fn display<W: Write>(
|
||||
&self,
|
||||
output: &mut W,
|
||||
names: Vec<String>,
|
||||
colored: bool,
|
||||
) -> Result<()> {
|
||||
for parameter in self
|
||||
.parameters
|
||||
.iter()
|
||||
.filter(|param| names.is_empty() || names.iter().any(|name| param.name == *name))
|
||||
{
|
||||
if colored {
|
||||
writeln!(
|
||||
output,
|
||||
"{} {} {}",
|
||||
parameter.colored_name(&self.config),
|
||||
"=".color(self.config.default_color),
|
||||
parameter.value.bold(),
|
||||
)?;
|
||||
} else {
|
||||
writeln!(output, "{} = {}", parameter.name, parameter.value)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,23 +6,60 @@
|
|||
pub mod args;
|
||||
|
||||
use crate::args::Args;
|
||||
use std::io;
|
||||
use std::io::{self, Write};
|
||||
use systeroid_core::config::Config;
|
||||
use systeroid_core::error::Result;
|
||||
use systeroid_core::sysctl::Sysctl;
|
||||
|
||||
/// Runs `systeroid`.
|
||||
pub fn run(args: Args) -> Result<()> {
|
||||
let config = Config::default();
|
||||
let mut stdout = io::stdout();
|
||||
let mut sysctl = Sysctl::init(config.sysctl)?;
|
||||
let mut config = Config::default();
|
||||
config.color.no_color = args.no_color;
|
||||
let (mut stdout, mut stderr) = (io::stdout(), io::stderr());
|
||||
let mut sysctl = Sysctl::init()?;
|
||||
|
||||
if let Some(kernel_docs) = args.kernel_docs {
|
||||
sysctl.update_docs(&kernel_docs)?;
|
||||
}
|
||||
|
||||
if args.display_all {
|
||||
sysctl.display(&mut stdout, args.param_names, !args.no_color)?;
|
||||
if args.param_names.is_empty() {
|
||||
sysctl
|
||||
.parameters
|
||||
.iter()
|
||||
.try_for_each(|parameter| parameter.display(&config.color, &mut stdout))?;
|
||||
} else {
|
||||
for mut param_name in args.param_names {
|
||||
let new_value = if param_name.contains('=') {
|
||||
let fields = param_name
|
||||
.split('=')
|
||||
.take(2)
|
||||
.map(String::from)
|
||||
.collect::<Vec<String>>();
|
||||
param_name = fields[0].to_string();
|
||||
Some(fields[1].to_string())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
match sysctl
|
||||
.parameters
|
||||
.iter_mut()
|
||||
.find(|param| param.name == *param_name)
|
||||
{
|
||||
Some(parameter) => {
|
||||
if let Some(new_value) = new_value {
|
||||
parameter.update(&new_value, &config.color, &mut stdout)?;
|
||||
} else {
|
||||
parameter.display(&config.color, &mut stdout)?;
|
||||
}
|
||||
}
|
||||
None => writeln!(
|
||||
stderr,
|
||||
"{}: cannot stat /proc/{}: No such file or directory",
|
||||
env!("CARGO_PKG_NAME"),
|
||||
param_name.replace(".", "/")
|
||||
)?,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue