#[cfg(unix)]
extern crate libc;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
extern crate byteorder;
extern crate chrono;
extern crate hex;
extern crate libflate;
#[cfg(unix)]
mod platform_specific_items {
    pub use libc::pid_t;
    pub use libc::sysconf;
    pub use libc::{_SC_CLK_TCK, _SC_PAGESIZE};
}
#[cfg(windows)]
mod platform_specific_items {
    pub type pid_t = i32; 
    pub fn sysconf(_: i32) -> i64 {
        panic!()
    }
    pub const _SC_CLK_TCK: i32 = 2;
    pub const _SC_PAGESIZE: i32 = 30;
}
use crate::platform_specific_items::*;
use std::collections::HashMap;
use std::ffi::CStr;
use std::fmt;
use std::fs::File;
use std::io::{self, Read, Write};
use std::mem;
use std::os::raw::c_char;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use chrono::{DateTime, Local};
const PROC_CONFIG_GZ: &str = "/proc/config.gz";
const BOOT_CONFIG: &str = "/boot/config";
trait IntoOption<T> {
    fn into_option(t: Self) -> Option<T>;
}
impl<T> IntoOption<T> for Option<T> {
    fn into_option(t: Option<T>) -> Option<T> {
        t
    }
}
impl<T, R> IntoOption<T> for Result<T, R> {
    fn into_option(t: Result<T, R>) -> Option<T> {
        t.ok()
    }
}
#[macro_use]
macro_rules! expect {
    ($e:expr) => {
        crate::IntoOption::into_option($e).unwrap_or_else(|| {
            panic!(
                "Failed to unwrap {}. Please report this as a procfs bug.",
                stringify!($e)
            )
        })
    };
    ($e:expr, $msg:expr) => {
        crate::IntoOption::into_option($e).unwrap_or_else(|| {
            panic!(
                "Failed to unwrap {} ({}). Please report this as a procfs bug.",
                stringify!($e),
                $msg
            )
        })
    };
}
#[macro_use]
macro_rules! from_str {
    ($t:tt, $e:expr) => {{
        let e = $e;
        $t::from_str_radix(e, 10).unwrap_or_else(|_| {
            panic!(
                "Failed to parse {} ({:?}) as a {}. Please report this as a procfs bug.",
                stringify!($e),
                e,
                stringify!($t),
            )
        })
    }};
    ($t:tt, $e:expr, $radix:expr) => {{
        let e = $e;
        $t::from_str_radix(e, $radix).unwrap_or_else(|_| {
            panic!(
                "Failed to parse {} ({:?}) as a {}. Please report this as a procfs bug.",
                stringify!($e),
                e,
                stringify!($t)
            )
        })
    }};
    ($t:tt, $e:expr, $radix:expr, pid:$pid:expr) => {{
        let e = $e;
        $t::from_str_radix(e, $radix).unwrap_or_else(|_| {
            panic!(
                "Failed to parse {} ({:?}) as a {} (pid {}). Please report this as a procfs bug.",
                stringify!($e),
                e,
                stringify!($t),
                $pid
            )
        })
    }};
}
pub(crate) fn read_file<P: AsRef<Path>>(path: P) -> ProcResult<String> {
    let mut f = FileWrapper::open(path)?;
    let mut buf = String::new();
    f.read_to_string(&mut buf)?;
    Ok(buf)
}
pub(crate) fn write_file<P: AsRef<Path>, T: AsRef<[u8]>>(path: P, buf: T) -> ProcResult<()> {
    let mut f = File::open(path)?;
    f.write_all(buf.as_ref())?;
    Ok(())
}
pub(crate) fn read_value<P: AsRef<Path>, T: FromStr<Err = E>, E: fmt::Debug>(
    path: P,
) -> ProcResult<T> {
    read_file(path).map(|buf| buf.trim().parse().unwrap())
}
pub(crate) fn write_value<P: AsRef<Path>, T: fmt::Display>(path: P, value: T) -> ProcResult<()> {
    write_file(path, value.to_string().as_bytes())
}
mod process;
pub use crate::process::*;
mod meminfo;
pub use crate::meminfo::*;
mod net;
pub use crate::net::*;
mod cpuinfo;
pub use crate::cpuinfo::*;
mod cgroups;
pub use crate::cgroups::*;
pub mod sys;
pub use crate::sys::kernel::Version as KernelVersion;
lazy_static! {
    
    
    
    static ref BOOTTIME: DateTime<Local> = {
        boot_time().unwrap()
    };
    
    
    
    static ref TICKS_PER_SECOND: i64 = {
        ticks_per_second().unwrap()
    };
    
    
    
    
    static ref KERNEL: KernelVersion = {
        KernelVersion::current().unwrap()
    };
    
    
    
    static ref PAGESIZE: i64 = {
        page_size().unwrap()
    };
}
fn convert_to_bytes(num: u64, unit: &str) -> u64 {
    match unit {
        "B" => num,
        "KiB" | "kiB" => num * 1024,
        "kB" | "KB" => num * 1000,
        "MiB" | "miB" => num * 1024 * 1024,
        "MB" | "mB" => num * 1000 * 1000,
        "GiB" | "giB" => num * 1024 * 1024 * 1024,
        "GB" | "gB" => num * 1000 * 1000 * 1000,
        unknown => panic!("Unknown unit type {}", unknown),
    }
}
fn convert_to_kibibytes(num: u64, unit: &str) -> u64 {
    match unit {
        "B" => num,
        "KiB" | "kiB" | "kB" | "KB" => num * 1024,
        "MiB" | "miB" | "MB" | "mB" => num * 1024 * 1024,
        "GiB" | "giB" | "GB" | "gB" => num * 1024 * 1024 * 1024,
        unknown => panic!("Unknown unit type {}", unknown),
    }
}
trait FromStrRadix: Sized {
    fn from_str_radix(t: &str, radix: u32) -> Result<Self, std::num::ParseIntError>;
}
impl FromStrRadix for u64 {
    fn from_str_radix(s: &str, radix: u32) -> Result<u64, std::num::ParseIntError> {
        u64::from_str_radix(s, radix)
    }
}
impl FromStrRadix for i32 {
    fn from_str_radix(s: &str, radix: u32) -> Result<i32, std::num::ParseIntError> {
        i32::from_str_radix(s, radix)
    }
}
fn split_into_num<T: FromStrRadix>(s: &str, sep: char, radix: u32) -> (T, T) {
    let mut s = s.split(sep);
    let a = match FromStrRadix::from_str_radix(s.next().unwrap(), radix) {
        Ok(v) => v,
        _ => panic!(),
    };
    let b = match FromStrRadix::from_str_radix(s.next().unwrap(), radix) {
        Ok(v) => v,
        _ => panic!(),
    };
    (a, b)
}
#[derive(Debug)]
struct IoErrorWrapper {
    path: PathBuf,
    inner: Option<Box<dyn std::error::Error + Send + Sync>>,
}
impl std::error::Error for IoErrorWrapper {}
impl fmt::Display for IoErrorWrapper {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        if let Some(inner) = &self.inner {
            write!(f, "IO Error({}): {}", self.path.display(), inner)
        } else {
            write!(f, "IO Error({})", self.path.display())
        }
    }
}
struct FileWrapper {
    inner: File,
    path: PathBuf,
}
impl FileWrapper {
    fn open<P: AsRef<Path>>(path: P) -> Result<FileWrapper, io::Error> {
        let p = path.as_ref();
        match File::open(&p) {
            Ok(f) => Ok(FileWrapper {
                inner: f,
                path: p.to_owned(),
            }),
            Err(e) => {
                let kind = e.kind();
                Err(io::Error::new(
                    kind,
                    IoErrorWrapper {
                        path: p.to_owned(),
                        inner: e.into_inner(),
                    },
                ))
            }
        }
    }
}
macro_rules! wrap_io_error {
    ($path:expr, $expr:expr) => {
        match $expr {
            Ok(v) => Ok(v),
            Err(e) => {
                let kind = e.kind();
                Err(io::Error::new(
                    kind,
                    IoErrorWrapper {
                        path: $path.clone(),
                        inner: e.into_inner(),
                    },
                ))
            }
        }
    };
}
impl Read for FileWrapper {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        wrap_io_error!(self.path, self.inner.read(buf))
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        wrap_io_error!(self.path, self.inner.read_to_end(buf))
    }
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        wrap_io_error!(self.path, self.inner.read_to_string(buf))
    }
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        wrap_io_error!(self.path, self.inner.read_exact(buf))
    }
}
pub type ProcResult<T> = Result<T, ProcError>;
#[derive(Debug)]
pub enum ProcError {
    
    
    
    
    PermissionDenied(Option<PathBuf>),
    
    
    NotFound(Option<PathBuf>),
    
    Incomplete(Option<PathBuf>),
    
    Io(std::io::Error, Option<PathBuf>),
    
    Other(String),
}
impl From<std::io::Error> for ProcError {
    fn from(io: std::io::Error) -> Self {
        use std::io::ErrorKind;
        let kind = io.kind();
        let path: Option<PathBuf> = io.get_ref().and_then(|inner| {
            if let Some(ref inner) = inner.downcast_ref::<IoErrorWrapper>() {
                Some(inner.path.clone())
            } else {
                None
            }
        });
        match kind {
            ErrorKind::PermissionDenied => ProcError::PermissionDenied(path),
            ErrorKind::NotFound => ProcError::NotFound(path),
            _other => ProcError::Io(io, path),
        }
    }
}
impl std::fmt::Display for ProcError {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        match self {
            
            ProcError::PermissionDenied(Some(p)) => write!(f, "Permission Denied: {}", p.display()),
            ProcError::NotFound(Some(p)) => write!(f, "File not found: {}", p.display()),
            ProcError::Incomplete(Some(p)) => write!(f, "Data incomplete: {}", p.display()),
            ProcError::Io(inner, Some(p)) => {
                write!(f, "Unexpected IO error({}): {}", p.display(), inner)
            }
            
            ProcError::PermissionDenied(None) => write!(f, "Permission Denied"),
            ProcError::NotFound(None) => write!(f, "File not found"),
            ProcError::Incomplete(None) => write!(f, "Data incomplete"),
            ProcError::Io(inner, None) => write!(f, "Unexpected IO error: {}", inner),
            ProcError::Other(s) => write!(f, "Uknown error {}", s),
        }
    }
}
impl std::error::Error for ProcError {}
#[derive(Debug)]
pub struct LoadAverage {
    
    pub one: f32,
    
    pub five: f32,
    
    pub fifteen: f32,
    
    pub cur: u32,
    
    pub max: u32,
    
    pub latest_pid: u32,
}
impl LoadAverage {
    
    pub fn new() -> ProcResult<LoadAverage> {
        let mut f = FileWrapper::open("/proc/loadavg")?;
        let mut s = String::new();
        f.read_to_string(&mut s)?;
        let mut s = s.split_whitespace();
        let one = f32::from_str(s.next().unwrap()).unwrap();
        let five = f32::from_str(s.next().unwrap()).unwrap();
        let fifteen = f32::from_str(s.next().unwrap()).unwrap();
        let curmax = s.next().unwrap();
        let latest_pid = u32::from_str(s.next().unwrap()).unwrap();
        let mut s = curmax.split('/');
        let cur = u32::from_str(s.next().unwrap()).unwrap();
        let max = u32::from_str(s.next().unwrap()).unwrap();
        Ok(LoadAverage {
            one,
            five,
            fifteen,
            cur,
            max,
            latest_pid,
        })
    }
}
pub fn ticks_per_second() -> std::io::Result<i64> {
    if cfg!(unix) {
        match unsafe { sysconf(_SC_CLK_TCK) } {
            -1 => Err(std::io::Error::last_os_error()),
            x => Ok(x.into()),
        }
    } else {
        panic!("Not supported on non-unix platforms")
    }
}
pub fn boot_time() -> ProcResult<DateTime<Local>> {
    let now = Local::now();
    let mut f = FileWrapper::open("/proc/uptime")?;
    let mut buf = String::new();
    f.read_to_string(&mut buf)?;
    let uptime_seconds = f32::from_str(buf.split_whitespace().next().unwrap()).unwrap();
    Ok(now - chrono::Duration::milliseconds((uptime_seconds * 1000.0) as i64))
}
pub fn page_size() -> std::io::Result<i64> {
    if cfg!(unix) {
        match unsafe { sysconf(_SC_PAGESIZE) } {
            -1 => Err(std::io::Error::last_os_error()),
            x => Ok(x.into()),
        }
    } else {
        panic!("Not supported on non-unix platforms")
    }
}
#[derive(Debug, PartialEq)]
pub enum ConfigSetting {
    Yes,
    Module,
    Value(String),
}
pub fn kernel_config() -> ProcResult<HashMap<String, ConfigSetting>> {
    use libflate::gzip::Decoder;
    use std::io::{BufRead, BufReader};
    let reader: Box<BufRead> = if Path::new(PROC_CONFIG_GZ).exists() {
        let file = FileWrapper::open(PROC_CONFIG_GZ)?;
        let decoder = Decoder::new(file)?;
        Box::new(BufReader::new(decoder))
    } else {
        let mut kernel: libc::utsname = unsafe { mem::zeroed() };
        if unsafe { libc::uname(&mut kernel) != 0 } {
            return Err(ProcError::Other("Failed to call uname()".to_string()));
        }
        let filename = format!(
            "{}-{}",
            BOOT_CONFIG,
            unsafe { CStr::from_ptr(kernel.release.as_ptr() as *const c_char) }.to_string_lossy()
        );
        if Path::new(&filename).exists() {
            let file = FileWrapper::open(filename)?;
            Box::new(BufReader::new(file))
        } else {
            let file = FileWrapper::open(BOOT_CONFIG)?;
            Box::new(BufReader::new(file))
        }
    };
    let mut map = HashMap::new();
    for line in reader.lines() {
        let line = line?;
        if line.starts_with('#') {
            continue;
        }
        if line.contains('=') {
            let mut s = line.splitn(2, '=');
            let name = expect!(s.next()).to_owned();
            let value = match expect!(s.next()) {
                "y" => ConfigSetting::Yes,
                "m" => ConfigSetting::Module,
                s => ConfigSetting::Value(s.to_owned()),
            };
            map.insert(name, value);
        }
    }
    Ok(map)
}
pub fn meminfo() -> ProcResult<Meminfo> {
    Meminfo::new()
}
#[cfg(test)]
mod tests {
    extern crate failure;
    use super::*;
    #[test]
    fn test_kernel_const() {
        println!("{:?}", *KERNEL);
    }
    #[test]
    fn test_kernel_from_str() {
        let k = KernelVersion::from_str("1.2.3").unwrap();
        assert_eq!(k.major, 1);
        assert_eq!(k.minor, 2);
        assert_eq!(k.patch, 3);
        let k = KernelVersion::from_str("4.9.16-gentoo").unwrap();
        assert_eq!(k.major, 4);
        assert_eq!(k.minor, 9);
        assert_eq!(k.patch, 16);
    }
    #[test]
    fn test_kernel_cmp() {
        let a = KernelVersion::from_str("1.2.3").unwrap();
        let b = KernelVersion::from_str("1.2.3").unwrap();
        let c = KernelVersion::from_str("1.2.4").unwrap();
        let d = KernelVersion::from_str("1.5.4").unwrap();
        let e = KernelVersion::from_str("2.5.4").unwrap();
        assert_eq!(a, b);
        assert!(a < c);
        assert!(a < d);
        assert!(a < e);
        assert!(e > d);
        assert!(e > c);
        assert!(e > b);
    }
    #[test]
    fn test_loadavg() {
        let load = LoadAverage::new().unwrap();
        println!("{:?}", load);
    }
    #[test]
    fn test_from_str() {
        assert_eq!(from_str!(u8, "12"), 12);
        assert_eq!(from_str!(u8, "A", 16), 10);
    }
    #[test]
    #[should_panic]
    fn test_from_str_panic() {
        let s = "four";
        from_str!(u8, s);
    }
    #[test]
    fn test_kernel_config() {
        
        
        match std::env::var("TRAVIS") {
            Ok(ref s) if s == "true" => return,
            _ => {}
        }
        let config = kernel_config().unwrap();
        println!("{:#?}", config);
    }
    #[test]
    fn test_file_io_errors() {
        fn inner<P: AsRef<Path>>(p: P) -> Result<(), ProcError> {
            let mut file = FileWrapper::open(p)?;
            let mut buf = [0; 128];
            file.read_exact(&mut buf[0..128])?;
            Ok(())
        }
        let err = inner("/this_should_not_exist").unwrap_err();
        println!("{}", err);
        match err {
            ProcError::NotFound(Some(p)) => {
                assert_eq!(p, Path::new("/this_should_not_exist"));
            }
            x => panic!("Unexpected return value: {:?}", x),
        }
        match inner("/proc/loadavg") {
            Err(ProcError::Io(_, Some(p))) => {
                assert_eq!(p, Path::new("/proc/loadavg"));
            }
            x => panic!("Unexpected return value: {:?}", x),
        }
    }
    
    #[test]
    fn test_failure() {
        fn inner() -> Result<(), failure::Error> {
            let _load = LoadAverage::new()?;
            Ok(())
        }
        let _ = inner();
        fn inner2() -> Result<(), failure::Error> {
            let proc = Process::new(1)?;
            let _io = proc.maps()?;
            Ok(())
        }
        let _ = inner2();
        
        
    }
}