1 unstable release
Uses new Rust 2024
| 0.1.0 | Mar 6, 2026 |
|---|
#548 in Unix APIs
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