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