Skip to content

Commit dfc0b1e

Browse files
committed
Added parser for /proc/<pid>/environ
1 parent 32aa416 commit dfc0b1e

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ currently the following interfaces are provided:
1515

1616
* `/proc/loadavg`
1717
* `/proc/<pid>/cwd`
18+
* `/proc/<pid>/environ`
1819
* `/proc/<pid>/limits`
1920
* `/proc/<pid>/mountinfo`
2021
* `/proc/<pid>/stat`

src/pid/environ.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//! Process initial environment from `/proc/[pid]/environ`.
2+
3+
use std::ffi::{OsStr, OsString};
4+
use std::fs::File;
5+
use std::io::{Result, Read};
6+
use std::os::unix::ffi::OsStrExt;
7+
use std::path::Path;
8+
9+
use parsers::map_result;
10+
use nom::IResult;
11+
12+
use libc::pid_t;
13+
14+
/// A list of environment variables and their values.
15+
pub type Environ = Vec<(OsString, OsString)>;
16+
17+
/// Parses the provided buffer.
18+
fn parse_environ(input: &[u8]) -> IResult<&[u8], Environ> {
19+
// Parse 'key=value" pair.
20+
named!(
21+
pair<&[u8], (&[u8], &[u8])>,
22+
tuple!(take_until_and_consume!("="), take_until!("\0"))
23+
);
24+
// Parse (key=value\0) list.
25+
named!(
26+
multi<&[u8],Vec<(&[u8], &[u8])> >,
27+
terminated!(
28+
separated_list!(tag!("\0"), pair),
29+
tag!("\0")
30+
)
31+
);
32+
multi(input).map(|r| {
33+
r.into_iter()
34+
.map(|(x, y)| {
35+
(
36+
OsString::from(OsStr::from_bytes(x)),
37+
OsString::from(OsStr::from_bytes(y)),
38+
)
39+
})
40+
.collect()
41+
})
42+
}
43+
44+
#[test]
45+
fn test_parse() {
46+
use nom::IResult::Done;
47+
let res = parse_environ(&b"key1=val1\0key2=val2\0"[..]);
48+
let reference: Environ = vec![
49+
("key1".into(), "val1".into()),
50+
("key2".into(), "val2".into()),
51+
];
52+
assert_eq!(res, Done(&b""[..], reference));
53+
}
54+
55+
/// Parses the provided environ file.
56+
fn environ_path<P: AsRef<Path>>(path: P) -> Result<Environ> {
57+
let mut buf = Vec::new();
58+
if File::open(path)?.read_to_end(&mut buf)? == 0 {
59+
// Don't attempt to parse an empty file.
60+
return Ok(Default::default());
61+
}
62+
map_result(parse_environ(&buf))
63+
}
64+
65+
/// Returns initial environment for the process with the provided pid as key-value pairs.
66+
pub fn environ(pid: pid_t) -> Result<Environ> {
67+
environ_path(format!("/proc/{}/environ", pid))
68+
}
69+
70+
/// Returns initial environment for the current process as key-value pairs.
71+
pub fn environ_self() -> Result<Environ> {
72+
environ_path("/proc/self/environ")
73+
}
74+
75+
#[test]
76+
fn test_environ() {
77+
assert!(environ_self().is_ok());
78+
}

src/pid/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ mod mountinfo;
66
mod stat;
77
mod statm;
88
mod status;
9+
mod environ;
910

1011
pub use pid::cwd::{cwd, cwd_self};
1112
pub use pid::limits::{Limit, Limits, limits, limits_self};
1213
pub use pid::mountinfo::{Mountinfo, mountinfo, mountinfo_self};
1314
pub use pid::statm::{Statm, statm, statm_self};
1415
pub use pid::status::{SeccompMode, Status, status, status_self};
1516
pub use pid::stat::{Stat, stat, stat_self};
17+
pub use pid::environ::{Environ, environ, environ_self};
1618

1719
/// The state of a process.
1820
#[derive(Debug, PartialEq, Eq, Hash)]

0 commit comments

Comments
 (0)