Coverage Report

Created: 2025-06-24 06:17

/rust/registry/src/index.crates.io-6f17d22bba15001f/nix-0.27.1/src/unistd.rs
Line
Count
Source (jump to first uncovered line)
1
//! Safe wrappers around functions found in libc "unistd.h" header
2
3
use crate::errno::{self, Errno};
4
#[cfg(not(target_os = "redox"))]
5
#[cfg(feature = "fs")]
6
use crate::fcntl::{at_rawfd, AtFlags};
7
#[cfg(feature = "fs")]
8
use crate::fcntl::{fcntl, FcntlArg::F_SETFD, FdFlag, OFlag};
9
#[cfg(all(
10
    feature = "fs",
11
    any(
12
        target_os = "openbsd",
13
        target_os = "netbsd",
14
        target_os = "freebsd",
15
        target_os = "dragonfly",
16
        target_os = "macos",
17
        target_os = "ios"
18
    )
19
))]
20
use crate::sys::stat::FileFlag;
21
#[cfg(feature = "fs")]
22
use crate::sys::stat::Mode;
23
use crate::{Error, NixPath, Result};
24
#[cfg(not(target_os = "redox"))]
25
use cfg_if::cfg_if;
26
use libc::{
27
    self, c_char, c_int, c_long, c_uint, c_void, gid_t, mode_t, off_t, pid_t,
28
    size_t, uid_t, PATH_MAX,
29
};
30
use std::convert::Infallible;
31
use std::ffi::{CStr, OsString};
32
#[cfg(not(target_os = "redox"))]
33
use std::ffi::{CString, OsStr};
34
#[cfg(not(target_os = "redox"))]
35
use std::os::unix::ffi::OsStrExt;
36
use std::os::unix::ffi::OsStringExt;
37
use std::os::unix::io::RawFd;
38
use std::os::unix::io::{AsFd, AsRawFd};
39
use std::path::PathBuf;
40
use std::{fmt, mem, ptr};
41
42
feature! {
43
    #![feature = "fs"]
44
    #[cfg(any(target_os = "android", target_os = "linux"))]
45
    pub use self::pivot_root::*;
46
}
47
48
#[cfg(any(
49
    target_os = "android",
50
    target_os = "dragonfly",
51
    target_os = "freebsd",
52
    target_os = "linux",
53
    target_os = "openbsd"
54
))]
55
pub use self::setres::*;
56
57
#[cfg(any(
58
    target_os = "android",
59
    target_os = "dragonfly",
60
    target_os = "freebsd",
61
    target_os = "linux",
62
    target_os = "openbsd"
63
))]
64
pub use self::getres::*;
65
66
feature! {
67
#![feature = "user"]
68
69
/// User identifier
70
///
71
/// Newtype pattern around `uid_t` (which is just alias). It prevents bugs caused by accidentally
72
/// passing wrong value.
73
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
74
pub struct Uid(uid_t);
75
76
impl Uid {
77
    /// Creates `Uid` from raw `uid_t`.
78
    pub const fn from_raw(uid: uid_t) -> Self {
79
        Uid(uid)
80
    }
81
82
    /// Returns Uid of calling process. This is practically a more Rusty alias for `getuid`.
83
    #[doc(alias("getuid"))]
84
    pub fn current() -> Self {
85
        getuid()
86
    }
87
88
    /// Returns effective Uid of calling process. This is practically a more Rusty alias for `geteuid`.
89
    #[doc(alias("geteuid"))]
90
    pub fn effective() -> Self {
91
        geteuid()
92
    }
93
94
    /// Returns true if the `Uid` represents privileged user - root. (If it equals zero.)
95
    pub const fn is_root(self) -> bool {
96
        self.0 == ROOT.0
97
    }
98
99
    /// Get the raw `uid_t` wrapped by `self`.
100
    pub const fn as_raw(self) -> uid_t {
101
        self.0
102
    }
103
}
104
105
impl From<Uid> for uid_t {
106
    fn from(uid: Uid) -> Self {
107
        uid.0
108
    }
109
}
110
111
impl From<uid_t> for Uid {
112
    fn from(uid: uid_t) -> Self {
113
        Uid(uid)
114
    }
115
}
116
117
impl fmt::Display for Uid {
118
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119
        fmt::Display::fmt(&self.0, f)
120
    }
121
}
122
123
/// Constant for UID = 0
124
pub const ROOT: Uid = Uid(0);
125
126
/// Group identifier
127
///
128
/// Newtype pattern around `gid_t` (which is just alias). It prevents bugs caused by accidentally
129
/// passing wrong value.
130
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
131
pub struct Gid(gid_t);
132
133
impl Gid {
134
    /// Creates `Gid` from raw `gid_t`.
135
    pub const fn from_raw(gid: gid_t) -> Self {
136
        Gid(gid)
137
    }
138
139
    /// Returns Gid of calling process. This is practically a more Rusty alias for `getgid`.
140
    #[doc(alias("getgid"))]
141
    pub fn current() -> Self {
142
        getgid()
143
    }
144
145
    /// Returns effective Gid of calling process. This is practically a more Rusty alias for `getegid`.
146
    #[doc(alias("getegid"))]
147
    pub fn effective() -> Self {
148
        getegid()
149
    }
150
151
    /// Get the raw `gid_t` wrapped by `self`.
152
    pub const fn as_raw(self) -> gid_t {
153
        self.0
154
    }
155
}
156
157
impl From<Gid> for gid_t {
158
    fn from(gid: Gid) -> Self {
159
        gid.0
160
    }
161
}
162
163
impl From<gid_t> for Gid {
164
    fn from(gid: gid_t) -> Self {
165
        Gid(gid)
166
    }
167
}
168
169
impl fmt::Display for Gid {
170
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
171
        fmt::Display::fmt(&self.0, f)
172
    }
173
}
174
}
175
176
feature! {
177
#![feature = "process"]
178
/// Process identifier
179
///
180
/// Newtype pattern around `pid_t` (which is just alias). It prevents bugs caused by accidentally
181
/// passing wrong value.
182
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
183
pub struct Pid(pid_t);
184
185
impl Pid {
186
    /// Creates `Pid` from raw `pid_t`.
187
    pub const fn from_raw(pid: pid_t) -> Self {
188
        Pid(pid)
189
    }
190
191
    /// Returns PID of calling process
192
    #[doc(alias("getpid"))]
193
    pub fn this() -> Self {
194
        getpid()
195
    }
196
197
    /// Returns PID of parent of calling process
198
    #[doc(alias("getppid"))]
199
    pub fn parent() -> Self {
200
        getppid()
201
    }
202
203
    /// Get the raw `pid_t` wrapped by `self`.
204
    pub const fn as_raw(self) -> pid_t {
205
        self.0
206
    }
207
}
208
209
impl From<Pid> for pid_t {
210
    fn from(pid: Pid) -> Self {
211
        pid.0
212
    }
213
}
214
215
impl fmt::Display for Pid {
216
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
217
        fmt::Display::fmt(&self.0, f)
218
    }
219
}
220
221
/// Represents the successful result of calling `fork`
222
///
223
/// When `fork` is called, the process continues execution in the parent process
224
/// and in the new child.  This return type can be examined to determine whether
225
/// you are now executing in the parent process or in the child.
226
#[derive(Clone, Copy, Debug)]
227
pub enum ForkResult {
228
    Parent { child: Pid },
229
    Child,
230
}
231
232
impl ForkResult {
233
    /// Return `true` if this is the child process of the `fork()`
234
    #[inline]
235
    pub fn is_child(self) -> bool {
236
        matches!(self, ForkResult::Child)
237
    }
238
239
    /// Returns `true` if this is the parent process of the `fork()`
240
    #[inline]
241
    pub fn is_parent(self) -> bool {
242
        !self.is_child()
243
    }
244
}
245
246
/// Create a new child process duplicating the parent process ([see
247
/// fork(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html)).
248
///
249
/// After successfully calling the fork system call, a second process will
250
/// be created which is identical to the original except for the pid and the
251
/// return value of this function.  As an example:
252
///
253
/// ```
254
/// use nix::{sys::wait::waitpid,unistd::{fork, ForkResult, write}};
255
///
256
/// match unsafe{fork()} {
257
///    Ok(ForkResult::Parent { child, .. }) => {
258
///        println!("Continuing execution in parent process, new child has pid: {}", child);
259
///        waitpid(child, None).unwrap();
260
///    }
261
///    Ok(ForkResult::Child) => {
262
///        // Unsafe to use `println!` (or `unwrap`) here. See Safety.
263
///        write(libc::STDOUT_FILENO, "I'm a new child process\n".as_bytes()).ok();
264
///        unsafe { libc::_exit(0) };
265
///    }
266
///    Err(_) => println!("Fork failed"),
267
/// }
268
/// ```
269
///
270
/// This will print something like the following (order nondeterministic).  The
271
/// thing to note is that you end up with two processes continuing execution
272
/// immediately after the fork call but with different match arms.
273
///
274
/// ```text
275
/// Continuing execution in parent process, new child has pid: 1234
276
/// I'm a new child process
277
/// ```
278
///
279
/// # Safety
280
///
281
/// In a multithreaded program, only [async-signal-safe] functions like `pause`
282
/// and `_exit` may be called by the child (the parent isn't restricted). Note
283
/// that memory allocation may **not** be async-signal-safe and thus must be
284
/// prevented.
285
///
286
/// Those functions are only a small subset of your operating system's API, so
287
/// special care must be taken to only invoke code you can control and audit.
288
///
289
/// [async-signal-safe]: https://man7.org/linux/man-pages/man7/signal-safety.7.html
290
#[inline]
291
pub unsafe fn fork() -> Result<ForkResult> {
292
    use self::ForkResult::*;
293
    let res = libc::fork();
294
295
    Errno::result(res).map(|res| match res {
296
        0 => Child,
297
        res => Parent { child: Pid(res) },
298
    })
299
}
300
301
/// Get the pid of this process (see
302
/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpid.html)).
303
///
304
/// Since you are running code, there is always a pid to return, so there
305
/// is no error case that needs to be handled.
306
#[inline]
307
pub fn getpid() -> Pid {
308
    Pid(unsafe { libc::getpid() })
309
}
310
311
/// Get the pid of this processes' parent (see
312
/// [getpid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getppid.html)).
313
///
314
/// There is always a parent pid to return, so there is no error case that needs
315
/// to be handled.
316
#[inline]
317
pub fn getppid() -> Pid {
318
    Pid(unsafe { libc::getppid() }) // no error handling, according to man page: "These functions are always successful."
319
}
320
321
/// Set a process group ID (see
322
/// [setpgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setpgid.html)).
323
///
324
/// Set the process group id (PGID) of a particular process.  If a pid of zero
325
/// is specified, then the pid of the calling process is used.  Process groups
326
/// may be used to group together a set of processes in order for the OS to
327
/// apply some operations across the group.
328
///
329
/// `setsid()` may be used to create a new process group.
330
#[inline]
331
pub fn setpgid(pid: Pid, pgid: Pid) -> Result<()> {
332
    let res = unsafe { libc::setpgid(pid.into(), pgid.into()) };
333
    Errno::result(res).map(drop)
334
}
335
#[inline]
336
pub fn getpgid(pid: Option<Pid>) -> Result<Pid> {
337
    let res = unsafe { libc::getpgid(pid.unwrap_or(Pid(0)).into()) };
338
    Errno::result(res).map(Pid)
339
}
340
341
/// Create new session and set process group id (see
342
/// [setsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsid.html)).
343
#[inline]
344
pub fn setsid() -> Result<Pid> {
345
    Errno::result(unsafe { libc::setsid() }).map(Pid)
346
}
347
348
/// Get the process group ID of a session leader
349
/// [getsid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsid.html).
350
///
351
/// Obtain the process group ID of the process that is the session leader of the process specified
352
/// by pid. If pid is zero, it specifies the calling process.
353
#[inline]
354
#[cfg(not(target_os = "redox"))]
355
pub fn getsid(pid: Option<Pid>) -> Result<Pid> {
356
    let res = unsafe { libc::getsid(pid.unwrap_or(Pid(0)).into()) };
357
    Errno::result(res).map(Pid)
358
}
359
}
360
361
feature! {
362
#![all(feature = "process", feature = "term")]
363
/// Get the terminal foreground process group (see
364
/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcgetpgrp.html)).
365
///
366
/// Get the group process id (GPID) of the foreground process group on the
367
/// terminal associated to file descriptor (FD).
368
#[inline]
369
pub fn tcgetpgrp(fd: c_int) -> Result<Pid> {
370
    let res = unsafe { libc::tcgetpgrp(fd) };
371
    Errno::result(res).map(Pid)
372
}
373
/// Set the terminal foreground process group (see
374
/// [tcgetpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/tcsetpgrp.html)).
375
///
376
/// Get the group process id (PGID) to the foreground process group on the
377
/// terminal associated to file descriptor (FD).
378
#[inline]
379
pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()> {
380
    let res = unsafe { libc::tcsetpgrp(fd, pgrp.into()) };
381
    Errno::result(res).map(drop)
382
}
383
}
384
385
feature! {
386
#![feature = "process"]
387
/// Get the group id of the calling process (see
388
///[getpgrp(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpgrp.html)).
389
///
390
/// Get the process group id (PGID) of the calling process.
391
/// According to the man page it is always successful.
392
#[inline]
393
pub fn getpgrp() -> Pid {
394
    Pid(unsafe { libc::getpgrp() })
395
}
396
397
/// Get the caller's thread ID (see
398
/// [gettid(2)](https://man7.org/linux/man-pages/man2/gettid.2.html).
399
///
400
/// This function is only available on Linux based systems.  In a single
401
/// threaded process, the main thread will have the same ID as the process.  In
402
/// a multithreaded process, each thread will have a unique thread id but the
403
/// same process ID.
404
///
405
/// No error handling is required as a thread id should always exist for any
406
/// process, even if threads are not being used.
407
#[cfg(any(target_os = "linux", target_os = "android"))]
408
#[inline]
409
pub fn gettid() -> Pid {
410
    Pid(unsafe { libc::syscall(libc::SYS_gettid) as pid_t })
411
}
412
}
413
414
feature! {
415
#![feature = "fs"]
416
/// Create a copy of the specified file descriptor (see
417
/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
418
///
419
/// The new file descriptor will have a new index but refer to the same
420
/// resource as the old file descriptor and the old and new file descriptors may
421
/// be used interchangeably.  The new and old file descriptor share the same
422
/// underlying resource, offset, and file status flags.  The actual index used
423
/// for the file descriptor will be the lowest fd index that is available.
424
///
425
/// The two file descriptors do not share file descriptor flags (e.g. `OFlag::FD_CLOEXEC`).
426
#[inline]
427
0
pub fn dup(oldfd: RawFd) -> Result<RawFd> {
428
0
    let res = unsafe { libc::dup(oldfd) };
429
0
430
0
    Errno::result(res)
431
0
}
432
433
/// Create a copy of the specified file descriptor using the specified fd (see
434
/// [dup(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/dup.html)).
435
///
436
/// This function behaves similar to `dup()` except that it will try to use the
437
/// specified fd instead of allocating a new one.  See the man pages for more
438
/// detail on the exact behavior of this function.
439
#[inline]
440
0
pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
441
0
    let res = unsafe { libc::dup2(oldfd, newfd) };
442
0
443
0
    Errno::result(res)
444
0
}
445
446
/// Create a new copy of the specified file descriptor using the specified fd
447
/// and flags (see [dup(2)](https://man7.org/linux/man-pages/man2/dup.2.html)).
448
///
449
/// This function behaves similar to `dup2()` but allows for flags to be
450
/// specified.
451
0
pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
452
0
    dup3_polyfill(oldfd, newfd, flags)
453
0
}
454
455
#[inline]
456
0
fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
457
0
    if oldfd == newfd {
458
0
        return Err(Errno::EINVAL);
459
0
    }
460
461
0
    let fd = dup2(oldfd, newfd)?;
462
463
0
    if flags.contains(OFlag::O_CLOEXEC) {
464
0
        if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) {
465
0
            let _ = close(fd);
466
0
            return Err(e);
467
0
        }
468
0
    }
469
470
0
    Ok(fd)
471
0
}
472
473
/// Change the current working directory of the calling process (see
474
/// [chdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html)).
475
///
476
/// This function may fail in a number of different scenarios.  See the man
477
/// pages for additional details on possible failure cases.
478
#[inline]
479
0
pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
480
0
    let res =
481
0
        path.with_nix_path(|cstr| unsafe { libc::chdir(cstr.as_ptr()) })?;
482
483
0
    Errno::result(res).map(drop)
484
0
}
485
486
/// Change the current working directory of the process to the one
487
/// given as an open file descriptor (see
488
/// [fchdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchdir.html)).
489
///
490
/// This function may fail in a number of different scenarios.  See the man
491
/// pages for additional details on possible failure cases.
492
#[inline]
493
#[cfg(not(target_os = "fuchsia"))]
494
0
pub fn fchdir(dirfd: RawFd) -> Result<()> {
495
0
    let res = unsafe { libc::fchdir(dirfd) };
496
0
497
0
    Errno::result(res).map(drop)
498
0
}
499
500
/// Creates new directory `path` with access rights `mode`.  (see [mkdir(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkdir.html))
501
///
502
/// # Errors
503
///
504
/// There are several situations where mkdir might fail:
505
///
506
/// - current user has insufficient rights in the parent directory
507
/// - the path already exists
508
/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
509
///
510
/// # Example
511
///
512
/// ```rust
513
/// use nix::unistd;
514
/// use nix::sys::stat;
515
/// use tempfile::tempdir;
516
///
517
/// let tmp_dir1 = tempdir().unwrap();
518
/// let tmp_dir2 = tmp_dir1.path().join("new_dir");
519
///
520
/// // create new directory and give read, write and execute rights to the owner
521
/// match unistd::mkdir(&tmp_dir2, stat::Mode::S_IRWXU) {
522
///    Ok(_) => println!("created {:?}", tmp_dir2),
523
///    Err(err) => println!("Error creating directory: {}", err),
524
/// }
525
/// ```
526
#[inline]
527
0
pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
528
0
    let res = path.with_nix_path(|cstr| unsafe {
529
0
        libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t)
530
0
    })?;
531
532
0
    Errno::result(res).map(drop)
533
0
}
534
535
/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
536
///
537
/// # Errors
538
///
539
/// There are several situations where mkfifo might fail:
540
///
541
/// - current user has insufficient rights in the parent directory
542
/// - the path already exists
543
/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X)
544
///
545
/// For a full list consult
546
/// [posix specification](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifo.html)
547
///
548
/// # Example
549
///
550
/// ```rust
551
/// use nix::unistd;
552
/// use nix::sys::stat;
553
/// use tempfile::tempdir;
554
///
555
/// let tmp_dir = tempdir().unwrap();
556
/// let fifo_path = tmp_dir.path().join("foo.pipe");
557
///
558
/// // create new fifo and give read, write and execute rights to the owner
559
/// match unistd::mkfifo(&fifo_path, stat::Mode::S_IRWXU) {
560
///    Ok(_) => println!("created {:?}", fifo_path),
561
///    Err(err) => println!("Error creating fifo: {}", err),
562
/// }
563
/// ```
564
#[inline]
565
#[cfg(not(target_os = "redox"))] // RedoxFS does not support fifo yet
566
0
pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
567
0
    let res = path.with_nix_path(|cstr| unsafe {
568
0
        libc::mkfifo(cstr.as_ptr(), mode.bits() as mode_t)
569
0
    })?;
570
571
0
    Errno::result(res).map(drop)
572
0
}
573
574
/// Creates new fifo special file (named pipe) with path `path` and access rights `mode`.
575
///
576
/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
577
///
578
/// If `dirfd` is `None`, then `path` is relative to the current working directory.
579
///
580
/// # References
581
///
582
/// [mkfifoat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html).
583
// mkfifoat is not implemented in OSX or android
584
#[inline]
585
#[cfg(not(any(
586
    target_os = "macos",
587
    target_os = "ios",
588
    target_os = "haiku",
589
    target_os = "android",
590
    target_os = "redox"
591
)))]
592
0
pub fn mkfifoat<P: ?Sized + NixPath>(
593
0
    dirfd: Option<RawFd>,
594
0
    path: &P,
595
0
    mode: Mode,
596
0
) -> Result<()> {
597
0
    let res = path.with_nix_path(|cstr| unsafe {
598
0
        libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t)
599
0
    })?;
600
601
0
    Errno::result(res).map(drop)
602
0
}
603
604
/// Creates a symbolic link at `path2` which points to `path1`.
605
///
606
/// If `dirfd` has a value, then `path2` is relative to directory associated
607
/// with the file descriptor.
608
///
609
/// If `dirfd` is `None`, then `path2` is relative to the current working
610
/// directory. This is identical to `libc::symlink(path1, path2)`.
611
///
612
/// See also [symlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
613
#[cfg(not(target_os = "redox"))]
614
0
pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
615
0
    path1: &P1,
616
0
    dirfd: Option<RawFd>,
617
0
    path2: &P2,
618
0
) -> Result<()> {
619
0
    let res = path1.with_nix_path(|path1| {
620
0
        path2.with_nix_path(|path2| unsafe {
621
0
            libc::symlinkat(
622
0
                path1.as_ptr(),
623
0
                dirfd.unwrap_or(libc::AT_FDCWD),
624
0
                path2.as_ptr(),
625
0
            )
626
0
        })
627
0
    })??;
628
0
    Errno::result(res).map(drop)
629
0
}
630
}
631
632
// Double the buffer capacity up to limit. In case it already has
633
// reached the limit, return Errno::ERANGE.
634
#[cfg(any(feature = "fs", feature = "user"))]
635
0
fn reserve_double_buffer_size<T>(buf: &mut Vec<T>, limit: usize) -> Result<()> {
636
    use std::cmp::min;
637
638
0
    if buf.capacity() >= limit {
639
0
        return Err(Errno::ERANGE);
640
0
    }
641
0
642
0
    let capacity = min(buf.capacity() * 2, limit);
643
0
    buf.reserve(capacity);
644
0
645
0
    Ok(())
646
0
}
647
648
feature! {
649
#![feature = "fs"]
650
651
/// Returns the current directory as a `PathBuf`
652
///
653
/// Err is returned if the current user doesn't have the permission to read or search a component
654
/// of the current path.
655
///
656
/// # Example
657
///
658
/// ```rust
659
/// use nix::unistd;
660
///
661
/// // assume that we are allowed to get current directory
662
/// let dir = unistd::getcwd().unwrap();
663
/// println!("The current directory is {:?}", dir);
664
/// ```
665
#[inline]
666
0
pub fn getcwd() -> Result<PathBuf> {
667
0
    let mut buf = Vec::with_capacity(512);
668
    loop {
669
        unsafe {
670
0
            let ptr = buf.as_mut_ptr() as *mut c_char;
671
0
672
0
            // The buffer must be large enough to store the absolute pathname plus
673
0
            // a terminating null byte, or else null is returned.
674
0
            // To safely handle this we start with a reasonable size (512 bytes)
675
0
            // and double the buffer size upon every error
676
0
            if !libc::getcwd(ptr, buf.capacity()).is_null() {
677
0
                let len = CStr::from_ptr(buf.as_ptr() as *const c_char)
678
0
                    .to_bytes()
679
0
                    .len();
680
0
                buf.set_len(len);
681
0
                buf.shrink_to_fit();
682
0
                return Ok(PathBuf::from(OsString::from_vec(buf)));
683
            } else {
684
0
                let error = Errno::last();
685
0
                // ERANGE means buffer was too small to store directory name
686
0
                if error != Errno::ERANGE {
687
0
                    return Err(error);
688
0
                }
689
0
            }
690
0
691
0
            // Trigger the internal buffer resizing logic.
692
0
            reserve_double_buffer_size(&mut buf, PATH_MAX as usize)?;
693
        }
694
    }
695
0
}
696
}
697
698
feature! {
699
#![all(feature = "user", feature = "fs")]
700
701
/// Computes the raw UID and GID values to pass to a `*chown` call.
702
// The cast is not unnecessary on all platforms.
703
#[allow(clippy::unnecessary_cast)]
704
fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (uid_t, gid_t) {
705
    // According to the POSIX specification, -1 is used to indicate that owner and group
706
    // are not to be changed.  Since uid_t and gid_t are unsigned types, we have to wrap
707
    // around to get -1.
708
    let uid = owner
709
        .map(Into::into)
710
        .unwrap_or_else(|| (0 as uid_t).wrapping_sub(1));
711
    let gid = group
712
        .map(Into::into)
713
        .unwrap_or_else(|| (0 as gid_t).wrapping_sub(1));
714
    (uid, gid)
715
}
716
717
/// Change the ownership of the file at `path` to be owned by the specified
718
/// `owner` (user) and `group` (see
719
/// [chown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
720
///
721
/// The owner/group for the provided path name will not be modified if `None` is
722
/// provided for that argument.  Ownership change will be attempted for the path
723
/// only if `Some` owner/group is provided.
724
#[inline]
725
pub fn chown<P: ?Sized + NixPath>(
726
    path: &P,
727
    owner: Option<Uid>,
728
    group: Option<Gid>,
729
) -> Result<()> {
730
    let res = path.with_nix_path(|cstr| {
731
        let (uid, gid) = chown_raw_ids(owner, group);
732
        unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
733
    })?;
734
735
    Errno::result(res).map(drop)
736
}
737
738
/// Change the ownership of the file referred to by the open file descriptor `fd` to be owned by
739
/// the specified `owner` (user) and `group` (see
740
/// [fchown(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)).
741
///
742
/// The owner/group for the provided file will not be modified if `None` is
743
/// provided for that argument.  Ownership change will be attempted for the path
744
/// only if `Some` owner/group is provided.
745
#[inline]
746
pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
747
    let (uid, gid) = chown_raw_ids(owner, group);
748
    let res = unsafe { libc::fchown(fd, uid, gid) };
749
    Errno::result(res).map(drop)
750
}
751
752
/// Flags for `fchownat` function.
753
#[derive(Clone, Copy, Debug)]
754
pub enum FchownatFlags {
755
    FollowSymlink,
756
    NoFollowSymlink,
757
}
758
759
/// Change the ownership of the file at `path` to be owned by the specified
760
/// `owner` (user) and `group`.
761
///
762
/// The owner/group for the provided path name will not be modified if `None` is
763
/// provided for that argument.  Ownership change will be attempted for the path
764
/// only if `Some` owner/group is provided.
765
///
766
/// The file to be changed is determined relative to the directory associated
767
/// with the file descriptor `dirfd` or the current working directory
768
/// if `dirfd` is `None`.
769
///
770
/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
771
/// then the mode of the symbolic link is changed.
772
///
773
/// `fchownat(None, path, owner, group, FchownatFlags::NoFollowSymlink)` is identical to
774
/// a call `libc::lchown(path, owner, group)`.  That's why `lchown` is unimplemented in
775
/// the `nix` crate.
776
///
777
/// # References
778
///
779
/// [fchownat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
780
#[cfg(not(target_os = "redox"))]
781
pub fn fchownat<P: ?Sized + NixPath>(
782
    dirfd: Option<RawFd>,
783
    path: &P,
784
    owner: Option<Uid>,
785
    group: Option<Gid>,
786
    flag: FchownatFlags,
787
) -> Result<()> {
788
    let atflag = match flag {
789
        FchownatFlags::FollowSymlink => AtFlags::empty(),
790
        FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
791
    };
792
    let res = path.with_nix_path(|cstr| unsafe {
793
        let (uid, gid) = chown_raw_ids(owner, group);
794
        libc::fchownat(
795
            at_rawfd(dirfd),
796
            cstr.as_ptr(),
797
            uid,
798
            gid,
799
            atflag.bits() as libc::c_int,
800
        )
801
    })?;
802
803
    Errno::result(res).map(drop)
804
}
805
}
806
807
feature! {
808
#![feature = "process"]
809
fn to_exec_array<S: AsRef<CStr>>(args: &[S]) -> Vec<*const c_char> {
810
    use std::iter::once;
811
    args.iter()
812
        .map(|s| s.as_ref().as_ptr())
813
        .chain(once(ptr::null()))
814
        .collect()
815
}
816
817
/// Replace the current process image with a new one (see
818
/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
819
///
820
/// See the `::nix::unistd::execve` system call for additional details.  `execv`
821
/// performs the same action but does not allow for customization of the
822
/// environment for the new process.
823
#[inline]
824
pub fn execv<S: AsRef<CStr>>(path: &CStr, argv: &[S]) -> Result<Infallible> {
825
    let args_p = to_exec_array(argv);
826
827
    unsafe { libc::execv(path.as_ptr(), args_p.as_ptr()) };
828
829
    Err(Errno::last())
830
}
831
832
/// Replace the current process image with a new one (see
833
/// [execve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
834
///
835
/// The execve system call allows for another process to be "called" which will
836
/// replace the current process image.  That is, this process becomes the new
837
/// command that is run. On success, this function will not return. Instead,
838
/// the new program will run until it exits.
839
///
840
/// `::nix::unistd::execv` and `::nix::unistd::execve` take as arguments a slice
841
/// of `::std::ffi::CString`s for `args` and `env` (for `execve`). Each element
842
/// in the `args` list is an argument to the new process. Each element in the
843
/// `env` list should be a string in the form "key=value".
844
#[inline]
845
pub fn execve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
846
    path: &CStr,
847
    args: &[SA],
848
    env: &[SE],
849
) -> Result<Infallible> {
850
    let args_p = to_exec_array(args);
851
    let env_p = to_exec_array(env);
852
853
    unsafe { libc::execve(path.as_ptr(), args_p.as_ptr(), env_p.as_ptr()) };
854
855
    Err(Errno::last())
856
}
857
858
/// Replace the current process image with a new one and replicate shell `PATH`
859
/// searching behavior (see
860
/// [exec(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html)).
861
///
862
/// See `::nix::unistd::execve` for additional details.  `execvp` behaves the
863
/// same as execv except that it will examine the `PATH` environment variables
864
/// for file names not specified with a leading slash.  For example, `execv`
865
/// would not work if "bash" was specified for the path argument, but `execvp`
866
/// would assuming that a bash executable was on the system `PATH`.
867
#[inline]
868
pub fn execvp<S: AsRef<CStr>>(
869
    filename: &CStr,
870
    args: &[S],
871
) -> Result<Infallible> {
872
    let args_p = to_exec_array(args);
873
874
    unsafe { libc::execvp(filename.as_ptr(), args_p.as_ptr()) };
875
876
    Err(Errno::last())
877
}
878
879
/// Replace the current process image with a new one and replicate shell `PATH`
880
/// searching behavior (see
881
/// [`execvpe(3)`](https://man7.org/linux/man-pages/man3/exec.3.html)).
882
///
883
/// This functions like a combination of `execvp(2)` and `execve(2)` to pass an
884
/// environment and have a search path. See these two for additional
885
/// information.
886
#[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
887
pub fn execvpe<SA: AsRef<CStr>, SE: AsRef<CStr>>(
888
    filename: &CStr,
889
    args: &[SA],
890
    env: &[SE],
891
) -> Result<Infallible> {
892
    let args_p = to_exec_array(args);
893
    let env_p = to_exec_array(env);
894
895
    unsafe {
896
        libc::execvpe(filename.as_ptr(), args_p.as_ptr(), env_p.as_ptr())
897
    };
898
899
    Err(Errno::last())
900
}
901
902
/// Replace the current process image with a new one (see
903
/// [fexecve(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fexecve.html)).
904
///
905
/// The `fexecve` function allows for another process to be "called" which will
906
/// replace the current process image.  That is, this process becomes the new
907
/// command that is run. On success, this function will not return. Instead,
908
/// the new program will run until it exits.
909
///
910
/// This function is similar to `execve`, except that the program to be executed
911
/// is referenced as a file descriptor instead of a path.
912
#[cfg(any(
913
    target_os = "android",
914
    target_os = "linux",
915
    target_os = "dragonfly",
916
    target_os = "freebsd"
917
))]
918
#[inline]
919
pub fn fexecve<SA: AsRef<CStr>, SE: AsRef<CStr>>(
920
    fd: RawFd,
921
    args: &[SA],
922
    env: &[SE],
923
) -> Result<Infallible> {
924
    let args_p = to_exec_array(args);
925
    let env_p = to_exec_array(env);
926
927
    unsafe { libc::fexecve(fd, args_p.as_ptr(), env_p.as_ptr()) };
928
929
    Err(Errno::last())
930
}
931
932
/// Execute program relative to a directory file descriptor (see
933
/// [execveat(2)](https://man7.org/linux/man-pages/man2/execveat.2.html)).
934
///
935
/// The `execveat` function allows for another process to be "called" which will
936
/// replace the current process image.  That is, this process becomes the new
937
/// command that is run. On success, this function will not return. Instead,
938
/// the new program will run until it exits.
939
///
940
/// This function is similar to `execve`, except that the program to be executed
941
/// is referenced as a file descriptor to the base directory plus a path.
942
#[cfg(any(target_os = "android", target_os = "linux"))]
943
#[inline]
944
pub fn execveat<SA: AsRef<CStr>, SE: AsRef<CStr>>(
945
    dirfd: RawFd,
946
    pathname: &CStr,
947
    args: &[SA],
948
    env: &[SE],
949
    flags: super::fcntl::AtFlags,
950
) -> Result<Infallible> {
951
    let args_p = to_exec_array(args);
952
    let env_p = to_exec_array(env);
953
954
    unsafe {
955
        libc::syscall(
956
            libc::SYS_execveat,
957
            dirfd,
958
            pathname.as_ptr(),
959
            args_p.as_ptr(),
960
            env_p.as_ptr(),
961
            flags,
962
        );
963
    };
964
965
    Err(Errno::last())
966
}
967
968
/// Daemonize this process by detaching from the controlling terminal (see
969
/// [daemon(3)](https://man7.org/linux/man-pages/man3/daemon.3.html)).
970
///
971
/// When a process is launched it is typically associated with a parent and it,
972
/// in turn, by its controlling terminal/process.  In order for a process to run
973
/// in the "background" it must daemonize itself by detaching itself.  Under
974
/// posix, this is done by doing the following:
975
///
976
/// 1. Parent process (this one) forks
977
/// 2. Parent process exits
978
/// 3. Child process continues to run.
979
///
980
/// `nochdir`:
981
///
982
/// * `nochdir = true`: The current working directory after daemonizing will
983
///    be the current working directory.
984
/// *  `nochdir = false`: The current working directory after daemonizing will
985
///    be the root direcory, `/`.
986
///
987
/// `noclose`:
988
///
989
/// * `noclose = true`: The process' current stdin, stdout, and stderr file
990
///   descriptors will remain identical after daemonizing.
991
/// * `noclose = false`: The process' stdin, stdout, and stderr will point to
992
///   `/dev/null` after daemonizing.
993
#[cfg(any(
994
    target_os = "android",
995
    target_os = "dragonfly",
996
    target_os = "freebsd",
997
    target_os = "illumos",
998
    target_os = "linux",
999
    target_os = "netbsd",
1000
    target_os = "openbsd",
1001
    target_os = "solaris"
1002
))]
1003
pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> {
1004
    let res = unsafe { libc::daemon(nochdir as c_int, noclose as c_int) };
1005
    Errno::result(res).map(drop)
1006
}
1007
}
1008
1009
feature! {
1010
#![feature = "hostname"]
1011
1012
/// Set the system host name (see
1013
/// [sethostname(2)](https://man7.org/linux/man-pages/man2/gethostname.2.html)).
1014
///
1015
/// Given a name, attempt to update the system host name to the given string.
1016
/// On some systems, the host name is limited to as few as 64 bytes.  An error
1017
/// will be returned if the name is not valid or the current process does not
1018
/// have permissions to update the host name.
1019
#[cfg(not(target_os = "redox"))]
1020
pub fn sethostname<S: AsRef<OsStr>>(name: S) -> Result<()> {
1021
    // Handle some differences in type of the len arg across platforms.
1022
    cfg_if! {
1023
        if #[cfg(any(target_os = "dragonfly",
1024
                     target_os = "freebsd",
1025
                     target_os = "illumos",
1026
                     target_os = "ios",
1027
                     target_os = "macos",
1028
                     target_os = "aix",
1029
                     target_os = "solaris", ))] {
1030
            type sethostname_len_t = c_int;
1031
        } else {
1032
            type sethostname_len_t = size_t;
1033
        }
1034
    }
1035
    let ptr = name.as_ref().as_bytes().as_ptr() as *const c_char;
1036
    let len = name.as_ref().len() as sethostname_len_t;
1037
1038
    let res = unsafe { libc::sethostname(ptr, len) };
1039
    Errno::result(res).map(drop)
1040
}
1041
1042
/// Get the host name and store it in an internally allocated buffer, returning an
1043
/// `OsString` on success (see
1044
/// [gethostname(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/gethostname.html)).
1045
///
1046
/// This function call attempts to get the host name for the running system and
1047
/// store it in an internal buffer, returning it as an `OsString` if successful.
1048
///
1049
/// ```no_run
1050
/// use nix::unistd;
1051
///
1052
/// let hostname = unistd::gethostname().expect("Failed getting hostname");
1053
/// let hostname = hostname.into_string().expect("Hostname wasn't valid UTF-8");
1054
/// println!("Hostname: {}", hostname);
1055
/// ```
1056
pub fn gethostname() -> Result<OsString> {
1057
    // The capacity is the max length of a hostname plus the NUL terminator.
1058
    let mut buffer: Vec<u8> = Vec::with_capacity(256);
1059
    let ptr = buffer.as_mut_ptr() as *mut c_char;
1060
    let len = buffer.capacity() as size_t;
1061
1062
    let res = unsafe { libc::gethostname(ptr, len) };
1063
    Errno::result(res).map(|_| {
1064
        unsafe {
1065
            buffer.as_mut_ptr().wrapping_add(len - 1).write(0); // ensure always null-terminated
1066
            let len = CStr::from_ptr(buffer.as_ptr() as *const c_char).len();
1067
            buffer.set_len(len);
1068
        }
1069
        OsString::from_vec(buffer)
1070
    })
1071
}
1072
}
1073
1074
/// Close a raw file descriptor
1075
///
1076
/// Be aware that many Rust types implicitly close-on-drop, including
1077
/// `std::fs::File`.  Explicitly closing them with this method too can result in
1078
/// a double-close condition, which can cause confusing `EBADF` errors in
1079
/// seemingly unrelated code.  Caveat programmer.  See also
1080
/// [close(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/close.html).
1081
///
1082
/// # Examples
1083
///
1084
/// ```no_run
1085
/// use std::os::unix::io::AsRawFd;
1086
/// use nix::unistd::close;
1087
///
1088
/// let f = tempfile::tempfile().unwrap();
1089
/// close(f.as_raw_fd()).unwrap();   // Bad!  f will also close on drop!
1090
/// ```
1091
///
1092
/// ```rust
1093
/// use std::os::unix::io::IntoRawFd;
1094
/// use nix::unistd::close;
1095
///
1096
/// let f = tempfile::tempfile().unwrap();
1097
/// close(f.into_raw_fd()).unwrap(); // Good.  into_raw_fd consumes f
1098
/// ```
1099
0
pub fn close(fd: RawFd) -> Result<()> {
1100
0
    let res = unsafe { libc::close(fd) };
1101
0
    Errno::result(res).map(drop)
1102
0
}
1103
1104
/// Read from a raw file descriptor.
1105
///
1106
/// See also [read(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html)
1107
0
pub fn read(fd: RawFd, buf: &mut [u8]) -> Result<usize> {
1108
0
    let res = unsafe {
1109
0
        libc::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len() as size_t)
1110
0
    };
1111
0
1112
0
    Errno::result(res).map(|r| r as usize)
1113
0
}
1114
1115
/// Write to a raw file descriptor.
1116
///
1117
/// See also [write(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html)
1118
0
pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
1119
0
    let res = unsafe {
1120
0
        libc::write(fd, buf.as_ptr() as *const c_void, buf.len() as size_t)
1121
0
    };
1122
0
1123
0
    Errno::result(res).map(|r| r as usize)
1124
0
}
1125
1126
feature! {
1127
#![feature = "fs"]
1128
1129
/// Directive that tells [`lseek`] and [`lseek64`] what the offset is relative to.
1130
///
1131
/// [`lseek`]: ./fn.lseek.html
1132
/// [`lseek64`]: ./fn.lseek64.html
1133
#[repr(i32)]
1134
#[derive(Clone, Copy, Debug)]
1135
pub enum Whence {
1136
    /// Specify an offset relative to the start of the file.
1137
    SeekSet = libc::SEEK_SET,
1138
    /// Specify an offset relative to the current file location.
1139
    SeekCur = libc::SEEK_CUR,
1140
    /// Specify an offset relative to the end of the file.
1141
    SeekEnd = libc::SEEK_END,
1142
    /// Specify an offset relative to the next location in the file greater than or
1143
    /// equal to offset that contains some data. If offset points to
1144
    /// some data, then the file offset is set to offset.
1145
    #[cfg(any(
1146
        target_os = "dragonfly",
1147
        target_os = "freebsd",
1148
        target_os = "illumos",
1149
        target_os = "linux",
1150
        target_os = "solaris"
1151
    ))]
1152
    SeekData = libc::SEEK_DATA,
1153
    /// Specify an offset relative to the next hole in the file greater than
1154
    /// or equal to offset. If offset points into the middle of a hole, then
1155
    /// the file offset should be set to offset. If there is no hole past offset,
1156
    /// then the file offset should be adjusted to the end of the file (i.e., there
1157
    /// is an implicit hole at the end of any file).
1158
    #[cfg(any(
1159
        target_os = "dragonfly",
1160
        target_os = "freebsd",
1161
        target_os = "illumos",
1162
        target_os = "linux",
1163
        target_os = "solaris"
1164
    ))]
1165
    SeekHole = libc::SEEK_HOLE,
1166
}
1167
1168
/// Move the read/write file offset.
1169
///
1170
/// See also [lseek(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/lseek.html)
1171
0
pub fn lseek(fd: RawFd, offset: off_t, whence: Whence) -> Result<off_t> {
1172
0
    let res = unsafe { libc::lseek(fd, offset, whence as i32) };
1173
0
1174
0
    Errno::result(res).map(|r| r as off_t)
1175
0
}
1176
1177
#[cfg(any(target_os = "linux", target_os = "android"))]
1178
0
pub fn lseek64(
1179
0
    fd: RawFd,
1180
0
    offset: libc::off64_t,
1181
0
    whence: Whence,
1182
0
) -> Result<libc::off64_t> {
1183
0
    let res = unsafe { libc::lseek64(fd, offset, whence as i32) };
1184
0
1185
0
    Errno::result(res).map(|r| r as libc::off64_t)
1186
0
}
1187
}
1188
1189
/// Create an interprocess channel.
1190
///
1191
/// See also [pipe(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pipe.html)
1192
0
pub fn pipe() -> std::result::Result<(RawFd, RawFd), Error> {
1193
0
    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
1194
0
1195
0
    let res = unsafe { libc::pipe(fds.as_mut_ptr() as *mut c_int) };
1196
0
1197
0
    Error::result(res)?;
1198
1199
0
    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
1200
0
}
1201
1202
feature! {
1203
#![feature = "fs"]
1204
/// Like `pipe`, but allows setting certain file descriptor flags.
1205
///
1206
/// The following flags are supported, and will be set atomically as the pipe is
1207
/// created:
1208
///
1209
/// - `O_CLOEXEC`:    Set the close-on-exec flag for the new file descriptors.
1210
#[cfg_attr(
1211
    target_os = "linux",
1212
    doc = "- `O_DIRECT`: Create a pipe that performs I/O in \"packet\" mode."
1213
)]
1214
#[cfg_attr(
1215
    target_os = "netbsd",
1216
    doc = "- `O_NOSIGPIPE`: Return `EPIPE` instead of raising `SIGPIPE`."
1217
)]
1218
/// - `O_NONBLOCK`:   Set the non-blocking flag for the ends of the pipe.
1219
///
1220
/// See also [pipe(2)](https://man7.org/linux/man-pages/man2/pipe.2.html)
1221
#[cfg(any(
1222
    target_os = "android",
1223
    target_os = "dragonfly",
1224
    target_os = "emscripten",
1225
    target_os = "freebsd",
1226
    target_os = "illumos",
1227
    target_os = "linux",
1228
    target_os = "redox",
1229
    target_os = "netbsd",
1230
    target_os = "openbsd",
1231
    target_os = "solaris"
1232
))]
1233
0
pub fn pipe2(flags: OFlag) -> Result<(RawFd, RawFd)> {
1234
0
    let mut fds = mem::MaybeUninit::<[c_int; 2]>::uninit();
1235
0
1236
0
    let res =
1237
0
        unsafe { libc::pipe2(fds.as_mut_ptr() as *mut c_int, flags.bits()) };
1238
0
1239
0
    Errno::result(res)?;
1240
1241
0
    unsafe { Ok((fds.assume_init()[0], fds.assume_init()[1])) }
1242
0
}
1243
1244
/// Truncate a file to a specified length
1245
///
1246
/// See also
1247
/// [truncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/truncate.html)
1248
#[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
1249
0
pub fn truncate<P: ?Sized + NixPath>(path: &P, len: off_t) -> Result<()> {
1250
0
    let res = path
1251
0
        .with_nix_path(|cstr| unsafe { libc::truncate(cstr.as_ptr(), len) })?;
1252
1253
0
    Errno::result(res).map(drop)
1254
0
}
1255
1256
/// Truncate a file to a specified length
1257
///
1258
/// See also
1259
/// [ftruncate(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/ftruncate.html)
1260
0
pub fn ftruncate<Fd: AsFd>(fd: Fd, len: off_t) -> Result<()> {
1261
0
    Errno::result(unsafe { libc::ftruncate(fd.as_fd().as_raw_fd(), len) }).map(drop)
1262
0
}
1263
1264
0
pub fn isatty(fd: RawFd) -> Result<bool> {
1265
0
    unsafe {
1266
0
        // ENOTTY means `fd` is a valid file descriptor, but not a TTY, so
1267
0
        // we return `Ok(false)`
1268
0
        if libc::isatty(fd) == 1 {
1269
0
            Ok(true)
1270
        } else {
1271
0
            match Errno::last() {
1272
0
                Errno::ENOTTY => Ok(false),
1273
0
                err => Err(err),
1274
            }
1275
        }
1276
    }
1277
0
}
1278
1279
/// Flags for `linkat` function.
1280
#[derive(Clone, Copy, Debug)]
1281
pub enum LinkatFlags {
1282
    SymlinkFollow,
1283
    NoSymlinkFollow,
1284
}
1285
1286
/// Link one file to another file
1287
///
1288
/// Creates a new link (directory entry) at `newpath` for the existing file at `oldpath`. In the
1289
/// case of a relative `oldpath`, the path is interpreted relative to the directory associated
1290
/// with file descriptor `olddirfd` instead of the current working directory and similiarly for
1291
/// `newpath` and file descriptor `newdirfd`. In case `flag` is LinkatFlags::SymlinkFollow and
1292
/// `oldpath` names a symoblic link, a new link for the target of the symbolic link is created.
1293
/// If either `olddirfd` or `newdirfd` is `None`, `AT_FDCWD` is used respectively where `oldpath`
1294
/// and/or `newpath` is then interpreted relative to the current working directory of the calling
1295
/// process. If either `oldpath` or `newpath` is absolute, then `dirfd` is ignored.
1296
///
1297
/// # References
1298
/// See also [linkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)
1299
#[cfg(not(target_os = "redox"))] // RedoxFS does not support symlinks yet
1300
0
pub fn linkat<P: ?Sized + NixPath>(
1301
0
    olddirfd: Option<RawFd>,
1302
0
    oldpath: &P,
1303
0
    newdirfd: Option<RawFd>,
1304
0
    newpath: &P,
1305
0
    flag: LinkatFlags,
1306
0
) -> Result<()> {
1307
0
    let atflag = match flag {
1308
0
        LinkatFlags::SymlinkFollow => AtFlags::AT_SYMLINK_FOLLOW,
1309
0
        LinkatFlags::NoSymlinkFollow => AtFlags::empty(),
1310
    };
1311
1312
0
    let res = oldpath.with_nix_path(|oldcstr| {
1313
0
        newpath.with_nix_path(|newcstr| unsafe {
1314
0
            libc::linkat(
1315
0
                at_rawfd(olddirfd),
1316
0
                oldcstr.as_ptr(),
1317
0
                at_rawfd(newdirfd),
1318
0
                newcstr.as_ptr(),
1319
0
                atflag.bits() as libc::c_int,
1320
0
            )
1321
0
        })
1322
0
    })??;
1323
0
    Errno::result(res).map(drop)
1324
0
}
1325
1326
/// Remove a directory entry
1327
///
1328
/// See also [unlink(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html)
1329
0
pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
1330
0
    let res =
1331
0
        path.with_nix_path(|cstr| unsafe { libc::unlink(cstr.as_ptr()) })?;
1332
0
    Errno::result(res).map(drop)
1333
0
}
1334
1335
/// Flags for `unlinkat` function.
1336
#[derive(Clone, Copy, Debug)]
1337
pub enum UnlinkatFlags {
1338
    RemoveDir,
1339
    NoRemoveDir,
1340
}
1341
1342
/// Remove a directory entry
1343
///
1344
/// In the case of a relative path, the directory entry to be removed is determined relative to
1345
/// the directory associated with the file descriptor `dirfd` or the current working directory
1346
/// if `dirfd` is `None`. In the case of an absolute `path` `dirfd` is ignored. If `flag` is
1347
/// `UnlinkatFlags::RemoveDir` then removal of the directory entry specified by `dirfd` and `path`
1348
/// is performed.
1349
///
1350
/// # References
1351
/// See also [unlinkat(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)
1352
#[cfg(not(target_os = "redox"))]
1353
0
pub fn unlinkat<P: ?Sized + NixPath>(
1354
0
    dirfd: Option<RawFd>,
1355
0
    path: &P,
1356
0
    flag: UnlinkatFlags,
1357
0
) -> Result<()> {
1358
0
    let atflag = match flag {
1359
0
        UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
1360
0
        UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
1361
    };
1362
0
    let res = path.with_nix_path(|cstr| unsafe {
1363
0
        libc::unlinkat(
1364
0
            at_rawfd(dirfd),
1365
0
            cstr.as_ptr(),
1366
0
            atflag.bits() as libc::c_int,
1367
0
        )
1368
0
    })?;
1369
0
    Errno::result(res).map(drop)
1370
0
}
1371
1372
#[inline]
1373
#[cfg(not(target_os = "fuchsia"))]
1374
0
pub fn chroot<P: ?Sized + NixPath>(path: &P) -> Result<()> {
1375
0
    let res =
1376
0
        path.with_nix_path(|cstr| unsafe { libc::chroot(cstr.as_ptr()) })?;
1377
1378
0
    Errno::result(res).map(drop)
1379
0
}
1380
1381
/// Commit filesystem caches to disk
1382
///
1383
/// See also [sync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sync.html)
1384
#[cfg(any(
1385
    target_os = "dragonfly",
1386
    target_os = "freebsd",
1387
    target_os = "linux",
1388
    target_os = "netbsd",
1389
    target_os = "openbsd"
1390
))]
1391
0
pub fn sync() {
1392
0
    unsafe { libc::sync() };
1393
0
}
1394
1395
/// Commit filesystem caches containing file referred to by the open file
1396
/// descriptor `fd` to disk
1397
///
1398
/// See also [syncfs(2)](https://man7.org/linux/man-pages/man2/sync.2.html)
1399
#[cfg(target_os = "linux")]
1400
0
pub fn syncfs(fd: RawFd) -> Result<()> {
1401
0
    let res = unsafe { libc::syncfs(fd) };
1402
0
1403
0
    Errno::result(res).map(drop)
1404
0
}
1405
1406
/// Synchronize changes to a file
1407
///
1408
/// See also [fsync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fsync.html)
1409
#[inline]
1410
0
pub fn fsync(fd: RawFd) -> Result<()> {
1411
0
    let res = unsafe { libc::fsync(fd) };
1412
0
1413
0
    Errno::result(res).map(drop)
1414
0
}
1415
1416
/// Synchronize the data of a file
1417
///
1418
/// See also
1419
/// [fdatasync(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/fdatasync.html)
1420
#[cfg(any(
1421
    target_os = "linux",
1422
    target_os = "android",
1423
    target_os = "emscripten",
1424
    target_os = "freebsd",
1425
    target_os = "fuchsia",
1426
    target_os = "netbsd",
1427
    target_os = "openbsd",
1428
    target_os = "illumos",
1429
    target_os = "solaris"
1430
))]
1431
#[inline]
1432
0
pub fn fdatasync(fd: RawFd) -> Result<()> {
1433
0
    let res = unsafe { libc::fdatasync(fd) };
1434
0
1435
0
    Errno::result(res).map(drop)
1436
0
}
1437
}
1438
1439
feature! {
1440
#![feature = "user"]
1441
1442
/// Get a real user ID
1443
///
1444
/// See also [getuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getuid.html)
1445
// POSIX requires that getuid is always successful, so no need to check return
1446
// value or errno.
1447
#[inline]
1448
pub fn getuid() -> Uid {
1449
    Uid(unsafe { libc::getuid() })
1450
}
1451
1452
/// Get the effective user ID
1453
///
1454
/// See also [geteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/geteuid.html)
1455
// POSIX requires that geteuid is always successful, so no need to check return
1456
// value or errno.
1457
#[inline]
1458
pub fn geteuid() -> Uid {
1459
    Uid(unsafe { libc::geteuid() })
1460
}
1461
1462
/// Get the real group ID
1463
///
1464
/// See also [getgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getgid.html)
1465
// POSIX requires that getgid is always successful, so no need to check return
1466
// value or errno.
1467
#[inline]
1468
pub fn getgid() -> Gid {
1469
    Gid(unsafe { libc::getgid() })
1470
}
1471
1472
/// Get the effective group ID
1473
///
1474
/// See also [getegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getegid.html)
1475
// POSIX requires that getegid is always successful, so no need to check return
1476
// value or errno.
1477
#[inline]
1478
pub fn getegid() -> Gid {
1479
    Gid(unsafe { libc::getegid() })
1480
}
1481
1482
/// Set the effective user ID
1483
///
1484
/// See also [seteuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/seteuid.html)
1485
#[inline]
1486
pub fn seteuid(euid: Uid) -> Result<()> {
1487
    let res = unsafe { libc::seteuid(euid.into()) };
1488
1489
    Errno::result(res).map(drop)
1490
}
1491
1492
/// Set the effective group ID
1493
///
1494
/// See also [setegid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setegid.html)
1495
#[inline]
1496
pub fn setegid(egid: Gid) -> Result<()> {
1497
    let res = unsafe { libc::setegid(egid.into()) };
1498
1499
    Errno::result(res).map(drop)
1500
}
1501
1502
/// Set the user ID
1503
///
1504
/// See also [setuid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setuid.html)
1505
#[inline]
1506
pub fn setuid(uid: Uid) -> Result<()> {
1507
    let res = unsafe { libc::setuid(uid.into()) };
1508
1509
    Errno::result(res).map(drop)
1510
}
1511
1512
/// Set the group ID
1513
///
1514
/// See also [setgid(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setgid.html)
1515
#[inline]
1516
pub fn setgid(gid: Gid) -> Result<()> {
1517
    let res = unsafe { libc::setgid(gid.into()) };
1518
1519
    Errno::result(res).map(drop)
1520
}
1521
}
1522
1523
feature! {
1524
#![all(feature = "fs", feature = "user")]
1525
/// Set the user identity used for filesystem checks per-thread.
1526
/// On both success and failure, this call returns the previous filesystem user
1527
/// ID of the caller.
1528
///
1529
/// See also [setfsuid(2)](https://man7.org/linux/man-pages/man2/setfsuid.2.html)
1530
#[cfg(any(target_os = "linux", target_os = "android"))]
1531
pub fn setfsuid(uid: Uid) -> Uid {
1532
    let prev_fsuid = unsafe { libc::setfsuid(uid.into()) };
1533
    Uid::from_raw(prev_fsuid as uid_t)
1534
}
1535
1536
/// Set the group identity used for filesystem checks per-thread.
1537
/// On both success and failure, this call returns the previous filesystem group
1538
/// ID of the caller.
1539
///
1540
/// See also [setfsgid(2)](https://man7.org/linux/man-pages/man2/setfsgid.2.html)
1541
#[cfg(any(target_os = "linux", target_os = "android"))]
1542
pub fn setfsgid(gid: Gid) -> Gid {
1543
    let prev_fsgid = unsafe { libc::setfsgid(gid.into()) };
1544
    Gid::from_raw(prev_fsgid as gid_t)
1545
}
1546
}
1547
1548
feature! {
1549
#![feature = "user"]
1550
1551
/// Get the list of supplementary group IDs of the calling process.
1552
///
1553
/// [Further reading](https://pubs.opengroup.org/onlinepubs/009695399/functions/getgroups.html)
1554
///
1555
/// **Note:** This function is not available for Apple platforms. On those
1556
/// platforms, checking group membership should be achieved via communication
1557
/// with the `opendirectoryd` service.
1558
#[cfg(not(any(target_os = "ios", target_os = "macos")))]
1559
pub fn getgroups() -> Result<Vec<Gid>> {
1560
    // First get the maximum number of groups. The value returned
1561
    // shall always be greater than or equal to one and less than or
1562
    // equal to the value of {NGROUPS_MAX} + 1.
1563
    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
1564
        Ok(Some(n)) => (n + 1) as usize,
1565
        Ok(None) | Err(_) => <usize>::max_value(),
1566
    };
1567
1568
    // Next, get the number of groups so we can size our Vec
1569
    let ngroups = unsafe { libc::getgroups(0, ptr::null_mut()) };
1570
1571
    // If there are no supplementary groups, return early.
1572
    // This prevents a potential buffer over-read if the number of groups
1573
    // increases from zero before the next call. It would return the total
1574
    // number of groups beyond the capacity of the buffer.
1575
    if ngroups == 0 {
1576
        return Ok(Vec::new());
1577
    }
1578
1579
    // Now actually get the groups. We try multiple times in case the number of
1580
    // groups has changed since the first call to getgroups() and the buffer is
1581
    // now too small.
1582
    let mut groups =
1583
        Vec::<Gid>::with_capacity(Errno::result(ngroups)? as usize);
1584
    loop {
1585
        // FIXME: On the platforms we currently support, the `Gid` struct has
1586
        // the same representation in memory as a bare `gid_t`. This is not
1587
        // necessarily the case on all Rust platforms, though. See RFC 1785.
1588
        let ngroups = unsafe {
1589
            libc::getgroups(
1590
                groups.capacity() as c_int,
1591
                groups.as_mut_ptr() as *mut gid_t,
1592
            )
1593
        };
1594
1595
        match Errno::result(ngroups) {
1596
            Ok(s) => {
1597
                unsafe { groups.set_len(s as usize) };
1598
                return Ok(groups);
1599
            }
1600
            Err(Errno::EINVAL) => {
1601
                // EINVAL indicates that the buffer size was too
1602
                // small, resize it up to ngroups_max as limit.
1603
                reserve_double_buffer_size(&mut groups, ngroups_max)
1604
                    .or(Err(Errno::EINVAL))?;
1605
            }
1606
            Err(e) => return Err(e),
1607
        }
1608
    }
1609
}
1610
1611
/// Set the list of supplementary group IDs for the calling process.
1612
///
1613
/// [Further reading](https://man7.org/linux/man-pages/man2/getgroups.2.html)
1614
///
1615
/// **Note:** This function is not available for Apple platforms. On those
1616
/// platforms, group membership management should be achieved via communication
1617
/// with the `opendirectoryd` service.
1618
///
1619
/// # Examples
1620
///
1621
/// `setgroups` can be used when dropping privileges from the root user to a
1622
/// specific user and group. For example, given the user `www-data` with UID
1623
/// `33` and the group `backup` with the GID `34`, one could switch the user as
1624
/// follows:
1625
///
1626
/// ```rust,no_run
1627
/// # use std::error::Error;
1628
/// # use nix::unistd::*;
1629
/// #
1630
/// # fn try_main() -> Result<(), Box<dyn Error>> {
1631
/// let uid = Uid::from_raw(33);
1632
/// let gid = Gid::from_raw(34);
1633
/// setgroups(&[gid])?;
1634
/// setgid(gid)?;
1635
/// setuid(uid)?;
1636
/// #
1637
/// #     Ok(())
1638
/// # }
1639
/// #
1640
/// # try_main().unwrap();
1641
/// ```
1642
#[cfg(not(any(
1643
    target_os = "ios",
1644
    target_os = "macos",
1645
    target_os = "redox",
1646
    target_os = "haiku"
1647
)))]
1648
pub fn setgroups(groups: &[Gid]) -> Result<()> {
1649
    cfg_if! {
1650
        if #[cfg(any(target_os = "aix",
1651
                     target_os = "dragonfly",
1652
                     target_os = "freebsd",
1653
                     target_os = "illumos",
1654
                     target_os = "ios",
1655
                     target_os = "macos",
1656
                     target_os = "netbsd",
1657
                     target_os = "openbsd",
1658
                     target_os = "solaris"))] {
1659
            type setgroups_ngroups_t = c_int;
1660
        } else {
1661
            type setgroups_ngroups_t = size_t;
1662
        }
1663
    }
1664
    // FIXME: On the platforms we currently support, the `Gid` struct has the
1665
    // same representation in memory as a bare `gid_t`. This is not necessarily
1666
    // the case on all Rust platforms, though. See RFC 1785.
1667
    let res = unsafe {
1668
        libc::setgroups(
1669
            groups.len() as setgroups_ngroups_t,
1670
            groups.as_ptr() as *const gid_t,
1671
        )
1672
    };
1673
1674
    Errno::result(res).map(drop)
1675
}
1676
1677
/// Calculate the supplementary group access list.
1678
///
1679
/// Gets the group IDs of all groups that `user` is a member of. The additional
1680
/// group `group` is also added to the list.
1681
///
1682
/// [Further reading](https://man7.org/linux/man-pages/man3/getgrouplist.3.html)
1683
///
1684
/// **Note:** This function is not available for Apple platforms. On those
1685
/// platforms, checking group membership should be achieved via communication
1686
/// with the `opendirectoryd` service.
1687
///
1688
/// # Errors
1689
///
1690
/// Although the `getgrouplist()` call does not return any specific
1691
/// errors on any known platforms, this implementation will return a system
1692
/// error of `EINVAL` if the number of groups to be fetched exceeds the
1693
/// `NGROUPS_MAX` sysconf value. This mimics the behaviour of `getgroups()`
1694
/// and `setgroups()`. Additionally, while some implementations will return a
1695
/// partial list of groups when `NGROUPS_MAX` is exceeded, this implementation
1696
/// will only ever return the complete list or else an error.
1697
#[cfg(not(any(
1698
    target_os = "aix",
1699
    target_os = "illumos",
1700
    target_os = "ios",
1701
    target_os = "macos",
1702
    target_os = "redox"
1703
)))]
1704
pub fn getgrouplist(user: &CStr, group: Gid) -> Result<Vec<Gid>> {
1705
    let ngroups_max = match sysconf(SysconfVar::NGROUPS_MAX) {
1706
        Ok(Some(n)) => n as c_int,
1707
        Ok(None) | Err(_) => <c_int>::max_value(),
1708
    };
1709
    use std::cmp::min;
1710
    let mut groups = Vec::<Gid>::with_capacity(min(ngroups_max, 8) as usize);
1711
    cfg_if! {
1712
        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
1713
            type getgrouplist_group_t = c_int;
1714
        } else {
1715
            type getgrouplist_group_t = gid_t;
1716
        }
1717
    }
1718
    let gid: gid_t = group.into();
1719
    loop {
1720
        let mut ngroups = groups.capacity() as i32;
1721
        let ret = unsafe {
1722
            libc::getgrouplist(
1723
                user.as_ptr(),
1724
                gid as getgrouplist_group_t,
1725
                groups.as_mut_ptr() as *mut getgrouplist_group_t,
1726
                &mut ngroups,
1727
            )
1728
        };
1729
1730
        // BSD systems only return 0 or -1, Linux returns ngroups on success.
1731
        if ret >= 0 {
1732
            unsafe { groups.set_len(ngroups as usize) };
1733
            return Ok(groups);
1734
        } else if ret == -1 {
1735
            // Returns -1 if ngroups is too small, but does not set errno.
1736
            // BSD systems will still fill the groups buffer with as many
1737
            // groups as possible, but Linux manpages do not mention this
1738
            // behavior.
1739
            reserve_double_buffer_size(&mut groups, ngroups_max as usize)
1740
                .map_err(|_| Errno::EINVAL)?;
1741
        }
1742
    }
1743
}
1744
1745
/// Initialize the supplementary group access list.
1746
///
1747
/// Sets the supplementary group IDs for the calling process using all groups
1748
/// that `user` is a member of. The additional group `group` is also added to
1749
/// the list.
1750
///
1751
/// [Further reading](https://man7.org/linux/man-pages/man3/initgroups.3.html)
1752
///
1753
/// **Note:** This function is not available for Apple platforms. On those
1754
/// platforms, group membership management should be achieved via communication
1755
/// with the `opendirectoryd` service.
1756
///
1757
/// # Examples
1758
///
1759
/// `initgroups` can be used when dropping privileges from the root user to
1760
/// another user. For example, given the user `www-data`, we could look up the
1761
/// UID and GID for the user in the system's password database (usually found
1762
/// in `/etc/passwd`). If the `www-data` user's UID and GID were `33` and `33`,
1763
/// respectively, one could switch the user as follows:
1764
///
1765
/// ```rust,no_run
1766
/// # use std::error::Error;
1767
/// # use std::ffi::CString;
1768
/// # use nix::unistd::*;
1769
/// #
1770
/// # fn try_main() -> Result<(), Box<dyn Error>> {
1771
/// let user = CString::new("www-data").unwrap();
1772
/// let uid = Uid::from_raw(33);
1773
/// let gid = Gid::from_raw(33);
1774
/// initgroups(&user, gid)?;
1775
/// setgid(gid)?;
1776
/// setuid(uid)?;
1777
/// #
1778
/// #     Ok(())
1779
/// # }
1780
/// #
1781
/// # try_main().unwrap();
1782
/// ```
1783
#[cfg(not(any(
1784
    target_os = "ios",
1785
    target_os = "macos",
1786
    target_os = "redox",
1787
    target_os = "haiku"
1788
)))]
1789
pub fn initgroups(user: &CStr, group: Gid) -> Result<()> {
1790
    cfg_if! {
1791
        if #[cfg(any(target_os = "ios", target_os = "macos"))] {
1792
            type initgroups_group_t = c_int;
1793
        } else {
1794
            type initgroups_group_t = gid_t;
1795
        }
1796
    }
1797
    let gid: gid_t = group.into();
1798
    let res =
1799
        unsafe { libc::initgroups(user.as_ptr(), gid as initgroups_group_t) };
1800
1801
    Errno::result(res).map(drop)
1802
}
1803
}
1804
1805
feature! {
1806
#![feature = "signal"]
1807
1808
/// Suspend the thread until a signal is received.
1809
///
1810
/// See also [pause(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pause.html).
1811
#[inline]
1812
#[cfg(not(target_os = "redox"))]
1813
pub fn pause() {
1814
    unsafe { libc::pause() };
1815
}
1816
1817
pub mod alarm {
1818
    //! Alarm signal scheduling.
1819
    //!
1820
    //! Scheduling an alarm will trigger a `SIGALRM` signal when the time has
1821
    //! elapsed, which has to be caught, because the default action for the
1822
    //! signal is to terminate the program. This signal also can't be ignored
1823
    //! because the system calls like `pause` will not be interrupted, see the
1824
    //! second example below.
1825
    //!
1826
    //! # Examples
1827
    //!
1828
    //! Canceling an alarm:
1829
    //!
1830
    //! ```
1831
    //! use nix::unistd::alarm;
1832
    //!
1833
    //! // Set an alarm for 60 seconds from now.
1834
    //! alarm::set(60);
1835
    //!
1836
    //! // Cancel the above set alarm, which returns the number of seconds left
1837
    //! // of the previously set alarm.
1838
    //! assert_eq!(alarm::cancel(), Some(60));
1839
    //! ```
1840
    //!
1841
    //! Scheduling an alarm and waiting for the signal:
1842
    //!
1843
    #![cfg_attr(target_os = "redox", doc = " ```rust,ignore")]
1844
    #![cfg_attr(not(target_os = "redox"), doc = " ```rust")]
1845
    //! use std::time::{Duration, Instant};
1846
    //!
1847
    //! use nix::unistd::{alarm, pause};
1848
    //! use nix::sys::signal::*;
1849
    //!
1850
    //! // We need to setup an empty signal handler to catch the alarm signal,
1851
    //! // otherwise the program will be terminated once the signal is delivered.
1852
    //! extern fn signal_handler(_: nix::libc::c_int) { }
1853
    //! let sa = SigAction::new(
1854
    //!     SigHandler::Handler(signal_handler),
1855
    //!     SaFlags::SA_RESTART,
1856
    //!     SigSet::empty()
1857
    //! );
1858
    //! unsafe {
1859
    //!     sigaction(Signal::SIGALRM, &sa);
1860
    //! }
1861
    //!
1862
    //! let start = Instant::now();
1863
    //!
1864
    //! // Set an alarm for 1 second from now.
1865
    //! alarm::set(1);
1866
    //!
1867
    //! // Pause the process until the alarm signal is received.
1868
    //! let mut sigset = SigSet::empty();
1869
    //! sigset.add(Signal::SIGALRM);
1870
    //! sigset.wait();
1871
    //!
1872
    //! assert!(start.elapsed() >= Duration::from_secs(1));
1873
    //! ```
1874
    //!
1875
    //! # References
1876
    //!
1877
    //! See also [alarm(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/alarm.html).
1878
1879
    /// Schedule an alarm signal.
1880
    ///
1881
    /// This will cause the system to generate a `SIGALRM` signal for the
1882
    /// process after the specified number of seconds have elapsed.
1883
    ///
1884
    /// Returns the leftover time of a previously set alarm if there was one.
1885
    pub fn set(secs: libc::c_uint) -> Option<libc::c_uint> {
1886
        assert!(secs != 0, "passing 0 to `alarm::set` is not allowed, to cancel an alarm use `alarm::cancel`");
1887
        alarm(secs)
1888
    }
1889
1890
    /// Cancel an previously set alarm signal.
1891
    ///
1892
    /// Returns the leftover time of a previously set alarm if there was one.
1893
    pub fn cancel() -> Option<libc::c_uint> {
1894
        alarm(0)
1895
    }
1896
1897
    fn alarm(secs: libc::c_uint) -> Option<libc::c_uint> {
1898
        match unsafe { libc::alarm(secs) } {
1899
            0 => None,
1900
            secs => Some(secs),
1901
        }
1902
    }
1903
}
1904
}
1905
1906
/// Suspend execution for an interval of time
1907
///
1908
/// See also [sleep(2)](https://pubs.opengroup.org/onlinepubs/009695399/functions/sleep.html#tag_03_705_05)
1909
// Per POSIX, does not fail
1910
#[inline]
1911
0
pub fn sleep(seconds: c_uint) -> c_uint {
1912
0
    unsafe { libc::sleep(seconds) }
1913
0
}
1914
1915
feature! {
1916
#![feature = "acct"]
1917
1918
#[cfg(not(any(target_os = "redox", target_os = "haiku")))]
1919
pub mod acct {
1920
    use crate::errno::Errno;
1921
    use crate::{NixPath, Result};
1922
    use std::ptr;
1923
1924
    /// Enable process accounting
1925
    ///
1926
    /// See also [acct(2)](https://linux.die.net/man/2/acct)
1927
    pub fn enable<P: ?Sized + NixPath>(filename: &P) -> Result<()> {
1928
        let res = filename
1929
            .with_nix_path(|cstr| unsafe { libc::acct(cstr.as_ptr()) })?;
1930
1931
        Errno::result(res).map(drop)
1932
    }
1933
1934
    /// Disable process accounting
1935
    pub fn disable() -> Result<()> {
1936
        let res = unsafe { libc::acct(ptr::null()) };
1937
1938
        Errno::result(res).map(drop)
1939
    }
1940
}
1941
}
1942
1943
feature! {
1944
#![feature = "fs"]
1945
/// Creates a regular file which persists even after process termination
1946
///
1947
/// * `template`: a path whose 6 rightmost characters must be X, e.g. `/tmp/tmpfile_XXXXXX`
1948
/// * returns: tuple of file descriptor and filename
1949
///
1950
/// Err is returned either if no temporary filename could be created or the template doesn't
1951
/// end with XXXXXX
1952
///
1953
/// See also [mkstemp(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mkstemp.html)
1954
///
1955
/// # Example
1956
///
1957
/// ```rust
1958
/// use nix::unistd;
1959
///
1960
/// let _ = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
1961
///     Ok((fd, path)) => {
1962
///         unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
1963
///         fd
1964
///     }
1965
///     Err(e) => panic!("mkstemp failed: {}", e)
1966
/// };
1967
/// // do something with fd
1968
/// ```
1969
#[inline]
1970
0
pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
1971
0
    let mut path =
1972
0
        template.with_nix_path(|path| path.to_bytes_with_nul().to_owned())?;
1973
0
    let p = path.as_mut_ptr() as *mut _;
1974
0
    let fd = unsafe { libc::mkstemp(p) };
1975
0
    let last = path.pop(); // drop the trailing nul
1976
0
    debug_assert!(last == Some(b'\0'));
1977
0
    let pathname = OsString::from_vec(path);
1978
0
    Errno::result(fd)?;
1979
0
    Ok((fd, PathBuf::from(pathname)))
1980
0
}
1981
}
1982
1983
feature! {
1984
#![all(feature = "fs", feature = "feature")]
1985
1986
/// Variable names for `pathconf`
1987
///
1988
/// Nix uses the same naming convention for these variables as the
1989
/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
1990
/// That is, `PathconfVar` variables have the same name as the abstract
1991
/// variables  shown in the `pathconf(2)` man page.  Usually, it's the same as
1992
/// the C variable name without the leading `_PC_`.
1993
///
1994
/// POSIX 1003.1-2008 standardizes all of these variables, but some OSes choose
1995
/// not to implement variables that cannot change at runtime.
1996
///
1997
/// # References
1998
///
1999
/// - [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html)
2000
/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
2001
/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
2002
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2003
#[repr(i32)]
2004
#[non_exhaustive]
2005
pub enum PathconfVar {
2006
    #[cfg(any(
2007
        target_os = "dragonfly",
2008
        target_os = "freebsd",
2009
        target_os = "linux",
2010
        target_os = "netbsd",
2011
        target_os = "openbsd",
2012
        target_os = "redox"
2013
    ))]
2014
    /// Minimum number of bits needed to represent, as a signed integer value,
2015
    /// the maximum size of a regular file allowed in the specified directory.
2016
    #[cfg_attr(docsrs, doc(cfg(all())))]
2017
    FILESIZEBITS = libc::_PC_FILESIZEBITS,
2018
    /// Maximum number of links to a single file.
2019
    LINK_MAX = libc::_PC_LINK_MAX,
2020
    /// Maximum number of bytes in a terminal canonical input line.
2021
    MAX_CANON = libc::_PC_MAX_CANON,
2022
    /// Minimum number of bytes for which space is available in a terminal input
2023
    /// queue; therefore, the maximum number of bytes a conforming application
2024
    /// may require to be typed as input before reading them.
2025
    MAX_INPUT = libc::_PC_MAX_INPUT,
2026
    /// Maximum number of bytes in a filename (not including the terminating
2027
    /// null of a filename string).
2028
    NAME_MAX = libc::_PC_NAME_MAX,
2029
    /// Maximum number of bytes the implementation will store as a pathname in a
2030
    /// user-supplied buffer of unspecified size, including the terminating null
2031
    /// character. Minimum number the implementation will accept as the maximum
2032
    /// number of bytes in a pathname.
2033
    PATH_MAX = libc::_PC_PATH_MAX,
2034
    /// Maximum number of bytes that is guaranteed to be atomic when writing to
2035
    /// a pipe.
2036
    PIPE_BUF = libc::_PC_PIPE_BUF,
2037
    #[cfg(any(
2038
        target_os = "android",
2039
        target_os = "dragonfly",
2040
        target_os = "illumos",
2041
        target_os = "linux",
2042
        target_os = "netbsd",
2043
        target_os = "openbsd",
2044
        target_os = "redox",
2045
        target_os = "solaris"
2046
    ))]
2047
    #[cfg_attr(docsrs, doc(cfg(all())))]
2048
    /// Symbolic links can be created.
2049
    POSIX2_SYMLINKS = libc::_PC_2_SYMLINKS,
2050
    #[cfg(any(
2051
        target_os = "android",
2052
        target_os = "dragonfly",
2053
        target_os = "freebsd",
2054
        target_os = "linux",
2055
        target_os = "openbsd",
2056
        target_os = "redox"
2057
    ))]
2058
    #[cfg_attr(docsrs, doc(cfg(all())))]
2059
    /// Minimum number of bytes of storage actually allocated for any portion of
2060
    /// a file.
2061
    POSIX_ALLOC_SIZE_MIN = libc::_PC_ALLOC_SIZE_MIN,
2062
    #[cfg(any(
2063
        target_os = "android",
2064
        target_os = "dragonfly",
2065
        target_os = "freebsd",
2066
        target_os = "linux",
2067
        target_os = "openbsd"
2068
    ))]
2069
    #[cfg_attr(docsrs, doc(cfg(all())))]
2070
    /// Recommended increment for file transfer sizes between the
2071
    /// `POSIX_REC_MIN_XFER_SIZE` and `POSIX_REC_MAX_XFER_SIZE` values.
2072
    POSIX_REC_INCR_XFER_SIZE = libc::_PC_REC_INCR_XFER_SIZE,
2073
    #[cfg(any(
2074
        target_os = "android",
2075
        target_os = "dragonfly",
2076
        target_os = "freebsd",
2077
        target_os = "linux",
2078
        target_os = "openbsd",
2079
        target_os = "redox"
2080
    ))]
2081
    #[cfg_attr(docsrs, doc(cfg(all())))]
2082
    /// Maximum recommended file transfer size.
2083
    POSIX_REC_MAX_XFER_SIZE = libc::_PC_REC_MAX_XFER_SIZE,
2084
    #[cfg(any(
2085
        target_os = "android",
2086
        target_os = "dragonfly",
2087
        target_os = "freebsd",
2088
        target_os = "linux",
2089
        target_os = "openbsd",
2090
        target_os = "redox"
2091
    ))]
2092
    #[cfg_attr(docsrs, doc(cfg(all())))]
2093
    /// Minimum recommended file transfer size.
2094
    POSIX_REC_MIN_XFER_SIZE = libc::_PC_REC_MIN_XFER_SIZE,
2095
    #[cfg(any(
2096
        target_os = "android",
2097
        target_os = "dragonfly",
2098
        target_os = "freebsd",
2099
        target_os = "linux",
2100
        target_os = "openbsd",
2101
        target_os = "redox"
2102
    ))]
2103
    #[cfg_attr(docsrs, doc(cfg(all())))]
2104
    ///  Recommended file transfer buffer alignment.
2105
    POSIX_REC_XFER_ALIGN = libc::_PC_REC_XFER_ALIGN,
2106
    #[cfg(any(
2107
        target_os = "android",
2108
        target_os = "dragonfly",
2109
        target_os = "freebsd",
2110
        target_os = "illumos",
2111
        target_os = "linux",
2112
        target_os = "netbsd",
2113
        target_os = "openbsd",
2114
        target_os = "redox",
2115
        target_os = "solaris"
2116
    ))]
2117
    #[cfg_attr(docsrs, doc(cfg(all())))]
2118
    /// Maximum number of bytes in a symbolic link.
2119
    SYMLINK_MAX = libc::_PC_SYMLINK_MAX,
2120
    /// The use of `chown` and `fchown` is restricted to a process with
2121
    /// appropriate privileges, and to changing the group ID of a file only to
2122
    /// the effective group ID of the process or to one of its supplementary
2123
    /// group IDs.
2124
    _POSIX_CHOWN_RESTRICTED = libc::_PC_CHOWN_RESTRICTED,
2125
    /// Pathname components longer than {NAME_MAX} generate an error.
2126
    _POSIX_NO_TRUNC = libc::_PC_NO_TRUNC,
2127
    /// This symbol shall be defined to be the value of a character that shall
2128
    /// disable terminal special character handling.
2129
    _POSIX_VDISABLE = libc::_PC_VDISABLE,
2130
    #[cfg(any(
2131
        target_os = "android",
2132
        target_os = "dragonfly",
2133
        target_os = "freebsd",
2134
        target_os = "illumos",
2135
        target_os = "linux",
2136
        target_os = "openbsd",
2137
        target_os = "redox",
2138
        target_os = "solaris"
2139
    ))]
2140
    #[cfg_attr(docsrs, doc(cfg(all())))]
2141
    /// Asynchronous input or output operations may be performed for the
2142
    /// associated file.
2143
    _POSIX_ASYNC_IO = libc::_PC_ASYNC_IO,
2144
    #[cfg(any(
2145
        target_os = "android",
2146
        target_os = "dragonfly",
2147
        target_os = "freebsd",
2148
        target_os = "illumos",
2149
        target_os = "linux",
2150
        target_os = "openbsd",
2151
        target_os = "redox",
2152
        target_os = "solaris"
2153
    ))]
2154
    #[cfg_attr(docsrs, doc(cfg(all())))]
2155
    /// Prioritized input or output operations may be performed for the
2156
    /// associated file.
2157
    _POSIX_PRIO_IO = libc::_PC_PRIO_IO,
2158
    #[cfg(any(
2159
        target_os = "android",
2160
        target_os = "dragonfly",
2161
        target_os = "freebsd",
2162
        target_os = "illumos",
2163
        target_os = "linux",
2164
        target_os = "netbsd",
2165
        target_os = "openbsd",
2166
        target_os = "redox",
2167
        target_os = "solaris"
2168
    ))]
2169
    #[cfg_attr(docsrs, doc(cfg(all())))]
2170
    /// Synchronized input or output operations may be performed for the
2171
    /// associated file.
2172
    _POSIX_SYNC_IO = libc::_PC_SYNC_IO,
2173
    #[cfg(any(target_os = "dragonfly", target_os = "openbsd"))]
2174
    #[cfg_attr(docsrs, doc(cfg(all())))]
2175
    /// The resolution in nanoseconds for all file timestamps.
2176
    _POSIX_TIMESTAMP_RESOLUTION = libc::_PC_TIMESTAMP_RESOLUTION,
2177
}
2178
2179
/// Like `pathconf`, but works with file descriptors instead of paths (see
2180
/// [fpathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
2181
///
2182
/// # Parameters
2183
///
2184
/// - `fd`:   The file descriptor whose variable should be interrogated
2185
/// - `var`:  The pathconf variable to lookup
2186
///
2187
/// # Returns
2188
///
2189
/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
2190
///     implementation level (for option variables).  Implementation levels are
2191
///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
2192
/// - `Ok(None)`: the variable has no limit (for limit variables) or is
2193
///     unsupported (for option variables)
2194
/// - `Err(x)`: an error occurred
2195
pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>> {
2196
    let raw = unsafe {
2197
        Errno::clear();
2198
        libc::fpathconf(fd, var as c_int)
2199
    };
2200
    if raw == -1 {
2201
        if errno::errno() == 0 {
2202
            Ok(None)
2203
        } else {
2204
            Err(Errno::last())
2205
        }
2206
    } else {
2207
        Ok(Some(raw))
2208
    }
2209
}
2210
2211
/// Get path-dependent configurable system variables (see
2212
/// [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html))
2213
///
2214
/// Returns the value of a path-dependent configurable system variable.  Most
2215
/// supported variables also have associated compile-time constants, but POSIX
2216
/// allows their values to change at runtime.  There are generally two types of
2217
/// `pathconf` variables: options and limits.  See [pathconf(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pathconf.html) for more details.
2218
///
2219
/// # Parameters
2220
///
2221
/// - `path`: Lookup the value of `var` for this file or directory
2222
/// - `var`:  The `pathconf` variable to lookup
2223
///
2224
/// # Returns
2225
///
2226
/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
2227
///     implementation level (for option variables).  Implementation levels are
2228
///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
2229
/// - `Ok(None)`: the variable has no limit (for limit variables) or is
2230
///     unsupported (for option variables)
2231
/// - `Err(x)`: an error occurred
2232
pub fn pathconf<P: ?Sized + NixPath>(
2233
    path: &P,
2234
    var: PathconfVar,
2235
) -> Result<Option<c_long>> {
2236
    let raw = path.with_nix_path(|cstr| unsafe {
2237
        Errno::clear();
2238
        libc::pathconf(cstr.as_ptr(), var as c_int)
2239
    })?;
2240
    if raw == -1 {
2241
        if errno::errno() == 0 {
2242
            Ok(None)
2243
        } else {
2244
            Err(Errno::last())
2245
        }
2246
    } else {
2247
        Ok(Some(raw))
2248
    }
2249
}
2250
}
2251
2252
feature! {
2253
#![feature = "feature"]
2254
2255
/// Variable names for `sysconf`
2256
///
2257
/// Nix uses the same naming convention for these variables as the
2258
/// [getconf(1)](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/getconf.html) utility.
2259
/// That is, `SysconfVar` variables have the same name as the abstract variables
2260
/// shown in the `sysconf(3)` man page.  Usually, it's the same as the C
2261
/// variable name without the leading `_SC_`.
2262
///
2263
/// All of these symbols are standardized by POSIX 1003.1-2008, but haven't been
2264
/// implemented by all platforms.
2265
///
2266
/// # References
2267
///
2268
/// - [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html)
2269
/// - [unistd.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html)
2270
/// - [limits.h](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html)
2271
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2272
#[repr(i32)]
2273
#[non_exhaustive]
2274
pub enum SysconfVar {
2275
    /// Maximum number of I/O operations in a single list I/O call supported by
2276
    /// the implementation.
2277
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2278
    #[cfg_attr(docsrs, doc(cfg(all())))]
2279
    AIO_LISTIO_MAX = libc::_SC_AIO_LISTIO_MAX,
2280
    /// Maximum number of outstanding asynchronous I/O operations supported by
2281
    /// the implementation.
2282
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2283
    #[cfg_attr(docsrs, doc(cfg(all())))]
2284
    AIO_MAX = libc::_SC_AIO_MAX,
2285
    #[cfg(any(
2286
        target_os = "android",
2287
        target_os = "dragonfly",
2288
        target_os = "freebsd",
2289
        target_os = "ios",
2290
        target_os = "linux",
2291
        target_os = "macos",
2292
        target_os = "openbsd"
2293
    ))]
2294
    #[cfg_attr(docsrs, doc(cfg(all())))]
2295
    /// The maximum amount by which a process can decrease its asynchronous I/O
2296
    /// priority level from its own scheduling priority.
2297
    AIO_PRIO_DELTA_MAX = libc::_SC_AIO_PRIO_DELTA_MAX,
2298
    /// Maximum length of argument to the exec functions including environment data.
2299
    ARG_MAX = libc::_SC_ARG_MAX,
2300
    /// Maximum number of functions that may be registered with `atexit`.
2301
    #[cfg(not(target_os = "redox"))]
2302
    #[cfg_attr(docsrs, doc(cfg(all())))]
2303
    ATEXIT_MAX = libc::_SC_ATEXIT_MAX,
2304
    /// Maximum obase values allowed by the bc utility.
2305
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2306
    #[cfg_attr(docsrs, doc(cfg(all())))]
2307
    BC_BASE_MAX = libc::_SC_BC_BASE_MAX,
2308
    /// Maximum number of elements permitted in an array by the bc utility.
2309
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2310
    #[cfg_attr(docsrs, doc(cfg(all())))]
2311
    BC_DIM_MAX = libc::_SC_BC_DIM_MAX,
2312
    /// Maximum scale value allowed by the bc utility.
2313
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2314
    #[cfg_attr(docsrs, doc(cfg(all())))]
2315
    BC_SCALE_MAX = libc::_SC_BC_SCALE_MAX,
2316
    /// Maximum length of a string constant accepted by the bc utility.
2317
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2318
    #[cfg_attr(docsrs, doc(cfg(all())))]
2319
    BC_STRING_MAX = libc::_SC_BC_STRING_MAX,
2320
    /// Maximum number of simultaneous processes per real user ID.
2321
    CHILD_MAX = libc::_SC_CHILD_MAX,
2322
    // The number of clock ticks per second.
2323
    CLK_TCK = libc::_SC_CLK_TCK,
2324
    /// Maximum number of weights that can be assigned to an entry of the
2325
    /// LC_COLLATE order keyword in the locale definition file
2326
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2327
    #[cfg_attr(docsrs, doc(cfg(all())))]
2328
    COLL_WEIGHTS_MAX = libc::_SC_COLL_WEIGHTS_MAX,
2329
    /// Maximum number of timer expiration overruns.
2330
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2331
    #[cfg_attr(docsrs, doc(cfg(all())))]
2332
    DELAYTIMER_MAX = libc::_SC_DELAYTIMER_MAX,
2333
    /// Maximum number of expressions that can be nested within parentheses by
2334
    /// the expr utility.
2335
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2336
    #[cfg_attr(docsrs, doc(cfg(all())))]
2337
    EXPR_NEST_MAX = libc::_SC_EXPR_NEST_MAX,
2338
    #[cfg(any(
2339
        target_os = "dragonfly",
2340
        target_os = "freebsd",
2341
        target_os = "illumos",
2342
        target_os = "ios",
2343
        target_os = "linux",
2344
        target_os = "macos",
2345
        target_os = "netbsd",
2346
        target_os = "openbsd",
2347
        target_os = "solaris"
2348
    ))]
2349
    #[cfg_attr(docsrs, doc(cfg(all())))]
2350
    /// Maximum length of a host name (not including the terminating null) as
2351
    /// returned from the `gethostname` function
2352
    HOST_NAME_MAX = libc::_SC_HOST_NAME_MAX,
2353
    /// Maximum number of iovec structures that one process has available for
2354
    /// use with `readv` or `writev`.
2355
    #[cfg(not(target_os = "redox"))]
2356
    #[cfg_attr(docsrs, doc(cfg(all())))]
2357
    IOV_MAX = libc::_SC_IOV_MAX,
2358
    /// Unless otherwise noted, the maximum length, in bytes, of a utility's
2359
    /// input line (either standard input or another file), when the utility is
2360
    /// described as processing text files. The length includes room for the
2361
    /// trailing newline.
2362
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2363
    #[cfg_attr(docsrs, doc(cfg(all())))]
2364
    LINE_MAX = libc::_SC_LINE_MAX,
2365
    /// Maximum length of a login name.
2366
    #[cfg(not(target_os = "haiku"))]
2367
    LOGIN_NAME_MAX = libc::_SC_LOGIN_NAME_MAX,
2368
    /// Maximum number of simultaneous supplementary group IDs per process.
2369
    NGROUPS_MAX = libc::_SC_NGROUPS_MAX,
2370
    /// Initial size of `getgrgid_r` and `getgrnam_r` data buffers
2371
    #[cfg(not(target_os = "redox"))]
2372
    #[cfg_attr(docsrs, doc(cfg(all())))]
2373
    GETGR_R_SIZE_MAX = libc::_SC_GETGR_R_SIZE_MAX,
2374
    /// Initial size of `getpwuid_r` and `getpwnam_r` data buffers
2375
    #[cfg(not(target_os = "redox"))]
2376
    #[cfg_attr(docsrs, doc(cfg(all())))]
2377
    GETPW_R_SIZE_MAX = libc::_SC_GETPW_R_SIZE_MAX,
2378
    /// The maximum number of open message queue descriptors a process may hold.
2379
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2380
    #[cfg_attr(docsrs, doc(cfg(all())))]
2381
    MQ_OPEN_MAX = libc::_SC_MQ_OPEN_MAX,
2382
    /// The maximum number of message priorities supported by the implementation.
2383
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2384
    #[cfg_attr(docsrs, doc(cfg(all())))]
2385
    MQ_PRIO_MAX = libc::_SC_MQ_PRIO_MAX,
2386
    /// A value one greater than the maximum value that the system may assign to
2387
    /// a newly-created file descriptor.
2388
    OPEN_MAX = libc::_SC_OPEN_MAX,
2389
    #[cfg(any(
2390
        target_os = "dragonfly",
2391
        target_os = "freebsd",
2392
        target_os = "ios",
2393
        target_os = "linux",
2394
        target_os = "macos",
2395
        target_os = "openbsd"
2396
    ))]
2397
    #[cfg_attr(docsrs, doc(cfg(all())))]
2398
    /// The implementation supports the Advisory Information option.
2399
    _POSIX_ADVISORY_INFO = libc::_SC_ADVISORY_INFO,
2400
    #[cfg(any(
2401
        target_os = "dragonfly",
2402
        target_os = "freebsd",
2403
        target_os = "illumos",
2404
        target_os = "ios",
2405
        target_os = "linux",
2406
        target_os = "macos",
2407
        target_os = "netbsd",
2408
        target_os = "openbsd",
2409
        target_os = "solaris"
2410
    ))]
2411
    #[cfg_attr(docsrs, doc(cfg(all())))]
2412
    /// The implementation supports barriers.
2413
    _POSIX_BARRIERS = libc::_SC_BARRIERS,
2414
    /// The implementation supports asynchronous input and output.
2415
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2416
    #[cfg_attr(docsrs, doc(cfg(all())))]
2417
    _POSIX_ASYNCHRONOUS_IO = libc::_SC_ASYNCHRONOUS_IO,
2418
    #[cfg(any(
2419
        target_os = "dragonfly",
2420
        target_os = "freebsd",
2421
        target_os = "illumos",
2422
        target_os = "ios",
2423
        target_os = "linux",
2424
        target_os = "macos",
2425
        target_os = "netbsd",
2426
        target_os = "openbsd",
2427
        target_os = "solaris"
2428
    ))]
2429
    #[cfg_attr(docsrs, doc(cfg(all())))]
2430
    /// The implementation supports clock selection.
2431
    _POSIX_CLOCK_SELECTION = libc::_SC_CLOCK_SELECTION,
2432
    #[cfg(any(
2433
        target_os = "dragonfly",
2434
        target_os = "freebsd",
2435
        target_os = "illumos",
2436
        target_os = "ios",
2437
        target_os = "linux",
2438
        target_os = "macos",
2439
        target_os = "netbsd",
2440
        target_os = "openbsd",
2441
        target_os = "solaris"
2442
    ))]
2443
    #[cfg_attr(docsrs, doc(cfg(all())))]
2444
    /// The implementation supports the Process CPU-Time Clocks option.
2445
    _POSIX_CPUTIME = libc::_SC_CPUTIME,
2446
    /// The implementation supports the File Synchronization option.
2447
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2448
    #[cfg_attr(docsrs, doc(cfg(all())))]
2449
    _POSIX_FSYNC = libc::_SC_FSYNC,
2450
    #[cfg(any(
2451
        target_os = "dragonfly",
2452
        target_os = "freebsd",
2453
        target_os = "illumos",
2454
        target_os = "ios",
2455
        target_os = "linux",
2456
        target_os = "macos",
2457
        target_os = "openbsd",
2458
        target_os = "solaris"
2459
    ))]
2460
    #[cfg_attr(docsrs, doc(cfg(all())))]
2461
    /// The implementation supports the IPv6 option.
2462
    _POSIX_IPV6 = libc::_SC_IPV6,
2463
    /// The implementation supports job control.
2464
    #[cfg(not(target_os = "redox"))]
2465
    #[cfg_attr(docsrs, doc(cfg(all())))]
2466
    _POSIX_JOB_CONTROL = libc::_SC_JOB_CONTROL,
2467
    /// The implementation supports memory mapped Files.
2468
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2469
    #[cfg_attr(docsrs, doc(cfg(all())))]
2470
    _POSIX_MAPPED_FILES = libc::_SC_MAPPED_FILES,
2471
    /// The implementation supports the Process Memory Locking option.
2472
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2473
    #[cfg_attr(docsrs, doc(cfg(all())))]
2474
    _POSIX_MEMLOCK = libc::_SC_MEMLOCK,
2475
    /// The implementation supports the Range Memory Locking option.
2476
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2477
    #[cfg_attr(docsrs, doc(cfg(all())))]
2478
    _POSIX_MEMLOCK_RANGE = libc::_SC_MEMLOCK_RANGE,
2479
    /// The implementation supports memory protection.
2480
    #[cfg(not(target_os = "redox"))]
2481
    #[cfg_attr(docsrs, doc(cfg(all())))]
2482
    _POSIX_MEMORY_PROTECTION = libc::_SC_MEMORY_PROTECTION,
2483
    /// The implementation supports the Message Passing option.
2484
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2485
    #[cfg_attr(docsrs, doc(cfg(all())))]
2486
    _POSIX_MESSAGE_PASSING = libc::_SC_MESSAGE_PASSING,
2487
    /// The implementation supports the Monotonic Clock option.
2488
    #[cfg(not(target_os = "redox"))]
2489
    #[cfg_attr(docsrs, doc(cfg(all())))]
2490
    _POSIX_MONOTONIC_CLOCK = libc::_SC_MONOTONIC_CLOCK,
2491
    #[cfg(any(
2492
        target_os = "android",
2493
        target_os = "dragonfly",
2494
        target_os = "freebsd",
2495
        target_os = "illumos",
2496
        target_os = "ios",
2497
        target_os = "linux",
2498
        target_os = "macos",
2499
        target_os = "openbsd",
2500
        target_os = "solaris"
2501
    ))]
2502
    #[cfg_attr(docsrs, doc(cfg(all())))]
2503
    /// The implementation supports the Prioritized Input and Output option.
2504
    _POSIX_PRIORITIZED_IO = libc::_SC_PRIORITIZED_IO,
2505
    /// The implementation supports the Process Scheduling option.
2506
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2507
    #[cfg_attr(docsrs, doc(cfg(all())))]
2508
    _POSIX_PRIORITY_SCHEDULING = libc::_SC_PRIORITY_SCHEDULING,
2509
    #[cfg(any(
2510
        target_os = "dragonfly",
2511
        target_os = "freebsd",
2512
        target_os = "illumos",
2513
        target_os = "ios",
2514
        target_os = "linux",
2515
        target_os = "macos",
2516
        target_os = "openbsd",
2517
        target_os = "solaris"
2518
    ))]
2519
    #[cfg_attr(docsrs, doc(cfg(all())))]
2520
    /// The implementation supports the Raw Sockets option.
2521
    _POSIX_RAW_SOCKETS = libc::_SC_RAW_SOCKETS,
2522
    #[cfg(any(
2523
        target_os = "dragonfly",
2524
        target_os = "freebsd",
2525
        target_os = "illumos",
2526
        target_os = "ios",
2527
        target_os = "linux",
2528
        target_os = "macos",
2529
        target_os = "netbsd",
2530
        target_os = "openbsd",
2531
        target_os = "solaris"
2532
    ))]
2533
    #[cfg_attr(docsrs, doc(cfg(all())))]
2534
    /// The implementation supports read-write locks.
2535
    _POSIX_READER_WRITER_LOCKS = libc::_SC_READER_WRITER_LOCKS,
2536
    #[cfg(any(
2537
        target_os = "android",
2538
        target_os = "dragonfly",
2539
        target_os = "freebsd",
2540
        target_os = "ios",
2541
        target_os = "linux",
2542
        target_os = "macos",
2543
        target_os = "openbsd"
2544
    ))]
2545
    #[cfg_attr(docsrs, doc(cfg(all())))]
2546
    /// The implementation supports realtime signals.
2547
    _POSIX_REALTIME_SIGNALS = libc::_SC_REALTIME_SIGNALS,
2548
    #[cfg(any(
2549
        target_os = "dragonfly",
2550
        target_os = "freebsd",
2551
        target_os = "illumos",
2552
        target_os = "ios",
2553
        target_os = "linux",
2554
        target_os = "macos",
2555
        target_os = "netbsd",
2556
        target_os = "openbsd",
2557
        target_os = "solaris"
2558
    ))]
2559
    #[cfg_attr(docsrs, doc(cfg(all())))]
2560
    /// The implementation supports the Regular Expression Handling option.
2561
    _POSIX_REGEXP = libc::_SC_REGEXP,
2562
    /// Each process has a saved set-user-ID and a saved set-group-ID.
2563
    #[cfg(not(target_os = "redox"))]
2564
    #[cfg_attr(docsrs, doc(cfg(all())))]
2565
    _POSIX_SAVED_IDS = libc::_SC_SAVED_IDS,
2566
    /// The implementation supports semaphores.
2567
    #[cfg(not(target_os = "redox"))]
2568
    #[cfg_attr(docsrs, doc(cfg(all())))]
2569
    _POSIX_SEMAPHORES = libc::_SC_SEMAPHORES,
2570
    /// The implementation supports the Shared Memory Objects option.
2571
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2572
    #[cfg_attr(docsrs, doc(cfg(all())))]
2573
    _POSIX_SHARED_MEMORY_OBJECTS = libc::_SC_SHARED_MEMORY_OBJECTS,
2574
    #[cfg(any(
2575
        target_os = "dragonfly",
2576
        target_os = "freebsd",
2577
        target_os = "ios",
2578
        target_os = "linux",
2579
        target_os = "macos",
2580
        target_os = "netbsd",
2581
        target_os = "openbsd"
2582
    ))]
2583
    #[cfg_attr(docsrs, doc(cfg(all())))]
2584
    /// The implementation supports the POSIX shell.
2585
    _POSIX_SHELL = libc::_SC_SHELL,
2586
    #[cfg(any(
2587
        target_os = "dragonfly",
2588
        target_os = "freebsd",
2589
        target_os = "ios",
2590
        target_os = "linux",
2591
        target_os = "macos",
2592
        target_os = "netbsd",
2593
        target_os = "openbsd"
2594
    ))]
2595
    #[cfg_attr(docsrs, doc(cfg(all())))]
2596
    /// The implementation supports the Spawn option.
2597
    _POSIX_SPAWN = libc::_SC_SPAWN,
2598
    #[cfg(any(
2599
        target_os = "dragonfly",
2600
        target_os = "freebsd",
2601
        target_os = "ios",
2602
        target_os = "linux",
2603
        target_os = "macos",
2604
        target_os = "netbsd",
2605
        target_os = "openbsd"
2606
    ))]
2607
    #[cfg_attr(docsrs, doc(cfg(all())))]
2608
    /// The implementation supports spin locks.
2609
    _POSIX_SPIN_LOCKS = libc::_SC_SPIN_LOCKS,
2610
    #[cfg(any(
2611
        target_os = "dragonfly",
2612
        target_os = "freebsd",
2613
        target_os = "ios",
2614
        target_os = "linux",
2615
        target_os = "macos",
2616
        target_os = "openbsd"
2617
    ))]
2618
    #[cfg_attr(docsrs, doc(cfg(all())))]
2619
    /// The implementation supports the Process Sporadic Server option.
2620
    _POSIX_SPORADIC_SERVER = libc::_SC_SPORADIC_SERVER,
2621
    #[cfg(any(
2622
        target_os = "ios",
2623
        target_os = "linux",
2624
        target_os = "macos",
2625
        target_os = "openbsd"
2626
    ))]
2627
    #[cfg_attr(docsrs, doc(cfg(all())))]
2628
    _POSIX_SS_REPL_MAX = libc::_SC_SS_REPL_MAX,
2629
    /// The implementation supports the Synchronized Input and Output option.
2630
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2631
    #[cfg_attr(docsrs, doc(cfg(all())))]
2632
    _POSIX_SYNCHRONIZED_IO = libc::_SC_SYNCHRONIZED_IO,
2633
    /// The implementation supports the Thread Stack Address Attribute option.
2634
    #[cfg(not(target_os = "redox"))]
2635
    #[cfg_attr(docsrs, doc(cfg(all())))]
2636
    _POSIX_THREAD_ATTR_STACKADDR = libc::_SC_THREAD_ATTR_STACKADDR,
2637
    /// The implementation supports the Thread Stack Size Attribute option.
2638
    #[cfg(not(target_os = "redox"))]
2639
    #[cfg_attr(docsrs, doc(cfg(all())))]
2640
    _POSIX_THREAD_ATTR_STACKSIZE = libc::_SC_THREAD_ATTR_STACKSIZE,
2641
    #[cfg(any(
2642
        target_os = "ios",
2643
        target_os = "linux",
2644
        target_os = "macos",
2645
        target_os = "netbsd",
2646
        target_os = "openbsd"
2647
    ))]
2648
    #[cfg_attr(docsrs, doc(cfg(all())))]
2649
    /// The implementation supports the Thread CPU-Time Clocks option.
2650
    _POSIX_THREAD_CPUTIME = libc::_SC_THREAD_CPUTIME,
2651
    /// The implementation supports the Non-Robust Mutex Priority Inheritance
2652
    /// option.
2653
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2654
    #[cfg_attr(docsrs, doc(cfg(all())))]
2655
    _POSIX_THREAD_PRIO_INHERIT = libc::_SC_THREAD_PRIO_INHERIT,
2656
    /// The implementation supports the Non-Robust Mutex Priority Protection option.
2657
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2658
    #[cfg_attr(docsrs, doc(cfg(all())))]
2659
    _POSIX_THREAD_PRIO_PROTECT = libc::_SC_THREAD_PRIO_PROTECT,
2660
    /// The implementation supports the Thread Execution Scheduling option.
2661
    #[cfg(not(target_os = "redox"))]
2662
    #[cfg_attr(docsrs, doc(cfg(all())))]
2663
    _POSIX_THREAD_PRIORITY_SCHEDULING = libc::_SC_THREAD_PRIORITY_SCHEDULING,
2664
    #[cfg(any(
2665
        target_os = "dragonfly",
2666
        target_os = "freebsd",
2667
        target_os = "ios",
2668
        target_os = "linux",
2669
        target_os = "macos",
2670
        target_os = "netbsd",
2671
        target_os = "openbsd"
2672
    ))]
2673
    #[cfg_attr(docsrs, doc(cfg(all())))]
2674
    /// The implementation supports the Thread Process-Shared Synchronization
2675
    /// option.
2676
    _POSIX_THREAD_PROCESS_SHARED = libc::_SC_THREAD_PROCESS_SHARED,
2677
    #[cfg(any(
2678
        target_os = "dragonfly",
2679
        target_os = "linux",
2680
        target_os = "openbsd"
2681
    ))]
2682
    #[cfg_attr(docsrs, doc(cfg(all())))]
2683
    /// The implementation supports the Robust Mutex Priority Inheritance option.
2684
    _POSIX_THREAD_ROBUST_PRIO_INHERIT = libc::_SC_THREAD_ROBUST_PRIO_INHERIT,
2685
    #[cfg(any(
2686
        target_os = "dragonfly",
2687
        target_os = "linux",
2688
        target_os = "openbsd"
2689
    ))]
2690
    #[cfg_attr(docsrs, doc(cfg(all())))]
2691
    /// The implementation supports the Robust Mutex Priority Protection option.
2692
    _POSIX_THREAD_ROBUST_PRIO_PROTECT = libc::_SC_THREAD_ROBUST_PRIO_PROTECT,
2693
    /// The implementation supports thread-safe functions.
2694
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2695
    #[cfg_attr(docsrs, doc(cfg(all())))]
2696
    _POSIX_THREAD_SAFE_FUNCTIONS = libc::_SC_THREAD_SAFE_FUNCTIONS,
2697
    #[cfg(any(
2698
        target_os = "dragonfly",
2699
        target_os = "freebsd",
2700
        target_os = "ios",
2701
        target_os = "linux",
2702
        target_os = "macos",
2703
        target_os = "openbsd"
2704
    ))]
2705
    #[cfg_attr(docsrs, doc(cfg(all())))]
2706
    /// The implementation supports the Thread Sporadic Server option.
2707
    _POSIX_THREAD_SPORADIC_SERVER = libc::_SC_THREAD_SPORADIC_SERVER,
2708
    /// The implementation supports threads.
2709
    #[cfg(not(target_os = "redox"))]
2710
    #[cfg_attr(docsrs, doc(cfg(all())))]
2711
    _POSIX_THREADS = libc::_SC_THREADS,
2712
    #[cfg(any(
2713
        target_os = "dragonfly",
2714
        target_os = "freebsd",
2715
        target_os = "ios",
2716
        target_os = "linux",
2717
        target_os = "macos",
2718
        target_os = "openbsd"
2719
    ))]
2720
    #[cfg_attr(docsrs, doc(cfg(all())))]
2721
    /// The implementation supports timeouts.
2722
    _POSIX_TIMEOUTS = libc::_SC_TIMEOUTS,
2723
    /// The implementation supports timers.
2724
    #[cfg(not(target_os = "redox"))]
2725
    #[cfg_attr(docsrs, doc(cfg(all())))]
2726
    _POSIX_TIMERS = libc::_SC_TIMERS,
2727
    #[cfg(any(
2728
        target_os = "dragonfly",
2729
        target_os = "freebsd",
2730
        target_os = "ios",
2731
        target_os = "linux",
2732
        target_os = "macos",
2733
        target_os = "openbsd"
2734
    ))]
2735
    #[cfg_attr(docsrs, doc(cfg(all())))]
2736
    /// The implementation supports the Trace option.
2737
    _POSIX_TRACE = libc::_SC_TRACE,
2738
    #[cfg(any(
2739
        target_os = "dragonfly",
2740
        target_os = "freebsd",
2741
        target_os = "ios",
2742
        target_os = "linux",
2743
        target_os = "macos",
2744
        target_os = "openbsd"
2745
    ))]
2746
    #[cfg_attr(docsrs, doc(cfg(all())))]
2747
    /// The implementation supports the Trace Event Filter option.
2748
    _POSIX_TRACE_EVENT_FILTER = libc::_SC_TRACE_EVENT_FILTER,
2749
    #[cfg(any(
2750
        target_os = "ios",
2751
        target_os = "linux",
2752
        target_os = "macos",
2753
        target_os = "openbsd"
2754
    ))]
2755
    #[cfg_attr(docsrs, doc(cfg(all())))]
2756
    _POSIX_TRACE_EVENT_NAME_MAX = libc::_SC_TRACE_EVENT_NAME_MAX,
2757
    #[cfg(any(
2758
        target_os = "dragonfly",
2759
        target_os = "freebsd",
2760
        target_os = "ios",
2761
        target_os = "linux",
2762
        target_os = "macos",
2763
        target_os = "openbsd"
2764
    ))]
2765
    #[cfg_attr(docsrs, doc(cfg(all())))]
2766
    /// The implementation supports the Trace Inherit option.
2767
    _POSIX_TRACE_INHERIT = libc::_SC_TRACE_INHERIT,
2768
    #[cfg(any(
2769
        target_os = "dragonfly",
2770
        target_os = "freebsd",
2771
        target_os = "ios",
2772
        target_os = "linux",
2773
        target_os = "macos",
2774
        target_os = "openbsd"
2775
    ))]
2776
    #[cfg_attr(docsrs, doc(cfg(all())))]
2777
    /// The implementation supports the Trace Log option.
2778
    _POSIX_TRACE_LOG = libc::_SC_TRACE_LOG,
2779
    #[cfg(any(
2780
        target_os = "ios",
2781
        target_os = "linux",
2782
        target_os = "macos",
2783
        target_os = "openbsd"
2784
    ))]
2785
    #[cfg_attr(docsrs, doc(cfg(all())))]
2786
    _POSIX_TRACE_NAME_MAX = libc::_SC_TRACE_NAME_MAX,
2787
    #[cfg(any(
2788
        target_os = "ios",
2789
        target_os = "linux",
2790
        target_os = "macos",
2791
        target_os = "openbsd"
2792
    ))]
2793
    #[cfg_attr(docsrs, doc(cfg(all())))]
2794
    _POSIX_TRACE_SYS_MAX = libc::_SC_TRACE_SYS_MAX,
2795
    #[cfg(any(
2796
        target_os = "ios",
2797
        target_os = "linux",
2798
        target_os = "macos",
2799
        target_os = "openbsd"
2800
    ))]
2801
    #[cfg_attr(docsrs, doc(cfg(all())))]
2802
    _POSIX_TRACE_USER_EVENT_MAX = libc::_SC_TRACE_USER_EVENT_MAX,
2803
    #[cfg(any(
2804
        target_os = "dragonfly",
2805
        target_os = "freebsd",
2806
        target_os = "ios",
2807
        target_os = "linux",
2808
        target_os = "macos",
2809
        target_os = "openbsd"
2810
    ))]
2811
    #[cfg_attr(docsrs, doc(cfg(all())))]
2812
    /// The implementation supports the Typed Memory Objects option.
2813
    _POSIX_TYPED_MEMORY_OBJECTS = libc::_SC_TYPED_MEMORY_OBJECTS,
2814
    /// Integer value indicating version of this standard (C-language binding)
2815
    /// to which the implementation conforms. For implementations conforming to
2816
    /// POSIX.1-2008, the value shall be 200809L.
2817
    _POSIX_VERSION = libc::_SC_VERSION,
2818
    #[cfg(any(
2819
        target_os = "dragonfly",
2820
        target_os = "freebsd",
2821
        target_os = "ios",
2822
        target_os = "linux",
2823
        target_os = "macos",
2824
        target_os = "netbsd",
2825
        target_os = "openbsd"
2826
    ))]
2827
    #[cfg_attr(docsrs, doc(cfg(all())))]
2828
    /// The implementation provides a C-language compilation environment with
2829
    /// 32-bit `int`, `long`, `pointer`, and `off_t` types.
2830
    _POSIX_V6_ILP32_OFF32 = libc::_SC_V6_ILP32_OFF32,
2831
    #[cfg(any(
2832
        target_os = "dragonfly",
2833
        target_os = "freebsd",
2834
        target_os = "ios",
2835
        target_os = "linux",
2836
        target_os = "macos",
2837
        target_os = "netbsd",
2838
        target_os = "openbsd"
2839
    ))]
2840
    #[cfg_attr(docsrs, doc(cfg(all())))]
2841
    /// The implementation provides a C-language compilation environment with
2842
    /// 32-bit `int`, `long`, and pointer types and an `off_t` type using at
2843
    /// least 64 bits.
2844
    _POSIX_V6_ILP32_OFFBIG = libc::_SC_V6_ILP32_OFFBIG,
2845
    #[cfg(any(
2846
        target_os = "dragonfly",
2847
        target_os = "freebsd",
2848
        target_os = "ios",
2849
        target_os = "linux",
2850
        target_os = "macos",
2851
        target_os = "netbsd",
2852
        target_os = "openbsd"
2853
    ))]
2854
    #[cfg_attr(docsrs, doc(cfg(all())))]
2855
    /// The implementation provides a C-language compilation environment with
2856
    /// 32-bit `int` and 64-bit `long`, `pointer`, and `off_t` types.
2857
    _POSIX_V6_LP64_OFF64 = libc::_SC_V6_LP64_OFF64,
2858
    #[cfg(any(
2859
        target_os = "dragonfly",
2860
        target_os = "freebsd",
2861
        target_os = "ios",
2862
        target_os = "linux",
2863
        target_os = "macos",
2864
        target_os = "netbsd",
2865
        target_os = "openbsd"
2866
    ))]
2867
    #[cfg_attr(docsrs, doc(cfg(all())))]
2868
    /// The implementation provides a C-language compilation environment with an
2869
    /// `int` type using at least 32 bits and `long`, pointer, and `off_t` types
2870
    /// using at least 64 bits.
2871
    _POSIX_V6_LPBIG_OFFBIG = libc::_SC_V6_LPBIG_OFFBIG,
2872
    /// The implementation supports the C-Language Binding option.
2873
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2874
    #[cfg_attr(docsrs, doc(cfg(all())))]
2875
    _POSIX2_C_BIND = libc::_SC_2_C_BIND,
2876
    /// The implementation supports the C-Language Development Utilities option.
2877
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2878
    #[cfg_attr(docsrs, doc(cfg(all())))]
2879
    _POSIX2_C_DEV = libc::_SC_2_C_DEV,
2880
    /// The implementation supports the Terminal Characteristics option.
2881
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2882
    #[cfg_attr(docsrs, doc(cfg(all())))]
2883
    _POSIX2_CHAR_TERM = libc::_SC_2_CHAR_TERM,
2884
    /// The implementation supports the FORTRAN Development Utilities option.
2885
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2886
    #[cfg_attr(docsrs, doc(cfg(all())))]
2887
    _POSIX2_FORT_DEV = libc::_SC_2_FORT_DEV,
2888
    /// The implementation supports the FORTRAN Runtime Utilities option.
2889
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2890
    #[cfg_attr(docsrs, doc(cfg(all())))]
2891
    _POSIX2_FORT_RUN = libc::_SC_2_FORT_RUN,
2892
    /// The implementation supports the creation of locales by the localedef
2893
    /// utility.
2894
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2895
    #[cfg_attr(docsrs, doc(cfg(all())))]
2896
    _POSIX2_LOCALEDEF = libc::_SC_2_LOCALEDEF,
2897
    #[cfg(any(
2898
        target_os = "dragonfly",
2899
        target_os = "freebsd",
2900
        target_os = "ios",
2901
        target_os = "linux",
2902
        target_os = "macos",
2903
        target_os = "netbsd",
2904
        target_os = "openbsd"
2905
    ))]
2906
    #[cfg_attr(docsrs, doc(cfg(all())))]
2907
    /// The implementation supports the Batch Environment Services and Utilities
2908
    /// option.
2909
    _POSIX2_PBS = libc::_SC_2_PBS,
2910
    #[cfg(any(
2911
        target_os = "dragonfly",
2912
        target_os = "freebsd",
2913
        target_os = "ios",
2914
        target_os = "linux",
2915
        target_os = "macos",
2916
        target_os = "netbsd",
2917
        target_os = "openbsd"
2918
    ))]
2919
    #[cfg_attr(docsrs, doc(cfg(all())))]
2920
    /// The implementation supports the Batch Accounting option.
2921
    _POSIX2_PBS_ACCOUNTING = libc::_SC_2_PBS_ACCOUNTING,
2922
    #[cfg(any(
2923
        target_os = "dragonfly",
2924
        target_os = "freebsd",
2925
        target_os = "ios",
2926
        target_os = "linux",
2927
        target_os = "macos",
2928
        target_os = "netbsd",
2929
        target_os = "openbsd"
2930
    ))]
2931
    #[cfg_attr(docsrs, doc(cfg(all())))]
2932
    /// The implementation supports the Batch Checkpoint/Restart option.
2933
    _POSIX2_PBS_CHECKPOINT = libc::_SC_2_PBS_CHECKPOINT,
2934
    #[cfg(any(
2935
        target_os = "dragonfly",
2936
        target_os = "freebsd",
2937
        target_os = "ios",
2938
        target_os = "linux",
2939
        target_os = "macos",
2940
        target_os = "netbsd",
2941
        target_os = "openbsd"
2942
    ))]
2943
    #[cfg_attr(docsrs, doc(cfg(all())))]
2944
    /// The implementation supports the Locate Batch Job Request option.
2945
    _POSIX2_PBS_LOCATE = libc::_SC_2_PBS_LOCATE,
2946
    #[cfg(any(
2947
        target_os = "dragonfly",
2948
        target_os = "freebsd",
2949
        target_os = "ios",
2950
        target_os = "linux",
2951
        target_os = "macos",
2952
        target_os = "netbsd",
2953
        target_os = "openbsd"
2954
    ))]
2955
    #[cfg_attr(docsrs, doc(cfg(all())))]
2956
    /// The implementation supports the Batch Job Message Request option.
2957
    _POSIX2_PBS_MESSAGE = libc::_SC_2_PBS_MESSAGE,
2958
    #[cfg(any(
2959
        target_os = "dragonfly",
2960
        target_os = "freebsd",
2961
        target_os = "ios",
2962
        target_os = "linux",
2963
        target_os = "macos",
2964
        target_os = "netbsd",
2965
        target_os = "openbsd"
2966
    ))]
2967
    #[cfg_attr(docsrs, doc(cfg(all())))]
2968
    /// The implementation supports the Track Batch Job Request option.
2969
    _POSIX2_PBS_TRACK = libc::_SC_2_PBS_TRACK,
2970
    /// The implementation supports the Software Development Utilities option.
2971
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2972
    #[cfg_attr(docsrs, doc(cfg(all())))]
2973
    _POSIX2_SW_DEV = libc::_SC_2_SW_DEV,
2974
    /// The implementation supports the User Portability Utilities option.
2975
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2976
    #[cfg_attr(docsrs, doc(cfg(all())))]
2977
    _POSIX2_UPE = libc::_SC_2_UPE,
2978
    /// Integer value indicating version of the Shell and Utilities volume of
2979
    /// POSIX.1 to which the implementation conforms.
2980
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2981
    #[cfg_attr(docsrs, doc(cfg(all())))]
2982
    _POSIX2_VERSION = libc::_SC_2_VERSION,
2983
    /// The size of a system page in bytes.
2984
    ///
2985
    /// POSIX also defines an alias named `PAGESIZE`, but Rust does not allow two
2986
    /// enum constants to have the same value, so nix omits `PAGESIZE`.
2987
    PAGE_SIZE = libc::_SC_PAGE_SIZE,
2988
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2989
    #[cfg_attr(docsrs, doc(cfg(all())))]
2990
    PTHREAD_DESTRUCTOR_ITERATIONS = libc::_SC_THREAD_DESTRUCTOR_ITERATIONS,
2991
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2992
    #[cfg_attr(docsrs, doc(cfg(all())))]
2993
    PTHREAD_KEYS_MAX = libc::_SC_THREAD_KEYS_MAX,
2994
    #[cfg(not(target_os = "redox"))]
2995
    #[cfg_attr(docsrs, doc(cfg(all())))]
2996
    PTHREAD_STACK_MIN = libc::_SC_THREAD_STACK_MIN,
2997
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
2998
    #[cfg_attr(docsrs, doc(cfg(all())))]
2999
    PTHREAD_THREADS_MAX = libc::_SC_THREAD_THREADS_MAX,
3000
    #[cfg(not(target_os = "haiku"))]
3001
    RE_DUP_MAX = libc::_SC_RE_DUP_MAX,
3002
    #[cfg(any(
3003
        target_os = "android",
3004
        target_os = "dragonfly",
3005
        target_os = "freebsd",
3006
        target_os = "ios",
3007
        target_os = "linux",
3008
        target_os = "macos",
3009
        target_os = "openbsd"
3010
    ))]
3011
    #[cfg_attr(docsrs, doc(cfg(all())))]
3012
    RTSIG_MAX = libc::_SC_RTSIG_MAX,
3013
    #[cfg(not(target_os = "redox"))]
3014
    #[cfg_attr(docsrs, doc(cfg(all())))]
3015
    SEM_NSEMS_MAX = libc::_SC_SEM_NSEMS_MAX,
3016
    #[cfg(any(
3017
        target_os = "android",
3018
        target_os = "dragonfly",
3019
        target_os = "freebsd",
3020
        target_os = "ios",
3021
        target_os = "linux",
3022
        target_os = "macos",
3023
        target_os = "openbsd"
3024
    ))]
3025
    #[cfg_attr(docsrs, doc(cfg(all())))]
3026
    SEM_VALUE_MAX = libc::_SC_SEM_VALUE_MAX,
3027
    #[cfg(any(
3028
        target_os = "android",
3029
        target_os = "dragonfly",
3030
        target_os = "freebsd",
3031
        target_os = "ios",
3032
        target_os = "linux",
3033
        target_os = "macos",
3034
        target_os = "openbsd"
3035
    ))]
3036
    #[cfg_attr(docsrs, doc(cfg(all())))]
3037
    SIGQUEUE_MAX = libc::_SC_SIGQUEUE_MAX,
3038
    STREAM_MAX = libc::_SC_STREAM_MAX,
3039
    #[cfg(any(
3040
        target_os = "dragonfly",
3041
        target_os = "freebsd",
3042
        target_os = "ios",
3043
        target_os = "linux",
3044
        target_os = "macos",
3045
        target_os = "netbsd",
3046
        target_os = "openbsd"
3047
    ))]
3048
    #[cfg_attr(docsrs, doc(cfg(all())))]
3049
    SYMLOOP_MAX = libc::_SC_SYMLOOP_MAX,
3050
    #[cfg(not(target_os = "redox"))]
3051
    #[cfg_attr(docsrs, doc(cfg(all())))]
3052
    TIMER_MAX = libc::_SC_TIMER_MAX,
3053
    TTY_NAME_MAX = libc::_SC_TTY_NAME_MAX,
3054
    TZNAME_MAX = libc::_SC_TZNAME_MAX,
3055
    #[cfg(any(
3056
        target_os = "android",
3057
        target_os = "dragonfly",
3058
        target_os = "freebsd",
3059
        target_os = "ios",
3060
        target_os = "linux",
3061
        target_os = "macos",
3062
        target_os = "openbsd"
3063
    ))]
3064
    #[cfg_attr(docsrs, doc(cfg(all())))]
3065
    /// The implementation supports the X/Open Encryption Option Group.
3066
    _XOPEN_CRYPT = libc::_SC_XOPEN_CRYPT,
3067
    #[cfg(any(
3068
        target_os = "android",
3069
        target_os = "dragonfly",
3070
        target_os = "freebsd",
3071
        target_os = "ios",
3072
        target_os = "linux",
3073
        target_os = "macos",
3074
        target_os = "openbsd"
3075
    ))]
3076
    #[cfg_attr(docsrs, doc(cfg(all())))]
3077
    /// The implementation supports the Issue 4, Version 2 Enhanced
3078
    /// Internationalization Option Group.
3079
    _XOPEN_ENH_I18N = libc::_SC_XOPEN_ENH_I18N,
3080
    #[cfg(any(
3081
        target_os = "android",
3082
        target_os = "dragonfly",
3083
        target_os = "freebsd",
3084
        target_os = "ios",
3085
        target_os = "linux",
3086
        target_os = "macos",
3087
        target_os = "openbsd"
3088
    ))]
3089
    #[cfg_attr(docsrs, doc(cfg(all())))]
3090
    _XOPEN_LEGACY = libc::_SC_XOPEN_LEGACY,
3091
    #[cfg(any(
3092
        target_os = "android",
3093
        target_os = "dragonfly",
3094
        target_os = "freebsd",
3095
        target_os = "ios",
3096
        target_os = "linux",
3097
        target_os = "macos",
3098
        target_os = "openbsd"
3099
    ))]
3100
    #[cfg_attr(docsrs, doc(cfg(all())))]
3101
    /// The implementation supports the X/Open Realtime Option Group.
3102
    _XOPEN_REALTIME = libc::_SC_XOPEN_REALTIME,
3103
    #[cfg(any(
3104
        target_os = "android",
3105
        target_os = "dragonfly",
3106
        target_os = "freebsd",
3107
        target_os = "ios",
3108
        target_os = "linux",
3109
        target_os = "macos",
3110
        target_os = "openbsd"
3111
    ))]
3112
    #[cfg_attr(docsrs, doc(cfg(all())))]
3113
    /// The implementation supports the X/Open Realtime Threads Option Group.
3114
    _XOPEN_REALTIME_THREADS = libc::_SC_XOPEN_REALTIME_THREADS,
3115
    /// The implementation supports the Issue 4, Version 2 Shared Memory Option
3116
    /// Group.
3117
    #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
3118
    #[cfg_attr(docsrs, doc(cfg(all())))]
3119
    _XOPEN_SHM = libc::_SC_XOPEN_SHM,
3120
    #[cfg(any(
3121
        target_os = "dragonfly",
3122
        target_os = "freebsd",
3123
        target_os = "ios",
3124
        target_os = "linux",
3125
        target_os = "macos",
3126
        target_os = "openbsd"
3127
    ))]
3128
    #[cfg_attr(docsrs, doc(cfg(all())))]
3129
    /// The implementation supports the XSI STREAMS Option Group.
3130
    _XOPEN_STREAMS = libc::_SC_XOPEN_STREAMS,
3131
    #[cfg(any(
3132
        target_os = "android",
3133
        target_os = "dragonfly",
3134
        target_os = "freebsd",
3135
        target_os = "ios",
3136
        target_os = "linux",
3137
        target_os = "macos",
3138
        target_os = "openbsd"
3139
    ))]
3140
    #[cfg_attr(docsrs, doc(cfg(all())))]
3141
    /// The implementation supports the XSI option
3142
    _XOPEN_UNIX = libc::_SC_XOPEN_UNIX,
3143
    #[cfg(any(
3144
        target_os = "android",
3145
        target_os = "dragonfly",
3146
        target_os = "freebsd",
3147
        target_os = "ios",
3148
        target_os = "linux",
3149
        target_os = "macos",
3150
        target_os = "openbsd"
3151
    ))]
3152
    #[cfg_attr(docsrs, doc(cfg(all())))]
3153
    /// Integer value indicating version of the X/Open Portability Guide to
3154
    /// which the implementation conforms.
3155
    _XOPEN_VERSION = libc::_SC_XOPEN_VERSION,
3156
    /// The number of pages of physical memory. Note that it is possible for
3157
    /// the product of this value to overflow.
3158
    #[cfg(any(target_os = "android", target_os = "linux"))]
3159
    _PHYS_PAGES = libc::_SC_PHYS_PAGES,
3160
    /// The number of currently available pages of physical memory.
3161
    #[cfg(any(target_os = "android", target_os = "linux"))]
3162
    _AVPHYS_PAGES = libc::_SC_AVPHYS_PAGES,
3163
    /// The number of processors configured.
3164
    #[cfg(any(target_os = "android", target_os = "linux"))]
3165
    _NPROCESSORS_CONF = libc::_SC_NPROCESSORS_CONF,
3166
    /// The number of processors currently online (available).
3167
    #[cfg(any(target_os = "android", target_os = "linux"))]
3168
    _NPROCESSORS_ONLN = libc::_SC_NPROCESSORS_ONLN,
3169
}
3170
3171
/// Get configurable system variables (see
3172
/// [sysconf(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html))
3173
///
3174
/// Returns the value of a configurable system variable.  Most supported
3175
/// variables also have associated compile-time constants, but POSIX
3176
/// allows their values to change at runtime.  There are generally two types of
3177
/// sysconf variables: options and limits.  See sysconf(3) for more details.
3178
///
3179
/// # Returns
3180
///
3181
/// - `Ok(Some(x))`: the variable's limit (for limit variables) or its
3182
///     implementation level (for option variables).  Implementation levels are
3183
///     usually a decimal-coded date, such as 200112 for POSIX 2001.12
3184
/// - `Ok(None)`: the variable has no limit (for limit variables) or is
3185
///     unsupported (for option variables)
3186
/// - `Err(x)`: an error occurred
3187
pub fn sysconf(var: SysconfVar) -> Result<Option<c_long>> {
3188
    let raw = unsafe {
3189
        Errno::clear();
3190
        libc::sysconf(var as c_int)
3191
    };
3192
    if raw == -1 {
3193
        if errno::errno() == 0 {
3194
            Ok(None)
3195
        } else {
3196
            Err(Errno::last())
3197
        }
3198
    } else {
3199
        Ok(Some(raw))
3200
    }
3201
}
3202
}
3203
3204
#[cfg(any(target_os = "android", target_os = "linux"))]
3205
#[cfg(feature = "fs")]
3206
mod pivot_root {
3207
    use crate::errno::Errno;
3208
    use crate::{NixPath, Result};
3209
3210
0
    pub fn pivot_root<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
3211
0
        new_root: &P1,
3212
0
        put_old: &P2,
3213
0
    ) -> Result<()> {
3214
0
        let res = new_root.with_nix_path(|new_root| {
3215
0
            put_old.with_nix_path(|put_old| unsafe {
3216
0
                libc::syscall(
3217
0
                    libc::SYS_pivot_root,
3218
0
                    new_root.as_ptr(),
3219
0
                    put_old.as_ptr(),
3220
0
                )
3221
0
            })
3222
0
        })??;
3223
3224
0
        Errno::result(res).map(drop)
3225
0
    }
3226
}
3227
3228
#[cfg(any(
3229
    target_os = "android",
3230
    target_os = "dragonfly",
3231
    target_os = "freebsd",
3232
    target_os = "linux",
3233
    target_os = "openbsd"
3234
))]
3235
mod setres {
3236
    feature! {
3237
    #![feature = "user"]
3238
3239
    use super::{Gid, Uid};
3240
    use crate::errno::Errno;
3241
    use crate::Result;
3242
3243
    /// Sets the real, effective, and saved uid.
3244
    /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
3245
    ///
3246
    /// * `ruid`: real user id
3247
    /// * `euid`: effective user id
3248
    /// * `suid`: saved user id
3249
    /// * returns: Ok or libc error code.
3250
    ///
3251
    /// Err is returned if the user doesn't have permission to set this UID.
3252
    #[inline]
3253
    pub fn setresuid(ruid: Uid, euid: Uid, suid: Uid) -> Result<()> {
3254
        let res =
3255
            unsafe { libc::setresuid(ruid.into(), euid.into(), suid.into()) };
3256
3257
        Errno::result(res).map(drop)
3258
    }
3259
3260
    /// Sets the real, effective, and saved gid.
3261
    /// ([see setresuid(2)](https://man7.org/linux/man-pages/man2/setresuid.2.html))
3262
    ///
3263
    /// * `rgid`: real group id
3264
    /// * `egid`: effective group id
3265
    /// * `sgid`: saved group id
3266
    /// * returns: Ok or libc error code.
3267
    ///
3268
    /// Err is returned if the user doesn't have permission to set this GID.
3269
    #[inline]
3270
    pub fn setresgid(rgid: Gid, egid: Gid, sgid: Gid) -> Result<()> {
3271
        let res =
3272
            unsafe { libc::setresgid(rgid.into(), egid.into(), sgid.into()) };
3273
3274
        Errno::result(res).map(drop)
3275
    }
3276
    }
3277
}
3278
3279
#[cfg(any(
3280
    target_os = "android",
3281
    target_os = "dragonfly",
3282
    target_os = "freebsd",
3283
    target_os = "linux",
3284
    target_os = "openbsd"
3285
))]
3286
mod getres {
3287
    feature! {
3288
    #![feature = "user"]
3289
3290
    use super::{Gid, Uid};
3291
    use crate::errno::Errno;
3292
    use crate::Result;
3293
3294
    /// Real, effective and saved user IDs.
3295
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
3296
    pub struct ResUid {
3297
        pub real: Uid,
3298
        pub effective: Uid,
3299
        pub saved: Uid,
3300
    }
3301
3302
    /// Real, effective and saved group IDs.
3303
    #[derive(Debug, Copy, Clone, Eq, PartialEq)]
3304
    pub struct ResGid {
3305
        pub real: Gid,
3306
        pub effective: Gid,
3307
        pub saved: Gid,
3308
    }
3309
3310
    /// Gets the real, effective, and saved user IDs.
3311
    ///
3312
    /// ([see getresuid(2)](http://man7.org/linux/man-pages/man2/getresuid.2.html))
3313
    ///
3314
    /// #Returns
3315
    ///
3316
    /// - `Ok((Uid, Uid, Uid))`: tuple of real, effective and saved uids on success.
3317
    /// - `Err(x)`: libc error code on failure.
3318
    ///
3319
    #[inline]
3320
    pub fn getresuid() -> Result<ResUid> {
3321
        let mut ruid = libc::uid_t::max_value();
3322
        let mut euid = libc::uid_t::max_value();
3323
        let mut suid = libc::uid_t::max_value();
3324
        let res = unsafe { libc::getresuid(&mut ruid, &mut euid, &mut suid) };
3325
3326
        Errno::result(res).map(|_| ResUid {
3327
            real: Uid(ruid),
3328
            effective: Uid(euid),
3329
            saved: Uid(suid),
3330
        })
3331
    }
3332
3333
    /// Gets the real, effective, and saved group IDs.
3334
    ///
3335
    /// ([see getresgid(2)](http://man7.org/linux/man-pages/man2/getresgid.2.html))
3336
    ///
3337
    /// #Returns
3338
    ///
3339
    /// - `Ok((Gid, Gid, Gid))`: tuple of real, effective and saved gids on success.
3340
    /// - `Err(x)`: libc error code on failure.
3341
    ///
3342
    #[inline]
3343
    pub fn getresgid() -> Result<ResGid> {
3344
        let mut rgid = libc::gid_t::max_value();
3345
        let mut egid = libc::gid_t::max_value();
3346
        let mut sgid = libc::gid_t::max_value();
3347
        let res = unsafe { libc::getresgid(&mut rgid, &mut egid, &mut sgid) };
3348
3349
        Errno::result(res).map(|_| ResGid {
3350
            real: Gid(rgid),
3351
            effective: Gid(egid),
3352
            saved: Gid(sgid),
3353
        })
3354
    }
3355
    }
3356
}
3357
3358
#[cfg(feature = "fs")]
3359
libc_bitflags! {
3360
    /// Options for access()
3361
    #[cfg_attr(docsrs, doc(cfg(feature = "fs")))]
3362
    pub struct AccessFlags : c_int {
3363
        /// Test for existence of file.
3364
        F_OK;
3365
        /// Test for read permission.
3366
        R_OK;
3367
        /// Test for write permission.
3368
        W_OK;
3369
        /// Test for execute (search) permission.
3370
        X_OK;
3371
    }
3372
}
3373
3374
feature! {
3375
#![feature = "fs"]
3376
3377
/// Checks the file named by `path` for accessibility according to the flags given by `amode`
3378
/// See [access(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html)
3379
0
pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
3380
0
    let res = path.with_nix_path(|cstr| unsafe {
3381
0
        libc::access(cstr.as_ptr(), amode.bits())
3382
0
    })?;
3383
0
    Errno::result(res).map(drop)
3384
0
}
3385
3386
/// Checks the file named by `path` for accessibility according to the flags given by `mode`
3387
///
3388
/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
3389
///
3390
/// If `dirfd` is `None`, then `path` is relative to the current working directory.
3391
///
3392
/// # References
3393
///
3394
/// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html)
3395
// redox: does not appear to support the *at family of syscalls.
3396
#[cfg(not(target_os = "redox"))]
3397
0
pub fn faccessat<P: ?Sized + NixPath>(
3398
0
    dirfd: Option<RawFd>,
3399
0
    path: &P,
3400
0
    mode: AccessFlags,
3401
0
    flags: AtFlags,
3402
0
) -> Result<()> {
3403
0
    let res = path.with_nix_path(|cstr| unsafe {
3404
0
        libc::faccessat(
3405
0
            at_rawfd(dirfd),
3406
0
            cstr.as_ptr(),
3407
0
            mode.bits(),
3408
0
            flags.bits(),
3409
0
        )
3410
0
    })?;
3411
0
    Errno::result(res).map(drop)
3412
0
}
3413
3414
/// Checks the file named by `path` for accessibility according to the flags given
3415
/// by `mode` using effective UID, effective GID and supplementary group lists.
3416
///
3417
/// # References
3418
///
3419
/// * [FreeBSD man page](https://www.freebsd.org/cgi/man.cgi?query=eaccess&sektion=2&n=1)
3420
/// * [Linux man page](https://man7.org/linux/man-pages/man3/euidaccess.3.html)
3421
#[cfg(any(
3422
    all(target_os = "linux", not(target_env = "uclibc")),
3423
    target_os = "freebsd",
3424
    target_os = "dragonfly"
3425
))]
3426
0
pub fn eaccess<P: ?Sized + NixPath>(path: &P, mode: AccessFlags) -> Result<()> {
3427
0
    let res = path.with_nix_path(|cstr| unsafe {
3428
0
        libc::eaccess(cstr.as_ptr(), mode.bits())
3429
0
    })?;
3430
0
    Errno::result(res).map(drop)
3431
0
}
3432
}
3433
3434
feature! {
3435
#![feature = "user"]
3436
3437
/// Representation of a User, based on `libc::passwd`
3438
///
3439
/// The reason some fields in this struct are `String` and others are `CString` is because some
3440
/// fields are based on the user's locale, which could be non-UTF8, while other fields are
3441
/// guaranteed to conform to [`NAME_REGEX`](https://serverfault.com/a/73101/407341), which only
3442
/// contains ASCII.
3443
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3444
#[derive(Debug, Clone, Eq, PartialEq)]
3445
pub struct User {
3446
    /// Username
3447
    pub name: String,
3448
    /// User password (probably hashed)
3449
    pub passwd: CString,
3450
    /// User ID
3451
    pub uid: Uid,
3452
    /// Group ID
3453
    pub gid: Gid,
3454
    /// User information
3455
    #[cfg(not(all(target_os = "android", target_pointer_width = "32")))]
3456
    pub gecos: CString,
3457
    /// Home directory
3458
    pub dir: PathBuf,
3459
    /// Path to shell
3460
    pub shell: PathBuf,
3461
    /// Login class
3462
    #[cfg(not(any(
3463
        target_os = "aix",
3464
        target_os = "android",
3465
        target_os = "fuchsia",
3466
        target_os = "haiku",
3467
        target_os = "illumos",
3468
        target_os = "linux",
3469
        target_os = "solaris"
3470
    )))]
3471
    #[cfg_attr(docsrs, doc(cfg(all())))]
3472
    pub class: CString,
3473
    /// Last password change
3474
    #[cfg(not(any(
3475
        target_os = "aix",
3476
        target_os = "android",
3477
        target_os = "fuchsia",
3478
        target_os = "haiku",
3479
        target_os = "illumos",
3480
        target_os = "linux",
3481
        target_os = "solaris"
3482
    )))]
3483
    #[cfg_attr(docsrs, doc(cfg(all())))]
3484
    pub change: libc::time_t,
3485
    /// Expiration time of account
3486
    #[cfg(not(any(
3487
        target_os = "aix",
3488
        target_os = "android",
3489
        target_os = "fuchsia",
3490
        target_os = "haiku",
3491
        target_os = "illumos",
3492
        target_os = "linux",
3493
        target_os = "solaris"
3494
    )))]
3495
    #[cfg_attr(docsrs, doc(cfg(all())))]
3496
    pub expire: libc::time_t,
3497
}
3498
3499
#[cfg(not(target_os = "redox"))] //RedoxFS does not support passwd
3500
impl From<&libc::passwd> for User {
3501
    fn from(pw: &libc::passwd) -> User {
3502
        unsafe {
3503
            User {
3504
                name: if pw.pw_name.is_null() {
3505
                    Default::default()
3506
                } else {
3507
                    CStr::from_ptr(pw.pw_name).to_string_lossy().into_owned()
3508
                },
3509
                passwd: if pw.pw_passwd.is_null() {
3510
                    Default::default()
3511
                } else {
3512
                    CString::new(CStr::from_ptr(pw.pw_passwd).to_bytes())
3513
                        .unwrap()
3514
                },
3515
                #[cfg(not(all(
3516
                    target_os = "android",
3517
                    target_pointer_width = "32"
3518
                )))]
3519
                gecos: if pw.pw_gecos.is_null() {
3520
                    Default::default()
3521
                } else {
3522
                    CString::new(CStr::from_ptr(pw.pw_gecos).to_bytes())
3523
                        .unwrap()
3524
                },
3525
                dir: if pw.pw_dir.is_null() {
3526
                    Default::default()
3527
                } else {
3528
                    PathBuf::from(OsStr::from_bytes(
3529
                        CStr::from_ptr(pw.pw_dir).to_bytes(),
3530
                    ))
3531
                },
3532
                shell: if pw.pw_shell.is_null() {
3533
                    Default::default()
3534
                } else {
3535
                    PathBuf::from(OsStr::from_bytes(
3536
                        CStr::from_ptr(pw.pw_shell).to_bytes(),
3537
                    ))
3538
                },
3539
                uid: Uid::from_raw(pw.pw_uid),
3540
                gid: Gid::from_raw(pw.pw_gid),
3541
                #[cfg(not(any(
3542
                    target_os = "aix",
3543
                    target_os = "android",
3544
                    target_os = "fuchsia",
3545
                    target_os = "haiku",
3546
                    target_os = "illumos",
3547
                    target_os = "linux",
3548
                    target_os = "solaris"
3549
                )))]
3550
                class: CString::new(CStr::from_ptr(pw.pw_class).to_bytes())
3551
                    .unwrap(),
3552
                #[cfg(not(any(
3553
                    target_os = "aix",
3554
                    target_os = "android",
3555
                    target_os = "fuchsia",
3556
                    target_os = "haiku",
3557
                    target_os = "illumos",
3558
                    target_os = "linux",
3559
                    target_os = "solaris"
3560
                )))]
3561
                change: pw.pw_change,
3562
                #[cfg(not(any(
3563
                    target_os = "aix",
3564
                    target_os = "android",
3565
                    target_os = "fuchsia",
3566
                    target_os = "haiku",
3567
                    target_os = "illumos",
3568
                    target_os = "linux",
3569
                    target_os = "solaris"
3570
                )))]
3571
                expire: pw.pw_expire,
3572
            }
3573
        }
3574
    }
3575
}
3576
3577
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3578
impl From<User> for libc::passwd {
3579
    fn from(u: User) -> Self {
3580
        let name = match CString::new(u.name) {
3581
            Ok(n) => n.into_raw(),
3582
            Err(_) => CString::new("").unwrap().into_raw(),
3583
        };
3584
        let dir = match u.dir.into_os_string().into_string() {
3585
            Ok(s) => CString::new(s.as_str()).unwrap().into_raw(),
3586
            Err(_) => CString::new("").unwrap().into_raw(),
3587
        };
3588
        let shell = match u.shell.into_os_string().into_string() {
3589
            Ok(s) => CString::new(s.as_str()).unwrap().into_raw(),
3590
            Err(_) => CString::new("").unwrap().into_raw(),
3591
        };
3592
        Self {
3593
            pw_name: name,
3594
            pw_passwd: u.passwd.into_raw(),
3595
            #[cfg(not(all(
3596
                target_os = "android",
3597
                target_pointer_width = "32"
3598
            )))]
3599
            pw_gecos: u.gecos.into_raw(),
3600
            pw_dir: dir,
3601
            pw_shell: shell,
3602
            pw_uid: u.uid.0,
3603
            pw_gid: u.gid.0,
3604
            #[cfg(not(any(
3605
                target_os = "aix",
3606
                target_os = "android",
3607
                target_os = "fuchsia",
3608
                target_os = "haiku",
3609
                target_os = "illumos",
3610
                target_os = "linux",
3611
                target_os = "solaris"
3612
            )))]
3613
            pw_class: u.class.into_raw(),
3614
            #[cfg(not(any(
3615
                target_os = "aix",
3616
                target_os = "android",
3617
                target_os = "fuchsia",
3618
                target_os = "haiku",
3619
                target_os = "illumos",
3620
                target_os = "linux",
3621
                target_os = "solaris"
3622
            )))]
3623
            pw_change: u.change,
3624
            #[cfg(not(any(
3625
                target_os = "aix",
3626
                target_os = "android",
3627
                target_os = "fuchsia",
3628
                target_os = "haiku",
3629
                target_os = "illumos",
3630
                target_os = "linux",
3631
                target_os = "solaris"
3632
            )))]
3633
            pw_expire: u.expire,
3634
            #[cfg(target_os = "illumos")]
3635
            pw_age: CString::new("").unwrap().into_raw(),
3636
            #[cfg(target_os = "illumos")]
3637
            pw_comment: CString::new("").unwrap().into_raw(),
3638
            #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
3639
            pw_fields: 0,
3640
        }
3641
    }
3642
}
3643
3644
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3645
impl User {
3646
    /// # Safety
3647
    ///
3648
    /// If `f` writes to its `*mut *mut libc::passwd` parameter, then it must
3649
    /// also initialize the value pointed to by its `*mut libc::group`
3650
    /// parameter.
3651
    unsafe fn from_anything<F>(f: F) -> Result<Option<Self>>
3652
    where
3653
        F: Fn(
3654
            *mut libc::passwd,
3655
            *mut c_char,
3656
            libc::size_t,
3657
            *mut *mut libc::passwd,
3658
        ) -> libc::c_int,
3659
    {
3660
        let buflimit = 1048576;
3661
        let bufsize = match sysconf(SysconfVar::GETPW_R_SIZE_MAX) {
3662
            Ok(Some(n)) => n as usize,
3663
            Ok(None) | Err(_) => 16384,
3664
        };
3665
3666
        let mut cbuf = Vec::with_capacity(bufsize);
3667
        let mut pwd = mem::MaybeUninit::<libc::passwd>::uninit();
3668
        let mut res = ptr::null_mut();
3669
3670
        loop {
3671
            let error = f(
3672
                pwd.as_mut_ptr(),
3673
                cbuf.as_mut_ptr(),
3674
                cbuf.capacity(),
3675
                &mut res,
3676
            );
3677
            if error == 0 {
3678
                if res.is_null() {
3679
                    return Ok(None);
3680
                } else {
3681
                    // SAFETY: `f` guarantees that `pwd` is initialized if `res`
3682
                    // is not null.
3683
                    let pwd = pwd.assume_init();
3684
                    return Ok(Some(User::from(&pwd)));
3685
                }
3686
            } else if Errno::last() == Errno::ERANGE {
3687
                // Trigger the internal buffer resizing logic.
3688
                reserve_double_buffer_size(&mut cbuf, buflimit)?;
3689
            } else {
3690
                return Err(Errno::last());
3691
            }
3692
        }
3693
    }
3694
3695
    /// Get a user by UID.
3696
    ///
3697
    /// Internally, this function calls
3698
    /// [getpwuid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
3699
    ///
3700
    /// # Examples
3701
    ///
3702
    /// ```
3703
    /// use nix::unistd::{Uid, User};
3704
    /// // Returns an Result<Option<User>>, thus the double unwrap.
3705
    /// let res = User::from_uid(Uid::from_raw(0)).unwrap().unwrap();
3706
    /// assert_eq!(res.name, "root");
3707
    /// ```
3708
    pub fn from_uid(uid: Uid) -> Result<Option<Self>> {
3709
        // SAFETY: `getpwuid_r` will write to `res` if it initializes the value
3710
        // at `pwd`.
3711
        unsafe {
3712
            User::from_anything(|pwd, cbuf, cap, res| {
3713
                libc::getpwuid_r(uid.0, pwd, cbuf, cap, res)
3714
            })
3715
        }
3716
    }
3717
3718
    /// Get a user by name.
3719
    ///
3720
    /// Internally, this function calls
3721
    /// [getpwnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwnam_r.html)
3722
    ///
3723
    /// # Examples
3724
    ///
3725
    /// ```
3726
    /// use nix::unistd::User;
3727
    /// // Returns an Result<Option<User>>, thus the double unwrap.
3728
    /// let res = User::from_name("root").unwrap().unwrap();
3729
    /// assert_eq!(res.name, "root");
3730
    /// ```
3731
    pub fn from_name(name: &str) -> Result<Option<Self>> {
3732
        let name = match CString::new(name) {
3733
            Ok(c_str) => c_str,
3734
            Err(_nul_error) => return Ok(None),
3735
        };
3736
        // SAFETY: `getpwnam_r` will write to `res` if it initializes the value
3737
        // at `pwd`.
3738
        unsafe {
3739
            User::from_anything(|pwd, cbuf, cap, res| {
3740
                libc::getpwnam_r(name.as_ptr(), pwd, cbuf, cap, res)
3741
            })
3742
        }
3743
    }
3744
}
3745
3746
/// Representation of a Group, based on `libc::group`
3747
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3748
#[derive(Debug, Clone, Eq, PartialEq)]
3749
pub struct Group {
3750
    /// Group name
3751
    pub name: String,
3752
    /// Group password
3753
    pub passwd: CString,
3754
    /// Group ID
3755
    pub gid: Gid,
3756
    /// List of Group members
3757
    pub mem: Vec<String>,
3758
}
3759
3760
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3761
impl From<&libc::group> for Group {
3762
    fn from(gr: &libc::group) -> Group {
3763
        unsafe {
3764
            Group {
3765
                name: if gr.gr_name.is_null() {
3766
                    Default::default()
3767
                } else {
3768
                    CStr::from_ptr(gr.gr_name).to_string_lossy().into_owned()
3769
                },
3770
                passwd: if gr.gr_passwd.is_null() {
3771
                    Default::default()
3772
                } else {
3773
                    CString::new(CStr::from_ptr(gr.gr_passwd).to_bytes())
3774
                        .unwrap()
3775
                },
3776
                gid: Gid::from_raw(gr.gr_gid),
3777
                mem: if gr.gr_mem.is_null() {
3778
                    Default::default()
3779
                } else {
3780
                    Group::members(gr.gr_mem)
3781
                },
3782
            }
3783
        }
3784
    }
3785
}
3786
3787
#[cfg(not(target_os = "redox"))] // RedoxFS does not support passwd
3788
impl Group {
3789
    unsafe fn members(mem: *mut *mut c_char) -> Vec<String> {
3790
        let mut ret = Vec::new();
3791
3792
        for i in 0.. {
3793
            let u = mem.offset(i);
3794
            if (*u).is_null() {
3795
                break;
3796
            } else {
3797
                let s = CStr::from_ptr(*u).to_string_lossy().into_owned();
3798
                ret.push(s);
3799
            }
3800
        }
3801
3802
        ret
3803
    }
3804
3805
    /// # Safety
3806
    ///
3807
    /// If `f` writes to its `*mut *mut libc::group` parameter, then it must
3808
    /// also initialize the value pointed to by its `*mut libc::group`
3809
    /// parameter.
3810
    unsafe fn from_anything<F>(f: F) -> Result<Option<Self>>
3811
    where
3812
        F: Fn(
3813
            *mut libc::group,
3814
            *mut c_char,
3815
            libc::size_t,
3816
            *mut *mut libc::group,
3817
        ) -> libc::c_int,
3818
    {
3819
        let buflimit = 1048576;
3820
        let bufsize = match sysconf(SysconfVar::GETGR_R_SIZE_MAX) {
3821
            Ok(Some(n)) => n as usize,
3822
            Ok(None) | Err(_) => 16384,
3823
        };
3824
3825
        let mut cbuf = Vec::with_capacity(bufsize);
3826
        let mut grp = mem::MaybeUninit::<libc::group>::uninit();
3827
        let mut res = ptr::null_mut();
3828
3829
        loop {
3830
            let error = f(
3831
                grp.as_mut_ptr(),
3832
                cbuf.as_mut_ptr(),
3833
                cbuf.capacity(),
3834
                &mut res,
3835
            );
3836
            if error == 0 {
3837
                if res.is_null() {
3838
                    return Ok(None);
3839
                } else {
3840
                    // SAFETY: `f` guarantees that `grp` is initialized if `res`
3841
                    // is not null.
3842
                    let grp = grp.assume_init();
3843
                    return Ok(Some(Group::from(&grp)));
3844
                }
3845
            } else if Errno::last() == Errno::ERANGE {
3846
                // Trigger the internal buffer resizing logic.
3847
                reserve_double_buffer_size(&mut cbuf, buflimit)?;
3848
            } else {
3849
                return Err(Errno::last());
3850
            }
3851
        }
3852
    }
3853
3854
    /// Get a group by GID.
3855
    ///
3856
    /// Internally, this function calls
3857
    /// [getgrgid_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
3858
    ///
3859
    /// # Examples
3860
    ///
3861
    // Disable this test on all OS except Linux as root group may not exist.
3862
    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
3863
    #[cfg_attr(target_os = "linux", doc = " ```")]
3864
    /// use nix::unistd::{Gid, Group};
3865
    /// // Returns an Result<Option<Group>>, thus the double unwrap.
3866
    /// let res = Group::from_gid(Gid::from_raw(0)).unwrap().unwrap();
3867
    /// assert!(res.name == "root");
3868
    /// ```
3869
    pub fn from_gid(gid: Gid) -> Result<Option<Self>> {
3870
        // SAFETY: `getgrgid_r` will write to `res` if it initializes the value
3871
        // at `grp`.
3872
        unsafe {
3873
            Group::from_anything(|grp, cbuf, cap, res| {
3874
                libc::getgrgid_r(gid.0, grp, cbuf, cap, res)
3875
            })
3876
        }
3877
    }
3878
3879
    /// Get a group by name.
3880
    ///
3881
    /// Internally, this function calls
3882
    /// [getgrnam_r(3)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpwuid_r.html)
3883
    ///
3884
    /// # Examples
3885
    ///
3886
    // Disable this test on all OS except Linux as root group may not exist.
3887
    #[cfg_attr(not(target_os = "linux"), doc = " ```no_run")]
3888
    #[cfg_attr(target_os = "linux", doc = " ```")]
3889
    /// use nix::unistd::Group;
3890
    /// // Returns an Result<Option<Group>>, thus the double unwrap.
3891
    /// let res = Group::from_name("root").unwrap().unwrap();
3892
    /// assert!(res.name == "root");
3893
    /// ```
3894
    pub fn from_name(name: &str) -> Result<Option<Self>> {
3895
        let name = match CString::new(name) {
3896
            Ok(c_str) => c_str,
3897
            Err(_nul_error) => return Ok(None),
3898
        };
3899
        // SAFETY: `getgrnam_r` will write to `res` if it initializes the value
3900
        // at `grp`.
3901
        unsafe {
3902
            Group::from_anything(|grp, cbuf, cap, res| {
3903
                libc::getgrnam_r(name.as_ptr(), grp, cbuf, cap, res)
3904
            })
3905
        }
3906
    }
3907
}
3908
}
3909
3910
feature! {
3911
#![feature = "term"]
3912
3913
/// Get the name of the terminal device that is open on file descriptor fd
3914
/// (see [`ttyname(3)`](https://man7.org/linux/man-pages/man3/ttyname.3.html)).
3915
#[cfg(not(target_os = "fuchsia"))]
3916
pub fn ttyname(fd: RawFd) -> Result<PathBuf> {
3917
    const PATH_MAX: usize = libc::PATH_MAX as usize;
3918
    let mut buf = vec![0_u8; PATH_MAX];
3919
    let c_buf = buf.as_mut_ptr() as *mut libc::c_char;
3920
3921
    let ret = unsafe { libc::ttyname_r(fd, c_buf, buf.len()) };
3922
    if ret != 0 {
3923
        return Err(Errno::from_i32(ret));
3924
    }
3925
3926
    let nul = buf.iter().position(|c| *c == b'\0').unwrap();
3927
    buf.truncate(nul);
3928
    Ok(OsString::from_vec(buf).into())
3929
}
3930
}
3931
3932
feature! {
3933
#![all(feature = "socket", feature = "user")]
3934
3935
/// Get the effective user ID and group ID associated with a Unix domain socket.
3936
///
3937
/// See also [getpeereid(3)](https://www.freebsd.org/cgi/man.cgi?query=getpeereid)
3938
#[cfg(any(
3939
    target_os = "macos",
3940
    target_os = "ios",
3941
    target_os = "freebsd",
3942
    target_os = "openbsd",
3943
    target_os = "netbsd",
3944
    target_os = "dragonfly",
3945
))]
3946
pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)> {
3947
    let mut uid = 1;
3948
    let mut gid = 1;
3949
3950
    let ret = unsafe { libc::getpeereid(fd, &mut uid, &mut gid) };
3951
3952
    Errno::result(ret).map(|_| (Uid(uid), Gid(gid)))
3953
}
3954
}
3955
3956
feature! {
3957
#![all(feature = "fs")]
3958
3959
/// Set the file flags.
3960
///
3961
/// See also [chflags(2)](https://www.freebsd.org/cgi/man.cgi?query=chflags&sektion=2)
3962
#[cfg(any(
3963
    target_os = "openbsd",
3964
    target_os = "netbsd",
3965
    target_os = "freebsd",
3966
    target_os = "dragonfly",
3967
    target_os = "macos",
3968
    target_os = "ios"
3969
))]
3970
pub fn chflags<P: ?Sized + NixPath>(path: &P, flags: FileFlag) -> Result<()> {
3971
    let res = path.with_nix_path(|cstr| unsafe {
3972
        libc::chflags(cstr.as_ptr(), flags.bits())
3973
    })?;
3974
3975
    Errno::result(res).map(drop)
3976
}
3977
}