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(any(target_os = "redox", target_os = "fuchsia")))] 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