diff --git a/Cargo.toml b/Cargo.toml index 5a7149c..4128079 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "uinput-ioctls", + "cuse-lowlevel", "vuinputd", "vuinput-examples", ] diff --git a/cuse-lowlevel/Cargo.toml b/cuse-lowlevel/Cargo.toml new file mode 100644 index 0000000..074922e --- /dev/null +++ b/cuse-lowlevel/Cargo.toml @@ -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 ", "Johannes Leupolz "] +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" \ No newline at end of file diff --git a/cuse-lowlevel/README.md b/cuse-lowlevel/README.md new file mode 100644 index 0000000..3e2f10f --- /dev/null +++ b/cuse-lowlevel/README.md @@ -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. \ No newline at end of file diff --git a/cuse-lowlevel/build.rs b/cuse-lowlevel/build.rs new file mode 100644 index 0000000..0c45b92 --- /dev/null +++ b/cuse-lowlevel/build.rs @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +// +// Author: Richard Wiedenhöft +// Author: Johannes Leupolz +// +// 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 = 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, + ); +} \ No newline at end of file diff --git a/cuse-lowlevel/src/lib.rs b/cuse-lowlevel/src/lib.rs new file mode 100644 index 0000000..5a3b6c1 --- /dev/null +++ b/cuse-lowlevel/src/lib.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// +// Author: Richard Wiedenhöft +// Author: Johannes Leupolz +// +// 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, + }; +} \ No newline at end of file diff --git a/docs/BUILD.md b/docs/BUILD.md index 774f0ae..96e314f 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -3,7 +3,7 @@ ## 🔹 Prerequisites * 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): ```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 ``` diff --git a/vuinputd/Cargo.toml b/vuinputd/Cargo.toml index ae4690d..b252cd7 100644 --- a/vuinputd/Cargo.toml +++ b/vuinputd/Cargo.toml @@ -8,9 +8,9 @@ description = "Container-safe mediation daemon for /dev/uinput using CUSE." repository = "https://github.com/joleuger/vuinputd" [dependencies] -uinput-ioctls = { path = "../uinput-ioctls" } +uinput-ioctls = { path = "../uinput-ioctls", version = "0.1" } #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" nix = { version = "0.30", features = ["ioctl","process","sched","fs","event","user","socket","uio"] } libc = "0.2" # raw system calls diff --git a/vuinputd/src/main.rs b/vuinputd/src/main.rs index 53d8761..4be51ac 100644 --- a/vuinputd/src/main.rs +++ b/vuinputd/src/main.rs @@ -21,8 +21,7 @@ use libc::O_CLOEXEC; use libc::{iovec, off_t, size_t, EBADRQC, EIO, ENOENT}; use libc::{uinput_abs_setup, uinput_ff_erase, uinput_ff_upload, uinput_setup}; -use libfuse_sys::cuse_lowlevel; -use libfuse_sys::fuse_lowlevel; +use ::cuse_lowlevel::*; use log::{debug, error, info, trace}; use std::collections::HashMap; use std::ffi::{CStr, CString};