nix/
lib.rs

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
17pub 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)]
25pub mod dir;
26pub mod env;
27#[allow(missing_docs)]
28pub mod errno;
29pub mod features;
30#[allow(missing_docs)]
31pub 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"))]
41pub mod ifaddrs;
42#[cfg(any(target_os = "android",
43          target_os = "linux"))]
44#[allow(missing_docs)]
45pub mod kmod;
46#[cfg(any(target_os = "android",
47          target_os = "freebsd",
48          target_os = "linux"))]
49pub 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)]
56pub mod mqueue;
57#[cfg(not(target_os = "redox"))]
58pub mod net;
59pub mod poll;
60#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
61pub mod pty;
62pub mod sched;
63pub mod sys;
64#[allow(missing_docs)]
65pub 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)]
71pub mod ucontext;
72#[allow(missing_docs)]
73pub mod unistd;
74
75/*
76 *
77 * ===== Result / Error =====
78 *
79 */
80
81use libc::{c_char, PATH_MAX};
82
83use std::{ptr, result};
84use std::ffi::{CStr, OsStr};
85use std::os::unix::ffi::OsStrExt;
86use std::path::{Path, PathBuf};
87
88use errno::Errno;
89
90/// Nix Result Type
91pub 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.
103pub type Error = Errno;
104
105/// Common trait used to represent file system paths by many Nix functions.
106pub trait NixPath {
107    /// Is the path empty?
108    fn is_empty(&self) -> bool;
109
110    /// Length of the path in bytes
111    fn len(&self) -> usize;
112
113    /// Execute a function with this path as a `CStr`.
114    ///
115    /// Mostly used internally by Nix.
116    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
117        where F: FnOnce(&CStr) -> T;
118}
119
120impl NixPath for str {
121    fn is_empty(&self) -> bool {
122        NixPath::is_empty(OsStr::new(self))
123    }
124
125    fn len(&self) -> usize {
126        NixPath::len(OsStr::new(self))
127    }
128
129    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
135impl NixPath for OsStr {
136    fn is_empty(&self) -> bool {
137        self.as_bytes().is_empty()
138    }
139
140    fn len(&self) -> usize {
141        self.as_bytes().len()
142    }
143
144    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
150impl NixPath for CStr {
151    fn is_empty(&self) -> bool {
152        self.to_bytes().is_empty()
153    }
154
155    fn len(&self) -> usize {
156        self.to_bytes().len()
157    }
158
159    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
170impl NixPath for [u8] {
171    fn is_empty(&self) -> bool {
172        self.is_empty()
173    }
174
175    fn len(&self) -> usize {
176        self.len()
177    }
178
179    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
201impl NixPath for Path {
202    fn is_empty(&self) -> bool {
203        NixPath::is_empty(self.as_os_str())
204    }
205
206    fn len(&self) -> usize {
207        NixPath::len(self.as_os_str())
208    }
209
210    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
215impl NixPath for PathBuf {
216    fn is_empty(&self) -> bool {
217        NixPath::is_empty(self.as_os_str())
218    }
219
220    fn len(&self) -> usize {
221        NixPath::len(self.as_os_str())
222    }
223
224    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}