sysinfo-0.9.5/.gitignore010064400007650000024000000014711335155060700134360ustar0000000000000000 # Created by https://www.gitignore.io/api/osx,rust ### OSX ### *.DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns .com.apple.timemachine.donotpresent # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ### Rust ### # Generated by Cargo # will have compiled files and executables /target/ examples/target # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock Cargo.lock # These are backup files generated by rustfmt **/*.rs.bk rusty-tags.vi tags **.o simplesysinfo-0.9.5/.travis.yml010064400007650000024000000043611350340713200135510ustar0000000000000000language: rust matrix: include: - os: linux rust: stable dist: trusty - os: linux env: TARGET=armv7-unknown-linux-gnueabihf rust: stable dist: trusty - os: linux env: TARGET=arm-linux-androideabi rust: stable dist: trusty - os: linux env: TARGET=x86_64-apple-darwin rust: stable dist: trusty - os: linux env: TARGET=i686-unknown-linux-gnu rust: stable dist: trusty - os: linux env: TARGET=i686-unknown-linux-musl rust: stable dist: trusty - os: linux rust: nightly dist: trusty - os: linux env: TARGET=armv7-unknown-linux-gnueabihf rust: nightly dist: trusty - os: linux env: TARGET=arm-linux-androideabi rust: nightly dist: trusty - os: linux env: TARGET=x86_64-apple-darwin rust: nightly dist: trusty - os: linux env: TARGET=i686-unknown-linux-gnu rust: nightly dist: trusty - os: linux env: TARGET=i686-unknown-linux-musl rust: nightly dist: trusty - os: osx rust: stable - os: osx rust: nightly script: - rustc --version - sysctl -a | grep mem - if [[ "$TRAVIS_RUST_VERSION" == "nightly" ]]; then (rustup component add clippy-preview && cargo clippy) || touch clippy_install_failed; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cargo build --features debug; elif [[ -n "$TARGET" ]]; then rustup target add $TARGET;export EXTRA="--target=$TARGET"; fi - echo $EXTRA - if [[ -n "$EXTRA" ]]; then RUST_BACKTRACE=1 cargo check $EXTRA; else RUST_BACKTRACE=1 cargo build; fi - if [[ "$TRAVIS_RUST_VERSION" == "nightly" && -z "$EXTRA" ]]; then RUST_BACKTRACE=1 cargo bench; fi - if [[ -z "$EXTRA" ]]; then RUST_BACKTRACE=1 cargo test; fi - cd examples - if [[ -z "$EXTRA" ]]; then RUST_BACKTRACE=1 cargo build; fi - if [[ "$TRAVIS_RUST_VERSION" == "nightly" && -z "$EXTRA" && ! -f clippy_install_failed ]]; then cargo clippy $EXTRA || echo "clippy failed"; fi - cd .. - if [[ -z "$EXTRA" ]]; then make; fi - if [[ -z "$EXTRA" ]]; then LD_LIBRARY_PATH=./target/debug ./simple; fi sysinfo-0.9.5/appveyor.yml010064400007650000024000000010271342016302400140210ustar0000000000000000environment: matrix: - RUST: stable BITS: 32 - RUST: stable BITS: 64 install: - IF "%BITS%" == "32" SET ARCH=i686 - IF "%BITS%" == "64" SET ARCH=x86_64 - curl -sSf -o rustup-init.exe https://win.rustup.rs - rustup-init.exe --default-host "%ARCH%-pc-windows-gnu" --default-toolchain %RUST% -y - SET PATH=C:\Users\appveyor\.cargo\bin;C:\msys64\mingw%BITS%\bin;%PATH%;C:\msys64\usr\bin - rustc -Vv - cargo -Vv build_script: - cargo build - cargo test - cd examples - cargo build test: false sysinfo-0.9.5/benches/basic.rs010064400007650000024000000026271343623123700145070ustar0000000000000000#![feature(test)] extern crate test; extern crate sysinfo; use sysinfo::SystemExt; #[bench] fn bench_new(b: &mut test::Bencher) { b.iter(|| { sysinfo::System::new(); }); } #[bench] fn bench_refresh_all(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); b.iter(move || { s.refresh_all(); }); } #[bench] fn bench_refresh_system(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); s.refresh_system(); b.iter(move || { s.refresh_system(); }); } #[bench] fn bench_refresh_processes(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); b.iter(move || { s.refresh_processes(); }); } #[bench] fn bench_refresh_process(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); s.refresh_all(); let pid = *s.get_process_list().iter().take(1).next().unwrap().0; b.iter(move || { s.refresh_process(pid); }); } #[bench] fn bench_refresh_disks(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); b.iter(move || { s.refresh_disks(); }); } #[bench] fn bench_refresh_disk_lists(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); b.iter(move || { s.refresh_disk_list(); }); } #[bench] fn bench_refresh_network(b: &mut test::Bencher) { let mut s = sysinfo::System::new(); b.iter(move || { s.refresh_network(); }); } sysinfo-0.9.5/build.rs010064400007650000024000000003161346745444300131210ustar0000000000000000fn main() { if std::env::var("TARGET").unwrap().contains("-apple") { println!("cargo:rustc-link-lib=framework=IOKit"); println!("cargo:rustc-link-lib=framework=CoreFoundation"); } } sysinfo-0.9.5/Cargo.toml.orig010064400007650000024000000017321353520047400143330ustar0000000000000000[package] name = "sysinfo" version = "0.9.5" authors = ["Guillaume Gomez "] description = "Library to handle processes" repository = "https://github.com/GuillaumeGomez/sysinfo" license = "MIT" readme = "README.md" categories = ["filesystem", "os::macos-apis", "os::unix-apis", "os::windows-apis"] build = "build.rs" [dependencies] cfg-if = "0.1" rayon = "^1.0" doc-comment = "0.3" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "tlhelp32", "winbase", "winerror", "winioctl", "winnt"] } [target.'cfg(not(target_os = "unknown"))'.dependencies] libc = "0.2" [lib] name = "sysinfo" crate_type = ["rlib", "cdylib"] path = "src/sysinfo.rs" [features] c-interface = [] debug = ["libc/extra_traits"] [badges] travis-ci = { repository = "GuillaumeGomez/sysinfo" } appveyor = { repository = "GuillaumeGomez/sysinfo", service = "github" } sysinfo-0.9.5/Cargo.toml0000644000000030300000000000000105720ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "sysinfo" version = "0.9.5" authors = ["Guillaume Gomez "] build = "build.rs" description = "Library to handle processes" readme = "README.md" categories = ["filesystem", "os::macos-apis", "os::unix-apis", "os::windows-apis"] license = "MIT" repository = "https://github.com/GuillaumeGomez/sysinfo" [lib] name = "sysinfo" crate_type = ["rlib", "cdylib"] path = "src/sysinfo.rs" [dependencies.cfg-if] version = "0.1" [dependencies.doc-comment] version = "0.3" [dependencies.rayon] version = "^1.0" [features] c-interface = [] debug = ["libc/extra_traits"] [target."cfg(not(target_os = \"unknown\"))".dependencies.libc] version = "0.2" [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["fileapi", "handleapi", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "tlhelp32", "winbase", "winerror", "winioctl", "winnt"] [badges.appveyor] repository = "GuillaumeGomez/sysinfo" service = "github" [badges.travis-ci] repository = "GuillaumeGomez/sysinfo" sysinfo-0.9.5/LICENSE010064400007650000024000000020731333211327500124450ustar0000000000000000The MIT License (MIT) Copyright (c) 2015 Guillaume Gomez Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sysinfo-0.9.5/Makefile010064400007650000024000000014441333211327500131010ustar0000000000000000# # Sysinfo # # Copyright (c) 2017 Guillaume Gomez # # # Please note that this Makefile only generates the c example. # IDIR = ./src CC = gcc CFLAGS = -I$(IDIR) ODIR = examples/src LDIR = ./target/debug/ LDIR-RELEASE = ./target/release/ LIBS = -lsysinfo -lpthread _DEPS = sysinfo.h DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS)) _OBJ = simple.o OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ)) simple: $(OBJ) @echo "Compiling in debug mode" cargo build --features=c-interface gcc -o $@ $^ $(CFLAGS) -L$(LDIR) $(LIBS) release: $(OBJ) @echo "Compiling in release mode" cargo build --features=c-interface --release gcc -o simple $^ $(CFLAGS) -L$(LDIR-RELEASE) $(LIBS) $(ODIR)/%.o: %.c $(DEPS) $(CC) -c -o $@ $< $(CFLAGS) .PHONY: simple clean: @echo "Cleaning mess" rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ sysinfo-0.9.5/README.md010064400007650000024000000050011353425133300127130ustar0000000000000000# sysinfo [![][img_travis-ci]][travis-ci] [![Build status](https://ci.appveyor.com/api/projects/status/nhep876b3legunwd/branch/master?svg=true)](https://ci.appveyor.com/project/GuillaumeGomez/sysinfo/branch/master) [![][img_crates]][crates] [![][img_doc]][doc] [img_travis-ci]: https://api.travis-ci.org/GuillaumeGomez/sysinfo.png?branch=master [img_crates]: https://img.shields.io/crates/v/sysinfo.svg [img_doc]: https://img.shields.io/badge/rust-documentation-blue.svg [travis-ci]: https://travis-ci.org/GuillaumeGomez/sysinfo [crates]: https://crates.io/crates/sysinfo [doc]: https://docs.rs/sysinfo/ A system handler to interact with processes. Support the following platforms: * Linux * Raspberry * Mac OSX * Windows It also compiles for Android but never been tested on it. ### Running on Raspberry It'll be difficult to build on Raspberry. A good way-around is to be build on Linux before sending it to your Raspberry: ```bash rustup target add armv7-unknown-linux-gnueabihf cargo build --target=armv7-unknown-linux-gnueabihf ``` ## Code example You have an example into the `examples` folder. Just run `cargo run` inside the `examples` folder to start it. Otherwise, here is a little code sample: ```rust extern crate sysinfo; use sysinfo::{NetworkExt, System, SystemExt}; let mut sys = System::new(); // We display the disks: println!("=> disk list:"); for disk in sys.get_disks() { println!("{:?}", disk); } // Network data: println!("input data : {} B", sys.get_network().get_income()); println!("output data: {} B", sys.get_network().get_outcome()); // Components temperature: for component in sys.get_components_list() { println!("{:?}", component); } // Memory information: println!("total memory: {} kB", sys.get_total_memory()); println!("used memory : {} kB", sys.get_used_memory()); println!("total swap : {} kB", sys.get_total_swap()); println!("used swap : {} kB", sys.get_used_swap()); // Number of processors println!("NB processors: {}", sys.get_processor_list().len()); // To refresh all system information: sys.refresh_all(); ``` ## C interface It's possible to use this crate directly from C. Take a look at the `Makefile` and at the `examples/src/simple.c` file. To build the C example, just run: ```bash > make > ./simple # If needed: > LD_LIBRARY_PATH=target/release/ ./simple ``` ## Donations If you appreciate my work and want to support me, you can do it here: [![Become a patron](https://c5.patreon.com/external/logo/become_a_patron_button.png)](https://www.patreon.com/GuillaumeGomez) sysinfo-0.9.5/src/c_interface.rs010064400007650000024000000271111335155050600150420ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use std::borrow::BorrowMut; use std::ffi::CString; use libc::{self, c_char, c_float, c_uint, c_void, pid_t, size_t}; use ::{NetworkExt, Process, ProcessExt, ProcessorExt, System, SystemExt}; /// Equivalent of `System` struct. pub type CSystem = *mut c_void; /// Equivalent of `Process` struct. pub type CProcess = *const c_void; /// C string returned from `CString::into_raw`. pub type RString = *const c_char; /// Callback used by `get_process_list`. pub type ProcessLoop = extern "C" fn(pid: pid_t, process: CProcess, data: *mut c_void) -> bool; /// Equivalent of `System::new()`. #[no_mangle] pub extern "C" fn sysinfo_init() -> CSystem { let system = Box::new(System::new()); Box::into_raw(system) as CSystem } /// Equivalent of `System::drop`. Important in C to cleanup memory. #[no_mangle] pub extern "C" fn sysinfo_destroy(system: CSystem) { assert!(!system.is_null()); unsafe { Box::from_raw(system as *mut System); } } /// Equivalent of `System.refresh_system()`. #[no_mangle] pub extern "C" fn sysinfo_refresh_system(system: CSystem) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); system.refresh_system(); } Box::into_raw(system); } /// Equivalent of `System.refresh_all()`. #[no_mangle] pub extern "C" fn sysinfo_refresh_all(system: CSystem) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); system.refresh_all(); } Box::into_raw(system); } /// Equivalent of `System.refresh_processes()`. #[no_mangle] pub extern "C" fn sysinfo_refresh_processes(system: CSystem) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); system.refresh_processes(); } Box::into_raw(system); } /// Equivalent of `System.refresh_process()`. #[cfg(target_os = "linux")] #[no_mangle] pub extern "C" fn sysinfo_refresh_process(system: CSystem, pid: pid_t) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); system.refresh_process(pid); } Box::into_raw(system); } /// Equivalent of `System.refresh_disks()`. #[no_mangle] pub extern "C" fn sysinfo_refresh_disks(system: CSystem) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); system.refresh_disks(); } Box::into_raw(system); } /// Equivalent of `System.refresh_disk_list()`. #[no_mangle] pub extern "C" fn sysinfo_refresh_disk_list(system: CSystem) { assert!(!system.is_null()); let mut system: Box = unsafe { Box::from_raw(system as *mut System) }; { let system: &mut System = system.borrow_mut(); system.refresh_disk_list(); } Box::into_raw(system); } /// Equivalent of `System.get_total_memory()`. #[no_mangle] pub extern "C" fn sysinfo_get_total_memory(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_total_memory() as size_t; Box::into_raw(system); ret } /// Equivalent of `System.get_free_memory()`. #[no_mangle] pub extern "C" fn sysinfo_get_free_memory(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_free_memory() as size_t; Box::into_raw(system); ret } /// Equivalent of `System.get_used_memory()`. #[no_mangle] pub extern "C" fn sysinfo_get_used_memory(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_used_memory() as size_t; Box::into_raw(system); ret } /// Equivalent of `System.get_total_swap()`. #[no_mangle] pub extern "C" fn sysinfo_get_total_swap(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_total_swap() as size_t; Box::into_raw(system); ret } /// Equivalent of `System.get_free_swap()`. #[no_mangle] pub extern "C" fn sysinfo_get_free_swap(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_free_swap() as size_t; Box::into_raw(system); ret } /// Equivalent of `System.get_used_swap()`. #[no_mangle] pub extern "C" fn sysinfo_get_used_swap(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_used_swap() as size_t; Box::into_raw(system); ret } /// Equivalent of `system.get_network().get_income()`. #[no_mangle] pub extern "C" fn sysinfo_get_network_income(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_network().get_income() as size_t; Box::into_raw(system); ret } /// Equivalent of `system.get_network().get_outcome()`. #[no_mangle] pub extern "C" fn sysinfo_get_network_outcome(system: CSystem) -> size_t { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = system.get_network().get_outcome() as size_t; Box::into_raw(system); ret } /// Equivalent of `System.get_processors_usage()`. /// /// * `length` will contain the number of cpu usage added into `procs`. /// * `procs` will be allocated if it's null and will contain of cpu usage. #[no_mangle] pub extern "C" fn sysinfo_get_processors_usage(system: CSystem, length: *mut c_uint, procs: *mut *mut c_float) { assert!(!system.is_null()); if procs.is_null() || length.is_null() { return; } let system: Box = unsafe { Box::from_raw(system as *mut System) }; { let processors = system.get_processor_list(); unsafe { if (*procs).is_null() { (*procs) = libc::malloc(::std::mem::size_of::() * processors.len()) as *mut c_float; } for (pos, processor) in processors.iter().skip(1).enumerate() { (*(*procs).offset(pos as isize)) = processor.get_cpu_usage(); } *length = processors.len() as c_uint - 1; } } Box::into_raw(system); } /// Equivalent of `System.get_process_list()`. Returns an array ended by a null pointer. Must /// be freed. /// /// # /!\ WARNING /!\ /// /// While having this method returned processes, you should *never* call any refresh method! #[no_mangle] pub extern "C" fn sysinfo_get_processes(system: CSystem, fn_pointer: Option, data: *mut c_void) -> size_t { assert!(!system.is_null()); if let Some(fn_pointer) = fn_pointer { let system: Box = unsafe { Box::from_raw(system as *mut System) }; let len = { let entries = system.get_process_list(); for (pid, process) in entries { if !fn_pointer(*pid, process as *const Process as CProcess, data) { break } } entries.len() as size_t }; Box::into_raw(system); len } else { 0 } } /// Equivalent of `System.get_process`. /// /// # /!\ WARNING /!\ /// /// While having this method returned process, you should *never* call any /// refresh method! #[no_mangle] pub extern "C" fn sysinfo_get_process_by_pid(system: CSystem, pid: pid_t) -> CProcess { assert!(!system.is_null()); let system: Box = unsafe { Box::from_raw(system as *mut System) }; let ret = if let Some(process) = system.get_process(pid) { process as *const Process as CProcess } else { ::std::ptr::null() }; Box::into_raw(system); ret } /// Equivalent of iterating over `Process.tasks`. /// /// # /!\ WARNING /!\ /// /// While having this method processes, you should *never* call any refresh method! #[cfg(target_os = "linux")] #[no_mangle] pub extern "C" fn sysinfo_process_get_tasks(process: CProcess, fn_pointer: Option, data: *mut c_void) -> size_t { assert!(!process.is_null()); if let Some(fn_pointer) = fn_pointer { let process = process as *const Process; for (pid, process) in unsafe { (*process).tasks.iter() } { if !fn_pointer(*pid, process as *const Process as CProcess, data) { break } } unsafe { (*process).tasks.len() as size_t } } else { 0 } } /// Equivalent of `Process.pid`. #[no_mangle] pub extern "C" fn sysinfo_process_get_pid(process: CProcess) -> pid_t { assert!(!process.is_null()); let process = process as *const Process; unsafe { (*process).pid() } } /// Equivalent of `Process.parent`. /// /// In case there is no known parent, it returns `0`. #[no_mangle] pub extern "C" fn sysinfo_process_get_parent_pid(process: CProcess) -> pid_t { assert!(!process.is_null()); let process = process as *const Process; unsafe { (*process).parent().unwrap_or_else(|| 0) } } /// Equivalent of `Process.cpu_usage`. #[no_mangle] pub extern "C" fn sysinfo_process_get_cpu_usage(process: CProcess) -> c_float { assert!(!process.is_null()); let process = process as *const Process; unsafe { (*process).cpu_usage() } } /// Equivalent of `Process.memory`. #[no_mangle] pub extern "C" fn sysinfo_process_get_memory(process: CProcess) -> size_t { assert!(!process.is_null()); let process = process as *const Process; unsafe { (*process).memory() as usize } } /// Equivalent of `Process.exe`. #[no_mangle] pub extern "C" fn sysinfo_process_get_executable_path(process: CProcess) -> RString { assert!(!process.is_null()); let process = process as *const Process; unsafe { if let Some(p) = (*process).exe().to_str() { if let Ok(c) = CString::new(p) { return c.into_raw() as _; } } ::std::ptr::null() } } /// Equivalent of `Process.root`. #[no_mangle] pub extern "C" fn sysinfo_process_get_root_directory(process: CProcess) -> RString { assert!(!process.is_null()); let process = process as *const Process; unsafe { if let Some(p) = (*process).root().to_str() { if let Ok(c) = CString::new(p) { return c.into_raw() as _; } } ::std::ptr::null() } } /// Equivalent of `Process.cwd`. #[no_mangle] pub extern "C" fn sysinfo_process_get_current_directory(process: CProcess) -> RString { assert!(!process.is_null()); let process = process as *const Process; unsafe { if let Some(p) = (*process).cwd().to_str() { if let Ok(c) = CString::new(p) { return c.into_raw() as _; } } ::std::ptr::null() } } /// Frees a C string creating with `CString::into_raw`. #[no_mangle] pub extern "C" fn sysinfo_rstring_free(s: RString) { if !s.is_null() { unsafe { let _ = CString::from_raw(s as usize as *mut i8); } } } sysinfo-0.9.5/src/common.rs010064400007650000024000000102371350420322000140550ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // /// Trait to have a common fallback for the `Pid` type. pub trait AsU32 { /// Allows to convert `Pid` into `u32`. fn as_u32(&self) -> u32; } cfg_if!{ if #[cfg(any(windows, target_os = "unknown"))] { /// Process id. pub type Pid = usize; impl AsU32 for Pid { fn as_u32(&self) -> u32 { *self as u32 } } } else { use libc::pid_t; /// Process id. pub type Pid = pid_t; impl AsU32 for Pid { fn as_u32(&self) -> u32 { *self as u32 } } } } macro_rules! impl_get_set { ($name:ident, $with:ident, $without:ident) => { doc_comment! { concat!("Returns the value of the \"", stringify!($name), "\" refresh kind. # Examples ``` use sysinfo::RefreshKind; let r = RefreshKind::new(); assert_eq!(r.", stringify!($name), "(), false); let r = r.with_", stringify!($name), "(); assert_eq!(r.", stringify!($name), "(), true); ```"), pub fn $name(&self) -> bool { self.$name } } doc_comment! { concat!("Sets the value of the \"", stringify!($name), "\" refresh kind to `true`. # Examples ``` use sysinfo::RefreshKind; let r = RefreshKind::new(); assert_eq!(r.", stringify!($name), "(), false); let r = r.with_", stringify!($name), "(); assert_eq!(r.", stringify!($name), "(), true); ```"), pub fn $with(mut self) -> RefreshKind { self.$name = true; self } } doc_comment! { concat!("Sets the value of the \"", stringify!($name), "\" refresh kind to `false`. # Examples ``` use sysinfo::RefreshKind; let r = RefreshKind::everything(); assert_eq!(r.", stringify!($name), "(), true); let r = r.without_", stringify!($name), "(); assert_eq!(r.", stringify!($name), "(), false); ```"), pub fn $without(mut self) -> RefreshKind { self.$name = false; self } } } } /// Used to determine what you want to refresh specifically on [`System`] type. /// /// # Example /// /// ``` /// use sysinfo::{RefreshKind, System, SystemExt}; /// /// // We want everything except disks. /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disk_list()); /// /// assert_eq!(system.get_disks().len(), 0); /// assert!(system.get_process_list().len() > 0); /// ``` #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct RefreshKind { system: bool, network: bool, processes: bool, disk_list: bool, disks: bool, } impl RefreshKind { /// Creates a new `RefreshKind` with every refresh set to `false`. /// /// # Examples /// /// ``` /// use sysinfo::RefreshKind; /// /// let r = RefreshKind::new(); /// /// assert_eq!(r.system(), false); /// assert_eq!(r.network(), false); /// assert_eq!(r.processes(), false); /// assert_eq!(r.disk_list(), false); /// assert_eq!(r.disks(), false); /// ``` pub fn new() -> RefreshKind { RefreshKind { system: false, network: false, processes: false, disks: false, disk_list: false, } } /// Creates a new `RefreshKind` with every refresh set to `true`. /// /// # Examples /// /// ``` /// use sysinfo::RefreshKind; /// /// let r = RefreshKind::everything(); /// /// assert_eq!(r.system(), true); /// assert_eq!(r.network(), true); /// assert_eq!(r.processes(), true); /// assert_eq!(r.disk_list(), true); /// assert_eq!(r.disks(), true); /// ``` pub fn everything() -> RefreshKind { RefreshKind { system: true, network: true, processes: true, disks: true, disk_list: true, } } impl_get_set!(system, with_system, without_system); impl_get_set!(network, with_network, without_network); impl_get_set!(processes, with_processes, without_processes); impl_get_set!(disks, with_disks, without_disks); impl_get_set!(disk_list, with_disk_list, without_disk_list); } sysinfo-0.9.5/src/component.rs010064400007650000024000000011331333211327500145730ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use std::fmt::{Debug, Error, Formatter}; use sys::Component; use traits::ComponentExt; impl Debug for Component { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { if let Some(critical) = self.get_critical() { write!(f, "{}: {}°C (max: {}°C / critical: {}°C)", self.get_label(), self.get_temperature(), self.get_max(), critical) } else { write!(f, "{}: {}°C (max: {}°C)", self.get_label(), self.get_temperature(), self.get_max()) } } } sysinfo-0.9.5/src/linux/component.rs010064400007650000024000000124211333211327500157340ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use ComponentExt; use std::collections::HashMap; use std::ffi::OsStr; use std::fs::{File, read_dir}; use std::io::Read; use std::path::{Path, PathBuf}; /// More information can be found at /// pub struct Component { temperature: f32, max: f32, critical: Option, label: String, input_file: PathBuf, } fn get_file_line(file: &Path) -> Option { let mut reader = String::new(); if let Ok(mut f) = File::open(file) { if f.read_to_string(&mut reader).is_ok() { Some(reader) } else { None } } else { None } } fn append_files(components: &mut Vec, folder: &Path) { let mut matchings = HashMap::new(); if let Ok(dir) = read_dir(folder) { for entry in dir { if let Ok(entry) = entry { let entry = entry.path(); if entry.is_dir() || !entry.file_name().unwrap_or_else(|| OsStr::new("/")).to_str() .unwrap_or("").starts_with("temp") { continue; } if let Some(entry) = entry.file_name() { if let Some(entry) = entry.to_str() { if let Ok(id) = entry[4..5].parse::() { matchings.entry(id) .or_insert_with(|| Vec::with_capacity(1)) .push(entry[6..].to_owned()); } } } } } for (key, val) in &matchings { let mut found_input = None; let mut found_label = None; for (pos, v) in val.iter().enumerate() { match v.as_str() { "input" => { found_input = Some(pos); } "label" => { found_label = Some(pos); } _ => {} } if found_label.is_some() && found_input.is_some() { let mut p_label = folder.to_path_buf(); let mut p_input = folder.to_path_buf(); let mut p_crit = folder.to_path_buf(); let mut p_max = folder.to_path_buf(); p_label.push(&format!("temp{}_label", key)); p_input.push(&format!("temp{}_input", key)); p_max.push(&format!("temp{}_max", key)); p_crit.push(&format!("temp{}_crit", key)); if let Some(content) = get_file_line(p_label.as_path()) { let label = content.replace("\n", ""); let max = if let Some(max) = get_file_line(p_max.as_path()) { Some(max.replace("\n", "") .parse::().unwrap_or(100_000f32) / 1000f32) } else { None }; let crit = if let Some(crit) = get_file_line(p_crit.as_path()) { Some(crit.replace("\n", "") .parse::().unwrap_or(100_000f32) / 1000f32) } else { None }; components.push(Component::new(label, p_input.as_path(), max, crit)); break } } } } } } impl Component { /// Creates a new component with the given information. pub fn new(label: String, input_path: &Path, max: Option, critical: Option) -> Component { let mut c = Component { temperature: 0f32, label, input_file: input_path.to_path_buf(), max: max.unwrap_or(0.0), critical, }; c.update(); c } /// Updates the component. pub fn update(&mut self) { if let Some(content) = get_file_line(self.input_file.as_path()) { self.temperature = content.replace("\n", "") .parse::().unwrap_or(100_000f32) / 1000f32; if self.temperature > self.max { self.max = self.temperature; } } } } impl ComponentExt for Component { fn get_temperature(&self) -> f32 { self.temperature } fn get_max(&self) -> f32 { self.max } fn get_critical(&self) -> Option { self.critical } fn get_label(&self) -> &str { &self.label } } pub fn get_components() -> Vec { let mut ret = Vec::new(); if let Ok(dir) = read_dir(&Path::new("/sys/class/hwmon/")) { for entry in dir { if let Ok(entry) = entry { let entry = entry.path(); if !entry.is_dir() || !entry.file_name().unwrap_or_else(|| OsStr::new("/")).to_str() .unwrap_or("").starts_with("hwmon") { continue; } append_files(&mut ret, &entry); } } } ret.sort_by(|c1, c2| c1.label.to_lowercase().cmp(&c2.label.to_lowercase())); ret } sysinfo-0.9.5/src/linux/disk.rs010064400007650000024000000067771343553233600147140ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use ::DiskExt; use ::utils; use super::system::get_all_data; use libc::statvfs; use std::mem; use std::fmt::{Debug, Error, Formatter}; use std::path::{Path, PathBuf}; use std::ffi::{OsStr, OsString}; use std::os::unix::ffi::OsStrExt; /// Enum containing the different handled disks types. #[derive(Debug, PartialEq, Clone, Copy)] pub enum DiskType { /// HDD type. HDD, /// SSD type. SSD, /// Unknown type. Unknown(isize), } impl From for DiskType { fn from(t: isize) -> DiskType { match t { 0 => DiskType::SSD, 1 => DiskType::HDD, id => DiskType::Unknown(id), } } } fn find_type_for_name(name: &OsStr) -> DiskType { /* turn "sda1" into "sda": */ let mut trimmed: &[u8] = name.as_bytes(); while trimmed.len() > 1 && trimmed[trimmed.len()-1] >= b'0' && trimmed[trimmed.len()-1] <= b'9' { trimmed = &trimmed[..trimmed.len()-1] } let trimmed: &OsStr = OsStrExt::from_bytes(trimmed); let path = Path::new("/sys/block/").to_owned() .join(trimmed) .join("queue/rotational"); let rotational_int = get_all_data(path).unwrap_or_default().trim().parse(); DiskType::from(rotational_int.unwrap_or(-1)) } macro_rules! cast { ($x:expr) => { u64::from($x) } } pub fn new(name: &OsStr, mount_point: &Path, file_system: &[u8]) -> Disk { let mount_point_cpath = utils::to_cpath(mount_point); let type_ = find_type_for_name(name); let mut total = 0; let mut available = 0; unsafe { let mut stat: statvfs = mem::zeroed(); if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 { total = cast!(stat.f_bsize) * cast!(stat.f_blocks); available = cast!(stat.f_bsize) * cast!(stat.f_bavail); } } Disk { type_, name: name.to_owned(), file_system: file_system.to_owned(), mount_point: mount_point.to_owned(), total_space: cast!(total), available_space: cast!(available), } } /// Struct containing a disk information. pub struct Disk { type_: DiskType, name: OsString, file_system: Vec, mount_point: PathBuf, total_space: u64, available_space: u64, } impl Debug for Disk { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { write!(fmt, "Disk({:?})[FS: {:?}][Type: {:?}] mounted on {:?}: {}/{} B", self.get_name(), self.get_file_system(), self.get_type(), self.get_mount_point(), self.get_available_space(), self.get_total_space()) } } impl DiskExt for Disk { fn get_type(&self) -> DiskType { self.type_ } fn get_name(&self) -> &OsStr { &self.name } fn get_file_system(&self) -> &[u8] { &self.file_system } fn get_mount_point(&self) -> &Path { &self.mount_point } fn get_total_space(&self) -> u64 { self.total_space } fn get_available_space(&self) -> u64 { self.available_space } fn update(&mut self) -> bool { unsafe { let mut stat: statvfs = mem::zeroed(); let mount_point_cpath = utils::to_cpath(&self.mount_point); if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 { let tmp = cast!(stat.f_bsize) * cast!(stat.f_bavail); self.available_space = cast!(tmp); true } else { false } } } } sysinfo-0.9.5/src/linux/mod.rs010064400007650000024000000006051343553233600145210ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // pub mod component; pub mod disk; pub mod network; pub mod process; pub mod processor; pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; sysinfo-0.9.5/src/linux/network.rs010064400007650000024000000036631333211327500154330ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use std::fs::File; use std::io::{Error, ErrorKind, Read}; use NetworkExt; /// Contains network information. #[derive(Debug)] pub struct NetworkData { old_in: u64, old_out: u64, current_in: u64, current_out: u64, } impl NetworkExt for NetworkData { fn get_income(&self) -> u64 { self.current_in - self.old_in } fn get_outcome(&self) -> u64 { self.current_out - self.old_out } } pub fn new() -> NetworkData { NetworkData { old_in: 0, old_out: 0, current_in: 0, current_out: 0, } } fn read_things() -> Result<(u64, u64), Error> { fn read_interface_stat(iface: &str, typ: &str) -> Result { let mut file = File::open(format!("/sys/class/net/{}/statistics/{}_bytes", iface, typ))?; let mut content = String::new(); file.read_to_string(&mut content)?; content.trim() .parse() .map_err(|_| Error::new(ErrorKind::Other, "Failed to parse network stat")) } let default_interface = { let mut file = File::open("/proc/net/route")?; let mut content = String::new(); file.read_to_string(&mut content)?; content.lines() .filter(|l| l.split_whitespace().nth(2).map(|l| l != "00000000").unwrap_or(false)) .last() .and_then(|l| l.split_whitespace().nth(0)) .ok_or_else(|| Error::new(ErrorKind::Other, "Default device not found"))? .to_owned() }; Ok((read_interface_stat(&default_interface, "rx")?, read_interface_stat(&default_interface, "tx")?)) } pub fn update_network(n: &mut NetworkData) { if let Ok((new_in, new_out)) = read_things() { n.old_in = n.current_in; n.old_out = n.current_out; n.current_in = new_in; n.current_out = new_out; } // TODO: maybe handle error here? } sysinfo-0.9.5/src/linux/process.rs010064400007650000024000000145221335146546600154310ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use std::collections::HashMap; use std::fmt::{self, Formatter, Debug}; use std::path::{Path, PathBuf}; use libc::{c_int, gid_t, kill, uid_t}; use Pid; use ::ProcessExt; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] pub enum ProcessStatus { /// Waiting in uninterruptible disk sleep. Idle, /// Running. Run, /// Sleeping in an interruptible waiting. Sleep, /// Stopped (on a signal) or (before Linux 2.6.33) trace stopped. Stop, /// Zombie. Zombie, /// Tracing stop (Linux 2.6.33 onward). Tracing, /// Dead. Dead, /// Wakekill (Linux 2.6.33 to 3.13 only). Wakekill, /// Waking (Linux 2.6.33 to 3.13 only). Waking, /// Parked (Linux 3.9 to 3.13 only). Parked, /// Unknown. Unknown(u32), } impl From for ProcessStatus { fn from(status: u32) -> ProcessStatus { match status { 1 => ProcessStatus::Idle, 2 => ProcessStatus::Run, 3 => ProcessStatus::Sleep, 4 => ProcessStatus::Stop, 5 => ProcessStatus::Zombie, x => ProcessStatus::Unknown(x), } } } impl From for ProcessStatus { fn from(status: char) -> ProcessStatus { match status { 'R' => ProcessStatus::Run, 'S' => ProcessStatus::Sleep, 'D' => ProcessStatus::Idle, 'Z' => ProcessStatus::Zombie, 'T' => ProcessStatus::Stop, 't' => ProcessStatus::Tracing, 'X' | 'x' => ProcessStatus::Dead, 'K' => ProcessStatus::Wakekill, 'W' => ProcessStatus::Waking, 'P' => ProcessStatus::Parked, x => ProcessStatus::Unknown(x as u32), } } } impl ProcessStatus { /// Used to display `ProcessStatus`. pub fn to_string(&self) -> &str { match *self { ProcessStatus::Idle => "Idle", ProcessStatus::Run => "Runnable", ProcessStatus::Sleep => "Sleeping", ProcessStatus::Stop => "Stopped", ProcessStatus::Zombie => "Zombie", ProcessStatus::Tracing => "Tracing", ProcessStatus::Dead => "Dead", ProcessStatus::Wakekill => "Wakekill", ProcessStatus::Waking => "Waking", ProcessStatus::Parked => "Parked", ProcessStatus::Unknown(_) => "Unknown", } } } impl fmt::Display for ProcessStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_string()) } } /// Struct containing a process' information. #[derive(Clone)] pub struct Process { pub(crate) name: String, pub(crate) cmd: Vec, pub(crate) exe: PathBuf, pub(crate) pid: Pid, parent: Option, pub(crate) environ: Vec, pub(crate) cwd: PathBuf, pub(crate) root: PathBuf, pub(crate) memory: u64, utime: u64, stime: u64, old_utime: u64, old_stime: u64, start_time: u64, updated: bool, cpu_usage: f32, /// User id of the process owner. pub uid: uid_t, /// Group id of the process owner. pub gid: gid_t, pub(crate) status: ProcessStatus, /// Tasks run by this process. pub tasks: HashMap, } impl ProcessExt for Process { fn new(pid: Pid, parent: Option, start_time: u64) -> Process { Process { name: String::new(), pid, parent, cmd: Vec::new(), environ: Vec::new(), exe: PathBuf::new(), cwd: PathBuf::new(), root: PathBuf::new(), memory: 0, cpu_usage: 0., utime: 0, stime: 0, old_utime: 0, old_stime: 0, updated: true, start_time, uid: 0, gid: 0, status: ProcessStatus::Unknown(0), tasks: HashMap::new(), } } fn kill(&self, signal: ::Signal) -> bool { unsafe { kill(self.pid, signal as c_int) == 0 } } fn name(&self) -> &str { &self.name } fn cmd(&self) -> &[String] { &self.cmd } fn exe(&self) -> &Path { self.exe.as_path() } fn pid(&self) -> Pid { self.pid } fn environ(&self) -> &[String] { &self.environ } fn cwd(&self) -> &Path { self.cwd.as_path() } fn root(&self) -> &Path { self.root.as_path() } fn memory(&self) -> u64 { self.memory } fn parent(&self) -> Option { self.parent } /// Returns the status of the processus (idle, run, zombie, etc). `None` means that /// `sysinfo` doesn't have enough rights to get this information. fn status(&self) -> ProcessStatus { self.status } fn start_time(&self) -> u64 { self.start_time } fn cpu_usage(&self) -> f32 { self.cpu_usage } } #[allow(unused_must_use)] impl Debug for Process { fn fmt(&self, f: &mut Formatter) -> fmt::Result { writeln!(f, "pid: {}", self.pid); writeln!(f, "parent: {:?}", self.parent); writeln!(f, "name: {}", self.name); writeln!(f, "environment:"); for var in &self.environ { if !var.is_empty() { writeln!(f, "\t{}", var); } } writeln!(f, "command:"); for arg in &self.cmd { writeln!(f, "\t{}", arg); } writeln!(f, "executable path: {:?}", self.exe); writeln!(f, "current working directory: {:?}", self.cwd); writeln!(f, "owner/group: {}:{}", self.uid, self.gid); writeln!(f, "memory usage: {} kB", self.memory); writeln!(f, "cpu usage: {}%", self.cpu_usage); writeln!(f, "status: {}", self.status); write!(f, "root path: {:?}", self.root) } } pub fn compute_cpu_usage(p: &mut Process, nb_processors: u64, total_time: f32) { p.cpu_usage = ((p.utime - p.old_utime + p.stime - p.old_stime) * nb_processors * 100) as f32 / total_time; p.updated = false; } pub fn set_time(p: &mut Process, utime: u64, stime: u64) { p.old_utime = p.utime; p.old_stime = p.stime; p.utime = utime; p.stime = stime; p.updated = true; } pub fn has_been_updated(p: &Process) -> bool { p.updated } sysinfo-0.9.5/src/linux/processor.rs010064400007650000024000000120671343553233600157660ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // #![allow(clippy::too_many_arguments)] use ::ProcessorExt; /// Struct containing values to compute a CPU usage. #[derive(Clone, Copy)] pub struct CpuValues { user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64, } impl CpuValues { /// Creates a new instance of `CpuValues` with everything set to `0`. pub fn new() -> CpuValues { CpuValues { user: 0, nice: 0, system: 0, idle: 0, iowait: 0, irq: 0, softirq: 0, steal: 0, guest: 0, guest_nice: 0, } } /// Creates a new instance of `CpuValues` with everything set to the corresponding argument. pub fn new_with_values(user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64) -> CpuValues { CpuValues { user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice, } } /*pub fn is_zero(&self) -> bool { self.user == 0 && self.nice == 0 && self.system == 0 && self.idle == 0 && self.iowait == 0 && self.irq == 0 && self.softirq == 0 && self.steal == 0 && self.guest == 0 && self.guest_nice == 0 }*/ /// Sets the given argument to the corresponding fields. pub fn set(&mut self, user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64) { self.user = user; self.nice = nice; self.system = system; self.idle = idle; self.iowait = iowait; self.irq = irq; self.softirq = softirq; self.steal = steal; self.guest = guest; self.guest_nice = guest_nice; } /// Returns work time. pub fn work_time(&self) -> u64 { self.user + self.nice + self.system } /// Returns total time. pub fn total_time(&self) -> u64 { self.work_time() + self.idle + self.iowait + self.irq + self.softirq + self.steal + self.guest + self.guest_nice } } /// Struct containing a processor information. pub struct Processor { old_values: CpuValues, new_values: CpuValues, name: String, cpu_usage: f32, total_time: u64, old_total_time: u64, } impl Processor { #[allow(dead_code)] fn new() -> Processor { Processor { name: String::new(), old_values: CpuValues::new(), new_values: CpuValues::new(), cpu_usage: 0f32, total_time: 0, old_total_time: 0, } } fn new_with_values(name: &str, user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64) -> Processor { Processor { name: name.to_owned(), old_values: CpuValues::new(), new_values: CpuValues::new_with_values(user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice), cpu_usage: 0f32, total_time: 0, old_total_time: 0, } } fn set(&mut self, user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64) { fn min(a: u64, b: u64) -> f32 { (if a == b { 1 } else if a > b { a - b } else { b - a }) as f32 } //if !self.new_values.is_zero() { self.old_values = self.new_values; //} self.new_values.set(user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice); self.cpu_usage = min(self.new_values.work_time(), self.old_values.work_time()) / min(self.new_values.total_time(), self.old_values.total_time()); self.old_total_time = self.old_values.total_time(); self.total_time = self.new_values.total_time(); } } impl ProcessorExt for Processor { fn get_cpu_usage(&self) -> f32 { self.cpu_usage } fn get_name(&self) -> &str { &self.name } } pub fn new_processor(name: &str, user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64) -> Processor { Processor::new_with_values(name, user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice) } pub fn set_processor(p: &mut Processor, user: u64, nice: u64, system: u64, idle: u64, iowait: u64, irq: u64, softirq: u64, steal: u64, guest: u64, guest_nice: u64) { p.set(user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice) } pub fn get_raw_times(p: &Processor) -> (u64, u64) { (p.new_values.total_time(), p.old_values.total_time()) } sysinfo-0.9.5/src/linux/system.rs010064400007650000024000000465541353425133300152760ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use sys::component::{self, Component}; use sys::processor::*; use sys::process::*; use sys::Disk; use sys::disk; use sys::network; use sys::NetworkData; use ::{DiskExt, ProcessExt, RefreshKind, SystemExt}; use Pid; use std::cell::UnsafeCell; use std::collections::HashMap; use std::fs::{self, File, read_link}; use std::io::{self, BufRead, BufReader, Read}; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::time::SystemTime; use libc::{uid_t, sysconf, _SC_CLK_TCK, _SC_PAGESIZE}; use utils::realpath; use rayon::prelude::*; macro_rules! to_str { ($e:expr) => { unsafe { ::std::str::from_utf8_unchecked($e) } } } /// Structs containing system's information. #[derive(Debug)] pub struct System { process_list: Process, mem_total: u64, mem_free: u64, swap_total: u64, swap_free: u64, processors: Vec, page_size_kb: u64, temperatures: Vec, disks: Vec, network: NetworkData, uptime: u64, } impl System { fn clear_procs(&mut self) { if !self.processors.is_empty() { let (new, old) = get_raw_times(&self.processors[0]); let total_time = (if old > new { 1 } else { new - old }) as f32; let mut to_delete = Vec::new(); let nb_processors = self.processors.len() as u64 - 1; for (pid, proc_) in &mut self.process_list.tasks { if !has_been_updated(proc_) { to_delete.push(*pid); } else { compute_cpu_usage(proc_, nb_processors, total_time); } } for pid in to_delete { self.process_list.tasks.remove(&pid); } } } fn refresh_processors(&mut self, limit: Option) { if let Ok(f) = File::open("/proc/stat") { let buf = BufReader::new(f); let mut i = 0; let first = self.processors.is_empty(); let mut it = buf.split(b'\n'); let mut count = 0; while let Some(Ok(line)) = it.next() { if &line[..3] != b"cpu" { break; } count += 1; let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); if first { self.processors.push(new_processor( to_str!(parts.next().unwrap_or(&[])), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0))); } else { parts.next(); // we don't want the name again set_processor(&mut self.processors[i], parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0), parts.next().map(|v| {to_u64(v)}).unwrap_or(0)); i += 1; } if let Some(limit) = limit { if count >= limit { break; } } } } } } impl SystemExt for System { fn new_with_specifics(refreshes: RefreshKind) -> System { let mut s = System { process_list: Process::new(0, None, 0), mem_total: 0, mem_free: 0, swap_total: 0, swap_free: 0, processors: Vec::new(), page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 }, temperatures: component::get_components(), disks: Vec::new(), network: network::new(), uptime: get_uptime(), }; s.refresh_specifics(refreshes); s } fn refresh_system(&mut self) { self.uptime = get_uptime(); for component in &mut self.temperatures { component.update(); } if let Ok(data) = get_all_data("/proc/meminfo") { for line in data.split('\n') { let field = match line.split(':').next() { Some("MemTotal") => &mut self.mem_total, Some("MemAvailable") | Some("MemFree") => &mut self.mem_free, Some("SwapTotal") => &mut self.swap_total, Some("SwapFree") => &mut self.swap_free, _ => continue, }; if let Some(val_str) = line.rsplit(' ').nth(1) { if let Ok(value) = u64::from_str(val_str) { *field = value; } } } } self.refresh_processors(None); } fn refresh_processes(&mut self) { self.uptime = get_uptime(); if refresh_procs(&mut self.process_list, "/proc", self.page_size_kb, 0, self.uptime, get_secs_since_epoch()) { self.clear_procs(); } } fn refresh_process(&mut self, pid: Pid) -> bool { self.uptime = get_uptime(); let found = match _get_process_data(&Path::new("/proc/").join(pid.to_string()), &mut self.process_list, self.page_size_kb, 0, self.uptime, get_secs_since_epoch()) { Ok(Some(p)) => { self.process_list.tasks.insert(p.pid(), p); false } Ok(_) => true, Err(_) => false, }; if found && !self.processors.is_empty() { self.refresh_processors(Some(1)); let (new, old) = get_raw_times(&self.processors[0]); let total_time = (if old > new { 1 } else { new - old }) as f32; let nb_processors = self.processors.len() as u64 - 1; if let Some(p) = self.process_list.tasks.get_mut(&pid) { compute_cpu_usage(p, nb_processors, total_time); } } found } fn refresh_disks(&mut self) { for disk in &mut self.disks { disk.update(); } } fn refresh_disk_list(&mut self) { self.disks = get_all_disks(); } fn refresh_network(&mut self) { network::update_network(&mut self.network); } // COMMON PART // // Need to be moved into a "common" file to avoid duplication. fn get_process_list(&self) -> &HashMap { &self.process_list.tasks } fn get_process(&self, pid: Pid) -> Option<&Process> { self.process_list.tasks.get(&pid) } fn get_network(&self) -> &NetworkData { &self.network } fn get_processor_list(&self) -> &[Processor] { &self.processors[..] } fn get_total_memory(&self) -> u64 { self.mem_total } fn get_free_memory(&self) -> u64 { self.mem_free } fn get_used_memory(&self) -> u64 { self.mem_total - self.mem_free } fn get_total_swap(&self) -> u64 { self.swap_total } fn get_free_swap(&self) -> u64 { self.swap_free } // need to be checked fn get_used_swap(&self) -> u64 { self.swap_total - self.swap_free } fn get_components_list(&self) -> &[Component] { &self.temperatures[..] } fn get_disks(&self) -> &[Disk] { &self.disks[..] } fn get_uptime(&self) -> u64 { self.uptime } } impl Default for System { fn default() -> System { System::new() } } pub fn get_all_data>(file_path: P) -> io::Result { use std::error::Error; let mut file = File::open(file_path.as_ref())?; let mut data = vec![0; 16_385]; let size = file.read(&mut data)?; data.truncate(size); let data = String::from_utf8(data).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.description()))?; Ok(data) } fn to_u64(v: &[u8]) -> u64 { let mut x = 0; for c in v { x *= 10; x += u64::from(c - b'0'); } x } struct Wrap<'a>(UnsafeCell<&'a mut Process>); impl<'a> Wrap<'a> { fn get(&self) -> &'a mut Process { unsafe { *(self.0.get()) } } } unsafe impl<'a> Send for Wrap<'a> {} unsafe impl<'a> Sync for Wrap<'a> {} fn refresh_procs>( proc_list: &mut Process, path: P, page_size_kb: u64, pid: Pid, uptime: u64, now: u64, ) -> bool { if let Ok(d) = fs::read_dir(path.as_ref()) { let folders = d.filter_map(|entry| { if let Ok(entry) = entry { let entry = entry.path(); if entry.is_dir() { Some(entry) } else { None } } else { None } }).collect::>(); if pid == 0 { let proc_list = Wrap(UnsafeCell::new(proc_list)); folders.par_iter() .filter_map(|e| { if let Ok(p) = _get_process_data(e.as_path(), proc_list.get(), page_size_kb, pid, uptime, now) { p } else { None } }) .collect::>() } else { folders.iter() .filter_map(|e| { if let Ok(p) = _get_process_data(e.as_path(), proc_list, page_size_kb, pid, uptime, now) { p } else { None } }) .collect::>() }.into_iter().for_each(|e| { proc_list.tasks.insert(e.pid(), e); }); true } else { false } } fn update_time_and_memory( path: &Path, entry: &mut Process, parts: &[&str], page_size_kb: u64, parent_memory: u64, pid: Pid, uptime: u64, now: u64, ) { // we get the rss { entry.memory = u64::from_str(parts[23]).unwrap_or(0) * page_size_kb; if entry.memory >= parent_memory { entry.memory -= parent_memory; } set_time(entry, u64::from_str(parts[13]).unwrap_or(0), u64::from_str(parts[14]).unwrap_or(0)); } refresh_procs(entry, path.join(Path::new("task")), page_size_kb, pid, uptime, now); } macro_rules! unwrap_or_return { ($data:expr) => {{ match $data { Some(x) => x, None => return Err(()), } }} } fn _get_process_data( path: &Path, proc_list: &mut Process, page_size_kb: u64, pid: Pid, uptime: u64, now: u64, ) -> Result, ()> { if let Some(Ok(nb)) = path.file_name().and_then(|x| x.to_str()).map(Pid::from_str) { if nb == pid { return Err(()); } let mut tmp = PathBuf::from(path); tmp.push("stat"); if let Ok(data) = get_all_data(&tmp) { // The stat file is "interesting" to parse, because spaces cannot // be used as delimiters. The second field stores the command name // sourrounded by parentheses. Unfortunately, whitespace and // parentheses are legal parts of the command, so parsing has to // proceed like this: The first field is delimited by the first // whitespace, the second field is everything until the last ')' // in the entire string. All other fields are delimited by // whitespace. let mut parts = Vec::new(); let mut data_it = data.splitn(2, ' '); parts.push(unwrap_or_return!(data_it.next())); // The following loses the ) from the input, but that's ok because // we're not using it anyway. let mut data_it = unwrap_or_return!(data_it.next()).rsplitn(2, ')'); let data = unwrap_or_return!(data_it.next()); parts.push(unwrap_or_return!(data_it.next())); parts.extend(data.split_whitespace()); let parent_memory = proc_list.memory; if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) { update_time_and_memory(path, entry, &parts, page_size_kb, parent_memory, nb, uptime, now); return Ok(None); } let parent_pid = if proc_list.pid != 0 { Some(proc_list.pid) } else { match Pid::from_str(parts[3]) { Ok(p) if p != 0 => Some(p), _ => None, } }; let clock_cycle = unsafe { sysconf(_SC_CLK_TCK) } as u64; let since_boot = u64::from_str(parts[21]).unwrap_or(0) / clock_cycle; let start_time = now.checked_sub( uptime.checked_sub(since_boot).unwrap_or_else(|| 0), ).unwrap_or_else(|| 0); let mut p = Process::new(nb, parent_pid, start_time); p.status = parts[2].chars() .next() .and_then(|c| Some(ProcessStatus::from(c))) .unwrap_or(ProcessStatus::Unknown(0)); tmp = PathBuf::from(path); tmp.push("status"); if let Ok(status_data) = get_all_data(&tmp) { // We're only interested in the lines starting with Uid: and Gid: // here. From these lines, we're looking at the second entry to get // the effective u/gid. let f = |h: &str, n: &str| -> Option { if h.starts_with(n) { h.split_whitespace().nth(2).unwrap_or("0").parse().ok() } else { None } }; let mut set_uid = false; let mut set_gid = false; for line in status_data.lines() { if let Some(u) = f(line, "Uid:") { assert!(!set_uid); set_uid = true; p.uid = u; } if let Some(g) = f(line, "Gid:") { assert!(!set_gid); set_gid = true; p.gid = g; } } assert!(set_uid && set_gid); } if proc_list.pid != 0 { // If we're getting information for a child, no need to get those info since we // already have them... p.cmd = proc_list.cmd.clone(); p.name = proc_list.name.clone(); p.environ = proc_list.environ.clone(); p.exe = proc_list.exe.clone(); p.cwd = proc_list.cwd.clone(); p.root = proc_list.root.clone(); } else { tmp = PathBuf::from(path); tmp.push("cmdline"); p.cmd = copy_from_file(&tmp); p.name = p.cmd.get(0) .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned()) .unwrap_or_default(); tmp = PathBuf::from(path); tmp.push("environ"); p.environ = copy_from_file(&tmp); tmp = PathBuf::from(path); tmp.push("exe"); p.exe = read_link(tmp.to_str() .unwrap_or_else(|| "")).unwrap_or_else(|_| PathBuf::new()); tmp = PathBuf::from(path); tmp.push("cwd"); p.cwd = realpath(&tmp); tmp = PathBuf::from(path); tmp.push("root"); p.root = realpath(&tmp); } update_time_and_memory(path, &mut p, &parts, page_size_kb, proc_list.memory, nb, uptime, now); return Ok(Some(p)); } } Err(()) } fn copy_from_file(entry: &Path) -> Vec { match File::open(entry.to_str().unwrap_or("/")) { Ok(mut f) => { let mut data = vec![0; 16_384]; if let Ok(size) = f.read(&mut data) { data.truncate(size); data.split(|x| *x == b'\0') .filter_map(|x| ::std::str::from_utf8(x).map(|x| x.trim().to_owned()).ok()) .filter(|x| !x.is_empty()) .collect() } else { Vec::new() } } Err(_) => Vec::new(), } } fn get_all_disks() -> Vec { let content = get_all_data("/proc/mounts").unwrap_or_default(); let disks = content.lines() .filter(|line| { let line = line.trim_start(); // While the `sd` prefix is most common, some disks instead use the `nvme` prefix. This // prefix refers to NVM (non-volatile memory) cabale SSDs. These disks run on the NVMe // storage controller protocol (not the scsi protocol) and as a result use a different // prefix to support NVMe namespaces. // // In some other cases, it uses a device mapper to map physical block devices onto // higher-level virtual block devices (on `/dev/mapper`). line.starts_with("/dev/sd") || line.starts_with("/dev/nvme") || line.starts_with("/dev/mapper/") }); let mut ret = vec![]; for line in disks { let mut split = line.split(' '); if let (Some(name), Some(mountpt), Some(fs)) = (split.next(), split.next(), split.next()) { ret.push(disk::new(name[5..].as_ref(), Path::new(mountpt), fs.as_bytes())); } } ret } fn get_uptime() -> u64 { let content = get_all_data("/proc/uptime").unwrap_or_default(); u64::from_str_radix(content.split('.').next().unwrap_or_else(|| "0"), 10).unwrap_or_else(|_| 0) } fn get_secs_since_epoch() -> u64 { match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) { Ok(n) => n.as_secs(), Err(_) => panic!("SystemTime before UNIX EPOCH!"), } }sysinfo-0.9.5/src/mac/component.rs010064400007650000024000000020521333211327500153340ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use ComponentExt; /// Struct containing a component information (temperature and name for the moment). pub struct Component { temperature: f32, max: f32, critical: Option, label: String, } impl Component { /// Creates a new `Component` with the given information. pub fn new(label: String, max: Option, critical: Option) -> Component { Component { temperature: 0f32, label, max: max.unwrap_or(0.0), critical, } } } impl ComponentExt for Component { fn get_temperature(&self) -> f32 { self.temperature } fn get_max(&self) -> f32 { self.max } fn get_critical(&self) -> Option { self.critical } fn get_label(&self) -> &str { &self.label } } pub fn update_component(comp: &mut Component, temperature: f32) { comp.temperature = temperature; if comp.temperature > comp.max { comp.max = comp.temperature; } } sysinfo-0.9.5/src/mac/disk.rs010064400007650000024000000060111333211327500142630ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use ::DiskExt; use ::utils; use libc::statfs; use std::mem; use std::fmt::{Debug, Error, Formatter}; use std::path::{Path, PathBuf}; use std::ffi::{OsStr, OsString}; /// Enum containing the different handled disks types. #[derive(Debug, PartialEq, Clone, Copy)] pub enum DiskType { /// HDD type. HDD, /// SSD type. SSD, /// Unknown type. Unknown(isize), } impl From for DiskType { fn from(t: isize) -> DiskType { match t { 0 => DiskType::HDD, 1 => DiskType::SSD, id => DiskType::Unknown(id), } } } pub fn new(name: OsString, mount_point: &Path, type_: DiskType) -> Disk { let mount_point_cpath = utils::to_cpath(mount_point); let mut total_space = 0; let mut available_space = 0; let mut file_system = None; unsafe { let mut stat: statfs = mem::zeroed(); if statfs(mount_point_cpath.as_ptr() as *const i8, &mut stat) == 0 { total_space = u64::from(stat.f_bsize) * stat.f_blocks; available_space = stat.f_bfree * stat.f_blocks; let mut vec = Vec::with_capacity(stat.f_fstypename.len()); for x in &stat.f_fstypename { if *x == 0 { break } vec.push(*x as u8); } file_system = Some(vec); } } Disk { type_, name, file_system: file_system.unwrap_or_else(|| b"".to_vec()), mount_point: mount_point.to_owned(), total_space, available_space, } } /// Struct containing a disk information. pub struct Disk { type_: DiskType, name: OsString, file_system: Vec, mount_point: PathBuf, total_space: u64, available_space: u64, } impl Debug for Disk { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { write!(fmt, "Disk({:?})[FS: {:?}][Type: {:?}] mounted on {:?}: {}/{} B", self.get_name(), self.get_file_system(), self.get_type(), self.get_mount_point(), self.get_available_space(), self.get_total_space()) } } impl DiskExt for Disk { fn get_type(&self) -> DiskType { self.type_ } fn get_name(&self) -> &OsStr { &self.name } fn get_file_system(&self) -> &[u8] { &self.file_system } fn get_mount_point(&self) -> &Path { &self.mount_point } fn get_total_space(&self) -> u64 { self.total_space } fn get_available_space(&self) -> u64 { self.available_space } fn update(&mut self) -> bool { unsafe { let mut stat: statfs = mem::zeroed(); let mount_point_cpath = utils::to_cpath(&self.mount_point); if statfs(mount_point_cpath.as_ptr() as *const i8, &mut stat) == 0 { self.available_space = u64::from(stat.f_bsize) * stat.f_bavail; true } else { false } } } } sysinfo-0.9.5/src/mac/ffi.rs010064400007650000024000000261251350337531000141050ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use libc::{c_int, c_char, c_void, c_uchar, c_uint, size_t, c_ushort}; extern "C" { pub static kCFAllocatorDefault: CFAllocatorRef; pub fn proc_pidinfo(pid: c_int, flavor: c_int, arg: u64, buffer: *mut c_void, buffersize: c_int) -> c_int; pub fn proc_listallpids(buffer: *mut c_void, buffersize: c_int) -> c_int; //pub fn proc_name(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; //pub fn proc_regionfilename(pid: c_int, address: u64, buffer: *mut c_void, // buffersize: u32) -> c_int; //pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; pub fn IOMasterPort(a: i32, b: *mut mach_port_t) -> i32; pub fn IOServiceMatching(a: *const c_char) -> *mut c_void; pub fn IOServiceGetMatchingServices(a: mach_port_t, b: *mut c_void, c: *mut io_iterator_t) -> i32; pub fn IOIteratorNext(iterator: io_iterator_t) -> io_object_t; pub fn IOObjectRelease(obj: io_object_t) -> i32; pub fn IOServiceOpen(device: io_object_t, a: u32, t: u32, x: *mut io_connect_t) -> i32; pub fn IOServiceClose(a: io_connect_t) -> i32; pub fn IOConnectCallStructMethod(connection: mach_port_t, selector: u32, inputStruct: *mut KeyData_t, inputStructCnt: size_t, outputStruct: *mut KeyData_t, outputStructCnt: *mut size_t) -> i32; pub fn IORegistryEntryCreateCFProperties(entry: io_registry_entry_t, properties: *mut CFMutableDictionaryRef, allocator: CFAllocatorRef, options: IOOptionBits) -> kern_return_t; pub fn CFDictionaryContainsKey(d: CFDictionaryRef, key: *const c_void) -> Boolean; pub fn CFDictionaryGetValue(d: CFDictionaryRef, key: *const c_void) -> *const c_void; pub fn IORegistryEntryGetName(entry: io_registry_entry_t, name: *mut c_char) -> kern_return_t; pub fn CFRelease(cf: CFTypeRef); pub fn CFStringCreateWithCStringNoCopy(alloc: *mut c_void, cStr: *const c_char, encoding: CFStringEncoding, contentsDeallocator: *mut c_void) -> CFStringRef; pub static kCFAllocatorNull: CFAllocatorRef; pub fn mach_absolute_time() -> u64; //pub fn task_for_pid(host: u32, pid: pid_t, task: *mut task_t) -> u32; pub fn mach_task_self() -> u32; pub fn mach_host_self() -> u32; //pub fn task_info(host_info: u32, t: u32, c: *mut c_void, x: *mut u32) -> u32; pub fn host_statistics64(host_info: u32, x: u32, y: *mut c_void, z: *const u32) -> kern_return_t; pub fn host_processor_info(host_info: u32, t: u32, num_cpu_u: *mut u32, cpu_info: *mut *mut i32, num_cpu_info: *mut u32) -> kern_return_t; //pub fn host_statistics(host_priv: u32, flavor: u32, host_info: *mut c_void, // host_count: *const u32) -> u32; pub fn vm_deallocate(target_task: u32, address: *mut i32, size: u32) -> kern_return_t; // pub fn proc_pidpath(pid: i32, buf: *mut i8, bufsize: u32) -> i32; // pub fn proc_name(pid: i32, buf: *mut i8, bufsize: u32) -> i32; } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 macro_rules! cfg_if { ($( if #[cfg($($meta:meta),*)] { $($it:item)* } ) else * else { $($it2:item)* }) => { __cfg_if_items! { () ; $( ( ($($meta),*) ($($it)*) ), )* ( () ($($it2)*) ), } } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 macro_rules! __cfg_if_items { (($($not:meta,)*) ; ) => {}; (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 macro_rules! __cfg_if_apply { ($m:meta, $($it:item)*) => { $(#[$m] $it)* } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 cfg_if! { if #[cfg(any(target_arch = "arm", target_arch = "x86"))] { pub type timeval32 = ::libc::timeval; } else { use libc::timeval32; } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct if_data64 { pub ifi_type: c_uchar, pub ifi_typelen: c_uchar, pub ifi_physical: c_uchar, pub ifi_addrlen: c_uchar, pub ifi_hdrlen: c_uchar, pub ifi_recvquota: c_uchar, pub ifi_xmitquota: c_uchar, pub ifi_unused1: c_uchar, pub ifi_mtu: u32, pub ifi_metric: u32, pub ifi_baudrate: u64, pub ifi_ipackets: u64, pub ifi_ierrors: u64, pub ifi_opackets: u64, pub ifi_oerrors: u64, pub ifi_collisions: u64, pub ifi_ibytes: u64, pub ifi_obytes: u64, pub ifi_imcasts: u64, pub ifi_omcasts: u64, pub ifi_iqdrops: u64, pub ifi_noproto: u64, pub ifi_recvtiming: u32, pub ifi_xmittiming: u32, pub ifi_lastchange: timeval32, } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct if_msghdr2 { pub ifm_msglen: c_ushort, pub ifm_version: c_uchar, pub ifm_type: c_uchar, pub ifm_addrs: c_int, pub ifm_flags: c_int, pub ifm_index: c_ushort, pub ifm_snd_len: c_int, pub ifm_snd_maxlen: c_int, pub ifm_snd_drops: c_int, pub ifm_timer: c_int, pub ifm_data: if_data64, } #[cfg_attr(feature = "debug", derive(Debug))] #[repr(C)] pub struct __CFAllocator { __private: c_void, } #[cfg_attr(feature = "debug", derive(Debug))] #[repr(C)] pub struct __CFDictionary { __private: c_void, } #[cfg_attr(feature = "debug", derive(Debug))] #[repr(C)] pub struct __CFString { __private: c_void, } pub type CFAllocatorRef = *const __CFAllocator; pub type CFMutableDictionaryRef = *mut __CFDictionary; pub type CFDictionaryRef = *const __CFDictionary; #[allow(non_camel_case_types)] pub type io_name_t = [u8; 128]; #[allow(non_camel_case_types)] pub type io_registry_entry_t = io_object_t; pub type CFTypeRef = *const c_void; pub type CFStringRef = *const __CFString; //#[allow(non_camel_case_types)] //pub type policy_t = i32; #[allow(non_camel_case_types)] //pub type integer_t = i32; //#[allow(non_camel_case_types)] //pub type time_t = i64; //#[allow(non_camel_case_types)] //pub type suseconds_t = i32; //#[allow(non_camel_case_types)] //pub type mach_vm_size_t = u64; //#[allow(non_camel_case_types)] //pub type task_t = u32; //#[allow(non_camel_case_types)] //pub type pid_t = i32; #[allow(non_camel_case_types)] pub type natural_t = u32; #[allow(non_camel_case_types)] pub type mach_port_t = u32; #[allow(non_camel_case_types)] pub type io_object_t = mach_port_t; #[allow(non_camel_case_types)] pub type io_iterator_t = io_object_t; #[allow(non_camel_case_types)] pub type io_connect_t = io_object_t; #[allow(non_camel_case_types)] pub type boolean_t = c_uint; #[allow(non_camel_case_types)] pub type kern_return_t = c_int; pub type Boolean = c_uchar; pub type IOOptionBits = u32; pub type CFStringEncoding = u32; /*#[repr(C)] pub struct task_thread_times_info { pub user_time: time_value, pub system_time: time_value, }*/ /*#[repr(C)] pub struct task_basic_info_64 { pub suspend_count: integer_t, pub virtual_size: mach_vm_size_t, pub resident_size: mach_vm_size_t, pub user_time: time_value_t, pub system_time: time_value_t, pub policy: policy_t, }*/ #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct vm_statistics64 { pub free_count: natural_t, pub active_count: natural_t, pub inactive_count: natural_t, pub wire_count: natural_t, pub zero_fill_count: u64, pub reactivations: u64, pub pageins: u64, pub pageouts: u64, pub faults: u64, pub cow_faults: u64, pub lookups: u64, pub hits: u64, pub purges: u64, pub purgeable_count: natural_t, pub speculative_count: natural_t, pub decompressions: u64, pub compressions: u64, pub swapins: u64, pub swapouts: u64, pub compressor_page_count: natural_t, pub throttled_count: natural_t, pub external_page_count: natural_t, pub internal_page_count: natural_t, pub total_uncompressed_pages_in_compressor: u64, } #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct Val_t { pub key: [i8; 5], pub data_size: u32, pub data_type: [i8; 5], // UInt32Char_t pub bytes: [i8; 32], // SMCBytes_t } #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct KeyData_vers_t { pub major: u8, pub minor: u8, pub build: u8, pub reserved: [u8; 1], pub release: u16, } #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct KeyData_pLimitData_t { pub version: u16, pub length: u16, pub cpu_plimit: u32, pub gpu_plimit: u32, pub mem_plimit: u32, } #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct KeyData_keyInfo_t { pub data_size: u32, pub data_type: u32, pub data_attributes: u8, } #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct KeyData_t { pub key: u32, pub vers: KeyData_vers_t, pub p_limit_data: KeyData_pLimitData_t, pub key_info: KeyData_keyInfo_t, pub result: u8, pub status: u8, pub data8: u8, pub data32: u32, pub bytes: [i8; 32], // SMCBytes_t } #[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))] #[repr(C)] pub struct xsw_usage { pub xsu_total: u64, pub xsu_avail: u64, pub xsu_used: u64, pub xsu_pagesize: u32, pub xsu_encrypted: boolean_t, } //pub const HOST_CPU_LOAD_INFO_COUNT: usize = 4; //pub const HOST_CPU_LOAD_INFO: u32 = 3; pub const KERN_SUCCESS: kern_return_t = 0; pub const HW_NCPU: u32 = 3; pub const CTL_HW: u32 = 6; pub const CTL_VM: u32 = 2; pub const VM_SWAPUSAGE: u32 = 5; pub const PROCESSOR_CPU_LOAD_INFO: u32 = 2; pub const CPU_STATE_USER: u32 = 0; pub const CPU_STATE_SYSTEM: u32 = 1; pub const CPU_STATE_IDLE: u32 = 2; pub const CPU_STATE_NICE: u32 = 3; pub const CPU_STATE_MAX: usize = 4; pub const HW_MEMSIZE: u32 = 24; //pub const TASK_THREAD_TIMES_INFO: u32 = 3; //pub const TASK_THREAD_TIMES_INFO_COUNT: u32 = 4; //pub const TASK_BASIC_INFO_64: u32 = 5; //pub const TASK_BASIC_INFO_64_COUNT: u32 = 10; pub const HOST_VM_INFO64: u32 = 4; pub const HOST_VM_INFO64_COUNT: u32 = 38; pub const MACH_PORT_NULL: i32 = 0; pub const KERNEL_INDEX_SMC: i32 = 2; pub const SMC_CMD_READ_KEYINFO: u8 = 9; pub const SMC_CMD_READ_BYTES: u8 = 5; // pub const PROC_PIDPATHINFO_MAXSIZE: usize = 4096; pub const KIO_RETURN_SUCCESS: i32 = 0; #[allow(non_upper_case_globals)] pub const kCFStringEncodingMacRoman: CFStringEncoding = 0; sysinfo-0.9.5/src/mac/mod.rs010064400007650000024000000006151333211327500141140ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // pub mod component; pub mod disk; mod ffi; pub mod network; pub mod process; pub mod processor; pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process,ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; sysinfo-0.9.5/src/mac/network.rs010064400007650000024000000041641353517573300150450ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use libc::{self, c_char, CTL_NET, NET_RT_IFLIST2, PF_ROUTE, RTM_IFINFO2}; use std::ptr::null_mut; use sys::ffi; use NetworkExt; /// Contains network information. pub struct NetworkData { old_in: u64, old_out: u64, current_in: u64, current_out: u64, } impl NetworkExt for NetworkData { fn get_income(&self) -> u64 { self.current_in - self.old_in } fn get_outcome(&self) -> u64 { self.current_out - self.old_out } } pub fn new() -> NetworkData { NetworkData { old_in: 0, old_out: 0, current_in: 0, current_out: 0, } } #[allow(clippy::cast_ptr_alignment)] pub fn update_network(n: &mut NetworkData) { let mib = &mut [CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0]; let mut len = 0; if unsafe { libc::sysctl(mib.as_mut_ptr(), 6, null_mut(), &mut len, null_mut(), 0) } < 0 { // TODO: might be nice to put an error in here... return } let mut buf = Vec::with_capacity(len); unsafe { buf.set_len(len); if libc::sysctl(mib.as_mut_ptr(), 6, buf.as_mut_ptr(), &mut len, null_mut(), 0) < 0 { // TODO: might be nice to put an error in here... return } } let buf = buf.as_ptr() as *const c_char; let lim = unsafe { buf.add(len) }; let mut next = buf; let mut totalibytes = 0u64; let mut totalobytes = 0u64; while next < lim { unsafe { let ifm = next as *const libc::if_msghdr; next = next.offset((*ifm).ifm_msglen as isize); if (*ifm).ifm_type == RTM_IFINFO2 as u8 { let if2m: *const ffi::if_msghdr2 = ifm as *const ffi::if_msghdr2; totalibytes += (*if2m).ifm_data.ifi_ibytes; totalobytes += (*if2m).ifm_data.ifi_obytes; } } } n.old_in = if n.current_in > totalibytes { 0 } else { n.current_in }; n.current_in = totalibytes; n.old_out = if n.current_out > totalibytes { 0 } else { n.current_out }; n.current_out = totalobytes; } sysinfo-0.9.5/src/mac/process.rs010064400007650000024000000157441343701320700150240ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use std::fmt::{self, Formatter, Debug}; use std::path::{Path, PathBuf}; use libc::{c_int, gid_t, kill, uid_t}; use Pid; use ::ProcessExt; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] pub enum ProcessStatus { /// Process being created by fork. Idle, /// Currently runnable. Run, /// Sleeping on an address. Sleep, /// Process debugging or suspension. Stop, /// Awaiting collection by parent. Zombie, /// Unknown. Unknown(u32), } impl From for ProcessStatus { fn from(status: u32) -> ProcessStatus { match status { 1 => ProcessStatus::Idle, 2 => ProcessStatus::Run, 3 => ProcessStatus::Sleep, 4 => ProcessStatus::Stop, 5 => ProcessStatus::Zombie, x => ProcessStatus::Unknown(x), } } } impl ProcessStatus { /// Used to display `ProcessStatus`. pub fn to_string(&self) -> &str { match *self { ProcessStatus::Idle => "Idle", ProcessStatus::Run => "Runnable", ProcessStatus::Sleep => "Sleeping", ProcessStatus::Stop => "Stopped", ProcessStatus::Zombie => "Zombie", ProcessStatus::Unknown(_) => "Unknown", } } } impl fmt::Display for ProcessStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_string()) } } /// Enum describing the different status of a thread. #[derive(Clone, Debug)] pub enum ThreadStatus { /// Thread is running normally. Running, /// Thread is stopped. Stopped, /// Thread is waiting normally. Waiting, /// Thread is in an uninterruptible wait Uninterruptible, /// Thread is halted at a clean point. Halted, /// Unknown. Unknown(i32), } impl From for ThreadStatus { fn from(status: i32) -> ThreadStatus { match status { 1 => ThreadStatus::Running, 2 => ThreadStatus::Stopped, 3 => ThreadStatus::Waiting, 4 => ThreadStatus::Uninterruptible, 5 => ThreadStatus::Halted, x => ThreadStatus::Unknown(x), } } } impl ThreadStatus { /// Used to display `ThreadStatus`. pub fn to_string(&self) -> &str { match *self { ThreadStatus::Running => "Running", ThreadStatus::Stopped => "Stopped", ThreadStatus::Waiting => "Waiting", ThreadStatus::Uninterruptible => "Uninterruptible", ThreadStatus::Halted => "Halted", ThreadStatus::Unknown(_) => "Unknown", } } } impl fmt::Display for ThreadStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_string()) } } /// Struct containing a process' information. #[derive(Clone)] pub struct Process { pub(crate) name: String, pub(crate) cmd: Vec, pub(crate) exe: PathBuf, pid: Pid, parent: Option, pub(crate) environ: Vec, cwd: PathBuf, pub(crate) root: PathBuf, pub(crate) memory: u64, utime: u64, stime: u64, old_utime: u64, old_stime: u64, start_time: u64, updated: bool, cpu_usage: f32, /// User id of the process owner. pub uid: uid_t, /// Group id of the process owner. pub gid: gid_t, pub(crate) process_status: ProcessStatus, /// Status of process (running, stopped, waiting, etc). `None` means `sysinfo` doesn't have /// enough rights to get this information. /// /// This is very likely this one that you want instead of `process_status`. pub status: Option, } impl ProcessExt for Process { fn new(pid: Pid, parent: Option, start_time: u64) -> Process { Process { name: String::new(), pid, parent, cmd: Vec::new(), environ: Vec::new(), exe: PathBuf::new(), cwd: PathBuf::new(), root: PathBuf::new(), memory: 0, cpu_usage: 0., utime: 0, stime: 0, old_utime: 0, old_stime: 0, updated: true, start_time, uid: 0, gid: 0, process_status: ProcessStatus::Unknown(0), status: None, } } fn kill(&self, signal: ::Signal) -> bool { unsafe { kill(self.pid, signal as c_int) == 0 } } fn name(&self) -> &str { &self.name } fn cmd(&self) -> &[String] { &self.cmd } fn exe(&self) -> &Path { self.exe.as_path() } fn pid(&self) -> Pid { self.pid } fn environ(&self) -> &[String] { &self.environ } fn cwd(&self) -> &Path { self.cwd.as_path() } fn root(&self) -> &Path { self.root.as_path() } fn memory(&self) -> u64 { self.memory } fn parent(&self) -> Option { self.parent } fn status(&self) -> ProcessStatus { self.process_status } fn start_time(&self) -> u64 { self.start_time } fn cpu_usage(&self) -> f32 { self.cpu_usage } } #[allow(unused_must_use)] impl Debug for Process { fn fmt(&self, f: &mut Formatter) -> fmt::Result { writeln!(f, "pid: {}", self.pid); writeln!(f, "parent: {:?}", self.parent); writeln!(f, "name: {}", self.name); writeln!(f, "environment:"); for var in &self.environ { if !var.is_empty() { writeln!(f, "\t{}", var); } } writeln!(f, "command:"); for arg in &self.cmd { writeln!(f, "\t{}", arg); } writeln!(f, "executable path: {:?}", self.exe); writeln!(f, "current working directory: {:?}", self.cwd); writeln!(f, "owner/group: {}:{}", self.uid, self.gid); writeln!(f, "memory usage: {} kB", self.memory); writeln!(f, "cpu usage: {}%", self.cpu_usage); writeln!(f, "status: {}", match self.status { Some(ref v) => v.to_string(), None => "Unknown", }); write!(f, "root path: {:?}", self.root) } } pub fn compute_cpu_usage(p: &mut Process, time: u64, task_time: u64) { let system_time_delta = task_time - p.old_utime; let time_delta = time - p.old_stime; p.old_utime = task_time; p.old_stime = time; p.cpu_usage = if time_delta == 0 { 0f32 } else { (system_time_delta as f64 * 100f64 / time_delta as f64) as f32 }; p.updated = true; } /*pub fn set_time(p: &mut Process, utime: u64, stime: u64) { p.old_utime = p.utime; p.old_stime = p.stime; p.utime = utime; p.stime = stime; p.updated = true; }*/ pub fn has_been_updated(p: &mut Process) -> bool { let old = p.updated; p.updated = false; old } pub fn force_update(p: &mut Process) { p.updated = true; } sysinfo-0.9.5/src/mac/processor.rs010064400007650000024000000041401333211327500153510ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use std::ops::Deref; use std::sync::Arc; use sys::ffi; use ::ProcessorExt; pub struct UnsafePtr(*mut T); unsafe impl Send for UnsafePtr {} unsafe impl Sync for UnsafePtr {} impl Deref for UnsafePtr { type Target = *mut T; fn deref(&self) -> &*mut T { &self.0 } } pub struct ProcessorData { pub cpu_info: UnsafePtr, pub num_cpu_info: u32, } impl ProcessorData { pub fn new(cpu_info: *mut i32, num_cpu_info: u32) -> ProcessorData { ProcessorData { cpu_info: UnsafePtr(cpu_info), num_cpu_info, } } } impl Drop for ProcessorData { fn drop(&mut self) { if !self.cpu_info.0.is_null() { let prev_cpu_info_size = ::std::mem::size_of::() as u32 * self.num_cpu_info; unsafe { ffi::vm_deallocate(ffi::mach_task_self(), self.cpu_info.0, prev_cpu_info_size); } self.cpu_info.0 = ::std::ptr::null_mut(); } } } /// Struct containing a processor information. pub struct Processor { name: String, cpu_usage: f32, processor_data: Arc, } impl Processor { fn new(name: String, processor_data: Arc) -> Processor { Processor { name, cpu_usage: 0f32, processor_data, } } } impl ProcessorExt for Processor { fn get_cpu_usage(&self) -> f32 { self.cpu_usage } fn get_name(&self) -> &str { &self.name } } pub fn set_cpu_usage(p: &mut Processor, usage: f32) { p.cpu_usage = usage; } pub fn create_proc(name: String, processor_data: Arc) -> Processor { Processor::new(name, processor_data) } pub fn update_proc(p: &mut Processor, cpu_usage: f32, processor_data: Arc) { p.cpu_usage = cpu_usage; p.processor_data = processor_data; } pub fn set_cpu_proc(p: &mut Processor, cpu_usage: f32) { p.cpu_usage = cpu_usage; } pub fn get_processor_data(p: &Processor) -> Arc { Arc::clone(&p.processor_data) } sysinfo-0.9.5/src/mac/system.rs010064400007650000024000001024171353517610600146730ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use sys::ffi; use sys::component::Component; use sys::network::{self, NetworkData}; use sys::processor::*; use sys::process::*; use sys::disk::{self, Disk, DiskType}; use ::{ComponentExt, DiskExt, ProcessExt, ProcessorExt, RefreshKind, SystemExt}; use std::borrow::Borrow; use std::cell::UnsafeCell; use std::collections::HashMap; use std::ffi::{OsStr, OsString}; use std::mem::MaybeUninit; use std::ops::Deref; use std::os::unix::ffi::OsStringExt; use std::sync::Arc; use std::path::{Path, PathBuf}; use sys::processor; use std::{fs, mem, ptr}; use libc::{self, c_void, c_int, size_t, c_char, sysconf, _SC_PAGESIZE}; use utils; use Pid; use std::process::Command; use rayon::prelude::*; /// Structs containing system's information. pub struct System { process_list: HashMap, mem_total: u64, mem_free: u64, swap_total: u64, swap_free: u64, processors: Vec, page_size_kb: u64, temperatures: Vec, connection: Option, disks: Vec, network: NetworkData, uptime: u64, port: ffi::mach_port_t, } impl Drop for System { fn drop(&mut self) { if let Some(conn) = self.connection { unsafe { ffi::IOServiceClose(conn); } } } } // code from https://github.com/Chris911/iStats fn get_io_service_connection() -> Option { let mut master_port: ffi::mach_port_t = 0; let mut iterator: ffi::io_iterator_t = 0; unsafe { ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); let matching_dictionary = ffi::IOServiceMatching(b"AppleSMC\0".as_ptr() as *const i8); let result = ffi::IOServiceGetMatchingServices(master_port, matching_dictionary, &mut iterator); if result != ffi::KIO_RETURN_SUCCESS { //println!("Error: IOServiceGetMatchingServices() = {}", result); return None; } let device = ffi::IOIteratorNext(iterator); ffi::IOObjectRelease(iterator); if device == 0 { //println!("Error: no SMC found"); return None; } let mut conn = 0; let result = ffi::IOServiceOpen(device, ffi::mach_task_self(), 0, &mut conn); ffi::IOObjectRelease(device); if result != ffi::KIO_RETURN_SUCCESS { //println!("Error: IOServiceOpen() = {}", result); return None; } Some(conn) } } unsafe fn strtoul(s: *mut c_char, size: c_int, base: c_int) -> u32 { let mut total = 0u32; for i in 0..size { total += if base == 16 { (*s.offset(i as isize) as u32) << (((size - 1 - i) as u32) << 3) } else { (*s.offset(i as isize) as u32) << ((size - 1 - i) << 3) as u32 }; } total } unsafe fn ultostr(s: *mut c_char, val: u32) { *s = 0; libc::sprintf(s, b"%c%c%c%c\0".as_ptr() as *const i8, val >> 24, val >> 16, val >> 8, val); } unsafe fn perform_call(conn: ffi::io_connect_t, index: c_int, input_structure: *mut ffi::KeyData_t, output_structure: *mut ffi::KeyData_t) -> i32 { let mut structure_output_size = mem::size_of::(); ffi::IOConnectCallStructMethod(conn, index as u32, input_structure, mem::size_of::(), output_structure, &mut structure_output_size) } unsafe fn read_key(con: ffi::io_connect_t, key: *mut c_char) -> Result { let mut input_structure: ffi::KeyData_t = mem::zeroed::(); let mut output_structure: ffi::KeyData_t = mem::zeroed::(); let mut val: ffi::Val_t = mem::zeroed::(); input_structure.key = strtoul(key, 4, 16); input_structure.data8 = ffi::SMC_CMD_READ_KEYINFO; let result = perform_call(con, ffi::KERNEL_INDEX_SMC, &mut input_structure, &mut output_structure); if result != ffi::KIO_RETURN_SUCCESS { return Err(result); } val.data_size = output_structure.key_info.data_size; ultostr(val.data_type.as_mut_ptr(), output_structure.key_info.data_type); input_structure.key_info.data_size = val.data_size; input_structure.data8 = ffi::SMC_CMD_READ_BYTES; let result = perform_call(con, ffi::KERNEL_INDEX_SMC, &mut input_structure, &mut output_structure); if result != ffi::KIO_RETURN_SUCCESS { Err(result) } else { libc::memcpy(val.bytes.as_mut_ptr() as *mut c_void, output_structure.bytes.as_mut_ptr() as *mut c_void, mem::size_of::<[u8; 32]>()); Ok(val) } } unsafe fn get_temperature(con: ffi::io_connect_t, key: *mut c_char) -> f32 { if let Ok(val) = read_key(con, key) { if val.data_size > 0 && libc::strcmp(val.data_type.as_ptr(), b"sp78\0".as_ptr() as *const i8) == 0 { // convert fp78 value to temperature let x = (i32::from(val.bytes[0]) << 6) + (i32::from(val.bytes[1]) >> 2); return x as f32 / 64f32; } } 0f32 } unsafe fn get_unchecked_str(cp: *mut u8, start: *mut u8) -> String { let len = cp as usize - start as usize; let part = Vec::from_raw_parts(start, len, len); let tmp = String::from_utf8_unchecked(part.clone()); mem::forget(part); tmp } macro_rules! unwrapper { ($b:expr, $ret:expr) => {{ match $b { Ok(x) => x, _ => return $ret, } }} } unsafe fn check_value(dict: ffi::CFMutableDictionaryRef, key: &[u8]) -> bool { let key = ffi::CFStringCreateWithCStringNoCopy(ptr::null_mut(), key.as_ptr() as *const c_char, ffi::kCFStringEncodingMacRoman, ffi::kCFAllocatorNull as *mut c_void); let ret = ffi::CFDictionaryContainsKey(dict as ffi::CFDictionaryRef, key as *const c_void) != 0 && *(ffi::CFDictionaryGetValue(dict as ffi::CFDictionaryRef, key as *const c_void) as *const ffi::Boolean) != 0; ffi::CFRelease(key as *const c_void); ret } fn make_name(v: &[u8]) -> OsString { for (pos, x) in v.iter().enumerate() { if *x == 0 { return OsStringExt::from_vec(v[0..pos].to_vec()) } } OsStringExt::from_vec(v.to_vec()) } fn get_disk_types() -> HashMap { let mut master_port: ffi::mach_port_t = 0; let mut media_iterator: ffi::io_iterator_t = 0; let mut ret = HashMap::new(); unsafe { ffi::IOMasterPort(ffi::MACH_PORT_NULL, &mut master_port); let matching_dictionary = ffi::IOServiceMatching(b"IOMedia\0".as_ptr() as *const i8); let result = ffi::IOServiceGetMatchingServices(master_port, matching_dictionary, &mut media_iterator); if result != ffi::KERN_SUCCESS as i32 { //println!("Error: IOServiceGetMatchingServices() = {}", result); return ret; } loop { let next_media = ffi::IOIteratorNext(media_iterator); if next_media == 0 { break; } let mut props = MaybeUninit::::uninit(); let result = ffi::IORegistryEntryCreateCFProperties(next_media, props.as_mut_ptr(), ffi::kCFAllocatorDefault, 0); let props = props.assume_init(); if result == ffi::KERN_SUCCESS as i32 && check_value(props, b"Whole\0") { let mut name: ffi::io_name_t = mem::zeroed(); if ffi::IORegistryEntryGetName(next_media, name.as_mut_ptr() as *mut c_char) == ffi::KERN_SUCCESS as i32 { ret.insert(make_name(&name), if check_value(props, b"RAID\0") { DiskType::Unknown(-1) } else { DiskType::SSD }); } ffi::CFRelease(props as *mut _); } ffi::IOObjectRelease(next_media); } ffi::IOObjectRelease(media_iterator); } ret } fn get_disks() -> Vec { let disk_types = get_disk_types(); unwrapper!(fs::read_dir("/Volumes"), Vec::new()) .flat_map(|x| { if let Ok(ref entry) = x { let mount_point = utils::realpath(&entry.path()); if mount_point.as_os_str().is_empty() { None } else { let name = entry.path() .file_name() .unwrap_or_else(|| OsStr::new("")) .to_owned(); let type_ = disk_types.get(&name).cloned().unwrap_or(DiskType::Unknown(-2)); Some(disk::new(name, &mount_point, type_)) } } else { None } }) .collect() } fn get_uptime() -> u64 { let mut boottime: libc::timeval = unsafe { mem::zeroed() }; let mut len = mem::size_of::(); let mut mib: [c_int; 2] = [libc::CTL_KERN, libc::KERN_BOOTTIME]; unsafe { if libc::sysctl(mib.as_mut_ptr(), 2, &mut boottime as *mut libc::timeval as *mut _, &mut len, ::std::ptr::null_mut(), 0) < 0 { return 0; } } let bsec = boottime.tv_sec; let csec = unsafe { libc::time(::std::ptr::null_mut()) }; unsafe { libc::difftime(csec, bsec) as u64 } } fn parse_command_line + Borrow>(cmd: &[T]) -> Vec { let mut x = 0; let mut command = Vec::with_capacity(cmd.len()); while x < cmd.len() { let mut y = x; if cmd[y].starts_with('\'') || cmd[y].starts_with('"') { let c = if cmd[y].starts_with('\'') { '\'' } else { '"' }; while y < cmd.len() && !cmd[y].ends_with(c) { y += 1; } command.push(cmd[x..y].join(" ")); x = y; } else { command.push(cmd[x].to_owned()); } x += 1; } command } struct Wrap<'a>(UnsafeCell<&'a mut HashMap>); unsafe impl<'a> Send for Wrap<'a> {} unsafe impl<'a> Sync for Wrap<'a> {} fn update_process(wrap: &Wrap, pid: Pid, taskallinfo_size: i32, taskinfo_size: i32, threadinfo_size: i32, mib: &mut [c_int], mut size: size_t) -> Result, ()> { let mut proc_args = Vec::with_capacity(size as usize); unsafe { let mut thread_info = mem::zeroed::(); let (user_time, system_time, thread_status) = if ffi::proc_pidinfo(pid, libc::PROC_PIDTHREADINFO, 0, &mut thread_info as *mut libc::proc_threadinfo as *mut c_void, threadinfo_size) != 0 { (thread_info.pth_user_time, thread_info.pth_system_time, Some(ThreadStatus::from(thread_info.pth_run_state))) } else { (0, 0, None) }; if let Some(ref mut p) = (*wrap.0.get()).get_mut(&pid) { if p.memory == 0 { // We don't have access to this process' information. force_update(p); return Ok(None); } p.status = thread_status; let mut task_info = mem::zeroed::(); if ffi::proc_pidinfo(pid, libc::PROC_PIDTASKINFO, 0, &mut task_info as *mut libc::proc_taskinfo as *mut c_void, taskinfo_size) != taskinfo_size { return Err(()); } let task_time = user_time + system_time + task_info.pti_total_user + task_info.pti_total_system; let time = ffi::mach_absolute_time(); compute_cpu_usage(p, time, task_time); p.memory = task_info.pti_resident_size >> 10; // divide by 1024 return Ok(None); } let mut task_info = mem::zeroed::(); if ffi::proc_pidinfo(pid, libc::PROC_PIDTASKALLINFO, 0, &mut task_info as *mut libc::proc_taskallinfo as *mut c_void, taskallinfo_size as i32) != taskallinfo_size as i32 { match Command::new("/bin/ps") // not very nice, might be worth running a which first. .arg("wwwe") .arg("-o") .arg("ppid=,command=") .arg(pid.to_string().as_str()) .output() { Ok(o) => { let o = String::from_utf8(o.stdout).unwrap_or_else(|_| String::new()); let o = o.split(' ').filter(|c| !c.is_empty()).collect::>(); if o.len() < 2 { return Err(()); } let mut command = parse_command_line(&o[1..]); if let Some(ref mut x) = command.last_mut() { **x = x.replace("\n", ""); } let p = match i32::from_str_radix(&o[0].replace("\n", ""), 10) { Ok(x) => x, _ => return Err(()), }; let mut p = Process::new(pid, if p == 0 { None } else { Some(p) }, 0); p.exe = PathBuf::from(&command[0]); p.name = match p.exe.file_name() { Some(x) => x.to_str().unwrap_or_else(|| "").to_owned(), None => String::new(), }; p.cmd = command; return Ok(Some(p)); } _ => { return Err(()); } } } let parent = match task_info.pbsd.pbi_ppid as Pid { 0 => None, p => Some(p) }; let mut p = Process::new(pid, parent, task_info.pbsd.pbi_start_tvsec); p.memory = task_info.ptinfo.pti_resident_size >> 10; // divide by 1024 p.uid = task_info.pbsd.pbi_uid; p.gid = task_info.pbsd.pbi_gid; p.process_status = ProcessStatus::from(task_info.pbsd.pbi_status); let ptr: *mut u8 = proc_args.as_mut_slice().as_mut_ptr(); mib[0] = libc::CTL_KERN; mib[1] = libc::KERN_PROCARGS2; mib[2] = pid as c_int; /* * /---------------\ 0x00000000 * | ::::::::::::: | * |---------------| <-- Beginning of data returned by sysctl() is here. * | argc | * |---------------| * | exec_path | * |---------------| * | 0 | * |---------------| * | arg[0] | * |---------------| * | 0 | * |---------------| * | arg[n] | * |---------------| * | 0 | * |---------------| * | env[0] | * |---------------| * | 0 | * |---------------| * | env[n] | * |---------------| * | ::::::::::::: | * |---------------| <-- Top of stack. * : : * : : * \---------------/ 0xffffffff */ if libc::sysctl(mib.as_mut_ptr(), 3, ptr as *mut c_void, &mut size, ::std::ptr::null_mut(), 0) != -1 { let mut n_args: c_int = 0; libc::memcpy((&mut n_args) as *mut c_int as *mut c_void, ptr as *const c_void, mem::size_of::()); let mut cp = ptr.add(mem::size_of::()); let mut start = cp; if cp < ptr.add(size) { while cp < ptr.add(size) && *cp != 0 { cp = cp.offset(1); } p.exe = Path::new(get_unchecked_str(cp, start).as_str()).to_path_buf(); p.name = p.exe.file_name() .unwrap_or_else(|| OsStr::new("")) .to_str() .unwrap_or_else(|| "") .to_owned(); let mut need_root = true; if p.exe.is_absolute() { if let Some(parent) = p.exe.parent() { p.root = parent.to_path_buf(); need_root = false; } } while cp < ptr.add(size) && *cp == 0 { cp = cp.offset(1); } start = cp; let mut c = 0; let mut cmd = Vec::new(); while c < n_args && cp < ptr.add(size) { if *cp == 0 { c += 1; cmd.push(get_unchecked_str(cp, start)); start = cp.offset(1); } cp = cp.offset(1); } p.cmd = parse_command_line(&cmd); start = cp; while cp < ptr.add(size) { if *cp == 0 { if cp == start { break; } p.environ.push(get_unchecked_str(cp, start)); start = cp.offset(1); } cp = cp.offset(1); } if need_root { for env in p.environ.iter() { if env.starts_with("PATH=") { p.root = Path::new(&env[6..]).to_path_buf(); break } } } } } else { return Err(()); // not enough rights I assume? } Ok(Some(p)) } } fn get_proc_list() -> Option> { let count = unsafe { ffi::proc_listallpids(::std::ptr::null_mut(), 0) }; if count < 1 { return None; } let mut pids: Vec = Vec::with_capacity(count as usize); unsafe { pids.set_len(count as usize); } let count = count * mem::size_of::() as i32; let x = unsafe { ffi::proc_listallpids(pids.as_mut_ptr() as *mut c_void, count) }; if x < 1 || x as usize >= pids.len() { None } else { unsafe { pids.set_len(x as usize); } Some(pids) } } fn get_arg_max() -> usize { let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; let mut arg_max = 0i32; let mut size = mem::size_of::(); unsafe { if libc::sysctl(mib.as_mut_ptr(), 2, (&mut arg_max) as *mut i32 as *mut c_void, &mut size, ::std::ptr::null_mut(), 0) == -1 { 4096 // We default to this value } else { arg_max as usize } } } impl System { fn clear_procs(&mut self) { let mut to_delete = Vec::new(); for (pid, mut proc_) in &mut self.process_list { if !has_been_updated(&mut proc_) { to_delete.push(*pid); } } for pid in to_delete { self.process_list.remove(&pid); } } } impl SystemExt for System { fn new_with_specifics(refreshes: RefreshKind) -> System { let mut s = System { process_list: HashMap::new(), mem_total: 0, mem_free: 0, swap_total: 0, swap_free: 0, processors: Vec::new(), page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 >> 10 }, // divide by 1024 temperatures: Vec::new(), connection: get_io_service_connection(), disks: Vec::new(), network: network::new(), uptime: get_uptime(), port: unsafe { ffi::mach_host_self() }, }; s.refresh_specifics(refreshes); s } fn refresh_system(&mut self) { self.uptime = get_uptime(); unsafe fn get_sys_value(high: u32, low: u32, mut len: usize, value: *mut c_void, mib: &mut [i32; 2]) -> bool { mib[0] = high as i32; mib[1] = low as i32; libc::sysctl(mib.as_mut_ptr(), 2, value, &mut len as *mut usize, ::std::ptr::null_mut(), 0) == 0 } let mut mib = [0, 0]; unsafe { // get system values // get swap info let mut xs: ffi::xsw_usage = mem::zeroed::(); if get_sys_value(ffi::CTL_VM, ffi::VM_SWAPUSAGE, mem::size_of::(), &mut xs as *mut ffi::xsw_usage as *mut c_void, &mut mib) { self.swap_total = xs.xsu_total >> 10; // divide by 1024 self.swap_free = xs.xsu_avail >> 10; // divide by 1024 } // get ram info if self.mem_total < 1 { get_sys_value(ffi::CTL_HW, ffi::HW_MEMSIZE, mem::size_of::(), &mut self.mem_total as *mut u64 as *mut c_void, &mut mib); self.mem_total >>= 10; // divide by 1024 } let count: u32 = ffi::HOST_VM_INFO64_COUNT; let mut stat = mem::zeroed::(); if ffi::host_statistics64(self.port, ffi::HOST_VM_INFO64, &mut stat as *mut ffi::vm_statistics64 as *mut c_void, &count) == ffi::KERN_SUCCESS { // From the apple documentation: // // /* // * NB: speculative pages are already accounted for in "free_count", // * so "speculative_count" is the number of "free" pages that are // * used to hold data that was read speculatively from disk but // * haven't actually been used by anyone so far. // */ // self.mem_free = u64::from(stat.free_count) * self.page_size_kb; self.mem_free = self.mem_total - (u64::from(stat.active_count) + u64::from(stat.inactive_count) + u64::from(stat.wire_count) + u64::from(stat.speculative_count) - u64::from(stat.purgeable_count)) * self.page_size_kb; } if let Some(con) = self.connection { if self.temperatures.is_empty() { // getting CPU critical temperature let mut v = vec!('T' as i8, 'C' as i8, '0' as i8, 'D' as i8, 0); let tmp = get_temperature(con, v.as_mut_ptr()); let critical_temp = if tmp > 0f32 { Some(tmp) } else { None }; // getting CPU temperature // "TC0P" v[3] = 'P' as i8; let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); if temp > 0f32 { self.temperatures.push(Component::new("CPU".to_owned(), None, critical_temp)); } // getting GPU temperature // "TG0P" v[1] = 'G' as i8; let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); if temp > 0f32 { self.temperatures.push(Component::new("GPU".to_owned(), None, critical_temp)); } // getting battery temperature // "TB0T" v[1] = 'B' as i8; v[3] = 'T' as i8; let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); if temp > 0f32 { self.temperatures.push(Component::new("Battery".to_owned(), None, critical_temp)); } } else { let mut v = vec!('T' as i8, 'C' as i8, '0' as i8, 'P' as i8, 0); for comp in &mut self.temperatures { match &*comp.get_label() { "CPU" => { v[1] = 'C' as i8; v[3] = 'P' as i8; } "GPU" => { v[1] = 'G' as i8; v[3] = 'P' as i8; } _ => { v[1] = 'B' as i8; v[3] = 'T' as i8; } }; let temp = get_temperature(con, v.as_mut_ptr() as *mut i8); ::sys::component::update_component(comp, temp); } } } // get processor values let mut num_cpu_u = 0u32; let mut cpu_info: *mut i32 = ::std::ptr::null_mut(); let mut num_cpu_info = 0u32; if self.processors.is_empty() { let mut num_cpu = 0; if !get_sys_value(ffi::CTL_HW, ffi::HW_NCPU, mem::size_of::(), &mut num_cpu as *mut usize as *mut c_void, &mut mib) { num_cpu = 1; } self.processors.push( processor::create_proc("0".to_owned(), Arc::new(ProcessorData::new(::std::ptr::null_mut(), 0)))); if ffi::host_processor_info(self.port, ffi::PROCESSOR_CPU_LOAD_INFO, &mut num_cpu_u as *mut u32, &mut cpu_info as *mut *mut i32, &mut num_cpu_info as *mut u32) == ffi::KERN_SUCCESS { let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info)); for i in 0..num_cpu { let mut p = processor::create_proc(format!("{}", i + 1), Arc::clone(&proc_data)); let in_use = *cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize) + *cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_SYSTEM as isize) + *cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_NICE as isize); let total = in_use + *cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize); processor::set_cpu_proc(&mut p, in_use as f32 / total as f32); self.processors.push(p); } } } else if ffi::host_processor_info(self.port, ffi::PROCESSOR_CPU_LOAD_INFO, &mut num_cpu_u as *mut u32, &mut cpu_info as *mut *mut i32, &mut num_cpu_info as *mut u32) == ffi::KERN_SUCCESS { let mut pourcent = 0f32; let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info)); for (i, proc_) in self.processors.iter_mut().skip(1).enumerate() { let old_proc_data = &*processor::get_processor_data(proc_); let in_use = (*cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize) - *old_proc_data.cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_USER as isize)) + (*cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_SYSTEM as isize) - *old_proc_data.cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_SYSTEM as isize)) + (*cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_NICE as isize) - *old_proc_data.cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_NICE as isize)); let total = in_use + (*cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize) - *old_proc_data.cpu_info.offset((ffi::CPU_STATE_MAX * i) as isize + ffi::CPU_STATE_IDLE as isize)); processor::update_proc(proc_, in_use as f32 / total as f32, Arc::clone(&proc_data)); pourcent += proc_.get_cpu_usage(); } if self.processors.len() > 1 { let len = self.processors.len() - 1; if let Some(p) = self.processors.get_mut(0) { processor::set_cpu_usage(p, pourcent / len as f32); } } } } } fn refresh_network(&mut self) { network::update_network(&mut self.network); } fn refresh_processes(&mut self) { let count = unsafe { ffi::proc_listallpids(::std::ptr::null_mut(), 0) }; if count < 1 { return } if let Some(pids) = get_proc_list() { let taskallinfo_size = mem::size_of::() as i32; let taskinfo_size = mem::size_of::() as i32; let threadinfo_size = mem::size_of::() as i32; let arg_max = get_arg_max(); let entries: Vec = { let wrap = &Wrap(UnsafeCell::new(&mut self.process_list)); pids.par_iter() .flat_map(|pid| { let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; match update_process(wrap, *pid, taskallinfo_size, taskinfo_size, threadinfo_size, &mut mib, arg_max as size_t) { Ok(x) => x, Err(_) => None, } }) .collect() }; entries.into_iter().for_each(|entry| { self.process_list.insert(entry.pid(), entry); }); self.clear_procs(); } } fn refresh_process(&mut self, pid: Pid) -> bool { let taskallinfo_size = mem::size_of::() as i32; let taskinfo_size = mem::size_of::() as i32; let threadinfo_size = mem::size_of::() as i32; let mut mib: [c_int; 3] = [libc::CTL_KERN, libc::KERN_ARGMAX, 0]; let arg_max = get_arg_max(); match { let wrap = Wrap(UnsafeCell::new(&mut self.process_list)); update_process(&wrap, pid, taskallinfo_size, taskinfo_size, threadinfo_size, &mut mib, arg_max as size_t) } { Ok(Some(p)) => { self.process_list.insert(p.pid(), p); true } Ok(_) => true, Err(_) => false, } } fn refresh_disks(&mut self) { for disk in &mut self.disks { disk.update(); } } fn refresh_disk_list(&mut self) { self.disks = get_disks(); } // COMMON PART // // Need to be moved into a "common" file to avoid duplication. fn get_process_list(&self) -> &HashMap { &self.process_list } fn get_process(&self, pid: Pid) -> Option<&Process> { self.process_list.get(&pid) } fn get_processor_list(&self) -> &[Processor] { &self.processors[..] } fn get_network(&self) -> &NetworkData { &self.network } fn get_total_memory(&self) -> u64 { self.mem_total } fn get_free_memory(&self) -> u64 { self.mem_free } fn get_used_memory(&self) -> u64 { self.mem_total - self.mem_free } fn get_total_swap(&self) -> u64 { self.swap_total } fn get_free_swap(&self) -> u64 { self.swap_free } // need to be checked fn get_used_swap(&self) -> u64 { self.swap_total - self.swap_free } fn get_components_list(&self) -> &[Component] { &self.temperatures[..] } fn get_disks(&self) -> &[Disk] { &self.disks[..] } fn get_uptime(&self) -> u64 { self.uptime } } impl Default for System { fn default() -> System { System::new() } } sysinfo-0.9.5/src/process.rs010064400007650000024000000002101333211327500142420ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // // Functions 'set_time' and 'has_been_updated' will need to get moved here.sysinfo-0.9.5/src/processor.rs010064400007650000024000000004531333211327500146140ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use std::fmt::{self, Debug, Formatter}; use sys::Processor; use ::ProcessorExt; impl Debug for Processor { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "{}: {}%", self.get_name(), self.get_cpu_usage()) } } sysinfo-0.9.5/src/sysinfo.h010064400007650000024000000037361335155020500141000ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // #pragma once #include #include typedef void* CSystem; typedef const void* CProcess; typedef const char* RString; CSystem *sysinfo_init(); void sysinfo_destroy(CSystem system); void sysinfo_refresh_system(CSystem system); void sysinfo_refresh_all(CSystem system); void sysinfo_refresh_processes(CSystem system); #ifdef __linux__ void sysinfo_refresh_process(CSystem system, pid_t pid); #endif void sysinfo_refresh_disks(CSystem system); void sysinfo_refresh_disk_list(CSystem system); size_t sysinfo_get_total_memory(CSystem system); size_t sysinfo_get_free_memory(CSystem system); size_t sysinfo_get_used_memory(CSystem system); size_t sysinfo_get_total_swap(CSystem system); size_t sysinfo_get_free_swap(CSystem system); size_t sysinfo_get_used_swap(CSystem system); size_t sysinfo_get_network_income(CSystem system); size_t sysinfo_get_network_outcome(CSystem system); void sysinfo_get_processors_usage(CSystem system, unsigned int *length, float **procs); size_t sysinfo_get_processes(CSystem system, bool (*fn_pointer)(pid_t, CProcess, void*), void *data); #ifdef __linux__ size_t sysinfo_process_get_tasks(CProcess process, bool (*fn_pointer)(pid_t, CProcess, void*), void *data); #endif CProcess sysinfo_get_process_by_pid(CSystem system, pid_t pid); pid_t sysinfo_process_get_pid(CProcess process); pid_t sysinfo_process_get_parent_pid(CProcess process); float sysinfo_process_get_cpu_usage(CProcess process); size_t sysinfo_process_get_memory(CProcess process); RString sysinfo_process_get_executable_path(CProcess process); RString sysinfo_process_get_root_directory(CProcess process); RString sysinfo_process_get_current_directory(CProcess process); void sysinfo_rstring_free(RString str); sysinfo-0.9.5/src/sysinfo.rs010064400007650000024000000110161350420322000142530ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // //! `sysinfo` is a crate used to get a system's information. //! //! Before any attempt to read the different structs' information, you need to update them to //! get up-to-date information. //! //! # Examples //! //! ``` //! use sysinfo::{ProcessExt, SystemExt}; //! //! let mut system = sysinfo::System::new(); //! //! // First we update all information of our system struct. //! system.refresh_all(); //! //! // Now let's print every process' id and name: //! for (pid, proc_) in system.get_process_list() { //! println!("{}:{} => status: {:?}", pid, proc_.name(), proc_.status()); //! } //! //! // Then let's print the temperature of the different components: //! for component in system.get_components_list() { //! println!("{:?}", component); //! } //! //! // And then all disks' information: //! for disk in system.get_disks() { //! println!("{:?}", disk); //! } //! //! // And finally the RAM and SWAP information: //! println!("total memory: {} kB", system.get_total_memory()); //! println!("used memory : {} kB", system.get_used_memory()); //! println!("total swap : {} kB", system.get_total_swap()); //! println!("used swap : {} kB", system.get_used_swap()); //! ``` #![crate_name = "sysinfo"] #![crate_type = "lib"] #![crate_type = "rlib"] #![deny(missing_docs)] //#![deny(warnings)] #![allow(unknown_lints)] #[macro_use] extern crate cfg_if; #[cfg(not(target_os = "unknown"))] extern crate libc; extern crate rayon; #[macro_use] extern crate doc_comment; #[cfg(test)] doctest!("../README.md"); cfg_if! { if #[cfg(target_os = "macos")] { mod mac; use mac as sys; } else if #[cfg(windows)] { mod windows; use windows as sys; extern crate winapi; } else if #[cfg(unix)] { mod linux; use linux as sys; } else { mod unknown; use unknown as sys; } } pub use common::{ AsU32, Pid, RefreshKind, }; pub use sys::{ Component, Disk, DiskType, NetworkData, Process, ProcessStatus, Processor, System, }; pub use traits::{ ComponentExt, DiskExt, ProcessExt, ProcessorExt, SystemExt, NetworkExt, }; pub use utils::get_current_pid; #[cfg(feature = "c-interface")] pub use c_interface::*; mod common; mod component; mod process; mod processor; mod system; mod traits; mod utils; #[cfg(feature = "c-interface")] mod c_interface; /// An enum representing signal on UNIX-like systems. #[repr(C)] #[derive(Clone, PartialEq, PartialOrd, Debug, Copy)] pub enum Signal { /// Hangup detected on controlling terminal or death of controlling process. Hangup = 1, /// Interrupt from keyboard. Interrupt = 2, /// Quit from keyboard. Quit = 3, /// Illegal instruction. Illegal = 4, /// Trace/breakpoint trap. Trap = 5, /// Abort signal from C abort function. Abort = 6, // IOT trap. A synonym for SIGABRT. // IOT = 6, /// Bus error (bad memory access). Bus = 7, /// Floating point exception. FloatingPointException = 8, /// Kill signal. Kill = 9, /// User-defined signal 1. User1 = 10, /// Invalid memory reference. Segv = 11, /// User-defined signal 2. User2 = 12, /// Broken pipe: write to pipe with no readers. Pipe = 13, /// Timer signal from C alarm function. Alarm = 14, /// Termination signal. Term = 15, /// Stack fault on coprocessor (unused). Stklft = 16, /// Child stopped or terminated. Child = 17, /// Continue if stopped. Continue = 18, /// Stop process. Stop = 19, /// Stop typed at terminal. TSTP = 20, /// Terminal input for background process. TTIN = 21, /// Terminal output for background process. TTOU = 22, /// Urgent condition on socket. Urgent = 23, /// CPU time limit exceeded. XCPU = 24, /// File size limit exceeded. XFSZ = 25, /// Virtual alarm clock. VirtualAlarm = 26, /// Profiling time expired. Profiling = 27, /// Windows resize signal. Winch = 28, /// I/O now possible. IO = 29, // Pollable event (Sys V). Synonym for IO //Poll = 29, /// Power failure (System V). Power = 30, /// Bad argument to routine (SVr4). Sys = 31, } #[cfg(test)] mod test { use traits::{ProcessExt, SystemExt}; #[test] fn check_memory_usage() { let mut s = ::System::new(); s.refresh_all(); assert_eq!(s.get_process_list().iter().all(|(_, proc_)| proc_.memory() == 0), false); } } sysinfo-0.9.5/src/system.rs010064400007650000024000000035111350420322000141060ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // // Once https://github.com/rust-lang/rfcs/blob/master/text/1422-pub-restricted.md // feature gets stabilized, we can move common parts in here. #[cfg(test)] mod tests { use ::{ProcessExt, System, SystemExt}; use ::utils; #[test] fn test_refresh_system() { let mut sys = System::new(); sys.refresh_system(); assert!(sys.get_total_memory() != 0); assert!(sys.get_free_memory() != 0); assert!(sys.get_total_memory() >= sys.get_free_memory()); assert!(sys.get_total_swap() >= sys.get_free_swap()); } #[test] fn test_refresh_process() { let mut sys = System::new(); assert!(sys.refresh_process(utils::get_current_pid().expect("failed to get current pid"))); } #[test] fn test_get_process() { let mut sys = System::new(); sys.refresh_processes(); let p = sys.get_process(utils::get_current_pid().expect("failed to get current pid")) .expect("didn't find process"); assert!(p.memory() > 0); } #[test] fn check_if_send_and_sync() { trait Foo { fn foo(&self) {} } impl Foo for T where T: Send {} trait Bar { fn bar(&self) {} } impl Bar for T where T: Sync {} let mut sys = System::new(); sys.refresh_processes(); let p = sys.get_process(utils::get_current_pid().expect("failed to get current pid")) .expect("didn't find process"); p.foo(); // If this doesn't compile, it'll simply mean that the Process type // doesn't implement the Send trait. p.bar(); // If this doesn't compile, it'll simply mean that the Process type // doesn't implement the Sync trait. } } sysinfo-0.9.5/src/traits.rs010064400007650000024000000174671353425133300141220ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use sys::{Component, Disk, DiskType, NetworkData, Process, Processor}; use Pid; use ProcessStatus; use RefreshKind; use std::collections::HashMap; use std::ffi::OsStr; use std::path::Path; /// Contains all the methods of the `Disk` struct. pub trait DiskExt { /// Returns the disk type. fn get_type(&self) -> DiskType; /// Returns the disk name. fn get_name(&self) -> &OsStr; /// Returns the file system used on this disk (so for example: `EXT4`, `NTFS`, etc...). fn get_file_system(&self) -> &[u8]; /// Returns the mount point of the disk (`/` for example). fn get_mount_point(&self) -> &Path; /// Returns the total disk size, in bytes. fn get_total_space(&self) -> u64; /// Returns the available disk size, in bytes. fn get_available_space(&self) -> u64; /// Update the disk' information. fn update(&mut self) -> bool; } /// Contains all the methods of the `Process` struct. pub trait ProcessExt { /// Create a new process only containing the given information. /// /// On windows, the `start_time` argument is ignored. fn new(pid: Pid, parent: Option, start_time: u64) -> Self; /// Sends the given `signal` to the process. fn kill(&self, signal: ::Signal) -> bool; /// Returns the name of the process. fn name(&self) -> &str; /// Returns the command line. // /// // /// On Windows, this is always a one element vector. fn cmd(&self) -> &[String]; /// Returns the path to the process. fn exe(&self) -> &Path; /// Returns the pid of the process. fn pid(&self) -> Pid; /// Returns the environment of the process. /// /// Always empty on Windows except for current process. fn environ(&self) -> &[String]; /// Returns the current working directory. /// /// Always empty on Windows. fn cwd(&self) -> &Path; /// Returns the path of the root directory. /// /// Always empty on Windows. fn root(&self) -> &Path; /// Returns the memory usage (in kB). fn memory(&self) -> u64; /// Returns the parent pid. fn parent(&self) -> Option; /// Returns the status of the processus. fn status(&self) -> ProcessStatus; /// Returns the time of process launch (in seconds). fn start_time(&self) -> u64; /// Returns the total CPU usage. fn cpu_usage(&self) -> f32; } /// Contains all the methods of the `Processor` struct. pub trait ProcessorExt { /// Returns this processor's usage. /// /// Note: You'll need to refresh it at least twice at first if you want to have a /// non-zero value. fn get_cpu_usage(&self) -> f32; /// Returns this processor's name. fn get_name(&self) -> &str; } /// Contains all the methods of the [`System`] type. pub trait SystemExt: Sized { /// Creates a new [`System`] instance. It only contains the disks' list and the processes list /// at this stage. Use the [`refresh_all`] method to update its internal information (or any of /// the `refresh_` method). /// /// [`refresh_all`]: #method.refresh_all fn new() -> Self { let mut s = Self::new_with_specifics(RefreshKind::new()); s.refresh_disk_list(); s.refresh_all(); s } /// Creates a new [`System`] instance and refresh the data corresponding to the /// given [`RefreshKind`]. /// /// # Example /// /// ``` /// use sysinfo::{RefreshKind, System, SystemExt}; /// /// // We want everything except disks. /// let mut system = System::new_with_specifics(RefreshKind::everything().without_disk_list()); /// /// assert_eq!(system.get_disks().len(), 0); /// assert!(system.get_process_list().len() > 0); /// /// // If you want the disks list afterwards, just call the corresponding /// // "refresh_disk_list": /// system.refresh_disk_list(); /// assert!(system.get_disks().len() > 0); /// ``` fn new_with_specifics(refreshes: RefreshKind) -> Self; /// Refreshes according to the given [`RefreshKind`]. It calls the corresponding /// "refresh_" methods. /// /// # Examples /// /// ``` /// use sysinfo::{RefreshKind, System, SystemExt}; /// /// let mut s = System::new(); /// /// // Let's just update network data and processes: /// s.refresh_specifics(RefreshKind::new().with_network().with_processes()); /// ``` fn refresh_specifics(&mut self, refreshes: RefreshKind) { if refreshes.system() { self.refresh_system(); } if refreshes.network() { self.refresh_network(); } if refreshes.processes() { self.refresh_processes(); } if refreshes.disk_list() { self.refresh_disk_list(); } if refreshes.disks() { self.refresh_disks(); } } /// Refresh system information (such as memory, swap, CPU usage and components' temperature). fn refresh_system(&mut self); /// Get all processes and update their information. fn refresh_processes(&mut self); /// Refresh *only* the process corresponding to `pid`. Returns `false` if the process doesn't /// exist. fn refresh_process(&mut self, pid: Pid) -> bool; /// Refreshes the listed disks' information. fn refresh_disks(&mut self); /// The disk list will be emptied then completely recomputed. fn refresh_disk_list(&mut self); /// Refresh data network. fn refresh_network(&mut self); /// Refreshes all system, processes and disks information. fn refresh_all(&mut self) { self.refresh_system(); self.refresh_processes(); self.refresh_disks(); self.refresh_network(); } /// Returns the process list. fn get_process_list(&self) -> &HashMap; /// Returns the process corresponding to the given pid or `None` if no such process exists. fn get_process(&self, pid: Pid) -> Option<&Process>; /// Returns a list of process containing the given `name`. fn get_process_by_name(&self, name: &str) -> Vec<&Process> { let mut ret = vec!(); for val in self.get_process_list().values() { if val.name().contains(name) { ret.push(val); } } ret } /// The first processor in the array is the "main" one (aka the addition of all the others). fn get_processor_list(&self) -> &[Processor]; /// Returns total RAM size in KiB. fn get_total_memory(&self) -> u64; /// Returns free RAM size in KiB. fn get_free_memory(&self) -> u64; /// Returns used RAM size in KiB. fn get_used_memory(&self) -> u64; /// Returns SWAP size in KiB. fn get_total_swap(&self) -> u64; /// Returns free SWAP size in KiB. fn get_free_swap(&self) -> u64; /// Returns used SWAP size in KiB. fn get_used_swap(&self) -> u64; /// Returns components list. fn get_components_list(&self) -> &[Component]; /// Returns disks' list. fn get_disks(&self) -> &[Disk]; /// Returns network data. fn get_network(&self) -> &NetworkData; /// Returns system uptime. fn get_uptime(&self) -> u64; } /// Getting volume of incoming and outgoing data. pub trait NetworkExt { /// Returns the number of incoming bytes. fn get_income(&self) -> u64; /// Returns the number of outgoing bytes. fn get_outcome(&self) -> u64; } /// Getting a component temperature information. pub trait ComponentExt { /// Returns the component's temperature (in celsius degree). fn get_temperature(&self) -> f32; /// Returns the maximum temperature of this component. fn get_max(&self) -> f32; /// Returns the highest temperature before the computer halts. fn get_critical(&self) -> Option; /// Returns component's label. fn get_label(&self) -> &str; } sysinfo-0.9.5/src/unknown/component.rs010064400007650000024000000006301350420322000162620ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use ComponentExt; /// Dummy struct representing a component. pub struct Component { } impl ComponentExt for Component { fn get_temperature(&self) -> f32 { 0.0 } fn get_max(&self) -> f32 { 0.0 } fn get_critical(&self) -> Option { None } fn get_label(&self) -> &str { "" } } sysinfo-0.9.5/src/unknown/disk.rs010064400007650000024000000013701350420322000152140ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use ::DiskExt; use std::path::Path; use std::ffi::OsStr; /// Enum containing the different handled disks types. #[derive(Debug, PartialEq, Clone, Copy)] pub enum DiskType { } /// Struct containing a disk information. pub struct Disk { } impl DiskExt for Disk { fn get_type(&self) -> DiskType { unreachable!() } fn get_name(&self) -> &OsStr { unreachable!() } fn get_file_system(&self) -> &[u8] { &[] } fn get_mount_point(&self) -> &Path { Path::new("") } fn get_total_space(&self) -> u64 { 0 } fn get_available_space(&self) -> u64 { 0 } fn update(&mut self) -> bool { true } } sysinfo-0.9.5/src/unknown/mod.rs010064400007650000024000000006051350420322000150410ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // pub mod component; pub mod disk; pub mod network; pub mod process; pub mod processor; pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; sysinfo-0.9.5/src/unknown/network.rs010064400007650000024000000004441350420322000157540ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use NetworkExt; /// Contains network information. #[derive(Debug)] pub struct NetworkData; impl NetworkExt for NetworkData { fn get_income(&self) -> u64 { 0 } fn get_outcome(&self) -> u64 { 0 } } sysinfo-0.9.5/src/unknown/process.rs010064400007650000024000000023641350420322000157440ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use std::path::Path; use Pid; use ::ProcessExt; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] pub struct ProcessStatus; /// Struct containing a process' information. #[derive(Clone, Debug)] pub struct Process { pid: Pid, parent: Option, } impl ProcessExt for Process { fn new(pid: Pid, parent: Option, _start_time: u64) -> Process { Process { pid, parent, } } fn kill(&self, _signal: ::Signal) -> bool { false } fn name(&self) -> &str { "" } fn cmd(&self) -> &[String] { &[] } fn exe(&self) -> &Path { &Path::new("") } fn pid(&self) -> Pid { self.pid } fn environ(&self) -> &[String] { &[] } fn cwd(&self) -> &Path { &Path::new("") } fn root(&self) -> &Path { &Path::new("") } fn memory(&self) -> u64 { 0 } fn parent(&self) -> Option { self.parent } fn status(&self) -> ProcessStatus { ProcessStatus } fn start_time(&self) -> u64 { 0 } fn cpu_usage(&self) -> f32 { 0.0 } } sysinfo-0.9.5/src/unknown/processor.rs010064400007650000024000000004501350420322000162770ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use ::ProcessorExt; /// Dummy struct that represents a processor. pub struct Processor { } impl ProcessorExt for Processor { fn get_cpu_usage(&self) -> f32 { 0.0 } fn get_name(&self) -> &str { "" } } sysinfo-0.9.5/src/unknown/system.rs010064400007650000024000000035531350420322000156130ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use sys::component::Component; use sys::processor::*; use sys::process::*; use sys::Disk; use sys::NetworkData; use ::{RefreshKind, SystemExt}; use Pid; use std::collections::HashMap; /// Structs containing system's information. #[derive(Debug)] pub struct System { processes_list: HashMap, network: NetworkData, } impl SystemExt for System { fn new_with_specifics(_: RefreshKind) -> System { System { processes_list: Default::default(), network: NetworkData, } } fn refresh_system(&mut self) { } fn refresh_processes(&mut self) { } fn refresh_process(&mut self, _pid: Pid) -> bool { false } fn refresh_disks(&mut self) { } fn refresh_disk_list(&mut self) { } fn refresh_network(&mut self) { } // COMMON PART // // Need to be moved into a "common" file to avoid duplication. fn get_process_list(&self) -> &HashMap { &self.processes_list } fn get_process(&self, _pid: Pid) -> Option<&Process> { None } fn get_network(&self) -> &NetworkData { &self.network } fn get_processor_list(&self) -> &[Processor] { &[] } fn get_total_memory(&self) -> u64 { 0 } fn get_free_memory(&self) -> u64 { 0 } fn get_used_memory(&self) -> u64 { 0 } fn get_total_swap(&self) -> u64 { 0 } fn get_free_swap(&self) -> u64 { 0 } fn get_used_swap(&self) -> u64 { 0 } fn get_components_list(&self) -> &[Component] { &[] } fn get_disks(&self) -> &[Disk] { &[] } fn get_uptime(&self) -> u64 { 0 } } impl Default for System { fn default() -> System { System::new() } } sysinfo-0.9.5/src/utils.rs010064400007650000024000000055411353425133300137420ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] use std::fs; #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] use std::path::{Path, PathBuf}; #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] use std::ffi::OsStr; #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] use std::os::unix::ffi::OsStrExt; #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] use libc::{c_char, lstat, stat, S_IFLNK, S_IFMT}; use Pid; #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] pub fn realpath(original: &Path) -> PathBuf { use std::mem::MaybeUninit; fn and(x: u32, y: u32) -> u32 { x & y } if let Some(original_str) = original.to_str() { let ori = Path::new(original_str); // Right now lstat on windows doesn't work quite well if cfg!(windows) { return PathBuf::from(ori); } let result = PathBuf::from(original); let mut result_s = result.to_str().unwrap_or("").as_bytes().to_vec(); result_s.push(0); let mut buf = MaybeUninit::::uninit(); let res = unsafe { lstat(result_s.as_ptr() as *const c_char, buf.as_mut_ptr()) }; let buf = unsafe { buf.assume_init() }; if res < 0 || and(buf.st_mode.into(), S_IFMT.into()) != S_IFLNK.into() { PathBuf::new() } else { match fs::read_link(&result) { Ok(f) => f, Err(_) => PathBuf::new(), } } } else { PathBuf::new() } } /* convert a path to a NUL-terminated Vec suitable for use with C functions */ #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] pub fn to_cpath(path: &Path) -> Vec { let path_os: &OsStr = path.as_ref(); let mut cpath = path_os.as_bytes().to_vec(); cpath.push(0); cpath } /// Returns the pid for the current process. /// /// `Err` is returned in case the platform isn't supported. pub fn get_current_pid() -> Result { cfg_if! { if #[cfg(all(not(target_os = "windows"), not(target_os = "unknown")))] { fn inner() -> Result { unsafe { Ok(::libc::getpid()) } } } else if #[cfg(target_os = "windows")] { fn inner() -> Result { use winapi::um::processthreadsapi::GetCurrentProcessId; unsafe { Ok(GetCurrentProcessId() as Pid) } } } else if #[cfg(target_os = "unknown")] { fn inner() -> Result { Err("Unavailable on this platform") } } else { fn inner() -> Result { Err("Unknown platform") } } } inner() } sysinfo-0.9.5/src/windows/component.rs010064400007650000024000000017001333211327500162650ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use ComponentExt; /// Struct containing a component information (temperature and name for the moment). pub struct Component { temperature: f32, max: f32, critical: Option, label: String, } impl Component { /// Creates a new `Component` with the given information. pub fn new(label: String, max: Option, critical: Option) -> Component { Component { temperature: 0f32, label: label, max: max.unwrap_or(0.0), critical: critical, } } } impl ComponentExt for Component { fn get_temperature(&self) -> f32 { self.temperature } fn get_max(&self) -> f32 { self.max } fn get_critical(&self) -> Option { self.critical } fn get_label(&self) -> &str { &self.label } } pub fn get_components() -> Vec { Vec::new() } sysinfo-0.9.5/src/windows/disk.rs010064400007650000024000000053661333211327500152310ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use std::ffi::{OsStr, OsString}; use std::fmt::{Debug, Error, Formatter}; use std::str; use std::path::Path; use DiskExt; use winapi::um::fileapi::GetDiskFreeSpaceExW; use winapi::um::winnt::ULARGE_INTEGER; /// Enum containing the different handled disks types. #[derive(Debug, PartialEq, Clone, Copy)] pub enum DiskType { /// HDD type. HDD, /// SSD type. SSD, /// Unknown type. Unknown(isize), } impl From for DiskType { fn from(t: isize) -> DiskType { match t { 0 => DiskType::HDD, 1 => DiskType::SSD, id => DiskType::Unknown(id), } } } pub fn new_disk(name: &OsStr, mount_point: &[u16], file_system: &[u8], type_: DiskType, total_space: u64) -> Disk { let mut d = Disk { type_: type_, name: name.to_owned(), file_system: file_system.to_vec(), mount_point: mount_point.to_vec(), s_mount_point: String::from_utf16_lossy(&mount_point[..mount_point.len() - 1]), total_space: total_space, available_space: 0, }; d.update(); d } /// Struct containing a disk information. pub struct Disk { type_: DiskType, name: OsString, file_system: Vec, mount_point: Vec, s_mount_point: String, total_space: u64, available_space: u64, } impl Debug for Disk { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { write!(fmt, "Disk({:?})[FS: {:?}][Type: {:?}] mounted on {:?}: {}/{} B", self.get_name(), str::from_utf8(self.get_file_system()).unwrap(), self.get_type(), self.get_mount_point(), self.get_available_space(), self.get_total_space()) } } impl DiskExt for Disk { fn get_type(&self) -> DiskType { self.type_ } fn get_name(&self) -> &OsStr { &self.name } fn get_file_system(&self) -> &[u8] { &self.file_system } fn get_mount_point(&self) -> &Path { &Path::new(&self.s_mount_point) } fn get_total_space(&self) -> u64 { self.total_space } fn get_available_space(&self) -> u64 { self.available_space } fn update(&mut self) -> bool { if self.total_space != 0 { unsafe { let mut tmp: ULARGE_INTEGER = ::std::mem::zeroed(); if GetDiskFreeSpaceExW(self.mount_point.as_ptr(), ::std::ptr::null_mut(), ::std::ptr::null_mut(), &mut tmp) != 0 { self.available_space = *tmp.QuadPart(); return true; } } } false } } sysinfo-0.9.5/src/windows/ffi.rs010064400007650000024000000243461333211327500150420ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // use libc::{c_int, c_char, c_void, c_uchar, c_uint, size_t, uint32_t, uint64_t, c_ushort}; extern "C" { pub static kCFAllocatorDefault: CFAllocatorRef; pub fn proc_pidinfo(pid: c_int, flavor: c_int, arg: u64, buffer: *mut c_void, buffersize: c_int) -> c_int; pub fn proc_listallpids(buffer: *mut c_void, buffersize: c_int) -> c_int; //pub fn proc_name(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; //pub fn proc_regionfilename(pid: c_int, address: u64, buffer: *mut c_void, // buffersize: u32) -> c_int; //pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int; pub fn IOMasterPort(a: i32, b: *mut mach_port_t) -> i32; pub fn IOServiceMatching(a: *const c_char) -> *mut c_void; pub fn IOServiceGetMatchingServices(a: mach_port_t, b: *mut c_void, c: *mut io_iterator_t) -> i32; pub fn IOIteratorNext(iterator: io_iterator_t) -> io_object_t; pub fn IOObjectRelease(obj: io_object_t) -> i32; pub fn IOServiceOpen(device: io_object_t, a: u32, t: u32, x: *mut io_connect_t) -> i32; pub fn IOServiceClose(a: io_connect_t) -> i32; pub fn IOConnectCallStructMethod(connection: mach_port_t, selector: u32, inputStruct: *mut KeyData_t, inputStructCnt: size_t, outputStruct: *mut KeyData_t, outputStructCnt: *mut size_t) -> i32; pub fn IORegistryEntryCreateCFProperties(entry: io_registry_entry_t, properties: *mut CFMutableDictionaryRef, allocator: CFAllocatorRef, options: IOOptionBits) -> kern_return_t; pub fn CFDictionaryContainsKey(d: CFDictionaryRef, key: *const c_void) -> Boolean; pub fn CFDictionaryGetValue(d: CFDictionaryRef, key: *const c_void) -> *const c_void; pub fn IORegistryEntryGetName(entry: io_registry_entry_t, name: *mut c_char) -> kern_return_t; pub fn CFRelease(cf: CFTypeRef); pub fn CFStringCreateWithCStringNoCopy(alloc: *mut c_void, cStr: *const c_char, encoding: CFStringEncoding, contentsDeallocator: *mut c_void) -> CFStringRef; pub static kCFAllocatorNull: CFAllocatorRef; pub fn mach_absolute_time() -> u64; //pub fn task_for_pid(host: u32, pid: pid_t, task: *mut task_t) -> u32; pub fn mach_task_self() -> u32; pub fn mach_host_self() -> u32; //pub fn task_info(host_info: u32, t: u32, c: *mut c_void, x: *mut u32) -> u32; pub fn host_statistics64(host_info: u32, x: u32, y: *mut c_void, z: *const u32) -> u32; pub fn host_processor_info(host_info: u32, t: u32, num_cpu_u: *mut u32, cpu_info: *mut *mut i32, num_cpu_info: *mut u32) -> u32; //pub fn host_statistics(host_priv: u32, flavor: u32, host_info: *mut c_void, // host_count: *const u32) -> u32; pub fn vm_deallocate(target_task: u32, address: *mut i32, size: u32) -> u32; } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 macro_rules! cfg_if { ($( if #[cfg($($meta:meta),*)] { $($it:item)* } ) else * else { $($it2:item)* }) => { __cfg_if_items! { () ; $( ( ($($meta),*) ($($it)*) ), )* ( () ($($it2)*) ), } } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 macro_rules! __cfg_if_items { (($($not:meta,)*) ; ) => {}; (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => { __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* } __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* } } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 macro_rules! __cfg_if_apply { ($m:meta, $($it:item)*) => { $(#[$m] $it)* } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 cfg_if! { if #[cfg(any(target_arch = "arm", target_arch = "x86"))] { pub type timeval32 = ::libc::timeval; } else { use libc::timeval32; } } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 #[repr(C)] pub struct if_data64 { pub ifi_type: c_uchar, pub ifi_typelen: c_uchar, pub ifi_physical: c_uchar, pub ifi_addrlen: c_uchar, pub ifi_hdrlen: c_uchar, pub ifi_recvquota: c_uchar, pub ifi_xmitquota: c_uchar, pub ifi_unused1: c_uchar, pub ifi_mtu: uint32_t, pub ifi_metric: uint32_t, pub ifi_baudrate: uint64_t, pub ifi_ipackets: uint64_t, pub ifi_ierrors: uint64_t, pub ifi_opackets: uint64_t, pub ifi_oerrors: uint64_t, pub ifi_collisions: uint64_t, pub ifi_ibytes: uint64_t, pub ifi_obytes: uint64_t, pub ifi_imcasts: uint64_t, pub ifi_omcasts: uint64_t, pub ifi_iqdrops: uint64_t, pub ifi_noproto: uint64_t, pub ifi_recvtiming: uint32_t, pub ifi_xmittiming: uint32_t, pub ifi_lastchange: timeval32, } // TODO: waiting for https://github.com/rust-lang/libc/pull/678 #[repr(C)] pub struct if_msghdr2 { pub ifm_msglen: c_ushort, pub ifm_version: c_uchar, pub ifm_type: c_uchar, pub ifm_addrs: c_int, pub ifm_flags: c_int, pub ifm_index: c_ushort, pub ifm_snd_len: c_int, pub ifm_snd_maxlen: c_int, pub ifm_snd_drops: c_int, pub ifm_timer: c_int, pub ifm_data: if_data64, } #[repr(C)] pub struct __CFAllocator { __private: c_void, } #[repr(C)] pub struct __CFDictionary { __private: c_void, } #[repr(C)] pub struct __CFString { __private: c_void, } pub type CFAllocatorRef = *const __CFAllocator; pub type CFMutableDictionaryRef = *mut __CFDictionary; pub type CFDictionaryRef = *const __CFDictionary; #[allow(non_camel_case_types)] pub type io_name_t = [u8; 128]; #[allow(non_camel_case_types)] pub type io_registry_entry_t = io_object_t; pub type CFTypeRef = *const c_void; pub type CFStringRef = *const __CFString; //#[allow(non_camel_case_types)] //pub type policy_t = i32; #[allow(non_camel_case_types)] //pub type integer_t = i32; //#[allow(non_camel_case_types)] //pub type time_t = i64; //#[allow(non_camel_case_types)] //pub type suseconds_t = i32; //#[allow(non_camel_case_types)] //pub type mach_vm_size_t = u64; //#[allow(non_camel_case_types)] //pub type task_t = u32; //#[allow(non_camel_case_types)] //pub type pid_t = i32; #[allow(non_camel_case_types)] pub type natural_t = u32; #[allow(non_camel_case_types)] pub type mach_port_t = u32; #[allow(non_camel_case_types)] pub type io_object_t = mach_port_t; #[allow(non_camel_case_types)] pub type io_iterator_t = io_object_t; #[allow(non_camel_case_types)] pub type io_connect_t = io_object_t; #[allow(non_camel_case_types)] pub type boolean_t = c_uint; #[allow(non_camel_case_types)] pub type kern_return_t = c_int; pub type Boolean = c_uchar; pub type IOOptionBits = u32; pub type CFStringEncoding = u32; /*#[repr(C)] pub struct task_thread_times_info { pub user_time: time_value, pub system_time: time_value, }*/ /*#[repr(C)] pub struct task_basic_info_64 { pub suspend_count: integer_t, pub virtual_size: mach_vm_size_t, pub resident_size: mach_vm_size_t, pub user_time: time_value_t, pub system_time: time_value_t, pub policy: policy_t, }*/ #[repr(C)] pub struct vm_statistics64 { pub free_count: natural_t, pub active_count: natural_t, pub inactive_count: natural_t, pub wire_count: natural_t, pub zero_fill_count: u64, pub reactivations: u64, pub pageins: u64, pub pageouts: u64, pub faults: u64, pub cow_faults: u64, pub lookups: u64, pub hits: u64, pub purges: u64, pub purgeable_count: natural_t, pub speculative_count: natural_t, pub decompressions: u64, pub compressions: u64, pub swapins: u64, pub swapouts: u64, pub compressor_page_count: natural_t, pub throttled_count: natural_t, pub external_page_count: natural_t, pub internal_page_count: natural_t, pub total_uncompressed_pages_in_compressor: u64, } #[repr(C)] pub struct Val_t { pub key: [i8; 5], pub data_size: u32, pub data_type: [i8; 5], // UInt32Char_t pub bytes: [i8; 32], // SMCBytes_t } #[repr(C)] pub struct KeyData_vers_t { pub major: u8, pub minor: u8, pub build: u8, pub reserved: [u8; 1], pub release: u16, } #[repr(C)] pub struct KeyData_pLimitData_t { pub version: u16, pub length: u16, pub cpu_plimit: u32, pub gpu_plimit: u32, pub mem_plimit: u32, } #[repr(C)] pub struct KeyData_keyInfo_t { pub data_size: u32, pub data_type: u32, pub data_attributes: u8, } #[repr(C)] pub struct KeyData_t { pub key: u32, pub vers: KeyData_vers_t, pub p_limit_data: KeyData_pLimitData_t, pub key_info: KeyData_keyInfo_t, pub result: u8, pub status: u8, pub data8: u8, pub data32: u32, pub bytes: [i8; 32], // SMCBytes_t } #[repr(C)] pub struct xsw_usage { pub xsu_total: u64, pub xsu_avail: u64, pub xsu_used: u64, pub xsu_pagesize: u32, pub xsu_encrypted: boolean_t, } //pub const HOST_CPU_LOAD_INFO_COUNT: usize = 4; //pub const HOST_CPU_LOAD_INFO: u32 = 3; pub const KERN_SUCCESS: u32 = 0; pub const HW_NCPU: u32 = 3; pub const CTL_HW: u32 = 6; pub const CTL_VM: u32 = 2; pub const VM_SWAPUSAGE: u32 = 5; pub const PROCESSOR_CPU_LOAD_INFO: u32 = 2; pub const CPU_STATE_USER: u32 = 0; pub const CPU_STATE_SYSTEM: u32 = 1; pub const CPU_STATE_IDLE: u32 = 2; pub const CPU_STATE_NICE: u32 = 3; pub const CPU_STATE_MAX: usize = 4; pub const HW_MEMSIZE: u32 = 24; //pub const TASK_THREAD_TIMES_INFO: u32 = 3; //pub const TASK_THREAD_TIMES_INFO_COUNT: u32 = 4; //pub const TASK_BASIC_INFO_64: u32 = 5; //pub const TASK_BASIC_INFO_64_COUNT: u32 = 10; pub const HOST_VM_INFO64: u32 = 4; pub const HOST_VM_INFO64_COUNT: u32 = 38; pub const MACH_PORT_NULL: i32 = 0; pub const KERNEL_INDEX_SMC: i32 = 2; pub const SMC_CMD_READ_KEYINFO: u8 = 9; pub const SMC_CMD_READ_BYTES: u8 = 5; pub const KIO_RETURN_SUCCESS: i32 = 0; #[allow(non_upper_case_globals)] pub const kCFStringEncodingMacRoman: CFStringEncoding = 0; sysinfo-0.9.5/src/windows/macros.rs010064400007650000024000000005361343701320300155510ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // /// Allows to cast only when needed. #[macro_export] macro_rules! auto_cast { ($t:expr, $cast:ty) => {{ #[cfg(target_pointer_width = "32")] { $t as $cast } #[cfg(not(target_pointer_width = "32"))] { $t } }} } sysinfo-0.9.5/src/windows/mod.rs010064400007650000024000000013611333211327500150450ustar0000000000000000// // Sysinfo // // Copyright (c) 2015 Guillaume Gomez // /*pub mod component; pub mod disk; mod ffi; pub mod network; pub mod process; pub mod processor; pub mod system; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process,ProcessStatus}; pub use self::processor::Processor; pub use self::system::System;*/ mod component; mod disk; //mod ffi; #[macro_use] mod macros; mod network; mod process; mod processor; mod system; mod tools; pub use self::component::Component; pub use self::disk::{Disk, DiskType}; pub use self::network::NetworkData; pub use self::process::{Process, ProcessStatus}; pub use self::processor::Processor; pub use self::system::System; sysinfo-0.9.5/src/windows/network.rs010064400007650000024000000024221342016302400157510ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use NetworkExt; use windows::tools::KeyHandler; use windows::processor::Query; /// Contains network information. pub struct NetworkData { current_out: u64, current_in: u64, keys_in: Vec, keys_out: Vec, } impl NetworkExt for NetworkData { fn get_income(&self) -> u64 { self.current_in } fn get_outcome(&self) -> u64 { self.current_out } } pub fn new() -> NetworkData { NetworkData { current_in: 0, current_out: 0, keys_in: Vec::new(), keys_out: Vec::new(), } } pub fn refresh(network: &mut NetworkData, query: &Option) { if let &Some(ref query) = query { network.current_in = 0; for key in &network.keys_in { network.current_in += query.get_u64(&key.unique_id).expect("key disappeared"); } network.current_out = 0; for key in &network.keys_out { network.current_out += query.get_u64(&key.unique_id).expect("key disappeared"); } } } pub fn get_keys_in(network: &mut NetworkData) -> &mut Vec { &mut network.keys_in } pub fn get_keys_out(network: &mut NetworkData) -> &mut Vec { &mut network.keys_out } sysinfo-0.9.5/src/windows/process.rs010064400007650000024000000365501342016302400157470ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use std::fmt::{self, Formatter, Debug}; use std::mem::{size_of, zeroed}; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::str; use libc::{c_uint, c_void, memcpy}; use Pid; use ProcessExt; use winapi::shared::minwindef::{DWORD, FALSE, FILETIME, MAX_PATH/*, TRUE, USHORT*/}; use winapi::um::handleapi::CloseHandle; use winapi::um::winnt::{ HANDLE, ULARGE_INTEGER, /*THREAD_GET_CONTEXT, THREAD_QUERY_INFORMATION, THREAD_SUSPEND_RESUME,*/ /*, PWSTR*/ PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE, PROCESS_VM_READ, }; use winapi::um::processthreadsapi::{GetProcessTimes, OpenProcess, TerminateProcess}; use winapi::um::psapi::{ GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS, PROCESS_MEMORY_COUNTERS_EX, EnumProcessModulesEx, GetModuleBaseNameW, GetModuleFileNameExW, LIST_MODULES_ALL, }; use winapi::um::sysinfoapi::GetSystemTimeAsFileTime; use winapi::um::tlhelp32::{ CreateToolhelp32Snapshot, Process32First, Process32Next, PROCESSENTRY32, TH32CS_SNAPPROCESS, }; /// Enum describing the different status of a process. #[derive(Clone, Copy, Debug)] pub enum ProcessStatus { /// Currently runnable. Run, } impl ProcessStatus { /// Used to display `ProcessStatus`. pub fn to_string(&self) -> &str { match *self { ProcessStatus::Run => "Runnable", } } } impl fmt::Display for ProcessStatus { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_string()) } } fn get_process_handler(pid: Pid) -> Option { if pid == 0 { return None; } let options = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE; let process_handler = unsafe { OpenProcess(options, FALSE, pid as DWORD) }; if process_handler.is_null() { let options = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; let process_handler = unsafe { OpenProcess(options, FALSE, pid as DWORD) }; if process_handler.is_null() { None } else { Some(process_handler) } } else { Some(process_handler) } } #[derive(Clone)] struct HandleWrapper(HANDLE); impl Deref for HandleWrapper { type Target = HANDLE; fn deref(&self) -> &HANDLE { &self.0 } } unsafe impl Send for HandleWrapper {} unsafe impl Sync for HandleWrapper {} /// Struct containing a process' information. #[derive(Clone)] pub struct Process { name: String, cmd: Vec, exe: PathBuf, pid: Pid, environ: Vec, cwd: PathBuf, root: PathBuf, memory: u64, parent: Option, status: ProcessStatus, handle: HandleWrapper, old_cpu: u64, old_sys_cpu: u64, old_user_cpu: u64, start_time: u64, cpu_usage: f32, } // TODO: it's possible to get environment variables like it's done in // https://github.com/processhacker/processhacker // // They have a very nice function called PhGetProcessEnvironment. Just very complicated as it // seems... impl ProcessExt for Process { fn new(pid: Pid, parent: Option, _: u64) -> Process { if let Some(process_handler) = get_process_handler(pid) { let mut h_mod = ::std::ptr::null_mut(); let mut process_name = [0u16; MAX_PATH + 1]; let mut cb_needed = 0; unsafe { if EnumProcessModulesEx(process_handler, &mut h_mod, ::std::mem::size_of::() as DWORD, &mut cb_needed, LIST_MODULES_ALL) != 0 { GetModuleBaseNameW(process_handler, h_mod, process_name.as_mut_ptr(), MAX_PATH as DWORD + 1); } let mut pos = 0; for x in process_name.iter() { if *x == 0 { break } pos += 1; } let name = String::from_utf16_lossy(&process_name[..pos]); let environ = get_proc_env(process_handler, pid as u32, &name); let mut exe_buf = [0u16; MAX_PATH + 1]; GetModuleFileNameExW(process_handler, h_mod, exe_buf.as_mut_ptr(), MAX_PATH as DWORD + 1); pos = 0; for x in exe_buf.iter() { if *x == 0 { break } pos += 1; } let exe = PathBuf::from(String::from_utf16_lossy(&exe_buf[..pos])); let mut root = exe.clone(); root.pop(); Process { handle: HandleWrapper(process_handler), name: name, pid: pid, parent: parent, cmd: get_cmd_line(pid), environ: environ, exe: exe, cwd: PathBuf::new(), root: root, status: ProcessStatus::Run, memory: 0, cpu_usage: 0., old_cpu: 0, old_sys_cpu: 0, old_user_cpu: 0, start_time: get_start_time(process_handler), } } } else { Process { handle: HandleWrapper(::std::ptr::null_mut()), name: String::new(), pid: pid, parent: parent, cmd: get_cmd_line(pid), environ: Vec::new(), exe: get_executable_path(pid), cwd: PathBuf::new(), root: PathBuf::new(), status: ProcessStatus::Run, memory: 0, cpu_usage: 0., old_cpu: 0, old_sys_cpu: 0, old_user_cpu: 0, start_time: 0, } } } fn kill(&self, signal: ::Signal) -> bool { if self.handle.is_null() { false } else { unsafe { TerminateProcess(*self.handle, signal as c_uint) != 0 } } } fn name(&self) -> &str { &self.name } fn cmd(&self) -> &[String] { &self.cmd } fn exe(&self) -> &Path { self.exe.as_path() } fn pid(&self) -> Pid { self.pid } fn environ(&self) -> &[String] { &self.environ } fn cwd(&self) -> &Path { self.cwd.as_path() } fn root(&self) -> &Path { self.root.as_path() } fn memory(&self) -> u64 { self.memory } fn parent(&self) -> Option { self.parent } fn status(&self) -> ProcessStatus { self.status } fn start_time(&self) -> u64 { self.start_time } fn cpu_usage(&self) -> f32 { self.cpu_usage } } impl Drop for Process { fn drop(&mut self) { unsafe { if self.handle.is_null() { return } CloseHandle(*self.handle); } } } #[allow(unused_must_use)] impl Debug for Process { fn fmt(&self, f: &mut Formatter) -> fmt::Result { writeln!(f, "pid: {}", self.pid); writeln!(f, "name: {}", self.name); writeln!(f, "environment:"); for var in self.environ.iter() { if var.len() > 0 { writeln!(f, "\t{}", var); } } writeln!(f, "command:"); for arg in &self.cmd { writeln!(f, "\t{}", arg); } writeln!(f, "executable path: {:?}", self.exe); writeln!(f, "current working directory: {:?}", self.cwd); writeln!(f, "memory usage: {} kB", self.memory); writeln!(f, "cpu usage: {}", self.cpu_usage); writeln!(f, "root path: {:?}", self.root) } } unsafe fn get_start_time(handle: HANDLE) -> u64 { let mut fstart: FILETIME = zeroed(); let mut x = zeroed(); GetProcessTimes(handle, &mut fstart as *mut FILETIME, &mut x as *mut FILETIME, &mut x as *mut FILETIME, &mut x as *mut FILETIME); let tmp = (fstart.dwHighDateTime as u64) << 32 | (fstart.dwLowDateTime as u64); tmp / 10_000_000 - 11_644_473_600 } pub unsafe fn get_parent_process_id(pid: Pid) -> Option { let snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); let mut entry: PROCESSENTRY32 = zeroed(); entry.dwSize = size_of::() as u32; let mut not_the_end = Process32First(snapshot, &mut entry); while not_the_end != 0 { if pid == entry.th32ProcessID as usize { // TODO: if some day I have the motivation to add threads: // ListProcessThreads(entry.th32ProcessID); CloseHandle(snapshot); return Some(entry.th32ParentProcessID as usize); } not_the_end = Process32Next(snapshot, &mut entry); } CloseHandle(snapshot); None } /*fn run_wmi(args: &[&str]) -> Option { use std::process::Command; if let Ok(out) = Command::new("wmic") .args(args) .output() { if out.status.success() { return Some(String::from_utf8_lossy(&out.stdout).into_owned()); } } None }*/ fn get_cmd_line(_pid: Pid) -> Vec { /*let where_req = format!("ProcessId={}", pid); if let Some(ret) = run_wmi(&["process", "where", &where_req, "get", "CommandLine"]) { for line in ret.lines() { if line.is_empty() || line == "CommandLine" { continue } return vec![line.to_owned()]; } }*/ Vec::new() } unsafe fn get_proc_env(_handle: HANDLE, _pid: u32, _name: &str) -> Vec { let ret = Vec::new(); /* println!("current pid: {}", kernel32::GetCurrentProcessId()); if kernel32::GetCurrentProcessId() == pid { println!("current proc!"); for (key, value) in env::vars() { ret.push(format!("{}={}", key, value)); } return ret; } println!("1"); let snapshot_handle = kernel32::CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); if !snapshot_handle.is_null() { println!("2"); let mut target_thread: THREADENTRY32 = zeroed(); target_thread.dwSize = size_of::() as DWORD; if kernel32::Thread32First(snapshot_handle, &mut target_thread) == TRUE { println!("3"); loop { if target_thread.th32OwnerProcessID == pid { println!("4"); let thread_handle = kernel32::OpenThread(THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION | THREAD_GET_CONTEXT, FALSE, target_thread.th32ThreadID); if !thread_handle.is_null() { println!("5 -> {}", pid); if kernel32::SuspendThread(thread_handle) != DWORD::max_value() { println!("6"); let mut context = zeroed(); if kernel32::GetThreadContext(thread_handle, &mut context) != 0 { println!("7 --> {:?}", context); let mut x = vec![0u8; 10]; if kernel32::ReadProcessMemory(handle, context.MxCsr as usize as *mut winapi::c_void, x.as_mut_ptr() as *mut winapi::c_void, x.len() as u64, ::std::ptr::null_mut()) != 0 { for y in x { print!("{}", y as char); } println!(""); } else { println!("failure... {:?}", kernel32::GetLastError()); } } else { println!("-> {:?}", kernel32::GetLastError()); } kernel32::ResumeThread(thread_handle); } kernel32::CloseHandle(thread_handle); } break; } if kernel32::Thread32Next(snapshot_handle, &mut target_thread) != TRUE { break; } } } kernel32::CloseHandle(snapshot_handle); }*/ ret } pub fn get_executable_path(_pid: Pid) -> PathBuf { /*let where_req = format!("ProcessId={}", pid); if let Some(ret) = run_wmi(&["process", "where", &where_req, "get", "ExecutablePath"]) { for line in ret.lines() { if line.is_empty() || line == "ExecutablePath" { continue } return line.to_owned(); } }*/ PathBuf::new() } pub fn compute_cpu_usage(p: &mut Process, nb_processors: u64) { unsafe { let mut now: ULARGE_INTEGER = ::std::mem::zeroed(); let mut sys: ULARGE_INTEGER = ::std::mem::zeroed(); let mut user: ULARGE_INTEGER = ::std::mem::zeroed(); let mut ftime: FILETIME = zeroed(); let mut fsys: FILETIME = zeroed(); let mut fuser: FILETIME = zeroed(); GetSystemTimeAsFileTime(&mut ftime); memcpy(&mut now as *mut ULARGE_INTEGER as *mut c_void, &mut ftime as *mut FILETIME as *mut c_void, size_of::()); GetProcessTimes(*p.handle, &mut ftime as *mut FILETIME, &mut ftime as *mut FILETIME, &mut fsys as *mut FILETIME, &mut fuser as *mut FILETIME); memcpy(&mut sys as *mut ULARGE_INTEGER as *mut c_void, &mut fsys as *mut FILETIME as *mut c_void, size_of::()); memcpy(&mut user as *mut ULARGE_INTEGER as *mut c_void, &mut fuser as *mut FILETIME as *mut c_void, size_of::()); p.cpu_usage = ((*sys.QuadPart() - p.old_sys_cpu) as f32 + (*user.QuadPart() - p.old_user_cpu) as f32) / (*now.QuadPart() - p.old_cpu) as f32 / nb_processors as f32 * 100.; p.old_cpu = *now.QuadPart(); p.old_user_cpu = *user.QuadPart(); p.old_sys_cpu = *sys.QuadPart(); } } pub fn get_handle(p: &Process) -> HANDLE { *p.handle } pub fn update_proc_info(p: &mut Process) { update_memory(p); } pub fn update_memory(p: &mut Process) { unsafe { let mut pmc: PROCESS_MEMORY_COUNTERS_EX = zeroed(); if GetProcessMemoryInfo(*p.handle, &mut pmc as *mut PROCESS_MEMORY_COUNTERS_EX as *mut c_void as *mut PROCESS_MEMORY_COUNTERS, size_of::() as DWORD) != 0 { p.memory = (pmc.PrivateUsage as u64) >> 10u64; // / 1024; } } } sysinfo-0.9.5/src/windows/processor.rs010064400007650000024000000174261333211327500163160ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // use std::collections::HashMap; use std::sync::{Arc, Mutex}; use std::thread::{self/*, sleep*/, JoinHandle}; //use std::time::Duration; use ProcessorExt; use windows::tools::KeyHandler; use winapi::shared::minwindef::{FALSE, ULONG}; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::pdh::{ PDH_FMT_COUNTERVALUE, PDH_FMT_DOUBLE, PDH_FMT_LARGE, PDH_HCOUNTER, PDH_HQUERY, PdhAddCounterW, PdhCollectQueryData, PdhCollectQueryDataEx, PdhGetFormattedCounterValue, PdhOpenQueryA, }; use winapi::um::synchapi::{CreateEventA, WaitForSingleObject}; use winapi::um::winbase::{INFINITE, WAIT_OBJECT_0}; use winapi::um::winnt::HANDLE; #[derive(Debug)] pub enum CounterValue { Float(f32), Integer(u64), } impl CounterValue { pub fn get_f32(&self) -> f32 { match *self { CounterValue::Float(v) => v, _ => panic!("not a float"), } } pub fn get_u64(&self) -> u64 { match *self { CounterValue::Integer(v) => v, _ => panic!("not an integer"), } } } #[allow(dead_code)] #[derive(Debug)] struct Counter { counter: PDH_HCOUNTER, value: CounterValue, getter: Vec, } impl Counter { fn new_f32(counter: PDH_HCOUNTER, value: f32, getter: Vec) -> Counter { Counter { counter: counter, value: CounterValue::Float(value), getter: getter, } } fn new_u64(counter: PDH_HCOUNTER, value: u64, getter: Vec) -> Counter { Counter { counter: counter, value: CounterValue::Integer(value), getter: getter, } } } struct InternalQuery { query: PDH_HQUERY, event: HANDLE, data: Mutex>, } unsafe impl Send for InternalQuery {} unsafe impl Sync for InternalQuery {} impl InternalQuery { pub fn record(&self) -> bool { unsafe { let status = PdhCollectQueryData(self.query); if status != ERROR_SUCCESS as i32 { println!("error: {:?} {} {:?}", status, ERROR_SUCCESS, self.query); return false; } if PdhCollectQueryDataEx(self.query, 1, self.event) != ERROR_SUCCESS as i32 { return false; } if WaitForSingleObject(self.event, INFINITE) == WAIT_OBJECT_0 { if let Ok(ref mut data) = self.data.lock() { let mut counter_type: ULONG = 0; let mut display_value: PDH_FMT_COUNTERVALUE = ::std::mem::zeroed(); for (_, x) in data.iter_mut() { match x.value { CounterValue::Float(ref mut value) => { if PdhGetFormattedCounterValue(x.counter, PDH_FMT_DOUBLE, &mut counter_type, &mut display_value) == ERROR_SUCCESS as i32 { *value = *display_value.u.doubleValue() as f32 / 100f32; } } CounterValue::Integer(ref mut value) => { if PdhGetFormattedCounterValue(x.counter, PDH_FMT_LARGE, &mut counter_type, &mut display_value) == ERROR_SUCCESS as i32 { *value = *display_value.u.largeValue() as u64; } } } } } true } else { false } } } } pub struct Query { internal: Arc, thread: Option>, } impl Query { pub fn new() -> Option { let mut query = ::std::ptr::null_mut(); unsafe { if PdhOpenQueryA(::std::ptr::null_mut(), 0, &mut query) == ERROR_SUCCESS as i32 { let event = CreateEventA(::std::ptr::null_mut(), FALSE, FALSE, b"some_ev\0".as_ptr() as *const i8); if event.is_null() { None } else { let q = Arc::new(InternalQuery { query: query, event: event, data: Mutex::new(HashMap::new()), }); Some( Query { internal: q, thread: None, }) } } else { None } } } pub fn get(&self, name: &String) -> Option { if let Ok(data) = self.internal.data.lock() { if let Some(ref counter) = data.get(name) { return Some(counter.value.get_f32()); } } None } pub fn get_u64(&self, name: &String) -> Option { if let Ok(data) = self.internal.data.lock() { if let Some(ref counter) = data.get(name) { return Some(counter.value.get_u64()); } } None } pub fn add_counter(&mut self, name: &String, getter: Vec, value: CounterValue) -> bool { if let Ok(data) = self.internal.data.lock() { if data.contains_key(name) { return false; } } unsafe { let mut counter: PDH_HCOUNTER = ::std::mem::zeroed(); let ret = PdhAddCounterW(self.internal.query, getter.as_ptr(), 0, &mut counter); if ret == ERROR_SUCCESS as i32 { self.internal.data.lock() .expect("couldn't add counter...") .insert(name.clone(), match value { CounterValue::Float(v) => Counter::new_f32(counter, v, getter), CounterValue::Integer(v) => Counter::new_u64(counter, v, getter), }); } else { eprintln!("failed to add counter '{}': {:x}...", name, ret); return false; } } true } pub fn start(&mut self) { let internal = Arc::clone(&self.internal); self.thread = Some( thread::spawn(move || { loop { internal.record(); } })); } } /// Struct containing a processor information. pub struct Processor { name: String, cpu_usage: f32, key_idle: Option, key_used: Option, } impl ProcessorExt for Processor { fn get_cpu_usage(&self) -> f32 { self.cpu_usage } fn get_name(&self) -> &str { &self.name } } impl Processor { fn new_with_values(name: &str) -> Processor { Processor { name: name.to_owned(), cpu_usage: 0f32, key_idle: None, key_used: None, } } } pub fn create_processor(name: &str) -> Processor { Processor::new_with_values(name) } pub fn set_cpu_usage(p: &mut Processor, value: f32) { p.cpu_usage = value; } pub fn get_key_idle(p: &mut Processor) -> &mut Option { &mut p.key_idle } pub fn get_key_used(p: &mut Processor) -> &mut Option { &mut p.key_used } sysinfo-0.9.5/src/windows/system.rs010064400007650000024000000334321350341760200156170ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use sys::component::{self, Component}; use sys::disk::Disk; use sys::processor::*; use std::cell::UnsafeCell; use std::collections::HashMap; use std::mem::{size_of, zeroed}; use DiskExt; use Pid; use ProcessExt; use RefreshKind; use SystemExt; use windows::network::{self, NetworkData}; use windows::processor::CounterValue; use windows::tools::*; use windows::process::{ Process, compute_cpu_usage, get_handle, get_parent_process_id, update_proc_info, }; use winapi::shared::minwindef::{DWORD, FALSE}; use winapi::shared::winerror::ERROR_SUCCESS; use winapi::um::minwinbase::STILL_ACTIVE; use winapi::um::pdh::PdhEnumObjectItemsW; use winapi::um::processthreadsapi::GetExitCodeProcess; use winapi::um::psapi::K32EnumProcesses; use winapi::um::sysinfoapi::{ GlobalMemoryStatusEx, MEMORYSTATUSEX, }; use winapi::um::winnt::HANDLE; use rayon::prelude::*; const PROCESS_LEN: usize = 10192; /// Struct containing system's information. pub struct System { process_list: HashMap, mem_total: u64, mem_free: u64, swap_total: u64, swap_free: u64, processors: Vec, temperatures: Vec, disks: Vec, query: Option, network: NetworkData, uptime: u64, } impl System { fn clear_procs(&mut self) { if self.processors.len() > 0 { let mut to_delete = Vec::new(); for (pid, proc_) in self.process_list.iter_mut() { if !is_proc_running(get_handle(proc_)) { to_delete.push(*pid); } else { compute_cpu_usage(proc_, self.processors.len() as u64 - 1); } } for pid in to_delete { self.process_list.remove(&pid); } } } } struct Wrap(Process); unsafe impl Send for Wrap {} struct WrapSystem<'a>(UnsafeCell<&'a mut System>); impl<'a> WrapSystem<'a> { fn get(&self) -> &'a mut System { unsafe { *(self.0.get()) } } } unsafe impl<'a> Send for WrapSystem<'a> {} unsafe impl<'a> Sync for WrapSystem<'a> {} impl SystemExt for System { #[allow(non_snake_case)] fn new_with_specifics(refreshes: RefreshKind) -> System { let mut s = System { process_list: HashMap::new(), mem_total: 0, mem_free: 0, swap_total: 0, swap_free: 0, processors: init_processors(), temperatures: component::get_components(), disks: Vec::new(), query: Query::new(), network: network::new(), uptime: get_uptime(), }; // TODO: in case a translation fails, it might be nice to log it somewhere... if let Some(ref mut query) = s.query { let x = unsafe { load_symbols() }; if let Some(processor_trans) = get_translation(&"Processor".to_owned(), &x) { let idle_time_trans = get_translation(&"% Idle Time".to_owned(), &x); let proc_time_trans = get_translation(&"% Processor Time".to_owned(), &x); if let Some(ref proc_time_trans) = proc_time_trans { add_counter(format!("\\{}(_Total)\\{}", processor_trans, proc_time_trans), query, get_key_used(&mut s.processors[0]), "tot_0".to_owned(), CounterValue::Float(0.)); } if let Some(ref idle_time_trans) = idle_time_trans { add_counter(format!("\\{}(_Total)\\{}", processor_trans, idle_time_trans), query, get_key_idle(&mut s.processors[0]), "tot_1".to_owned(), CounterValue::Float(0.)); } for (pos, proc_) in s.processors.iter_mut().skip(1).enumerate() { if let Some(ref proc_time_trans) = proc_time_trans { add_counter(format!("\\{}({})\\{}", processor_trans, pos, proc_time_trans), query, get_key_used(proc_), format!("{}_0", pos), CounterValue::Float(0.)); } if let Some(ref idle_time_trans) = idle_time_trans { add_counter(format!("\\{}({})\\{}", processor_trans, pos, idle_time_trans), query, get_key_idle(proc_), format!("{}_1", pos), CounterValue::Float(0.)); } } } if let Some(network_trans) = get_translation(&"Network Interface".to_owned(), &x) { let network_in_trans = get_translation(&"Bytes Received/Sec".to_owned(), &x); let network_out_trans = get_translation(&"Bytes Sent/sec".to_owned(), &x); const PERF_DETAIL_WIZARD: DWORD = 400; const PDH_MORE_DATA: DWORD = 0x800007D2; let mut network_trans_utf16: Vec = network_trans.encode_utf16().collect(); network_trans_utf16.push(0); let mut dwCounterListSize: DWORD = 0; let mut dwInstanceListSize: DWORD = 0; let status = unsafe { PdhEnumObjectItemsW(::std::ptr::null(), ::std::ptr::null(), network_trans_utf16.as_ptr(), ::std::ptr::null_mut(), &mut dwCounterListSize, ::std::ptr::null_mut(), &mut dwInstanceListSize, PERF_DETAIL_WIZARD, 0) }; if status != PDH_MORE_DATA as i32 { panic!("got invalid status: {:x}", status); } let mut pwsCounterListBuffer: Vec = Vec::with_capacity(dwCounterListSize as usize); let mut pwsInstanceListBuffer: Vec = Vec::with_capacity(dwInstanceListSize as usize); unsafe { pwsCounterListBuffer.set_len(dwCounterListSize as usize); pwsInstanceListBuffer.set_len(dwInstanceListSize as usize); } let status = unsafe { PdhEnumObjectItemsW(::std::ptr::null(), ::std::ptr::null(), network_trans_utf16.as_ptr(), pwsCounterListBuffer.as_mut_ptr(), &mut dwCounterListSize, pwsInstanceListBuffer.as_mut_ptr(), &mut dwInstanceListSize, PERF_DETAIL_WIZARD, 0) }; if status != ERROR_SUCCESS as i32 { panic!("got invalid status: {:x}", status); } for (pos, x) in pwsInstanceListBuffer.split(|x| *x == 0) .filter(|x| x.len() > 0) .enumerate() { let net_interface = String::from_utf16(x).expect("invalid utf16"); if let Some(ref network_in_trans) = network_in_trans { let mut key_in = None; add_counter(format!("\\{}({})\\{}", network_trans, net_interface, network_in_trans), query, &mut key_in, format!("net{}_in", pos), CounterValue::Integer(0)); if key_in.is_some() { network::get_keys_in(&mut s.network).push(key_in.unwrap()); } } if let Some(ref network_out_trans) = network_out_trans { let mut key_out = None; add_counter(format!("\\{}({})\\{}", network_trans, net_interface, network_out_trans), query, &mut key_out, format!("net{}_out", pos), CounterValue::Integer(0)); if key_out.is_some() { network::get_keys_out(&mut s.network).push(key_out.unwrap()); } } } } query.start(); } s.refresh_specifics(refreshes); s } fn refresh_system(&mut self) { unsafe { let mut mem_info: MEMORYSTATUSEX = zeroed(); mem_info.dwLength = size_of::() as u32; GlobalMemoryStatusEx(&mut mem_info); self.mem_total = auto_cast!(mem_info.ullTotalPhys, u64); self.mem_free = auto_cast!(mem_info.ullAvailPhys, u64); //self.swap_total = auto_cast!(mem_info.ullTotalPageFile - mem_info.ullTotalPhys, u64); //self.swap_free = auto_cast!(mem_info.ullAvailPageFile, u64); } self.uptime = get_uptime(); if let Some(ref mut query) = self.query { for p in self.processors.iter_mut() { let mut idle_time = None; if let &mut Some(ref key_idle) = get_key_idle(p) { idle_time = Some(query.get(&key_idle.unique_id).expect("key disappeared")); } if let Some(idle_time) = idle_time { set_cpu_usage(p, 1. - idle_time); } } } } fn refresh_network(&mut self) { network::refresh(&mut self.network, &self.query); } fn refresh_process(&mut self, pid: Pid) -> bool { if refresh_existing_process(self, pid, true) == false { self.process_list.remove(&pid); false } else { true } } fn refresh_processes(&mut self) { // I think that 10192 as length will be enough to get all processes at once... let mut process_ids: Vec = Vec::with_capacity(PROCESS_LEN); let mut cb_needed = 0; unsafe { process_ids.set_len(PROCESS_LEN); } let size = ::std::mem::size_of::() * process_ids.len(); unsafe { if K32EnumProcesses(process_ids.as_mut_ptr(), size as DWORD, &mut cb_needed) == 0 { return } } let nb_processes = cb_needed / ::std::mem::size_of::() as DWORD; unsafe { process_ids.set_len(nb_processes as usize); } { let this = WrapSystem(UnsafeCell::new(self)); process_ids.par_iter() .filter_map(|pid| { let pid = *pid as usize; if !refresh_existing_process(this.get(), pid, false) { let ppid = unsafe { get_parent_process_id(pid) }; let mut p = Process::new(pid, ppid, 0); update_proc_info(&mut p); Some(Wrap(p)) } else { None } }) .collect::>() }.into_iter() .for_each(|p| { self.process_list.insert(p.0.pid(), p.0); }); self.clear_procs(); } fn refresh_disks(&mut self) { for disk in &mut self.disks { disk.update(); } } fn refresh_disk_list(&mut self) { self.disks = unsafe { get_disks() }; } fn get_process_list(&self) -> &HashMap { &self.process_list } fn get_process(&self, pid: Pid) -> Option<&Process> { self.process_list.get(&(pid as usize)) } fn get_processor_list(&self) -> &[Processor] { &self.processors[..] } fn get_total_memory(&self) -> u64 { self.mem_total >> 10 } fn get_free_memory(&self) -> u64 { self.mem_free >> 10 } fn get_used_memory(&self) -> u64 { (self.mem_total - self.mem_free) >> 10 } fn get_total_swap(&self) -> u64 { self.swap_total >> 10 } fn get_free_swap(&self) -> u64 { self.swap_free >> 10 } fn get_used_swap(&self) -> u64 { (self.swap_total - self.swap_free) >> 10 } fn get_components_list(&self) -> &[Component] { &self.temperatures[..] } fn get_disks(&self) -> &[Disk] { &self.disks[..] } fn get_network(&self) -> &NetworkData { &self.network } fn get_uptime(&self) -> u64 { self.uptime } } fn is_proc_running(handle: HANDLE) -> bool { let mut exit_code = 0; let ret = unsafe { GetExitCodeProcess(handle, &mut exit_code) }; !(ret == FALSE || exit_code != STILL_ACTIVE) } fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool { if let Some(ref mut entry) = s.process_list.get_mut(&(pid as usize)) { if !is_proc_running(get_handle(entry)) { return false; } update_proc_info(entry); if compute_cpu { compute_cpu_usage(entry, s.processors.len() as u64 - 1); } true } else { false } } sysinfo-0.9.5/src/windows/tools.rs010064400007650000024000000270131353425133300154320ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // use windows::processor::{create_processor, CounterValue, Processor, Query}; use sys::disk::{new_disk, Disk, DiskType}; use std::collections::HashMap; use std::ffi::OsStr; use std::mem::{size_of, zeroed}; use winapi::ctypes::c_void; use winapi::shared::minwindef::{BYTE, DWORD, MAX_PATH, TRUE}; use winapi::um::fileapi::{ CreateFileW, GetDriveTypeW, GetLogicalDrives, GetVolumeInformationW, OPEN_EXISTING, }; use winapi::um::handleapi::CloseHandle; use winapi::um::ioapiset::DeviceIoControl; use winapi::um::handleapi::INVALID_HANDLE_VALUE; use winapi::um::sysinfoapi::{ GetSystemInfo, GetTickCount64, SYSTEM_INFO, }; use winapi::um::winioctl::{ DISK_GEOMETRY, IOCTL_STORAGE_QUERY_PROPERTY, IOCTL_DISK_GET_DRIVE_GEOMETRY, }; use winapi::um::winnt::{ BOOLEAN, FILE_SHARE_READ, FILE_SHARE_WRITE, HANDLE, }; use winapi::um::winbase::DRIVE_FIXED; pub struct KeyHandler { pub unique_id: String, pub win_key: Vec, } impl KeyHandler { pub fn new(unique_id: String, win_key: Vec) -> KeyHandler { KeyHandler { unique_id: unique_id, win_key: win_key, } } } /*#[allow(non_snake_case)] #[allow(unused)] unsafe fn browser() { use winapi::um::pdh::{PdhBrowseCountersA, PDH_BROWSE_DLG_CONFIG_A}; use winapi::shared::winerror::ERROR_SUCCESS; let mut BrowseDlgData: PDH_BROWSE_DLG_CONFIG_A = ::std::mem::zeroed(); let mut CounterPathBuffer: [i8; 255] = ::std::mem::zeroed(); const PERF_DETAIL_WIZARD: u32 = 400; let text = b"Select a counter to monitor.\0"; BrowseDlgData.set_IncludeInstanceIndex(FALSE as u32); BrowseDlgData.set_SingleCounterPerAdd(TRUE as u32); BrowseDlgData.set_SingleCounterPerDialog(TRUE as u32); BrowseDlgData.set_LocalCountersOnly(FALSE as u32); BrowseDlgData.set_WildCardInstances(TRUE as u32); BrowseDlgData.set_HideDetailBox(TRUE as u32); BrowseDlgData.set_InitializePath(FALSE as u32); BrowseDlgData.set_DisableMachineSelection(FALSE as u32); BrowseDlgData.set_IncludeCostlyObjects(FALSE as u32); BrowseDlgData.set_ShowObjectBrowser(FALSE as u32); BrowseDlgData.hWndOwner = ::std::ptr::null_mut(); BrowseDlgData.szReturnPathBuffer = CounterPathBuffer.as_mut_ptr(); BrowseDlgData.cchReturnPathLength = 255; BrowseDlgData.pCallBack = None; BrowseDlgData.dwCallBackArg = 0; BrowseDlgData.CallBackStatus = ERROR_SUCCESS as i32; BrowseDlgData.dwDefaultDetailLevel = PERF_DETAIL_WIZARD; BrowseDlgData.szDialogBoxCaption = text as *const _ as usize as *mut i8; let ret = PdhBrowseCountersA(&mut BrowseDlgData as *mut _); println!("browser: {:?}", ret); for x in CounterPathBuffer.iter() { print!("{:?} ", *x); } println!(""); for x in 0..256 { print!("{:?} ", *BrowseDlgData.szReturnPathBuffer.offset(x)); } println!(""); }*/ pub fn init_processors() -> Vec { unsafe { let mut sys_info: SYSTEM_INFO = zeroed(); GetSystemInfo(&mut sys_info); let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1); for nb in 0..sys_info.dwNumberOfProcessors { ret.push(create_processor(&format!("CPU {}", nb + 1))); } ret.insert(0, create_processor("Total CPU")); ret } } pub unsafe fn open_drive(drive_name: &[u16], open_rights: DWORD) -> HANDLE { CreateFileW(drive_name.as_ptr(), open_rights, FILE_SHARE_READ | FILE_SHARE_WRITE, ::std::ptr::null_mut(), OPEN_EXISTING, 0, ::std::ptr::null_mut()) } pub unsafe fn get_drive_size(handle: HANDLE) -> u64 { let mut pdg: DISK_GEOMETRY = ::std::mem::zeroed(); let mut junk = 0; let result = DeviceIoControl(handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, ::std::ptr::null_mut(), 0, &mut pdg as *mut DISK_GEOMETRY as *mut c_void, size_of::() as DWORD, &mut junk, ::std::ptr::null_mut()); if result == TRUE { *pdg.Cylinders.QuadPart() as u64 * pdg.TracksPerCylinder as u64 * pdg.SectorsPerTrack as u64 * pdg.BytesPerSector as u64 } else { 0 } } pub unsafe fn get_disks() -> Vec { let mut disks = Vec::new(); let drives = GetLogicalDrives(); if drives == 0 { return disks; } for x in 0..size_of::() * 8 { if (drives >> x) & 1 == 0 { continue } let mount_point = [b'A' as u16 + x as u16, b':' as u16, b'\\' as u16, 0]; if GetDriveTypeW(mount_point.as_ptr()) != DRIVE_FIXED { continue } let mut name = [0u16; MAX_PATH + 1]; let mut file_system = [0u16; 32]; if GetVolumeInformationW(mount_point.as_ptr(), name.as_mut_ptr(), name.len() as DWORD, ::std::ptr::null_mut(), ::std::ptr::null_mut(), ::std::ptr::null_mut(), file_system.as_mut_ptr(), file_system.len() as DWORD) == 0 { continue } let mut pos = 0; for x in name.iter() { if *x == 0 { break } pos += 1; } let name = String::from_utf16_lossy(&name[..pos]); let name = OsStr::new(&name); pos = 0; for x in file_system.iter() { if *x == 0 { break } pos += 1; } let file_system: Vec = file_system[..pos].iter().map(|x| *x as u8).collect(); let drive_name = [b'\\' as u16, b'\\' as u16, b'.' as u16, b'\\' as u16, b'A' as u16 + x as u16, b':' as u16, 0]; let handle = open_drive(&drive_name, 0); if handle == INVALID_HANDLE_VALUE { disks.push(new_disk(name, &mount_point, &file_system, DiskType::Unknown(-1), 0)); CloseHandle(handle); continue } let disk_size = get_drive_size(handle); /*let mut spq_trim: ffi::STORAGE_PROPERTY_QUERY = ::std::mem::zeroed(); spq_trim.PropertyId = ffi::StorageDeviceTrimProperty; spq_trim.QueryType = ffi::PropertyStandardQuery; let mut dtd: ffi::DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed();*/ #[allow(non_snake_case)] #[repr(C)] struct STORAGE_PROPERTY_QUERY { PropertyId: i32, QueryType: i32, AdditionalParameters: [BYTE; 1] } #[allow(non_snake_case)] #[repr(C)] struct DEVICE_TRIM_DESCRIPTOR { Version: DWORD, Size: DWORD, TrimEnabled: BOOLEAN, } let mut spq_trim = STORAGE_PROPERTY_QUERY { PropertyId: 8i32, QueryType: 0i32, AdditionalParameters: [0], }; let mut dtd: DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed(); let mut dw_size = 0; if DeviceIoControl(handle, IOCTL_STORAGE_QUERY_PROPERTY, &mut spq_trim as *mut STORAGE_PROPERTY_QUERY as *mut c_void, size_of::() as DWORD, &mut dtd as *mut DEVICE_TRIM_DESCRIPTOR as *mut c_void, size_of::() as DWORD, &mut dw_size, ::std::ptr::null_mut()) == 0 || dw_size != size_of::() as DWORD { disks.push(new_disk(name, &mount_point, &file_system, DiskType::Unknown(-1), disk_size)); CloseHandle(handle); continue } let is_ssd = dtd.TrimEnabled != 0; CloseHandle(handle); disks.push(new_disk(name, &mount_point, &file_system, if is_ssd { DiskType::SSD } else { DiskType::HDD }, disk_size)); } disks } #[allow(non_snake_case)] pub unsafe fn load_symbols() -> HashMap { use winapi::um::winreg::{HKEY_PERFORMANCE_DATA, RegQueryValueExA}; let mut cbCounters = 0; let mut dwType = 0; let mut ret = HashMap::new(); let _dwStatus = RegQueryValueExA(HKEY_PERFORMANCE_DATA, b"Counter 009\0".as_ptr() as *const _, ::std::ptr::null_mut(), &mut dwType as *mut i32 as *mut _, ::std::ptr::null_mut(), &mut cbCounters as *mut i32 as *mut _); let mut lpmszCounters = Vec::with_capacity(cbCounters as usize); lpmszCounters.set_len(cbCounters as usize); let _dwStatus = RegQueryValueExA(HKEY_PERFORMANCE_DATA, b"Counter 009\0".as_ptr() as *const _, ::std::ptr::null_mut(), &mut dwType as *mut i32 as *mut _, lpmszCounters.as_mut_ptr(), &mut cbCounters as *mut i32 as *mut _); for (pos, s) in lpmszCounters.split(|x| *x == 0) .filter(|x| !x.is_empty()) .collect::>() .chunks(2) .filter(|&x| x.len() == 2) .filter_map(|x| { match (std::str::from_utf8(x[0]), String::from_utf8(x[1].to_vec())) { (Ok(n), Ok(s)) => { if let Ok(n) = u32::from_str_radix(n, 10) { Some((n, s)) } else { None } } _ => None, } }) { ret.insert(s, pos as u32); } ret } pub fn get_translation(s: &String, map: &HashMap) -> Option { use winapi::um::pdh::PdhLookupPerfNameByIndexW; if let Some(index) = map.get(s) { let mut size: usize = 0; unsafe { let _res = PdhLookupPerfNameByIndexW(::std::ptr::null(), *index, ::std::ptr::null_mut(), &mut size as *mut usize as *mut _); if size == 0 { return Some(String::new()); } else { let mut v = Vec::with_capacity(size); v.set_len(size); let _res = PdhLookupPerfNameByIndexW(::std::ptr::null(), *index, v.as_mut_ptr() as *mut _, &mut size as *mut usize as *mut _); return Some(String::from_utf16(&v[..size - 1]).expect("invalid utf16")); } } } None } pub fn add_counter(s: String, query: &mut Query, keys: &mut Option, counter_name: String, value: CounterValue) { let mut full = s.encode_utf16().collect::>(); full.push(0); if query.add_counter(&counter_name, full.clone(), value) { *keys = Some(KeyHandler::new(counter_name, full)); } } pub fn get_uptime() -> u64 { unsafe { GetTickCount64() / 1000 } } sysinfo-0.9.5/tests/disk_list.rs010064400007650000024000000004541333211327500151360ustar0000000000000000// // Sysinfo // // Copyright (c) 2017 Guillaume Gomez // extern crate sysinfo; #[test] fn test_disks() { use sysinfo::SystemExt; let s = sysinfo::System::new(); println!("total memory: {}", s.get_total_memory()); println!("total cpu cores: {}", s.get_processor_list().len()); } sysinfo-0.9.5/tests/process.rs010064400007650000024000000006521335155273200146350ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // extern crate sysinfo; #[test] fn test_process() { use sysinfo::{ProcessExt, SystemExt}; let mut s = sysinfo::System::new(); s.refresh_processes(); assert!(s.get_process_list().len() != 0); #[cfg(not(windows))] assert!(s.get_process_list() .values() .any(|p| p.exe().to_str().unwrap_or_else(|| "").len() != 0)); } sysinfo-0.9.5/tests/uptime.rs010064400007650000024000000003551333211327500144540ustar0000000000000000// // Sysinfo // // Copyright (c) 2018 Guillaume Gomez // extern crate sysinfo; #[test] fn test_uptime() { use sysinfo::SystemExt; let mut s = sysinfo::System::new(); s.refresh_all(); assert!(s.get_uptime() != 0); } sysinfo-0.9.5/.cargo_vcs_info.json0000644000000001120000000000000125720ustar00{ "git": { "sha1": "715da2c95d71635d26b248c24ee1873bfaaec2ea" } }