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 #![cfg_attr(test, deny(warnings))]
9 #![recursion_limit = "500"]
10 #![deny(unused)]
11 #![deny(unstable_features)]
12 #![deny(missing_copy_implementations)]
13 #![deny(missing_debug_implementations)]
14 #![warn(missing_docs)]
15 
16 // Re-exported external crates
17 pub use libc;
18 
19 // Private internal modules
20 #[macro_use] mod macros;
21 
22 // Public crates
23 #[cfg(not(target_os = "redox"))]
24 #[allow(missing_docs)]
25 pub mod dir;
26 pub mod env;
27 #[allow(missing_docs)]
28 pub mod errno;
29 pub mod features;
30 #[allow(missing_docs)]
31 pub mod fcntl;
32 #[cfg(any(target_os = "android",
33           target_os = "dragonfly",
34           target_os = "freebsd",
35           target_os = "ios",
36           target_os = "linux",
37           target_os = "macos",
38           target_os = "netbsd",
39           target_os = "illumos",
40           target_os = "openbsd"))]
41 pub mod ifaddrs;
42 #[cfg(any(target_os = "android",
43           target_os = "linux"))]
44 #[allow(missing_docs)]
45 pub mod kmod;
46 #[cfg(any(target_os = "android",
47           target_os = "freebsd",
48           target_os = "linux"))]
49 pub mod mount;
50 #[cfg(any(target_os = "dragonfly",
51           target_os = "freebsd",
52           target_os = "fushsia",
53           target_os = "linux",
54           target_os = "netbsd"))]
55 #[allow(missing_docs)]
56 pub mod mqueue;
57 #[cfg(not(target_os = "redox"))]
58 pub mod net;
59 pub mod poll;
60 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
61 pub mod pty;
62 pub mod sched;
63 pub mod sys;
64 #[allow(missing_docs)]
65 pub mod time;
66 // This can be implemented for other platforms as soon as libc
67 // provides bindings for them.
68 #[cfg(all(target_os = "linux",
69           any(target_arch = "x86", target_arch = "x86_64")))]
70 #[allow(missing_docs)]
71 pub mod ucontext;
72 #[allow(missing_docs)]
73 pub mod unistd;
74 
75 /*
76  *
77  * ===== Result / Error =====
78  *
79  */
80 
81 use libc::{c_char, PATH_MAX};
82 
83 use std::{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, Errno>;
92 
93 /// Nix's main error type.
94 ///
95 /// It's a wrapper around Errno.  As such, it's very interoperable with
96 /// [`std::io::Error`], but it has the advantages of:
97 /// * `Clone`
98 /// * `Copy`
99 /// * `Eq`
100 /// * Small size
101 /// * Represents all of the system's errnos, instead of just the most common
102 /// ones.
103 pub type Error = Errno;
104 
105 /// Common trait used to represent file system paths by many Nix functions.
106 pub trait NixPath {
107     /// Is the path empty?
is_empty(&self) -> bool108     fn is_empty(&self) -> bool;
109 
110     /// Length of the path in bytes
len(&self) -> usize111     fn len(&self) -> usize;
112 
113     /// Execute a function with this path as a `CStr`.
114     ///
115     /// Mostly used internally by Nix.
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T116     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
117         where F: FnOnce(&CStr) -> T;
118 }
119 
120 impl NixPath for str {
is_empty(&self) -> bool121     fn is_empty(&self) -> bool {
122         NixPath::is_empty(OsStr::new(self))
123     }
124 
len(&self) -> usize125     fn len(&self) -> usize {
126         NixPath::len(OsStr::new(self))
127     }
128 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T129     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
130         where F: FnOnce(&CStr) -> T {
131             OsStr::new(self).with_nix_path(f)
132         }
133 }
134 
135 impl NixPath for OsStr {
is_empty(&self) -> bool136     fn is_empty(&self) -> bool {
137         self.as_bytes().is_empty()
138     }
139 
len(&self) -> usize140     fn len(&self) -> usize {
141         self.as_bytes().len()
142     }
143 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T144     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
145         where F: FnOnce(&CStr) -> T {
146             self.as_bytes().with_nix_path(f)
147         }
148 }
149 
150 impl NixPath for CStr {
is_empty(&self) -> bool151     fn is_empty(&self) -> bool {
152         self.to_bytes().is_empty()
153     }
154 
len(&self) -> usize155     fn len(&self) -> usize {
156         self.to_bytes().len()
157     }
158 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T159     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
160             where F: FnOnce(&CStr) -> T {
161         // Equivalence with the [u8] impl.
162         if self.len() >= PATH_MAX as usize {
163             return Err(Errno::ENAMETOOLONG)
164         }
165 
166         Ok(f(self))
167     }
168 }
169 
170 impl NixPath for [u8] {
is_empty(&self) -> bool171     fn is_empty(&self) -> bool {
172         self.is_empty()
173     }
174 
len(&self) -> usize175     fn len(&self) -> usize {
176         self.len()
177     }
178 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T179     fn with_nix_path<T, F>(&self, f: F) -> Result<T>
180             where F: FnOnce(&CStr) -> T {
181         let mut buf = [0u8; PATH_MAX as usize];
182 
183         if self.len() >= PATH_MAX as usize {
184             return Err(Errno::ENAMETOOLONG)
185         }
186 
187         match self.iter().position(|b| *b == 0) {
188             Some(_) => Err(Errno::EINVAL),
189             None => {
190                 unsafe {
191                     // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
192                     ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
193                     Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
194                 }
195 
196             }
197         }
198     }
199 }
200 
201 impl NixPath for Path {
is_empty(&self) -> bool202     fn is_empty(&self) -> bool {
203         NixPath::is_empty(self.as_os_str())
204     }
205 
len(&self) -> usize206     fn len(&self) -> usize {
207         NixPath::len(self.as_os_str())
208     }
209 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T210     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
211         self.as_os_str().with_nix_path(f)
212     }
213 }
214 
215 impl NixPath for PathBuf {
is_empty(&self) -> bool216     fn is_empty(&self) -> bool {
217         NixPath::is_empty(self.as_os_str())
218     }
219 
len(&self) -> usize220     fn len(&self) -> usize {
221         NixPath::len(self.as_os_str())
222     }
223 
with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T224     fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
225         self.as_os_str().with_nix_path(f)
226     }
227 }
228