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}