Include relevant subset of code of libfuse-sys that has not been released by the original maintainer. By this opportunity, also remove the high level api of fuse, because we don't need it. Long term goal would be to migrate to a rust port with less unsafe code.

Upate build instructions
This commit is contained in:
Johannes Leupolz 2025-10-30 23:15:57 +00:00
parent f008dd6a4f
commit 6afa8acaa8
8 changed files with 204 additions and 6 deletions

View file

@ -1,6 +1,7 @@
[workspace] [workspace]
members = [ members = [
"uinput-ioctls", "uinput-ioctls",
"cuse-lowlevel",
"vuinputd", "vuinputd",
"vuinput-examples", "vuinput-examples",
] ]

19
cuse-lowlevel/Cargo.toml Normal file
View file

@ -0,0 +1,19 @@
[package]
name = "cuse-lowlevel"
version = "0.1.0"
edition = "2021"
license = "MIT AND LGPL-2.0-or-later"
description = "Raw bindings to the low level api of cuse and fuse in libfuse3"
repository = "https://github.com/joleuger/vuinputd"
authors = ["Richard Wiedenhöft <richard@wiedenhoeft.xyz>", "Johannes Leupolz <dev@leupolz.eu>"]
categories = ["external-ffi-bindings"]
keywords = ["cuse", "fuse", "bindings", "filesystem", "fs"]
readme = "README.md"
build = "build.rs"
[dependencies]
libc = "0.2"
[build-dependencies]
bindgen = "0.60"
pkg-config = "0.3"

28
cuse-lowlevel/README.md Normal file
View file

@ -0,0 +1,28 @@
# cuse-lowlevel
[crates.io]: https://crates.io/crates/cuse-lowlevel
**Raw bindings to the low level api of cuse and fuse in libfuse3**
---
## About
This crate is heavily based on libfuse-sys by Richard Wiedenhöft. See the [original repository](https://github.com/richard-w/libfuse-sys)
This fork here contains only the relevant subset of code of libfuse-sys to access the low-level api of cuse.
## Using cuse-lowlevel
Add the dependencies to your Cargo.toml
```toml
[dependencies]
cuse-lowlevel = { version = "0.1"}
libc = "*"
```
## License
This crate itself is published under the MIT license while libfuse is published under
LGPL2+. Take special care to ensure the terms of the LGPL2+ are honored when using this
crate.

120
cuse-lowlevel/build.rs Normal file
View file

@ -0,0 +1,120 @@
// SPDX-License-Identifier: MIT
//
// Author: Richard Wiedenhöft <richard@wiedenhoeft.xyz>
// Author: Johannes Leupolz <dev@leupolz.eu>
//
// This library is heavily baased on https://github.com/richard-w/libfuse-sys
// but adopted to only provide the low-level modules of fuse and cuse.
extern crate bindgen;
extern crate pkg_config;
use std::env;
use std::iter;
use std::path::PathBuf;
const FUSE_USE_VERSION: u32 = 314; //fuse version of ubuntu 24.04
fn fuse_binding_filter(builder: bindgen::Builder) -> bindgen::Builder {
let builder = builder
// Whitelist "fuse_*" symbols and blocklist everything else
.allowlist_recursively(false)
.allowlist_type("(?i)^fuse.*")
.allowlist_function("(?i)^fuse.*")
.allowlist_var("(?i)^fuse.*")
.blocklist_type("fuse_log_func_t")
.blocklist_function("fuse_set_log_func");
builder
}
fn cuse_binding_filter(builder: bindgen::Builder) -> bindgen::Builder {
builder
// Whitelist "cuse_*" symbols and blocklist everything else
.allowlist_recursively(false)
.allowlist_type("(?i)^cuse.*")
.allowlist_function("(?i)^cuse.*")
.allowlist_var("(?i)^cuse.*")
}
fn generate_fuse_bindings(
header: &str,
fuse_lib: &pkg_config::Library,
binding_filter: fn(bindgen::Builder) -> bindgen::Builder,
) {
// Find header file
let mut header_path: Option<PathBuf> = None;
for include_path in fuse_lib.include_paths.iter() {
let test_path = include_path.join(header);
if test_path.exists() {
header_path = Some(test_path);
break;
}
}
let header_path = header_path
.unwrap_or_else(|| panic!("Cannot find {}", header))
.to_str()
.unwrap_or_else(|| panic!("Path to {} contains invalid unicode characters", header))
.to_string();
// Gather fuse defines
let defines = fuse_lib.defines.iter().map(|(key, val)| match val {
Some(val) => format!("-D{}={}", key, val),
None => format!("-D{}", key),
});
// Gather include paths
let includes = fuse_lib
.include_paths
.iter()
.map(|dir| format!("-I{}", dir.display()));
// API version definition
let api_define = iter::once(format!("-DFUSE_USE_VERSION={}", FUSE_USE_VERSION));
// Chain compile flags
let compile_flags = defines.chain(includes).chain(api_define);
// Create bindgen builder
let mut builder = bindgen::builder()
// Add clang flags
.clang_args(compile_flags)
// Derive Debug, Copy and Default
.derive_default(true)
.derive_copy(true)
.derive_debug(true)
// Add CargoCallbacks so build.rs is rerun on header changes
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
builder = binding_filter(builder);
// Generate bindings
let bindings = builder
.header(header_path)
.generate()
.unwrap_or_else(|_| panic!("Failed to generate {} bindings", header));
// Write bindings to file
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let bindings_path = out_dir.join(&header.replace(".h", ".rs"));
bindings
.write_to_file(&bindings_path)
.unwrap_or_else(|_| panic!("Failed to write {}", bindings_path.display()));
}
fn main() {
let mut pkgcfg = pkg_config::Config::new();
// Find libfuse
let fuse3_lib = pkgcfg.cargo_metadata(true).probe("fuse3").expect("Failed to find pkg-config module fuse3");
// Generate lowlevel bindings
generate_fuse_bindings(
"fuse_lowlevel.h",
&fuse3_lib,
fuse_binding_filter,
);
// Generate lowlevel cuse bindings
generate_fuse_bindings(
"cuse_lowlevel.h",
&fuse3_lib,
cuse_binding_filter,
);
}

31
cuse-lowlevel/src/lib.rs Normal file
View file

@ -0,0 +1,31 @@
// SPDX-License-Identifier: MIT
//
// Author: Richard Wiedenhöft <richard@wiedenhoeft.xyz>
// Author: Johannes Leupolz <dev@leupolz.eu>
//
// This library is heavily baased on https://github.com/richard-w/libfuse-sys
// but adopted to only provide the low-level modules of fuse and cuse.
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(clippy::useless_transmute)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::missing_safety_doc)]
use libc::*;
pub mod fuse_lowlevel {
use super::*;
include!(concat!(env!("OUT_DIR"), "/fuse_lowlevel.rs"));
}
pub mod cuse_lowlevel {
use super::*;
include!(concat!(env!("OUT_DIR"), "/cuse_lowlevel.rs"));
use fuse_lowlevel::{
fuse_args, fuse_conn_info, fuse_file_info, fuse_pollhandle, fuse_req_t, fuse_session,
};
}

View file

@ -3,7 +3,7 @@
## 🔹 Prerequisites ## 🔹 Prerequisites
* Rust toolchain (recommended: install via [rustup](https://rustup.rs)) * Rust toolchain (recommended: install via [rustup](https://rustup.rs))
* Linux with `libfuse3-dev`, `libudev-dev` and `pkg-config` installed (for cuse/udev access) * Linux with `build-essential`, `libc6-dev`, `libfuse3-dev`, `libudev-dev` and `pkg-config` installed (for cuse/udev access)
--- ---
@ -19,7 +19,7 @@ cd vuinputd
Build all crates (daemon, forwarder, announce, common): Build all crates (daemon, forwarder, announce, common):
```bash ```bash
apt-get install libfuse3-dev pkg-config fuse3 libudev-dev apt-get install build-essential libc6-dev libfuse3-dev pkg-config fuse3 libudev-dev
cargo build --release cargo build --release
``` ```

View file

@ -8,9 +8,9 @@ description = "Container-safe mediation daemon for /dev/uinput using CUSE."
repository = "https://github.com/joleuger/vuinputd" repository = "https://github.com/joleuger/vuinputd"
[dependencies] [dependencies]
uinput-ioctls = { path = "../uinput-ioctls" } uinput-ioctls = { path = "../uinput-ioctls", version = "0.1" }
#fuse = "0.3" # FUSE/ CUSE interface #fuse = "0.3" # FUSE/ CUSE interface
libfuse-sys = { git = "https://github.com/richard-w/libfuse-sys.git", rev = "a9bc85e3c24d44d8577e79759c4ccf0a18050037", features = ["fuse_35","cuse_lowlevel"] } cuse-lowlevel = { path = "../cuse-lowlevel", version = "0.1" }
#fuse-backend-rs = "0.13.0" #fuse-backend-rs = "0.13.0"
nix = { version = "0.30", features = ["ioctl","process","sched","fs","event","user","socket","uio"] } nix = { version = "0.30", features = ["ioctl","process","sched","fs","event","user","socket","uio"] }
libc = "0.2" # raw system calls libc = "0.2" # raw system calls

View file

@ -21,8 +21,7 @@
use libc::O_CLOEXEC; use libc::O_CLOEXEC;
use libc::{iovec, off_t, size_t, EBADRQC, EIO, ENOENT}; use libc::{iovec, off_t, size_t, EBADRQC, EIO, ENOENT};
use libc::{uinput_abs_setup, uinput_ff_erase, uinput_ff_upload, uinput_setup}; use libc::{uinput_abs_setup, uinput_ff_erase, uinput_ff_upload, uinput_setup};
use libfuse_sys::cuse_lowlevel; use ::cuse_lowlevel::*;
use libfuse_sys::fuse_lowlevel;
use log::{debug, error, info, trace}; use log::{debug, error, info, trace};
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};