1 //! Rust friendly bindings to the various *nix system functions.
2 //!
3 //! Modules are structured according to the C header file that they would be
4 //! defined in.
5 #![crate_name = "nix"]
6 #![cfg(unix)]
7 #![allow(non_camel_case_types)]
8 // latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
9 // warnings even though the macro expands into something with allow(dead_code)
10 #![allow(dead_code)]
11 #![cfg_attr(test, deny(warnings))]
12 #![recursion_limit = "500"]
13 #![deny(unused)]
14 #![deny(unstable_features)]
15 #![deny(missing_copy_implementations)]
16 #![deny(missing_debug_implementations)]
17 
18 // Re-exported external crates
19 pub use libc;
20 
21 // Private internal modules
22 #[macro_use] mod macros;
23 
24 // Public crates
25 #[cfg(not(target_os = "redox"))]
26 pub mod dir;
27 pub mod env;
28 pub mod errno;
29 #[deny(missing_docs)]
30 pub mod features;
31 pub mod fcntl;
32 #[deny(missing_docs)]
33 #[cfg(any(target_os = "android",
34           target_os = "dragonfly",
35           target_os = "freebsd",
36           target_os = "ios",
37           target_os = "linux",
38           target_os = "macos",
39           target_os = "netbsd",
40           target_os = "openbsd"))]
41 pub mod ifaddrs;
42 #[cfg(any(target_os = "android",
43           target_os = "linux"))]
44 pub mod kmod;
45 #[cfg(any(target_os = "android",
46           target_os = "linux"))]
47 pub mod mount;
48 #[cfg(any(target_os = "dragonfly",
49           target_os = "freebsd",
50           target_os = "fushsia",
51           target_os = "linux",
52           target_os = "netbsd"))]
53 pub mod mqueue;
54 #[deny(missing_docs)]
55 #[cfg(not(target_os = "redox"))]
56 pub mod net;
57 #[deny(missing_docs)]
58 pub mod poll;
59 #[deny(missing_docs)]
60 #[cfg(not(target_os = "redox"))]
61 pub mod pty;
62 pub mod sched;
63 pub mod sys;
64 pub mod time;
65 // This can be implemented for other platforms as soon as libc
66 // provides bindings for them.
67 #[cfg(all(target_os = "linux",
68           any(target_arch = "x86", target_arch = "x86_64")))]
69 pub mod ucontext;
70 pub mod unistd;
71 
72 /*
73  *
74  * ===== Result / Error =====
75  *
76  */
77 
78 use libc::{c_char, PATH_MAX};
79 
80 use std::{error, fmt, ptr, result};
81 use std::ffi::{CStr, OsStr};
82 use std::os::unix::ffi::OsStrExt;
83 use std::path::{Path, PathBuf};
84 
85 use errno::Errno;
86 
87 /// Nix Result Type
88 pub type Result<T> = result::Result<T, Error>;
89 
90 /// Nix Error Type
91 ///
92 /// The nix error type provides a common way of dealing with
93 /// various system system/libc calls that might fail.  Each
94 /// error has a corresponding errno (usually the one from the
95 /// underlying OS) to which it can be mapped in addition to
96 /// implementing other common traits.
97 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
98 pub enum Error {
99     Sys(Errno),
100     InvalidPath,
101     /// The operation involved a conversion to Rust's native String type, which failed because the
102     /// string did not contain all valid UTF-8.
103     InvalidUtf8,
104     /// The operation is not supported by Nix, in this instance either use the libc bindings or
105     /// consult the module documentation to see if there is a more appropriate interface available.
106     UnsupportedOperation,
107 }
108 
109 impl Error {
110     /// Convert this `Error` to an [`Errno`](enum.Errno.html).
111     ///
112     /// # Example
113     ///
114     /// ```
115     /// # use nix::Error;
116     /// # use nix::errno::Errno;
117     /// let e = Error::from(Errno::EPERM);
118     /// assert_eq!(Some(Errno::EPERM), e.as_errno());
119     /// ```
as_errno(self) -> Option<Errno>120     pub fn as_errno(self) -> Option<Errno> {
121         if let Error::Sys(e) = self {
122             Some(e)
123         } else {
124             None
125         }
126     }
127 
128     /// Create a nix Error from a given errno
from_errno(errno: Errno) -> Error129     pub fn from_errno(errno: Errno) -> Error {
130         Error::Sys(errno)
131     }
132 
133     /// Get the current errno and convert it to a nix Error
last() -> Error134     pub fn last() -> Error {
135         Error::Sys(Errno::last())
136     }
137 
138     /// Create a new invalid argument error (`EINVAL`)
invalid_argument() -> Error139     pub fn invalid_argument() -> Error {
140         Error::Sys(Errno::EINVAL)
141     }
142 
143 }
144 
145 impl From<Errno> for Error {
from(errno: Errno) -> Error146     fn from(errno: Errno) -> Error { Error::from_errno(errno) }
147 }
148 
149 impl From<std::string::FromUtf8Error> for Error {
from(_: std::string::FromUtf8Error) -> Error150     fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
151 }
152 
153 impl error::Error for Error {}
154 
155 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result156     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157         match *self {
158             Error::InvalidPath => write!(f, "Invalid path"),
159             Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
160             Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
161             Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
162         }
163     }
164 }
165 
166 pub trait NixPath {
is_empty(&self) -> bool167     fn is_empty(&self) -> bool;
168 
len(&self) -> usize169     fn len(&self) -> usize;
170 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T171     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
172         where F: FnOnce(&CStr) -> T;
173 }
174 
175 impl NixPath for str {
is_empty(&self) -> bool176     fn is_empty(&self) -> bool {
177         NixPath::is_empty(OsStr::new(self))
178     }
179 
len(&self) -> usize180     fn len(&self) -> usize {
181         NixPath::len(OsStr::new(self))
182     }
183 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T184     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
185         where F: FnOnce(&CStr) -> T {
186             OsStr::new(self).with_nix_path(f)
187         }
188 }
189 
190 impl NixPath for OsStr {
is_empty(&self) -> bool191     fn is_empty(&self) -> bool {
192         self.as_bytes().is_empty()
193     }
194 
len(&self) -> usize195     fn len(&self) -> usize {
196         self.as_bytes().len()
197     }
198 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T199     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
200         where F: FnOnce(&CStr) -> T {
201             self.as_bytes().with_nix_path(f)
202         }
203 }
204 
205 impl NixPath for CStr {
is_empty(&self) -> bool206     fn is_empty(&self) -> bool {
207         self.to_bytes().is_empty()
208     }
209 
len(&self) -> usize210     fn len(&self) -> usize {
211         self.to_bytes().len()
212     }
213 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T214     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
215             where F: FnOnce(&CStr) -> T {
216         // Equivalence with the [u8] impl.
217         if self.len() >= PATH_MAX as usize {
218             return Err(Error::InvalidPath);
219         }
220 
221         Ok(f(self))
222     }
223 }
224 
225 impl NixPath for [u8] {
is_empty(&self) -> bool226     fn is_empty(&self) -> bool {
227         self.is_empty()
228     }
229 
len(&self) -> usize230     fn len(&self) -> usize {
231         self.len()
232     }
233 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T234     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
235             where F: FnOnce(&CStr) -> T {
236         let mut buf = [0u8; PATH_MAX as usize];
237 
238         if self.len() >= PATH_MAX as usize {
239             return Err(Error::InvalidPath);
240         }
241 
242         match self.iter().position(|b| *b == 0) {
243             Some(_) => Err(Error::InvalidPath),
244             None => {
245                 unsafe {
246                     // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
247                     ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
248                     Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
249                 }
250 
251             }
252         }
253     }
254 }
255 
256 impl NixPath for Path {
is_empty(&self) -> bool257     fn is_empty(&self) -> bool {
258         NixPath::is_empty(self.as_os_str())
259     }
260 
len(&self) -> usize261     fn len(&self) -> usize {
262         NixPath::len(self.as_os_str())
263     }
264 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T265     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
266         self.as_os_str().with_nix_path(f)
267     }
268 }
269 
270 impl NixPath for PathBuf {
is_empty(&self) -> bool271     fn is_empty(&self) -> bool {
272         NixPath::is_empty(self.as_os_str())
273     }
274 
len(&self) -> usize275     fn len(&self) -> usize {
276         NixPath::len(self.as_os_str())
277     }
278 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T279     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
280         self.as_os_str().with_nix_path(f)
281     }
282 }
283