Skip to content

Instantly share code, notes, and snippets.

@LuoZijun
Created July 9, 2019 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LuoZijun/2b8098f0a29c5bd7606f3eecb5bb2237 to your computer and use it in GitHub Desktop.
Save LuoZijun/2b8098f0a29c5bd7606f3eecb5bb2237 to your computer and use it in GitHub Desktop.
#![allow(unused)]
use std::path::Path;
use std::path::PathBuf;
use std::path::{Ancestors};
use std::fs::{OpenOptions, ReadDir,};
use std::io::{self, Read, Write};
use std::str::FromStr;
#[cfg(target_os = "linux")]
const PATH_PREFIX: &'static str = "/proc/sys";
#[cfg(not(target_os = "linux"))]
const PATH_PREFIX: &'static str = concat!(env!("PWD"), "/proc/sys");
#[cfg(target_os = "linux")]
const ROOT_PATH: &'static str = "/proc/sys/kernel";
#[cfg(not(target_os = "linux"))]
const ROOT_PATH: &'static str = concat!(env!("PWD"), "/proc/sys/kernel");
pub const CTL_MAXNAME: usize = 10;
#[derive(Debug)]
pub struct Mib {
path: PathBuf,
}
impl Mib {
pub fn name(&self) -> Result<String, io::Error> {
let name = self.path.strip_prefix(PATH_PREFIX)
.map_err(|e| io::Error::new(io::ErrorKind::NotFound, format!("{}", e)))?
.to_str()
.ok_or(io::Error::new(io::ErrorKind::Other, "Not a utf-8 seqs"))?;
Ok(name.replace("/", "."))
}
// Get Value by Mib
pub fn value(&self) -> Result<Vec<u8>, io::Error> {
if !self.path.is_file() {
return Err(io::Error::new(io::ErrorKind::Other, "Can not get value from a Node."));
}
let mut file = OpenOptions::new().read(true).write(false).open(&self.path)?;
let mut val = Vec::new();
file.read_to_end(&mut val)?;
Ok(val)
}
// Set Value By Mib
pub fn set_value(&self, val: &[u8]) -> Result<Vec<u8>, io::Error> {
let mut file = OpenOptions::new().read(false).write(true).open(&self.path)?;
file.write_all(val)?;
self.value()
}
// Get metadata ( ValueKind )
pub fn metadata(&self) -> Result<(), io::Error> {
unimplemented!()
}
#[inline]
pub fn description(&self) -> Result<String, std::io::Error> {
Err(io::Error::new(io::ErrorKind::Other, "Description not available on Linux"))
}
pub fn iter(&self) -> Result<MibIter, io::Error> {
MibIter::new(&self.path)
}
}
impl FromStr for Mib {
type Err = io::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let path = if s.starts_with(PATH_PREFIX) {
if s.ends_with(PATH_PREFIX) {
return Err(io::Error::from(io::ErrorKind::NotFound));
}
PathBuf::from(s)
} else {
PathBuf::from(PATH_PREFIX).join(s.replace(".", "/"))
};
// return absolute path, and ensure the path is exists.
let path = path.canonicalize()?;
debug_assert!(path.is_absolute());
debug_assert!(path.exists());
debug_assert!(path.starts_with(PATH_PREFIX));
Ok(Self { path, })
}
}
impl Default for Mib {
fn default() -> Self {
Self {
path: PathBuf::from(ROOT_PATH)
}
}
}
#[derive(Debug)]
pub struct MibIter {
dirs: Vec<ReadDir>,
}
impl MibIter {
fn new(path: &Path) -> Result<Self, io::Error> {
let root = Path::new(PATH_PREFIX);
debug_assert!(root.is_dir());
let mut dirs = Vec::new();
dirs.push(root.read_dir()?);
fn seek(dirs: &mut Vec<ReadDir>, stop_path: &Path) -> Result<(), io::Error> {
if dirs.len() == 0 {
return Ok(());
}
let idx = dirs.len() - 1;
let mut dir = match dirs.get_mut(idx) {
Some(dir) => dir,
None => return Ok(()),
};
loop {
let entry = dir.next();
if entry.is_none() {
dirs.remove(idx);
return seek(dirs, stop_path);
}
let entry = entry.unwrap()?;
let file_type = entry.file_type()?;
let file_path = entry.path();
if file_type.is_dir() {
dirs.push(file_path.read_dir()?);
if file_path == stop_path {
break;
}
return seek(dirs, stop_path);
} else if file_type.is_file() {
// println!("Skip: {:?}", file_path);
if file_path == stop_path {
break;
}
} else {
// TODO: symlink
unimplemented!()
}
}
Ok(())
}
seek(&mut dirs, &path)?;
Ok(MibIter {
dirs: dirs,
})
}
}
impl Iterator for MibIter {
type Item = Result<Mib, std::io::Error>;
fn next(&mut self) -> Option<Self::Item> {
if self.dirs.len() == 0 {
return None;
}
let idx = self.dirs.len() - 1;
let mut dir = self.dirs.get_mut(idx).unwrap();
match dir.next() {
Some(Ok(entry)) => {
let file_type = match entry.file_type() {
Ok(file_type) => file_type,
Err(e) => return Some(Err(e)),
};
let file_path = entry.path();
if file_type.is_dir() {
match file_path.read_dir() {
Ok(sub_dir) => self.dirs.push(sub_dir),
Err(e) => return Some(Err(e)),
}
self.next()
} else if file_type.is_file() {
let s = file_path.to_string_lossy().to_string();
Some(Mib::from_str(&s))
} else {
// TODO: hanlde symlink
unimplemented!()
}
},
Some(Err(e)) => return Some(Err(e)),
None => {
self.dirs.remove(idx);
self.next()
}
}
}
}
/*
macOS:
```python
import os
os.makedirs("proc/sys/kernel/keys")
os.makedirs("proc/sys/net/ipv4/")
os.system("touch proc/sys/kernel/a")
os.system("touch proc/sys/kernel/osrelease")
os.system("touch proc/sys/kernel/ostype")
os.system("touch proc/sys/kernel/version")
os.system("touch proc/sys/kernel/keys/root_maxbytes")
os.system("touch proc/sys/kernel/keys/root_maxkeys")
os.system("touch proc/sys/net/ipv4/ip_forward")
os.system("touch proc/sys/net/ipv4/tcp_mem")
os.system("touch proc/sys/net/ipv4/udp_mem")
```
*/
fn main() -> Result<(), io::Error> {
// Get Value
let mib = "kernel.ostype".parse::<Mib>()?;
println!("{:?}", mib.value());
// Walk (NextMib)
for x in mib.iter()? {
let next_mib = x?;
println!("{:?}", next_mib);
println!("{:?}", next_mib.value());
}
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment