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 // External crates
19 #[macro_use]
20 extern crate bitflags;
21 #[macro_use]
22 extern crate cfg_if;
23 extern crate void;
24 
25 // Re-exported external crates
26 pub extern crate libc;
27 
28 // Private internal modules
29 #[macro_use] mod macros;
30 
31 // Public crates
32 pub mod dir;
33 pub mod errno;
34 #[deny(missing_docs)]
35 pub mod features;
36 pub mod fcntl;
37 #[deny(missing_docs)]
38 #[cfg(any(target_os = "dragonfly",
39           target_os = "freebsd",
40           target_os = "ios",
41           target_os = "linux",
42           target_os = "macos",
43           target_os = "netbsd",
44           target_os = "openbsd"))]
45 pub mod ifaddrs;
46 #[cfg(any(target_os = "android",
47           target_os = "linux"))]
48 pub mod kmod;
49 #[cfg(any(target_os = "android",
50           target_os = "linux"))]
51 pub mod mount;
52 #[cfg(any(target_os = "dragonfly",
53           target_os = "freebsd",
54           target_os = "fushsia",
55           target_os = "linux",
56           target_os = "netbsd"))]
57 pub mod mqueue;
58 #[deny(missing_docs)]
59 pub mod net;
60 #[deny(missing_docs)]
61 pub mod poll;
62 #[deny(missing_docs)]
63 pub mod pty;
64 #[cfg(any(target_os = "android",
65           target_os = "linux"))]
66 pub mod sched;
67 pub mod sys;
68 // This can be implemented for other platforms as soon as libc
69 // provides bindings for them.
70 #[cfg(all(target_os = "linux",
71           any(target_arch = "x86", target_arch = "x86_64")))]
72 pub mod ucontext;
73 pub mod unistd;
74 
75 /*
76  *
77  * ===== Result / Error =====
78  *
79  */
80 
81 use libc::{c_char, PATH_MAX};
82 
83 use std::{error, fmt, ptr, result};
84 use std::ffi::{CStr, OsStr};
85 use std::os::unix::ffi::OsStrExt;
86 use std::path::{Path, PathBuf};
87 
88 use errno::Errno;
89 
90 /// Nix Result Type
91 pub type Result<T> = result::Result<T, Error>;
92 
93 /// Nix Error Type
94 ///
95 /// The nix error type provides a common way of dealing with
96 /// various system system/libc calls that might fail.  Each
97 /// error has a corresponding errno (usually the one from the
98 /// underlying OS) to which it can be mapped in addition to
99 /// implementing other common traits.
100 #[derive(Clone, Copy, Debug, PartialEq)]
101 pub enum Error {
102     Sys(Errno),
103     InvalidPath,
104     /// The operation involved a conversion to Rust's native String type, which failed because the
105     /// string did not contain all valid UTF-8.
106     InvalidUtf8,
107     /// The operation is not supported by Nix, in this instance either use the libc bindings or
108     /// consult the module documentation to see if there is a more appropriate interface available.
109     UnsupportedOperation,
110 }
111 
112 impl Error {
113     /// Convert this `Error` to an [`Errno`](enum.Errno.html).
114     ///
115     /// # Example
116     ///
117     /// ```
118     /// # use nix::Error;
119     /// # use nix::errno::Errno;
120     /// let e = Error::from(Errno::EPERM);
121     /// assert_eq!(Some(Errno::EPERM), e.as_errno());
122     /// ```
as_errno(&self) -> Option<Errno>123     pub fn as_errno(&self) -> Option<Errno> {
124         if let &Error::Sys(ref e) = self {
125             Some(*e)
126         } else {
127             None
128         }
129     }
130 
131     /// Create a nix Error from a given errno
from_errno(errno: Errno) -> Error132     pub fn from_errno(errno: Errno) -> Error {
133         Error::Sys(errno)
134     }
135 
136     /// Get the current errno and convert it to a nix Error
last() -> Error137     pub fn last() -> Error {
138         Error::Sys(Errno::last())
139     }
140 
141     /// Create a new invalid argument error (`EINVAL`)
invalid_argument() -> Error142     pub fn invalid_argument() -> Error {
143         Error::Sys(Errno::EINVAL)
144     }
145 
146 }
147 
148 impl From<Errno> for Error {
from(errno: Errno) -> Error149     fn from(errno: Errno) -> Error { Error::from_errno(errno) }
150 }
151 
152 impl From<std::string::FromUtf8Error> for Error {
from(_: std::string::FromUtf8Error) -> Error153     fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
154 }
155 
156 impl error::Error for Error {
description(&self) -> &str157     fn description(&self) -> &str {
158         match *self {
159             Error::InvalidPath => "Invalid path",
160             Error::InvalidUtf8 => "Invalid UTF-8 string",
161             Error::UnsupportedOperation => "Unsupported Operation",
162             Error::Sys(ref errno) => errno.desc(),
163         }
164     }
165 }
166 
167 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result168     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169         match *self {
170             Error::InvalidPath => write!(f, "Invalid path"),
171             Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
172             Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
173             Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
174         }
175     }
176 }
177 
178 pub trait NixPath {
len(&self) -> usize179     fn len(&self) -> usize;
180 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T181     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
182         where F: FnOnce(&CStr) -> T;
183 }
184 
185 impl NixPath for str {
len(&self) -> usize186     fn len(&self) -> usize {
187         NixPath::len(OsStr::new(self))
188     }
189 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T190     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
191         where F: FnOnce(&CStr) -> T {
192             OsStr::new(self).with_nix_path(f)
193         }
194 }
195 
196 impl NixPath for OsStr {
len(&self) -> usize197     fn len(&self) -> usize {
198         self.as_bytes().len()
199     }
200 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T201     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
202         where F: FnOnce(&CStr) -> T {
203             self.as_bytes().with_nix_path(f)
204         }
205 }
206 
207 impl NixPath for CStr {
len(&self) -> usize208     fn len(&self) -> usize {
209         self.to_bytes().len()
210     }
211 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T212     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
213             where F: FnOnce(&CStr) -> T {
214         // Equivalence with the [u8] impl.
215         if self.len() >= PATH_MAX as usize {
216             return Err(Error::InvalidPath);
217         }
218 
219         Ok(f(self))
220     }
221 }
222 
223 impl NixPath for [u8] {
len(&self) -> usize224     fn len(&self) -> usize {
225         self.len()
226     }
227 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T228     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
229             where F: FnOnce(&CStr) -> T {
230         let mut buf = [0u8; PATH_MAX as usize];
231 
232         if self.len() >= PATH_MAX as usize {
233             return Err(Error::InvalidPath);
234         }
235 
236         match self.iter().position(|b| *b == 0) {
237             Some(_) => Err(Error::InvalidPath),
238             None => {
239                 unsafe {
240                     // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
241                     ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
242                     Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
243                 }
244 
245             }
246         }
247     }
248 }
249 
250 impl NixPath for Path {
len(&self) -> usize251     fn len(&self) -> usize {
252         NixPath::len(self.as_os_str())
253     }
254 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T255     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
256         self.as_os_str().with_nix_path(f)
257     }
258 }
259 
260 impl NixPath for PathBuf {
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 /// Treats `None` as an empty string.
271 impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
len(&self) -> usize272     fn len(&self) -> usize {
273         self.map_or(0, NixPath::len)
274     }
275 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T276     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
277         if let Some(nix_path) = *self {
278             nix_path.with_nix_path(f)
279         } else {
280             unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
281         }
282     }
283 }
284