nix

repository·master·Indexed 25 days ago

https://github.com/nix-rust/nix

Rust friendly bindings to *nix platform APIs (Linux, Darwin, etc.). Version 0.31.3 provides safe, idiomatic wrappers around libc functionality, using Rust's type system to enforce correct system call usage and returning nix::Result instead of raw return codes. It supports a wide range of Tier 1, 2, and 3 targets and requires Rust 1.69 or higher. Optional functionality is enabled via Cargo features, including support for process management, networking, filesystem operations, and kernel module loading.

Tokens
10.4K
Snippets
22
Records
72
Agent score
82%

What's inside nix

  1. Overview of nix

    master
    nix provides friendly, safe Rust bindings to various *nix platform APIs (such as Linux and Darwin). Unlike the libc crate which exposes unsafe functions, nix wraps libc functionality with types and abstractions that enforce legal and safe usage, returning nix::Result instead of requiring manual handling of return codes and errno.
  2. Handle syscall and libc function errors

    master

    Most syscall and libc functions return an ErrnoSentinel value on error. To convert these into a standard Rust Result<T, Errno>, use the Errno::result() utility function. This provides a more idiomatic way to handle errors in Rust compared to checking raw integer return codes.

    pub fn dup(oldfd: RawFd) -> Result<RawFd> {
        let res = unsafe { libc::dup(oldfd) };
    
        Errno::result(res)
    }
  3. Use MaybeUninit for libc-initialized structures

    master
    When using a libc function to initialize a variable that allows for uninitialized memory, define the variable using std::mem::MaybeUninit. This avoids the performance overhead of zeroing or manually initializing the memory before the libc call.
  4. Deprecate an interface

    master

    When an interface needs to be removed, it must first be deprecated for at least one release. Use the #[deprecated] attribute at the top of the interface. The <Version> should be the version where the deprecation occurs (typically the next release), and the note should provide a user-friendly explanation, such as suggesting a replacement interface.

    #[deprecated(since = "<Version>", note = "<Note to our user>")]
  5. Enable Nix features via Cargo

    master

    Nix uses Cargo features to enable optional functionality. You can enable these in any combination in your Cargo.toml to include specific *nix API bindings:

    • acct - Process accounting
    • aio - POSIX AIO
    • dir - Directory iteration
    • env - Environment variables
    • event - Event-driven APIs (e.g., kqueue, epoll)
    • fanotify - Linux fanotify filesystem monitoring
    • feature - Runtime OS characteristic querying
    • fs - File system functionality
    • hostname - System hostname management
    • inotify - Linux inotify filesystem notifications
    • ioctl - ioctl syscall and wrappers
    • kmod - Kernel module loading/unloading
    • mman - Memory management
    • mount - File system mounting
    • mqueue - POSIX message queues
    • net - Networking functionality
    • personality - Process execution domain
    • poll - poll and select APIs
    • process - Process management
    • pthread - POSIX threads
    • ptrace - Process tracing/debugging
    • quota - File system quotas
    • reboot - System rebooting
    • resource - Process resource limits
    • sched - Process scheduling
    • socket - Sockets
    • signal - Signal handling
    • syslog - System logging
    • term - Terminal control
    • time - OS clock querying
    • ucontext - User thread context
    • uio - Vectored I/O
    • user - Users and groups
    • zerocopy - sendfile and copy_file_range APIs
  6. Monitor filesystem events with Inotify

    master

    The Inotify API provides a Linux-only mechanism to monitor filesystem events. You can initialize an instance, add watches on specific paths, and read triggered events.

    To use it:

    1. Initialize an Inotify instance using Inotify::init(flags: InitFlags).
    2. Add a watch to a path using instance.add_watch(path, mask: AddWatchFlags), which returns a WatchDescriptor.
    3. Retrieve events using instance.read_events(), which returns a Vec<InotifyEvent>.
    4. Remove a watch using instance.rm_watch(wd: WatchDescriptor).
    # use nix::sys::inotify::{AddWatchFlags,InitFlags,Inotify};
    #
    // We create a new inotify instance.
    let instance = Inotify::init(InitFlags::empty()).unwrap();
    
    // We add a new watch on directory "test" for all events.
    let wd = instance.add_watch("test", AddWatchFlags::IN_ALL_EVENTS).unwrap();
    
    loop {
        // We read from our inotify instance for events.
        let events = instance.read_events().unwrap();
        println!("Events: {:?}", events);
    }
  7. Use the Epoll API for event notification

    master

    The Epoll struct provides a safe wrapper around the Linux epoll system calls. You can use it to monitor multiple file descriptors for I/O events.

    Workflow:

    1. Create an instance using Epoll::new(flags).
    2. Register file descriptors using add(), modify(), or delete().
    3. Wait for events using wait(), which blocks until events occur or a timeout is reached.

    Note: Epoll wraps an OwnedFd, ensuring the file descriptor is closed when the object is dropped.

  8. Compare libc and nix APIs

    master

    The following example demonstrates how nix improves upon the libc API by providing a safe, high-level interface for the gethostname system call. While libc requires an unsafe block and manual buffer management, nix returns a Result<OsString>.

    // libc api (unsafe, requires handling return code/errno)
    pub unsafe extern fn gethostname(name: *mut c_char, len: size_t) -> c_int;
    
    // nix api (returns a nix::Result<OsString>)
    pub fn gethostname() -> Result<OsString>;
  9. Define bitflags using libc_bitflags!

    master

    For C functions that use bitwise flags, use the libc_bitflags! macro. This is a wrapper around the bitflags crate that automatically pulls constant values from libc. The resulting type should follow CamelCase naming, typically ending in Flags (e.g., ProtFlags for constants starting with PROT_).

    libc_bitflags!{
        pub struct ProtFlags: libc::c_int {
            PROT_NONE;
            PROT_READ;
            PROT_WRITE;
            PROT_EXEC;
            #[cfg(linux_android)]
            PROT_GROWSDOWN;
            #[cfg(linux_android)]
            PROT_GROWSUP;
        }
    }
  10. Supported Platforms and Tiers

    master

    nix support is categorized into three tiers based on CI testing rigor:

    • Tier 1: Builds and tests are run in CI. Failures block new code.
    • Tier 2: Builds are run in CI. Build failures block new code; test failures do not.
    • Tier 3: Builds are run in CI. Build failures do not necessarily block new code.

    Tier 1 Targets:

    • aarch64-apple-darwin
    • aarch64-unknown-linux-gnu
    • arm-unknown-linux-gnueabi
    • armv7-unknown-linux-gnueabihf
    • i686-unknown-freebsd
    • i686-unknown-linux-gnu
    • i686-unknown-linux-musl
    • mips-unknown-linux-gnu
    • mips64-unknown-linux-gnuabi64
    • mips64el-unknown-linux-gnuabi64
    • mipsel-unknown-linux-gnu
    • powerpc64le-unknown-linux-gnu
    • x86_64-unknown-freebsd
    • x86_64-unknown-linux-gnu
    • x86_64-unknown-linux-musl