#syscalls #linux #linux-mount #mount #openat2

lisy

Linux specific high and middle level system level API library

1 unstable release

Uses new Rust 2024

0.1.0 Mar 6, 2026

#548 in Unix APIs

MIT license

140KB
3K SLoC

Linux specific System API

Higher level APIs targeting newer Linux kernel features.

This crate provides somewhat higher level access to more modern features of the Linux kernel, such as builder-style access to the new mount API, openat2(2) call with a builder for the struct open_how parameters, all the new features of the statx(2) system call (such as finding out whether a path is a mount point), or to build user namespace file descriptors (which requires spawning processes and is therefore somewhat inconvenient to do manually).

See the documentation for details.

$ cargo doc --no-deps --open

Contribution

See the CONTRIBUTING.md file.


lib.rs:

Linux specific System API

Higher level APIs targeting newer Linux kernel features.

This crate provides somewhat higher level access to more modern features of the Linux kernel, such as builder-style access to the new mount API, openat2(2) call with a builder for the struct open_how parameters, all the new features of the statx(2) system call (such as finding out whether a path is a mount point), or to build user namespace file descriptors (which requires spawning processes and is therefore somewhat inconvenient to do manually).

The new open API:

In the standard library files are simply opened by path, but this leaves out some important features:

  • Opening files relative to a directory handle.
  • Treating such a handle as if we were chrooted into the directory.
  • Deciding whether or not symlinks should be followed, not only for the final component, but also during the entire path traversal.

The OpenHow builder can be used for these things.

#
#
#
#
use lisy::open::OpenHow;

let ct_dir = OpenHow::new_directory()       // start with `O_DIRECTORY | O_CLOEXEC | O_NOCTTY`
    .resolve_no_symlinks(true)              // do not allow *any* symlinks in the path
    .resolve_no_xdev(true)                  // do not allow crossing file system boundaries
    .open("/my/container")                  // returns an `OwnedFd`
    .context("failed to open /my/container")?;

// Now open a file within `/my/container` as if it was the root file system:
let file_in_container = OpenHow::new_read()
    .at_fd(&ct_dir)                         // open relative to `ct_dir`
    .resolve_in_root(true)                  // virtually "chroot" into `ct_dir`
    .open_file("/usr/share/some/file")      // convenience method to get a `std::fs::File`
    .context("failed to open /my/container/usr/share/some/file")?;
#

The new mount API:

This provides handles representing file systems, superblocks and mount trees.

#
#
#
#
use lisy::mount::{Mount, MountSetAttr, MoveMount, OpenTree};
use lisy::userns::{IdMapping, Userns};

// Open a directory as a new detached mount tree:
let mount = Mount::open_tree("/mnt/a", OpenTree::CLOEXEC | OpenTree::CLONE, 0)
    .context("failed to clone tree at /mnt/a")?;

// Prepare a user namespace for ID mapping
let userns = Userns::builder().context("failed to prepare user namespace")?;
userns.map_gids(&[IdMapping::new(0..65536, 100000)])?;
userns.map_uids(&[IdMapping::new(0..65536, 100000)])?;
let userns = userns
    .into_fd()
    .context("failed to finish creating user namespace")?;

// Apply the namespace
mount
    .setattr(
        &MountSetAttr::new().idmap(&userns),
        libc::AT_RECURSIVE | libc::AT_NO_AUTOMOUNT,
    )
    .context("failed to apply idmapping to mount tree")?;

// Bind-mount into place:
mount
    .move_mount("/mnt/mapped", MoveMount::empty())
    .context("failed to move id-mapped mount into place")?;
#

Dependencies

~140KB