Skip to content

Commit 761f89a

Browse files
committed
Process::environment for macOS (closes #209)
1 parent b3a7244 commit 761f89a

File tree

6 files changed

+55
-5
lines changed

6 files changed

+55
-5
lines changed

heim-process/src/sys/macos/bindings/proc_args.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,20 @@ use std::ptr;
55
use heim_common::sys::macos::sysctl;
66
use heim_common::{Error, Result};
77

8+
use crate::Pid;
9+
810
pub fn args_max() -> Result<libc::c_int> {
911
sysctl::sysctl(&mut [libc::CTL_KERN, libc::KERN_ARGMAX])
1012
}
1113

1214
// TODO: https://chromium.googlesource.com/crashpad/crashpad/+/360e441c53ab4191a6fd2472cc57c3343a2f6944/util/posix/process_util_mac.cc#32
15+
// TODO: Use `process::ProcessResult`
1316
#[allow(trivial_casts)]
14-
pub fn proc_args(pid: libc::pid_t) -> Result<Vec<u8>> {
17+
pub fn proc_args(pid: Pid) -> Result<Vec<u8>> {
1518
// Command line for `kernel_task` process can't be fetched
1619
if pid == 0 {
17-
return Ok(Vec::new());
20+
// TODO: Return `ProcessError::AccessDenied`
21+
return Err(io::Error::from(io::ErrorKind::PermissionDenied).into());
1822
}
1923

2024
let mut args_max = args_max()? as usize;

heim-process/src/sys/macos/process/command.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::ffi::{OsStr, OsString};
2+
use std::io;
23
use std::os::unix::ffi::OsStrExt;
34

45
use crate::sys::macos::{pid_exists, wrappers};
@@ -48,6 +49,9 @@ pub async fn command(pid: Pid) -> ProcessResult<Command> {
4849
Err(e.into())
4950
}
5051
}
52+
Err(e) if e.as_inner().kind() == io::ErrorKind::PermissionDenied => {
53+
Err(ProcessError::AccessDenied(pid))
54+
}
5155
Err(e) => Err(e.into()),
5256
}
5357
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use std::io;
2+
3+
use crate::sys::macos::{pid_exists, wrappers};
4+
use crate::sys::unix::Environment;
5+
use crate::{Pid, ProcessError, ProcessResult};
6+
7+
pub async fn environment(pid: Pid) -> ProcessResult<Environment> {
8+
match wrappers::ProcArgs::get(pid) {
9+
Ok(proc_args) => Ok(proc_args.environment()),
10+
Err(e) if e.raw_os_error() == Some(libc::EINVAL) => {
11+
if pid_exists(pid).await? {
12+
Err(ProcessError::ZombieProcess(pid))
13+
} else {
14+
Err(e.into())
15+
}
16+
}
17+
Err(e) if e.as_inner().kind() == io::ErrorKind::PermissionDenied => {
18+
Err(ProcessError::AccessDenied(pid))
19+
}
20+
Err(e) => Err(e.into()),
21+
}
22+
}

heim-process/src/sys/macos/process/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::{Pid, ProcessError, ProcessResult, Status};
2020

2121
mod command;
2222
mod cpu_times;
23+
mod env;
2324
mod memory;
2425

2526
pub use self::command::{Command, CommandIter};
@@ -71,6 +72,9 @@ impl Process {
7172
pub async fn cwd(&self) -> ProcessResult<PathBuf> {
7273
match darwin_libproc::pid_cwd(self.pid) {
7374
Ok(path) => Ok(path),
75+
Err(e) if e.kind() == io::ErrorKind::PermissionDenied => {
76+
Err(ProcessError::AccessDenied(self.pid))
77+
}
7478
Err(e) => Err(catch_zombie(e, self.pid)),
7579
}
7680
}
@@ -83,7 +87,7 @@ impl Process {
8387
}
8488

8589
pub async fn environment(&self) -> ProcessResult<Environment> {
86-
unimplemented!()
90+
env::environment(self.pid).await
8791
}
8892

8993
pub async fn create_time(&self) -> ProcessResult<Time> {

heim-process/src/sys/macos/wrappers/proc_args.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::ffi::{OsStr, OsString};
33
use std::os::unix::ffi::{OsStrExt, OsStringExt};
44

55
use crate::sys::macos::bindings;
6+
use crate::sys::unix::Environment;
67
use crate::Pid;
78
use heim_common::Result;
89

@@ -29,6 +30,21 @@ impl ProcArgs {
2930
OsStr::from_bytes(&self.0[start..end])
3031
}
3132

33+
pub fn environment(&self) -> Environment {
34+
// env vars are starting right after the arguments block
35+
// and ends when second `\0` appears.
36+
let start = self.arguments_range().1 + 1;
37+
38+
// This sounds like a dirty hack, but we just pass
39+
// all that remaining data into the `Environment`,
40+
// which will stop consuming data when it finds that second `\0` byte.
41+
//
42+
// It looks bad to assume that it will behave correctly,
43+
// but doing another one iteration on the bytes in order to find
44+
// that trailing null sounds not so great either.
45+
Environment::from_bytes(&self.0[start..])
46+
}
47+
3248
pub fn arguments(&self) -> ProcArgsArguments<'_> {
3349
let (start, end) = self.arguments_range();
3450
ProcArgsArguments {

heim-process/tests/smoke.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ async fn smoke_processes() {
5555
try_method!(process.parent_pid());
5656
try_method!(process.name());
5757
try_method!(process.command());
58-
#[cfg(not(target_os = "windows"))] // Not implemented yet
5958
try_method!(process.exe());
59+
#[cfg(not(target_os = "windows"))] // Not implemented yet
6060
try_method!(process.cwd());
6161
try_method!(process.status());
62-
#[cfg(target_os = "linux")] // Not implemented yet for all platforms
62+
#[cfg(any(target_os = "linux", target_os = "macos"))] // Not implemented yet for all platforms
6363
try_method!(process.environment());
6464
try_method!(process.create_time());
6565
try_method!(process.cpu_time());

0 commit comments

Comments
 (0)