Repository: GuillaumeGomez/sysinfo
Pull request #136 (2018-09-22 23:39:51)

Update


Patch:
diff --git a/.gitignore b/.gitignore
index 9c74450..228a3e8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,3 +45,4 @@ rusty-tags.vi
 tags
 
 **.o
+simple
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index d2e070e..b41e263 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "sysinfo"
-version = "0.5.8"
+version = "0.6.0"
 authors = ["Guillaume Gomez <guillaume1.gomez@gmail.com>"]
 
 description = "Library to handle processes"
diff --git a/examples/src/simple.c b/examples/src/simple.c
index 0465d88..f065fb8 100644
--- a/examples/src/simple.c
+++ b/examples/src/simple.c
@@ -12,11 +12,14 @@
 #include "sysinfo.h"
 
 void print_process(CProcess process) {
-    printf("process[%d]: parent: %d, cpu_usage: %f, memory: %ld\n",
+    RString exe = sysinfo_process_get_executable_path(process);
+    printf("process[%d]: parent: %d, cpu_usage: %f, memory: %ld, executable path: '%s'\n",
            sysinfo_process_get_pid(process),
            sysinfo_process_get_parent_pid(process),
            sysinfo_process_get_cpu_usage(process),
-           sysinfo_process_get_memory(process));
+           sysinfo_process_get_memory(process),
+           exe);
+    sysinfo_rstring_free(exe);
 }
 
 void check_tasks(CSystem system) {
diff --git a/src/c_interface.rs b/src/c_interface.rs
index c57bf13..f4e9cb5 100644
--- a/src/c_interface.rs
+++ b/src/c_interface.rs
@@ -5,13 +5,16 @@
 //
 
 use std::borrow::BorrowMut;
-use libc::{self, c_uint, c_float, c_void, pid_t, size_t};
+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;
 
@@ -210,11 +213,12 @@ pub extern "C" fn sysinfo_get_processors_usage(system: CSystem,
     Box::into_raw(system);
 }
 
-/// Equivalent of `System.get_process_list()`. Returns an array ended by a null pointer. Must be freed.
+/// Equivalent of `System.get_process_list()`. Returns an array ended by a null pointer. Must
+/// be freed.
 ///
 /// # /!\ WARNING /!\
 ///
-/// While having this method processes, you should *never* call any refresh method!
+/// 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<ProcessLoop>,
                                         data: *mut c_void) -> size_t {
@@ -294,7 +298,7 @@ pub extern "C" fn sysinfo_process_get_pid(process: CProcess) -> pid_t {
 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(0) }
+    unsafe { (*process).parent().unwrap_or_else(|| 0) }
 }
 
 /// Equivalent of `Process.cpu_usage`.
@@ -310,5 +314,58 @@ pub extern "C" fn sysinfo_process_get_cpu_usage(process: CProcess) -> c_float {
 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 }
+    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); }
+    }
 }
diff --git a/src/linux/process.rs b/src/linux/process.rs
index 99ae41f..d3deadd 100644
--- a/src/linux/process.rs
+++ b/src/linux/process.rs
@@ -4,11 +4,13 @@
 // Copyright (c) 2015 Guillaume Gomez
 //
 
-use std::fmt::{self, Formatter, Debug};
 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 Pid;
 use ::ProcessExt;
 
 /// Enum describing the different status of a process.
@@ -99,12 +101,12 @@ impl fmt::Display for ProcessStatus {
 pub struct Process {
     pub(crate) name: String,
     pub(crate) cmd: Vec<String>,
-    pub(crate) exe: String,
+    pub(crate) exe: PathBuf,
     pub(crate) pid: Pid,
     parent: Option<Pid>,
     pub(crate) environ: Vec<String>,
-    pub(crate) cwd: String,
-    pub(crate) root: String,
+    pub(crate) cwd: PathBuf,
+    pub(crate) root: PathBuf,
     pub(crate) memory: u64,
     utime: u64,
     stime: u64,
@@ -130,9 +132,9 @@ impl ProcessExt for Process {
             parent,
             cmd: Vec::new(),
             environ: Vec::new(),
-            exe: String::new(),
-            cwd: String::new(),
-            root: String::new(),
+            exe: PathBuf::new(),
+            cwd: PathBuf::new(),
+            root: PathBuf::new(),
             memory: 0,
             cpu_usage: 0.,
             utime: 0,
@@ -160,8 +162,8 @@ impl ProcessExt for Process {
         &self.cmd
     }
 
-    fn exe(&self) -> &str {
-        &self.exe
+    fn exe(&self) -> &Path {
+        self.exe.as_path()
     }
 
     fn pid(&self) -> Pid {
@@ -172,12 +174,12 @@ impl ProcessExt for Process {
         &self.environ
     }
 
-    fn cwd(&self) -> &str {
-        &self.cwd
+    fn cwd(&self) -> &Path {
+        self.cwd.as_path()
     }
 
-    fn root(&self) -> &str {
-        &self.root
+    fn root(&self) -> &Path {
+        self.root.as_path()
     }
 
     fn memory(&self) -> u64 {
@@ -219,13 +221,13 @@ impl Debug for Process {
         for arg in &self.cmd {
             writeln!(f, "\t{}", arg);
         }
-        writeln!(f, "executable path: {}", self.exe);
-        writeln!(f, "current working directory: {}", self.cwd);
+        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)
+        write!(f, "root path: {:?}", self.root)
     }
 }
 
diff --git a/src/linux/system.rs b/src/linux/system.rs
index c3df933..1ad8c9a 100644
--- a/src/linux/system.rs
+++ b/src/linux/system.rs
@@ -159,8 +159,8 @@ impl SystemExt for System {
     }
 
     fn refresh_process(&mut self, pid: Pid) -> bool {
-        let found = match _get_process_data(&Path::new("/proc/").join(pid.to_string()), &mut self.process_list,
-                                self.page_size_kb, 0) {
+        let found = match _get_process_data(&Path::new("/proc/").join(pid.to_string()),
+                                            &mut self.process_list, self.page_size_kb, 0) {
             Ok(Some(p)) => {
                 self.process_list.tasks.insert(p.pid(), p);
                 false
@@ -437,6 +437,8 @@ fn _get_process_data(path: &Path, proc_list: &mut Process, page_size_kb: u64,
             }
 
             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();
@@ -448,7 +450,7 @@ fn _get_process_data(path: &Path, proc_list: &mut Process, page_size_kb: u64,
                 tmp.push("cmdline");
                 p.cmd = copy_from_file(&tmp);
                 p.name = p.cmd.get(0)
-                              .map(|x| x.split('/').last().unwrap_or("").to_owned())
+                              .map(|x| x.split('/').last().unwrap_or_else(|| "").to_owned())
                               .unwrap_or(String::new());
                 tmp = PathBuf::from(path);
                 tmp.push("environ");
@@ -456,21 +458,15 @@ fn _get_process_data(path: &Path, proc_list: &mut Process, page_size_kb: u64,
                 tmp = PathBuf::from(path);
                 tmp.push("exe");
 
-                let s = read_link(tmp.to_str().unwrap_or(""));
+                p.exe = read_link(tmp.to_str()
+                                     .unwrap_or_else(|| "")).unwrap_or_else(|_| PathBuf::new());
 
-                if s.is_ok() {
-                    p.exe = if let Ok(s) = s {
-                        s.to_str().unwrap_or("").to_owned()
-                    } else {
-                        String::new()
-                    };
-                }
                 tmp = PathBuf::from(path);
                 tmp.push("cwd");
-                p.cwd = realpath(&tmp).to_str().unwrap_or("").to_owned();
+                p.cwd = realpath(&tmp);
                 tmp = PathBuf::from(path);
                 tmp.push("root");
-                p.root = realpath(&tmp).to_str().unwrap_or("").to_owned();
+                p.root = realpath(&tmp);
             }
 
             update_time_and_memory(path, &mut p, &parts, page_size_kb, proc_list.memory, nb);
diff --git a/src/mac/process.rs b/src/mac/process.rs
index ffb6bb1..bec0a39 100644
--- a/src/mac/process.rs
+++ b/src/mac/process.rs
@@ -5,9 +5,11 @@
 //
 
 use std::fmt::{self, Formatter, Debug};
+use std::path::{Path, PathBuf};
+
 use libc::{c_int, gid_t, kill, uid_t};
-use Pid;
 
+use Pid;
 use ::ProcessExt;
 
 /// Enum describing the different status of a process.
@@ -115,12 +117,12 @@ impl fmt::Display for ThreadStatus {
 pub struct Process {
     pub(crate) name: String,
     pub(crate) cmd: Vec<String>,
-    pub(crate) exe: String,
+    pub(crate) exe: PathBuf,
     pid: Pid,
     parent: Option<Pid>,
     pub(crate) environ: Vec<String>,
-    cwd: String,
-    root: String,
+    cwd: PathBuf,
+    pub(crate) root: PathBuf,
     pub(crate) memory: u64,
     utime: u64,
     stime: u64,
@@ -149,9 +151,9 @@ impl ProcessExt for Process {
             parent,
             cmd: Vec::new(),
             environ: Vec::new(),
-            exe: String::new(),
-            cwd: String::new(),
-            root: String::new(),
+            exe: PathBuf::new(),
+            cwd: PathBuf::new(),
+            root: PathBuf::new(),
             memory: 0,
             cpu_usage: 0.,
             utime: 0,
@@ -179,8 +181,8 @@ impl ProcessExt for Process {
         &self.cmd
     }
 
-    fn exe(&self) -> &str {
-        &self.exe
+    fn exe(&self) -> &Path {
+        self.exe.as_path()
     }
 
     fn pid(&self) -> Pid {
@@ -191,12 +193,12 @@ impl ProcessExt for Process {
         &self.environ
     }
 
-    fn cwd(&self) -> &str {
-        &self.cwd
+    fn cwd(&self) -> &Path {
+        self.cwd.as_path()
     }
 
-    fn root(&self) -> &str {
-        &self.root
+    fn root(&self) -> &Path {
+        self.root.as_path()
     }
 
     fn memory(&self) -> u64 {
@@ -236,8 +238,8 @@ impl Debug for Process {
         for arg in &self.cmd {
             writeln!(f, "\t{}", arg);
         }
-        writeln!(f, "executable path: {}", self.exe);
-        writeln!(f, "current working directory: {}", self.cwd);
+        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);
@@ -245,7 +247,7 @@ impl Debug for Process {
             Some(ref v) => v.to_string(),
             None        => "Unknown",
         });
-        write!(f, "root path: {}", self.root)
+        write!(f, "root path: {:?}", self.root)
     }
 }
 
diff --git a/src/mac/system.rs b/src/mac/system.rs
index 537b0e8..39371d2 100644
--- a/src/mac/system.rs
+++ b/src/mac/system.rs
@@ -10,14 +10,19 @@ use sys::network::{self, NetworkData};
 use sys::processor::*;
 use sys::process::*;
 use sys::disk::{self, Disk, DiskType};
+
 use ::{ComponentExt, DiskExt, ProcessExt, ProcessorExt, SystemExt};
+
 use std::collections::HashMap;
 use std::ffi::{OsStr, OsString};
 use std::os::unix::ffi::OsStringExt;
-use libc::{self, c_void, c_int, size_t, c_char, sysconf, _SC_PAGESIZE};
 use std::sync::Arc;
+use std::path::Path;
 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;
 
@@ -388,9 +393,18 @@ fn update_process(wrap: &mut Wrap, pid: Pid,
                 while cp < ptr.offset(size as isize) && *cp != 0 {
                     cp = cp.offset(1);
                 }
-                p.exe = get_unchecked_str(cp, start);
-                if let Some(l) = p.exe.split('/').last() {
-                    p.name = l.to_owned();
+                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.offset(size as isize) && *cp == 0 {
                     cp = cp.offset(1);
@@ -418,6 +432,14 @@ fn update_process(wrap: &mut Wrap, pid: Pid,
                     }
                     cp = cp.offset(1);
                 }
+                if need_root == true {
+                    for env in p.environ.iter() {
+                        if env.starts_with("PATH=") {
+                            p.root = Path::new(&env[6..]).to_path_buf();
+                            break
+                        }
+                    }
+                }
             }
         } else {
             // we don't have enough priviledges to get access to these info
diff --git a/src/sysinfo.h b/src/sysinfo.h
index 9bce98a..db6d340 100644
--- a/src/sysinfo.h
+++ b/src/sysinfo.h
@@ -11,34 +11,39 @@
 
 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);
+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);
+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);
+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);
+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);
+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);
diff --git a/src/traits.rs b/src/traits.rs
index 11cb267..99034be 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -55,7 +55,7 @@ pub trait ProcessExt {
     fn cmd(&self) -> &[String];
 
     /// Returns the path to the processus.
-    fn exe(&self) -> &str;
+    fn exe(&self) -> &Path;
 
     /// Returns the pid of the processus.
     fn pid(&self) -> Pid;
@@ -68,12 +68,12 @@ pub trait ProcessExt {
     /// Returns the current working directory.
     ///
     /// Always empty on Windows.
-    fn cwd(&self) -> &str;
+    fn cwd(&self) -> &Path;
 
     /// Returns the path of the root directory.
     ///
     /// Always empty on Windows.
-    fn root(&self) -> &str;
+    fn root(&self) -> &Path;
 
     /// Returns the memory usage (in kB).
     fn memory(&self) -> u64;
diff --git a/src/windows/process.rs b/src/windows/process.rs
index e11f620..7804897 100644
--- a/src/windows/process.rs
+++ b/src/windows/process.rs
@@ -4,8 +4,9 @@
 // Copyright (c) 2018 Guillaume Gomez
 //
 
-use std::mem::{size_of, zeroed};
 use std::fmt::{self, Formatter, Debug};
+use std::mem::{size_of, zeroed};
+use std::path::{Path, PathBuf};
 use std::str;
 
 use libc::{c_uint, c_void, memcpy};
@@ -75,11 +76,11 @@ fn get_process_handler(pid: Pid) -> Option<HANDLE> {
 pub struct Process {
     name: String,
     cmd: Vec<String>,
-    exe: String,
+    exe: PathBuf,
     pid: Pid,
     environ: Vec<String>,
-    cwd: String,
-    root: String,
+    cwd: PathBuf,
+    root: PathBuf,
     memory: u64,
     parent: Option<Pid>,
     status: ProcessStatus,
@@ -131,8 +132,8 @@ impl ProcessExt for Process {
                     cmd: get_cmd_line(pid),
                     environ: environ,
                     exe: get_executable_path(pid),
-                    cwd: String::new(),
-                    root: String::new(),
+                    cwd: PathBuf::new(),
+                    root: PathBuf::new(),
                     status: ProcessStatus::Run,
                     memory: 0,
                     cpu_usage: 0.,
@@ -151,8 +152,8 @@ impl ProcessExt for Process {
                 cmd: get_cmd_line(pid),
                 environ: Vec::new(),
                 exe: get_executable_path(pid),
-                cwd: String::new(),
-                root: String::new(),
+                cwd: PathBuf::new(),
+                root: PathBuf::new(),
                 status: ProcessStatus::Run,
                 memory: 0,
                 cpu_usage: 0.,
@@ -177,8 +178,8 @@ impl ProcessExt for Process {
         &self.cmd
     }
 
-    fn exe(&self) -> &str {
-        &self.exe
+    fn exe(&self) -> &Path {
+        self.exe.as_path()
     }
 
     fn pid(&self) -> Pid {
@@ -189,12 +190,12 @@ impl ProcessExt for Process {
         &self.environ
     }
 
-    fn cwd(&self) -> &str {
-        &self.cwd
+    fn cwd(&self) -> &Path {
+        self.cwd.as_path()
     }
 
-    fn root(&self) -> &str {
-        &self.root
+    fn root(&self) -> &Path {
+        self.root.as_path()
     }
 
     fn memory(&self) -> u64 {
@@ -244,11 +245,11 @@ impl Debug for Process {
         for arg in &self.cmd {
             writeln!(f, "\t{}", arg);
         }
-        writeln!(f, "executable path: {}", self.exe);
-        writeln!(f, "current working directory: {}", self.cwd);
+        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)
+        writeln!(f, "root path: {:?}", self.root)
     }
 }
 
@@ -374,7 +375,7 @@ unsafe fn get_proc_env(_handle: HANDLE, _pid: u32, _name: &str) -> Vec<String> {
     ret
 }
 
-pub fn get_executable_path(_pid: Pid) -> String {
+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"]) {
@@ -385,7 +386,7 @@ pub fn get_executable_path(_pid: Pid) -> String {
             return line.to_owned();
         }
     }*/
-    String::new()
+    PathBuf::new()
 }
 
 pub fn compute_cpu_usage(p: &mut Process, nb_processors: u64) {


Test patch:
diff --git a/tests/process.rs b/tests/process.rs
new file mode 100644
index 0000000..82c0882
--- /dev/null
+++ b/tests/process.rs
@@ -0,0 +1,20 @@
+// 
+// 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));
+}