Created
July 9, 2019 15:34
-
-
Save LuoZijun/2b8098f0a29c5bd7606f3eecb5bb2237 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![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