1#![crate_name = "nix"]
45#![cfg(unix)]
46#![allow(non_camel_case_types)]
47#![allow(clippy::too_long_first_doc_paragraph)]
50#![recursion_limit = "500"]
51#![deny(unused)]
52#![deny(unexpected_cfgs)]
53#![allow(unused_macros)]
54#![cfg_attr(
55 not(all(
56 feature = "acct",
57 feature = "aio",
58 feature = "dir",
59 feature = "env",
60 feature = "event",
61 feature = "fanotify",
62 feature = "feature",
63 feature = "fs",
64 feature = "hostname",
65 feature = "inotify",
66 feature = "ioctl",
67 feature = "kmod",
68 feature = "mman",
69 feature = "mount",
70 feature = "mqueue",
71 feature = "net",
72 feature = "personality",
73 feature = "poll",
74 feature = "process",
75 feature = "pthread",
76 feature = "ptrace",
77 feature = "quota",
78 feature = "reboot",
79 feature = "resource",
80 feature = "sched",
81 feature = "socket",
82 feature = "signal",
83 feature = "syslog",
84 feature = "term",
85 feature = "time",
86 feature = "ucontext",
87 feature = "uio",
88 feature = "user",
89 feature = "zerocopy",
90 )),
91 allow(unused_imports)
92)]
93#![deny(unstable_features)]
94#![deny(missing_copy_implementations)]
95#![deny(missing_debug_implementations)]
96#![warn(missing_docs)]
97#![cfg_attr(docsrs, feature(doc_cfg))]
98#![deny(clippy::cast_ptr_alignment)]
99#![deny(unsafe_op_in_unsafe_fn)]
100#![allow(clippy::unwrap_or_default)]
105
106pub use libc;
108
109#[macro_use]
111mod macros;
112
113#[cfg(not(target_os = "redox"))]
115feature! {
116 #![feature = "dir"]
117 pub mod dir;
118}
119feature! {
120 #![feature = "env"]
121 pub mod env;
122}
123#[allow(missing_docs)]
124pub mod errno;
125feature! {
126 #![feature = "feature"]
127
128 #[deny(missing_docs)]
129 pub mod features;
130}
131pub mod fcntl;
132feature! {
133 #![feature = "net"]
134
135 #[cfg(any(linux_android,
136 bsd,
137 solarish))]
138 #[deny(missing_docs)]
139 pub mod ifaddrs;
140 #[cfg(not(target_os = "redox"))]
141 #[deny(missing_docs)]
142 pub mod net;
143}
144#[cfg(linux_android)]
145feature! {
146 #![feature = "kmod"]
147 pub mod kmod;
148}
149feature! {
150 #![feature = "mount"]
151 pub mod mount;
152}
153#[cfg(any(
154 freebsdlike,
155 all(target_os = "linux", not(target_env = "ohos")),
156 target_os = "netbsd"
157))]
158feature! {
159 #![feature = "mqueue"]
160 pub mod mqueue;
161}
162feature! {
163 #![feature = "poll"]
164 pub mod poll;
165}
166#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
167feature! {
168 #![feature = "term"]
169 #[deny(missing_docs)]
170 pub mod pty;
171}
172feature! {
173 #![feature = "sched"]
174 pub mod sched;
175}
176pub mod sys;
177feature! {
178 #![feature = "time"]
179 pub mod time;
180}
181#[cfg(all(
184 target_os = "linux",
185 any(
186 target_arch = "aarch64",
187 target_arch = "s390x",
188 target_arch = "x86",
189 target_arch = "x86_64"
190 )
191))]
192feature! {
193 #![feature = "ucontext"]
194 #[allow(missing_docs)]
195 pub mod ucontext;
196}
197pub mod unistd;
198
199#[cfg(any(feature = "poll", feature = "event"))]
200mod poll_timeout;
201
202#[cfg(any(
203 target_os = "freebsd",
204 target_os = "haiku",
205 target_os = "linux",
206 target_os = "netbsd",
207 apple_targets
208))]
209feature! {
210 #![feature = "process"]
211 pub mod spawn;
212}
213
214feature! {
215 #![feature = "syslog"]
216 pub mod syslog;
217}
218
219use std::ffi::{CStr, CString, OsStr};
220use std::mem::MaybeUninit;
221use std::os::unix::ffi::OsStrExt;
222use std::path::{Path, PathBuf};
223use std::{ptr, result, slice};
224
225use errno::Errno;
226
227pub type Result<T> = result::Result<T, Errno>;
229
230pub type Error = Errno;
241
242pub trait NixPath {
244 fn is_empty(&self) -> bool;
246
247 fn len(&self) -> usize;
249
250 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
254 where
255 F: FnOnce(&CStr) -> T;
256}
257
258impl NixPath for str {
259 fn is_empty(&self) -> bool {
260 NixPath::is_empty(OsStr::new(self))
261 }
262
263 fn len(&self) -> usize {
264 NixPath::len(OsStr::new(self))
265 }
266
267 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
268 where
269 F: FnOnce(&CStr) -> T,
270 {
271 OsStr::new(self).with_nix_path(f)
272 }
273}
274
275impl NixPath for OsStr {
276 fn is_empty(&self) -> bool {
277 self.as_bytes().is_empty()
278 }
279
280 fn len(&self) -> usize {
281 self.as_bytes().len()
282 }
283
284 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
285 where
286 F: FnOnce(&CStr) -> T,
287 {
288 self.as_bytes().with_nix_path(f)
289 }
290}
291
292impl NixPath for CStr {
293 fn is_empty(&self) -> bool {
294 self.to_bytes().is_empty()
295 }
296
297 fn len(&self) -> usize {
298 self.to_bytes().len()
299 }
300
301 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
302 where
303 F: FnOnce(&CStr) -> T,
304 {
305 Ok(f(self))
306 }
307}
308
309impl NixPath for [u8] {
310 fn is_empty(&self) -> bool {
311 self.is_empty()
312 }
313
314 fn len(&self) -> usize {
315 self.len()
316 }
317
318 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
319 where
320 F: FnOnce(&CStr) -> T,
321 {
322 const MAX_STACK_ALLOCATION: usize = 1024;
329
330 if self.len() >= MAX_STACK_ALLOCATION {
331 return with_nix_path_allocating(self, f);
332 }
333
334 let mut buf = MaybeUninit::<[u8; MAX_STACK_ALLOCATION]>::uninit();
335 let buf_ptr = buf.as_mut_ptr().cast();
336
337 unsafe {
338 ptr::copy_nonoverlapping(self.as_ptr(), buf_ptr, self.len());
339 buf_ptr.add(self.len()).write(0);
340 }
341
342 match CStr::from_bytes_with_nul(unsafe {
343 slice::from_raw_parts(buf_ptr, self.len() + 1)
344 }) {
345 Ok(s) => Ok(f(s)),
346 Err(_) => Err(Errno::EINVAL),
347 }
348 }
349}
350
351#[cold]
352#[inline(never)]
353fn with_nix_path_allocating<T, F>(from: &[u8], f: F) -> Result<T>
354where
355 F: FnOnce(&CStr) -> T,
356{
357 match CString::new(from) {
358 Ok(s) => Ok(f(&s)),
359 Err(_) => Err(Errno::EINVAL),
360 }
361}
362
363impl NixPath for Path {
364 fn is_empty(&self) -> bool {
365 NixPath::is_empty(self.as_os_str())
366 }
367
368 fn len(&self) -> usize {
369 NixPath::len(self.as_os_str())
370 }
371
372 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
373 where
374 F: FnOnce(&CStr) -> T,
375 {
376 self.as_os_str().with_nix_path(f)
377 }
378}
379
380impl NixPath for PathBuf {
381 fn is_empty(&self) -> bool {
382 NixPath::is_empty(self.as_os_str())
383 }
384
385 fn len(&self) -> usize {
386 NixPath::len(self.as_os_str())
387 }
388
389 fn with_nix_path<T, F>(&self, f: F) -> Result<T>
390 where
391 F: FnOnce(&CStr) -> T,
392 {
393 self.as_os_str().with_nix_path(f)
394 }
395}
396
397#[cfg(any(
401 all(apple_targets, feature = "mount"),
402 all(linux_android, any(feature = "mount", feature = "fanotify"))
403))]
404pub(crate) fn with_opt_nix_path<P, T, F>(path: Option<&P>, f: F) -> Result<T>
405where
406 P: ?Sized + NixPath,
407 F: FnOnce(*const libc::c_char) -> T,
408{
409 match path {
410 Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())),
411 None => Ok(f(ptr::null())),
412 }
413}