pledge/
lib.rs

1mod promise;
2
3use std::ffi::NulError;
4use std::os::raw::c_int;
5use std::{error, fmt};
6
7#[derive(PartialEq, Eq, Debug)]
8pub enum Error {
9    UnsupportedPlatform,
10    Promises(NulError),
11    Execpromises(NulError),
12    Other(c_int),
13}
14
15impl Error {
16    pub fn ignore_platform(self) -> Result<(), Self> {
17        match self {
18            Error::UnsupportedPlatform => Ok(()),
19            x => Err(x),
20        }
21    }
22}
23
24impl fmt::Display for Error {
25    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
26        match *self {
27            Error::UnsupportedPlatform => write!(f, "pledge is unsupported on this platform"),
28            Error::Promises(_) => write!(f, "unexpected NUL character in promises argument"),
29            Error::Execpromises(_) => write!(f, "unexpected NUL character in execpromises argument"),
30            Error::Other(errno) => write!(f, "unable to pledge ({})", errno),
31        }
32    }
33}
34
35impl error::Error for Error {
36    fn description(&self) -> &str {
37        match *self {
38            Error::UnsupportedPlatform => "pledge is unsupported on this platform",
39            Error::Promises(_) => "unexpected NUL character in promises argument",
40            Error::Execpromises(_) => "unexpected NUL character in execpromises argument",
41            Error::Other(_) => "unable to pledge",
42        }
43    }
44}
45
46pub use promise::Promise;
47
48pub trait ToPromiseString {
49    fn to_promise_string(&self) -> String;
50}
51
52impl ToPromiseString for [Promise] {
53    fn to_promise_string(&self) -> String {
54        self.iter()
55            .map(|p| p.to_promise_string())
56            .collect::<Vec<&'static str>>()
57            .join(" ")
58    }
59}
60
61#[cfg(target_os = "openbsd")]
62mod openbsd;
63
64#[cfg(target_os = "openbsd")]
65pub use openbsd::pledge;
66
67#[cfg(not(target_os = "openbsd"))]
68pub fn pledge<'p, 'e, P, E>(_: P, _: E) -> Result<(), Error>
69where P: Into<Option<&'p str>>, E: Into<Option<&'e str>> {
70    Err(Error::UnsupportedPlatform)
71}
72
73#[macro_export]
74macro_rules! pledge {
75    [$($promises:ident)*, $($execpromises:ident)*] => {
76        {
77            let mut promises = Vec::new();
78            let mut execpromises = Vec::new();
79            $(
80                promises.push($crate::Promise::$promises);
81            )*
82            $(
83                execpromises.push($crate::Promise::$execpromises);
84            )*
85            let promises = $crate::ToPromiseString::to_promise_string(&*promises);
86            let execpromises = $crate::ToPromiseString::to_promise_string(&*execpromises);
87            $crate::pledge(&*promises, &*execpromises)
88        }
89    };
90}
91
92#[macro_export]
93macro_rules! pledge_promises {
94    [$($promises:ident)*] => {
95        {
96            let mut promises = Vec::new();
97            $(
98                promises.push($crate::Promise::$promises);
99            )*
100            let promises = $crate::ToPromiseString::to_promise_string(&*promises);
101            $crate::pledge(&*promises, None)
102        }
103    };
104}
105
106#[macro_export]
107macro_rules! pledge_execpromises {
108    [$($execpromises:ident)*] => {
109        {
110            let mut execpromises = Vec::new();
111            $(
112                execpromises.push($crate::Promise::$execpromises);
113            )*
114            let execpromises = $crate::ToPromiseString::to_promise_string(&*execpromises);
115            $crate::pledge(None, &*execpromises)
116        }
117    };
118}
119
120#[cfg(test)]
121mod tests {
122    use super::{pledge, Promise, ToPromiseString};
123
124    #[test]
125    fn test_promise_str() {
126        use super::ToPromiseString;
127
128        assert_eq!(vec![].to_promise_string(), "");
129        assert_eq!(vec![Promise::Dns].to_promise_string(), "dns");
130        assert_eq!(
131            vec![Promise::Stdio, Promise::ProtExec].to_promise_string(),
132            "stdio prot_exec"
133        );
134    }
135
136    #[test]
137    #[cfg(not(target_os = "openbsd"))]
138    fn test_pledge_unsupported() {
139        use super::Error;
140        assert_eq!(pledge_promises![Stdio].unwrap_err(), Error::UnsupportedPlatform);
141    }
142
143    #[test]
144    #[cfg(target_os = "openbsd")]
145    fn test_pledge_supported() {
146        pledge_promises![Stdio].unwrap();
147        assert!(pledge_promises![Stdio Audio].is_err());
148    }
149
150    #[test]
151    #[cfg(target_os = "openbsd")]
152    fn test_as_string() {
153        pledge("stdio", None).unwrap();
154        println!("hello world");
155    }
156}