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 
14 #[macro_use]
15 extern crate bitflags;
16 
17 #[macro_use]
18 extern crate cfg_if;
19 extern crate void;
20 
21 #[cfg(test)]
22 extern crate nix_test as nixtest;
23 
24 #[macro_use] mod macros;
25 
26 // In rust 1.8+ this should be `pub extern crate libc` but prior
27 // to https://github.com/rust-lang/rust/issues/26775 being resolved
28 // it is necessary to get a little creative.
29 pub mod libc {
30     extern crate libc;
31     pub use self::libc::*;
32 }
33 
34 pub use errno::Errno;
35 
36 pub mod errno;
37 pub mod features;
38 pub mod fcntl;
39 
40 #[cfg(any(target_os = "linux", target_os = "android"))]
41 pub mod mount;
42 
43 #[cfg(target_os = "linux")]
44 pub mod mqueue;
45 
46 pub mod pty;
47 
48 #[cfg(any(target_os = "linux", target_os = "macos"))]
49 pub mod poll;
50 
51 pub mod net;
52 
53 #[cfg(any(target_os = "linux", target_os = "android"))]
54 pub mod sched;
55 
56 pub mod sys;
57 
58 // This can be implemented for other platforms as soon as libc
59 // provides bindings for them.
60 #[cfg(all(target_os = "linux",
61           any(target_arch = "x86", target_arch = "x86_64")))]
62 pub mod ucontext;
63 
64 pub mod unistd;
65 
66 /*
67  *
68  * ===== Result / Error =====
69  *
70  */
71 
72 use libc::c_char;
73 use std::{ptr, result};
74 use std::ffi::{CStr, OsStr};
75 use std::path::{Path, PathBuf};
76 use std::os::unix::ffi::OsStrExt;
77 use std::fmt;
78 use std::error;
79 use libc::PATH_MAX;
80 
81 /// Nix Result Type
82 pub type Result<T> = result::Result<T, Error>;
83 
84 /// Nix Error Type
85 ///
86 /// The nix error type provides a common way of dealing with
87 /// various system system/libc calls that might fail.  Each
88 /// error has a corresponding errno (usually the one from the
89 /// underlying OS) to which it can be mapped in addition to
90 /// implementing other common traits.
91 #[derive(Clone, Copy, Debug, PartialEq)]
92 pub enum Error {
93     Sys(errno::Errno),
94     InvalidPath,
95     /// The operation involved a conversion to Rust's native String type, which failed because the
96     /// string did not contain all valid UTF-8.
97     InvalidUtf8,
98     /// The operation is not supported by Nix, in this instance either use the libc bindings or
99     /// consult the module documentation to see if there is a more appropriate interface available.
100     UnsupportedOperation,
101 }
102 
103 impl Error {
104 
105     /// Create a nix Error from a given errno
from_errno(errno: errno::Errno) -> Error106     pub fn from_errno(errno: errno::Errno) -> Error {
107         Error::Sys(errno)
108     }
109 
110     /// Get the current errno and convert it to a nix Error
last() -> Error111     pub fn last() -> Error {
112         Error::Sys(errno::Errno::last())
113     }
114 
115     /// Create a new invalid argument error (`EINVAL`)
invalid_argument() -> Error116     pub fn invalid_argument() -> Error {
117         Error::Sys(errno::EINVAL)
118     }
119 
120 }
121 
122 impl From<errno::Errno> for Error {
from(errno: errno::Errno) -> Error123     fn from(errno: errno::Errno) -> Error { Error::from_errno(errno) }
124 }
125 
126 impl From<std::string::FromUtf8Error> for Error {
from(_: std::string::FromUtf8Error) -> Error127     fn from(_: std::string::FromUtf8Error) -> Error { Error::InvalidUtf8 }
128 }
129 
130 impl error::Error for Error {
description(&self) -> &str131     fn description(&self) -> &str {
132         match self {
133             &Error::InvalidPath => "Invalid path",
134             &Error::InvalidUtf8 => "Invalid UTF-8 string",
135             &Error::UnsupportedOperation => "Unsupported Operation",
136             &Error::Sys(ref errno) => errno.desc(),
137         }
138     }
139 }
140 
141 impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result142     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143         match self {
144             &Error::InvalidPath => write!(f, "Invalid path"),
145             &Error::InvalidUtf8 => write!(f, "Invalid UTF-8 string"),
146             &Error::UnsupportedOperation => write!(f, "Unsupported Operation"),
147             &Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
148         }
149     }
150 }
151 
152 pub trait NixPath {
len(&self) -> usize153     fn len(&self) -> usize;
154 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T155     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
156         where F: FnOnce(&CStr) -> T;
157 }
158 
159 impl NixPath for str {
len(&self) -> usize160     fn len(&self) -> usize {
161         NixPath::len(OsStr::new(self))
162     }
163 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T164     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
165         where F: FnOnce(&CStr) -> T {
166             OsStr::new(self).with_nix_path(f)
167         }
168 }
169 
170 impl NixPath for OsStr {
len(&self) -> usize171     fn len(&self) -> usize {
172         self.as_bytes().len()
173     }
174 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T175     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
176         where F: FnOnce(&CStr) -> T {
177             self.as_bytes().with_nix_path(f)
178         }
179 }
180 
181 impl NixPath for CStr {
len(&self) -> usize182     fn len(&self) -> usize {
183         self.to_bytes().len()
184     }
185 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T186     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
187             where F: FnOnce(&CStr) -> T {
188         // Equivalence with the [u8] impl.
189         if self.len() >= PATH_MAX as usize {
190             return Err(Error::InvalidPath);
191         }
192 
193         Ok(f(self))
194     }
195 }
196 
197 impl NixPath for [u8] {
len(&self) -> usize198     fn len(&self) -> usize {
199         self.len()
200     }
201 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T202     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
203             where F: FnOnce(&CStr) -> T {
204         let mut buf = [0u8; PATH_MAX as usize];
205 
206         if self.len() >= PATH_MAX as usize {
207             return Err(Error::InvalidPath);
208         }
209 
210         match self.iter().position(|b| *b == 0) {
211             Some(_) => Err(Error::InvalidPath),
212             None => {
213                 unsafe {
214                     // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
215                     ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
216                     Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
217                 }
218 
219             }
220         }
221     }
222 }
223 
224 impl NixPath for Path {
len(&self) -> usize225     fn len(&self) -> usize {
226         NixPath::len(self.as_os_str())
227     }
228 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T229     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
230         self.as_os_str().with_nix_path(f)
231     }
232 }
233 
234 impl NixPath for PathBuf {
len(&self) -> usize235     fn len(&self) -> usize {
236         NixPath::len(self.as_os_str())
237     }
238 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T239     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
240         self.as_os_str().with_nix_path(f)
241     }
242 }
243 
244 /// Treats `None` as an empty string.
245 impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
len(&self) -> usize246     fn len(&self) -> usize {
247         self.map_or(0, NixPath::len)
248     }
249 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T250     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
251         if let Some(nix_path) = *self {
252             nix_path.with_nix_path(f)
253         } else {
254             unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
255         }
256     }
257 }
258