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