From 1f8fc31ddc1975a1f2e7c2fa8f7f611eab761680 Mon Sep 17 00:00:00 2001 From: Kayla Firestack Date: Mon, 18 Oct 2021 13:27:51 -0400 Subject: [PATCH] split mount into a library crate for rust reuse update makefile to output shared library and rust build fix default.nix to properly get the binary name for `ln`ing - move binary to main.rs add rustfmt and gitignore files move build.rs file into bch_bindgen for reuse between projects add outputs to nix flake and checks add mount.toml to makefile --- Makefile | 40 +- flake.nix | 8 +- rust-src/bch_bindgen/.gitignore | 15 + rust-src/bch_bindgen/Cargo.lock | 484 ++++++++++++++++++ rust-src/bch_bindgen/Cargo.toml | 26 + rust-src/bch_bindgen/build.rs | 74 +++ rust-src/bch_bindgen/rustfmt.toml | 2 + rust-src/bch_bindgen/src/bcachefs.rs | 124 +++++ rust-src/bch_bindgen/src/keyutils.rs | 6 + .../src/keyutils_wrapper.h | 0 rust-src/bch_bindgen/src/lib.rs | 7 + .../src/libbcachefs_wrapper.h | 4 + rust-src/bch_bindgen/src/rs.rs | 58 +++ rust-src/mount/.gitignore | 15 + rust-src/mount/Cargo.lock | 350 +++++++++++-- rust-src/mount/Cargo.toml | 28 +- rust-src/mount/README.md | 62 +++ rust-src/mount/build.rs | 67 --- rust-src/mount/default.nix | 4 +- rust-src/mount/module.nix | 54 ++ rust-src/mount/rustfmt.toml | 2 + rust-src/mount/src/filesystem.rs | 238 +++++---- rust-src/mount/src/key.rs | 23 +- rust-src/mount/src/lib.rs | 181 ++----- rust-src/mount/src/main.rs | 63 +++ 25 files changed, 1545 insertions(+), 390 deletions(-) create mode 100644 rust-src/bch_bindgen/.gitignore create mode 100644 rust-src/bch_bindgen/Cargo.lock create mode 100644 rust-src/bch_bindgen/Cargo.toml create mode 100644 rust-src/bch_bindgen/build.rs create mode 100644 rust-src/bch_bindgen/rustfmt.toml create mode 100644 rust-src/bch_bindgen/src/bcachefs.rs create mode 100644 rust-src/bch_bindgen/src/keyutils.rs rename rust-src/{mount => bch_bindgen}/src/keyutils_wrapper.h (100%) create mode 100644 rust-src/bch_bindgen/src/lib.rs rename rust-src/{mount => bch_bindgen}/src/libbcachefs_wrapper.h (59%) create mode 100644 rust-src/bch_bindgen/src/rs.rs create mode 100644 rust-src/mount/.gitignore create mode 100644 rust-src/mount/README.md delete mode 100644 rust-src/mount/build.rs create mode 100644 rust-src/mount/module.nix create mode 100644 rust-src/mount/rustfmt.toml create mode 100644 rust-src/mount/src/main.rs diff --git a/Makefile b/Makefile index 9ee1ff0..dc56d7b 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,13 @@ CFLAGS+=-std=gnu89 -O2 -g -MMD -Wall \ -DVERSION_STRING='"$(VERSION)"' \ $(EXTRA_CFLAGS) LDFLAGS+=$(CFLAGS) $(EXTRA_LDFLAGS) +CARGO_ARGS= +CARGO=cargo $(CARGO_ARGS) +CARGO_PROFILE=release +# CARGO_PROFILE=debug +CARGO_BUILD_ARGS=--$(CARGO_PROFILE) +CARGO_BUILD=$(CARGO) build $(CARGO_BUILD_ARGS) VERSION?=$(shell git describe --dirty=+ 2>/dev/null || echo v0.1-nogit) include Makefile.compiler @@ -49,7 +55,6 @@ endif CFLAGS+=$(PKGCONFIG_CFLAGS) LDLIBS+=$(PKGCONFIG_LDLIBS) - LDLIBS+=-lm -lpthread -lrt -lscrypt -lkeyutils -laio -ldl LDLIBS+=$(EXTRA_LDLIBS) @@ -72,7 +77,10 @@ ifeq ($(STATUS),0) endif .PHONY: all -all: bcachefs bcachefs.5 +all: bcachefs bcachefs.5 lib + +.PHONY: lib +lib: libbcachefs.so .PHONY: tests tests: tests/test_helper @@ -107,19 +115,25 @@ DEPS=$(SRCS:.c=.d) OBJS=$(SRCS:.c=.o) bcachefs: $(filter-out ./tests/%.o, $(OBJS)) -MOUNT_SRCS=$(shell find mount/src -type f -iname '*.rs') \ - mount/Cargo.toml mount/Cargo.lock mount/build.rs +RUST_SRCS=$(shell find rust-src/ -type f -iname '*.rs') +MOUNT_SRCS=$(filter %mount, $(RUST_SRCS)) debug: CFLAGS+=-Werror -DCONFIG_BCACHEFS_DEBUG=y -DCONFIG_VALGRIND=y debug: bcachefs -libbcachefs_mount.a: $(MOUNT_SRCS) - LIBBCACHEFS_INCLUDE=$(CURDIR) cargo build --manifest-path mount/Cargo.toml --release - cp mount/target/release/libbcachefs_mount.a $@ - MOUNT_OBJ=$(filter-out ./bcachefs.o ./tests/%.o ./cmd_%.o , $(OBJS)) -mount.bcachefs: libbcachefs_mount.a $(MOUNT_OBJ) - $(CC) -Wl,--gc-sections libbcachefs_mount.a $(MOUNT_OBJ) -o $@ $(LDLIBS) +libbcachefs.so: LDFLAGS+=-shared +libbcachefs.so: $(MOUNT_OBJ) + $(CC) $(LDFLAGS) $+ -o $@ $(LDLIBS) + +MOUNT_TOML=rust-src/mount/Cargo.toml +mount.bcachefs: lib $(MOUNT_SRCS) + LIBBCACHEFS_LIB=$(CURDIR) \ + LIBBCACHEFS_INCLUDE=$(CURDIR) \ + $(CARGO_BUILD) --manifest-path $(MOUNT_TOML) + + ln -f rust-src/mount/target/$(CARGO_PROFILE)/bcachefs-mount $@ + tests/test_helper: $(filter ./tests/%.o, $(OBJS)) @@ -136,7 +150,7 @@ cmd_version.o : .version .PHONY: install install: INITRAMFS_HOOK=$(INITRAMFS_DIR)/hooks/bcachefs install: INITRAMFS_SCRIPT=$(INITRAMFS_DIR)/scripts/local-premount/bcachefs -install: bcachefs +install: bcachefs lib $(INSTALL) -m0755 -D bcachefs -t $(DESTDIR)$(ROOT_SBINDIR) $(INSTALL) -m0755 fsck.bcachefs $(DESTDIR)$(ROOT_SBINDIR) $(INSTALL) -m0755 mkfs.bcachefs $(DESTDIR)$(ROOT_SBINDIR) @@ -144,13 +158,15 @@ install: bcachefs $(INSTALL) -m0755 -D initramfs/script $(DESTDIR)$(INITRAMFS_SCRIPT) $(INSTALL) -m0755 -D initramfs/hook $(DESTDIR)$(INITRAMFS_HOOK) $(INSTALL) -m0755 -D mount.bcachefs.sh $(DESTDIR)$(ROOT_SBINDIR) + $(INSTALL) -m0755 -D libbcachefs.so -t $(PREFIX)/lib/ + sed -i '/^# Note: make install replaces/,$$d' $(DESTDIR)$(INITRAMFS_HOOK) echo "copy_exec $(ROOT_SBINDIR)/bcachefs /sbin/bcachefs" >> $(DESTDIR)$(INITRAMFS_HOOK) .PHONY: clean clean: $(RM) bcachefs mount.bcachefs libbcachefs_mount.a tests/test_helper .version $(OBJS) $(DEPS) $(DOCGENERATED) - $(RM) -rf mount/target + $(RM) -rf rust-src/*/target .PHONY: deb deb: all diff --git a/flake.nix b/flake.nix index 36dda0e..02df6c7 100644 --- a/flake.nix +++ b/flake.nix @@ -32,15 +32,19 @@ tools toolsValgrind toolsDebug + mount + bch_bindgen kernel; - musl-tools = pkgs.pkgsMusl.bcachefs.tools; - musl-mount = pkgs.pkgsMusl.bcachefs.mount; + tools-musl = pkgs.pkgsMusl.bcachefs.tools; + mount-musl = pkgs.pkgsMusl.bcachefs.mount; }; checks = { kernelSrc = packages.kernel.src; inherit (packages) + mount + bch_bindgen toolsValgrind; }; diff --git a/rust-src/bch_bindgen/.gitignore b/rust-src/bch_bindgen/.gitignore new file mode 100644 index 0000000..0aa133a --- /dev/null +++ b/rust-src/bch_bindgen/.gitignore @@ -0,0 +1,15 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +# Required By Nix +# Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/rust-src/bch_bindgen/Cargo.lock b/rust-src/bch_bindgen/Cargo.lock new file mode 100644 index 0000000..2138d33 --- /dev/null +++ b/rust-src/bch_bindgen/Cargo.lock @@ -0,0 +1,484 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bch_bindgen" +version = "0.1.0" +dependencies = [ + "anyhow", + "bindgen", + "bitfield", + "byteorder", + "gag", + "libc", + "memoffset", + "pkg-config", + "tracing", + "tracing-attributes", + "udev", + "uuid", +] + +[[package]] +name = "bindgen" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "0.19.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cexpr" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10612c0ec0e0a1ff0e97980647cb058a6e7aedb913d01d009c406b8b7d0b26ee" +dependencies = [ + "glob", + "libc", +] + +[[package]] +name = "filedescriptor" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed3d8a5e20435ff00469e51a0d82049bae66504b5c429920dadf9bb54d47b3f" +dependencies = [ + "libc", + "thiserror", + "winapi", +] + +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] +name = "gag" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a713bee13966e9fbffdf7193af71d54a6b35a0bb34997cd6c9519ebeb5005972" +dependencies = [ + "filedescriptor", + "tempfile", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6" + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nom" +version = "6.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" +dependencies = [ + "bitvec", + "funty", + "memchr", + "version_check", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + +[[package]] +name = "pkg-config" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9b1041b4387893b91ee6746cddfc28516aff326a3519fb2adf820932c5e6cb" + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro2" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + +[[package]] +name = "rand" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "syn" +version = "1.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5239bc68e0fef57495900cfea4e8dc75596d9a319d7e16b1e0a440d24e6fe0a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602eca064b2d83369e2b2f34b09c70b605402801927c65c11071ac911d299b88" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad553cc2c78e8de258400763a647e80e6d1b31ee237275d756f6836d204494c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98863d0dd09fa59a1b79c6750ad80dbda6b75f4e71c437a6a1a8cb91a8bcbd77" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46125608c26121c81b0c6d693eab5a420e416da7e43c426d2e8f7df8da8a3acf" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "udev" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24953d50a3bce0f5f5a9a2766567072dc9af8096f8c40ea81815da651066bc9f" +dependencies = [ + "libc", + "libudev-sys", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/rust-src/bch_bindgen/Cargo.toml b/rust-src/bch_bindgen/Cargo.toml new file mode 100644 index 0000000..91cc77f --- /dev/null +++ b/rust-src/bch_bindgen/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "bch_bindgen" +version = "0.1.0" +authors = [ "Kayla Firestack ", "Yuxuan Shui " ] +edition = "2018" + +[lib] +crate-type = ["lib"] +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tracing = "0.1.26" +anyhow = "1.0" +udev = "0.4" +uuid = "0.8" +bitfield = "0.13" +memoffset = "0.5" +byteorder = "1.3" +tracing-attributes = "0.1.15" +libc = "0.2.69" +gag = "1.0.0" + + +[build-dependencies] +pkg-config = "0.3" +bindgen = { version = "0.59.1", default-features = false } diff --git a/rust-src/bch_bindgen/build.rs b/rust-src/bch_bindgen/build.rs new file mode 100644 index 0000000..fd570db --- /dev/null +++ b/rust-src/bch_bindgen/build.rs @@ -0,0 +1,74 @@ +fn main() { + use std::path::PathBuf; + // use std::process::Command; + + let out_dir: PathBuf = std::env::var_os("OUT_DIR").expect("ENV Var 'OUT_DIR' Expected").into(); + let top_dir: PathBuf = std::env::var_os("CARGO_MANIFEST_DIR") + .expect("ENV Var 'CARGO_MANIFEST_DIR' Expected") + .into(); + let libbcachefs_inc_dir = + std::env::var("LIBBCACHEFS_INCLUDE").unwrap_or_else(|_| top_dir.join("libbcachefs").display().to_string()); + let libbcachefs_inc_dir = std::path::Path::new(&libbcachefs_inc_dir); + println!("{}", libbcachefs_inc_dir.display()); + + println!("cargo:rustc-link-lib=dylib=bcachefs"); + println!("cargo:rustc-link-search={}", env!("LIBBCACHEFS_LIB")); + + let _libbcachefs_dir = top_dir.join("libbcachefs").join("libbcachefs"); + let bindings = bindgen::builder() + .header(top_dir.join("src").join("libbcachefs_wrapper.h").display().to_string()) + .clang_arg(format!("-I{}", libbcachefs_inc_dir.join("include").display())) + .clang_arg(format!("-I{}", libbcachefs_inc_dir.display())) + .clang_arg("-DZSTD_STATIC_LINKING_ONLY") + .clang_arg("-DNO_BCACHEFS_FS") + .clang_arg("-D_GNU_SOURCE") + .derive_debug(true) + .derive_default(true) + .derive_eq(true) + .layout_tests(true) + .default_enum_style(bindgen::EnumVariation::Rust { non_exhaustive: true }) + .allowlist_function(".*bch2_.*") + // .allowlist_function("bch2_read_super") + // .allowlist_function("bch2_sb_field_.*") + // .allowlist_function("bch2_super_write") + // .allowlist_function("bch2_chacha_encrypt_key") + // .allowlist_function("__bch2_super_read") + .allowlist_function("bio_.*") + .allowlist_function("bch2_super_write_fd") + .allowlist_function("derive_passphrase") + .allowlist_function("request_key") + .allowlist_function("add_key") + .allowlist_function("keyctl_search") + .blocklist_type("bch_extent_ptr") + .blocklist_type("btree_node") + .blocklist_type("bch_extent_crc32") + .blocklist_type("rhash_lock_head") + .blocklist_type("srcu_struct") + .allowlist_var("BCH_.*") + .allowlist_var("KEY_SPEC_.*") + .allowlist_type("bch_kdf_types") + .allowlist_type("bch_sb_field_.*") + .allowlist_type("bch_encrypted_key") + .allowlist_type("nonce") + .newtype_enum("bch_kdf_types") + .opaque_type("gendisk") + .opaque_type("bkey") + // .opaque_type("bch_extent_ptr") + // .opaque_type("bch_extent_crc32") + .opaque_type("open_bucket.*") + .generate() + .expect("BindGen Generation Failiure: [libbcachefs_wrapper]"); + bindings + .write_to_file(out_dir.join("bcachefs.rs")) + .expect("Writing to output file failed for: `bcachefs.rs`"); + + let keyutils = pkg_config::probe_library("libkeyutils").expect("Failed to find keyutils lib"); + let bindings = bindgen::builder() + .header(top_dir.join("src").join("keyutils_wrapper.h").display().to_string()) + .clang_args(keyutils.include_paths.iter().map(|p| format!("-I{}", p.display()))) + .generate() + .expect("BindGen Generation Failiure: [Keyutils]"); + bindings + .write_to_file(out_dir.join("keyutils.rs")) + .expect("Writing to output file failed for: `keyutils.rs`"); +} diff --git a/rust-src/bch_bindgen/rustfmt.toml b/rust-src/bch_bindgen/rustfmt.toml new file mode 100644 index 0000000..a2b7f32 --- /dev/null +++ b/rust-src/bch_bindgen/rustfmt.toml @@ -0,0 +1,2 @@ +max_width=120 +hard_tabs = true diff --git a/rust-src/bch_bindgen/src/bcachefs.rs b/rust-src/bch_bindgen/src/bcachefs.rs new file mode 100644 index 0000000..cc98ffc --- /dev/null +++ b/rust-src/bch_bindgen/src/bcachefs.rs @@ -0,0 +1,124 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/bcachefs.rs")); + +use bitfield::bitfield; +bitfield! { + pub struct bch_scrypt_flags(u64); + pub N, _: 15, 0; + pub R, _: 31, 16; + pub P, _: 47, 32; +} +bitfield! { + pub struct bch_crypt_flags(u64); + pub TYPE, _: 4, 0; +} +use memoffset::offset_of; +impl bch_sb_field_crypt { + pub fn scrypt_flags(&self) -> Option { + use std::convert::TryInto; + match bch_kdf_types(bch_crypt_flags(self.flags).TYPE().try_into().ok()?) { + bch_kdf_types::BCH_KDF_SCRYPT => Some(bch_scrypt_flags(self.kdf_flags)), + _ => None, + } + } + pub fn key(&self) -> &bch_encrypted_key { + &self.key + } +} +impl PartialEq for bch_sb { + fn eq(&self, other: &Self) -> bool { + self.magic.b == other.magic.b + && self.user_uuid.b == other.user_uuid.b + && self.block_size == other.block_size + && self.version == other.version + && self.uuid.b == other.uuid.b + && self.seq == other.seq + } +} + +impl std::fmt::Debug for bch_sb { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("bch_sb") + .field("uuid", &self.uuid()) + .field("version", &(self.version, self.version_min)) + .field("block_size", &self.block_size) + .field("device_idx", &self.dev_idx) + .field("seq", &self.seq) + .field("csum", &(self.csum.lo, self.csum.hi)) + .field("offset", &self.offset) + .finish_non_exhaustive() + } +} + + +impl bch_sb { + pub fn crypt(&self) -> Option<&bch_sb_field_crypt> { + unsafe { + let ptr = bch2_sb_field_get(self as *const _ as *mut _, bch_sb_field_type::BCH_SB_FIELD_crypt) as *const u8; + if ptr.is_null() { + None + } else { + let offset = offset_of!(bch_sb_field_crypt, field); + Some(&*((ptr.sub(offset)) as *const _)) + } + } + } + pub fn uuid(&self) -> uuid::Uuid { + uuid::Uuid::from_bytes(self.user_uuid.b) + } + + /// Get the nonce used to encrypt the superblock + pub fn nonce(&self) -> nonce { + use byteorder::{LittleEndian, ReadBytesExt}; + let mut internal_uuid = &self.uuid.b[..]; + let dword1 = internal_uuid.read_u32::().unwrap(); + let dword2 = internal_uuid.read_u32::().unwrap(); + nonce { + d: [0, 0, dword1, dword2], + } + } +} +impl bch_sb_handle { + pub fn sb(&self) -> &bch_sb { + unsafe { &*self.sb } + } + + pub fn bdev(&self) -> &block_device { + unsafe { &*self.bdev } + } +} + +#[repr(C)] +// #[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct bch_extent_ptr { + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>, +} + +#[repr(C, packed(8))] +pub struct btree_node { + pub csum: bch_csum, + pub magic: __le64, + pub flags: __le64, + pub min_key: bpos, + pub max_key: bpos, + pub _ptr: bch_extent_ptr, + pub format: bkey_format, + pub __bindgen_anon_1: btree_node__bindgen_ty_1, +} + +#[repr(C, packed(8))] +// #[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct bch_extent_crc32 { + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, + pub csum: __u32, +} + +// #[repr(u8)] +pub enum rhash_lock_head {} +pub enum srcu_struct {} diff --git a/rust-src/bch_bindgen/src/keyutils.rs b/rust-src/bch_bindgen/src/keyutils.rs new file mode 100644 index 0000000..30fc56f --- /dev/null +++ b/rust-src/bch_bindgen/src/keyutils.rs @@ -0,0 +1,6 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/keyutils.rs")); diff --git a/rust-src/mount/src/keyutils_wrapper.h b/rust-src/bch_bindgen/src/keyutils_wrapper.h similarity index 100% rename from rust-src/mount/src/keyutils_wrapper.h rename to rust-src/bch_bindgen/src/keyutils_wrapper.h diff --git a/rust-src/bch_bindgen/src/lib.rs b/rust-src/bch_bindgen/src/lib.rs new file mode 100644 index 0000000..c19b5a2 --- /dev/null +++ b/rust-src/bch_bindgen/src/lib.rs @@ -0,0 +1,7 @@ +pub mod bcachefs; +pub mod keyutils; +pub mod rs; + +pub mod c { + pub use crate::bcachefs::*; +} diff --git a/rust-src/mount/src/libbcachefs_wrapper.h b/rust-src/bch_bindgen/src/libbcachefs_wrapper.h similarity index 59% rename from rust-src/mount/src/libbcachefs_wrapper.h rename to rust-src/bch_bindgen/src/libbcachefs_wrapper.h index 9d9754c..2a0e702 100644 --- a/rust-src/mount/src/libbcachefs_wrapper.h +++ b/rust-src/bch_bindgen/src/libbcachefs_wrapper.h @@ -1,4 +1,8 @@ #include "../libbcachefs/super-io.h" #include "../libbcachefs/checksum.h" #include "../libbcachefs/bcachefs_format.h" +#include "../libbcachefs/opts.h" +#include "../libbcachefs.h" #include "../crypto.h" +#include "../include/linux/bio.h" + diff --git a/rust-src/bch_bindgen/src/rs.rs b/rust-src/bch_bindgen/src/rs.rs new file mode 100644 index 0000000..4452f0b --- /dev/null +++ b/rust-src/bch_bindgen/src/rs.rs @@ -0,0 +1,58 @@ +use crate::bcachefs; + +pub const SUPERBLOCK_MAGIC: uuid::Uuid = uuid::Uuid::from_u128( + 0x_c68573f6_4e1a_45ca_8265_f57f48ba6d81 +); + +extern "C" { + pub static stdout: *mut libc::FILE; +} + +pub enum ReadSuperErr { + Io(std::io::Error), +} + +type RResult = std::io::Result>; + +#[tracing_attributes::instrument(skip(opts))] +pub fn read_super_opts(path: &std::path::Path, mut opts: bcachefs::bch_opts) -> RResult { + // let devp = camino::Utf8Path::from_path(devp).unwrap(); + + use std::os::unix::ffi::OsStrExt; + let path = std::ffi::CString::new(path.as_os_str().as_bytes())?; + + let mut sb = std::mem::MaybeUninit::zeroed(); + + // use gag::{BufferRedirect}; + // // Stop libbcachefs from spamming the output + // let gag = BufferRedirect::stderr().unwrap(); + // tracing::trace!("entering libbcachefs"); + + let ret = unsafe { crate::bcachefs::bch2_read_super(path.as_ptr(), &mut opts, sb.as_mut_ptr()) }; + tracing::trace!(%ret); + + match -ret { + libc::EACCES => Err(std::io::Error::new( + std::io::ErrorKind::PermissionDenied, + "Access Permission Denied", + )), + 0 => Ok(Ok(unsafe { sb.assume_init() })), + 22 => Ok(Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Not a BCacheFS SuperBlock", + ))), + code => { + tracing::debug!(msg = "BCacheFS return error code", ?code); + Ok(Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Failed to Read SuperBlock", + ))) + } + } +} + +#[tracing_attributes::instrument] +pub fn read_super(path: &std::path::Path) -> RResult { + let opts = bcachefs::bch_opts::default(); //unsafe {std::mem::MaybeUninit::zeroed().assume_init()}; + read_super_opts(path, opts) +} diff --git a/rust-src/mount/.gitignore b/rust-src/mount/.gitignore new file mode 100644 index 0000000..644cd42 --- /dev/null +++ b/rust-src/mount/.gitignore @@ -0,0 +1,15 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +# Needed by nix +# Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/rust-src/mount/Cargo.lock b/rust-src/mount/Cargo.lock index 77ccbba..92d13cf 100644 --- a/rust-src/mount/Cargo.lock +++ b/rust-src/mount/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.7.10" @@ -18,6 +20,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" version = "1.0.28" @@ -43,39 +54,56 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "bcachefs-mount" -version = "0.1.0" +version = "0.3.1" dependencies = [ "anyhow", - "bindgen", - "bitfield", + "bch_bindgen", "byteorder", + "camino", "clap", "either", - "env_logger", "errno", "gag", "getset", "itertools", "libc", - "log", - "memoffset", "parse-display", - "pkg-config", "rpassword", "structopt", + "tracing", + "tracing-attributes", + "tracing-log", + "tracing-subscriber", + "udev", + "uuid", +] + +[[package]] +name = "bch_bindgen" +version = "0.1.0" +dependencies = [ + "anyhow", + "bindgen", + "bitfield", + "byteorder", + "gag", + "libc", + "memoffset", + "pkg-config", + "tracing", + "tracing-attributes", "udev", "uuid", ] [[package]] name = "bindgen" -version = "0.53.2" +version = "0.59.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb26d6a69a335b8cb0e7c7e9775cd5666611dc50a37177c3f2cedcfc040e8c8" +checksum = "453c49e5950bb0eb63bb3df640e31618846c89d5b7faa54040d76e98e0134375" dependencies = [ "bitflags", "cexpr", - "cfg-if", "clang-sys", "lazy_static", "lazycell", @@ -99,17 +127,35 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitvec" +version = "0.19.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8942c8d352ae1838c9dda0b0ca2ab657696ef2232a20147cf1b30ae1a9cb4321" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "camino" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d74260d9bf6944e2208aa46841b4b8f0d7ffc0849a06837b2f510337f86b2b" + [[package]] name = "cexpr" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +checksum = "db507a7679252d2276ed0dd8113c6875ec56d3089f9225b2b42c30cc1f8e5c89" dependencies = [ "nom", ] @@ -120,11 +166,29 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "winapi", +] + [[package]] name = "clang-sys" -version = "0.29.3" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a" +checksum = "10612c0ec0e0a1ff0e97980647cb058a6e7aedb913d01d009c406b8b7d0b26ee" dependencies = [ "glob", "libc", @@ -136,7 +200,7 @@ version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" dependencies = [ - "ansi_term", + "ansi_term 0.11.0", "atty", "bitflags", "strsim", @@ -152,15 +216,6 @@ version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" -[[package]] -name = "env_logger" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "log", -] - [[package]] name = "errno" version = "0.2.5" @@ -183,12 +238,29 @@ dependencies = [ ] [[package]] -name = "gag" -version = "0.1.10" +name = "filedescriptor" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc0b9f53275dc5fada808f1d2f82e3688a6c14d735633d1590b7be8eb2307b5" +checksum = "9ed3d8a5e20435ff00469e51a0d82049bae66504b5c429920dadf9bb54d47b3f" dependencies = [ "libc", + "thiserror", + "winapi", +] + +[[package]] +name = "funty" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" + +[[package]] +name = "gag" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a713bee13966e9fbffdf7193af71d54a6b35a0bb34997cd6c9519ebeb5005972" +dependencies = [ + "filedescriptor", "tempfile", ] @@ -204,7 +276,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] @@ -254,6 +326,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + [[package]] name = "lazy_static" version = "1.4.0" @@ -288,7 +366,16 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", +] + +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata", ] [[package]] @@ -308,14 +395,35 @@ dependencies = [ [[package]] name = "nom" -version = "5.1.1" +version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6" +checksum = "9c5c51b9083a3c620fa67a2a635d1ce7d95b897e957d6b28ff9a5da960a103a6" dependencies = [ + "bitvec", + "funty", "memchr", "version_check", ] +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "parse-display" version = "0.1.1" @@ -347,6 +455,12 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pin-project-lite" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" + [[package]] name = "pkg-config" version = "0.3.17" @@ -429,6 +543,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" + [[package]] name = "rand" version = "0.7.3" @@ -488,6 +608,15 @@ dependencies = [ "thread_local", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax", +] + [[package]] name = "regex-syntax" version = "0.6.17" @@ -519,11 +648,49 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" + +[[package]] +name = "serde_json" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f9e390c27c3c0ce8bc5d725f6e4d30a29d26659494aa4b17535f7522c5c950" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sharded-slab" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740223c51853f3145fe7c90360d2d4232f2b62e3449489c207eccde818979982" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" -version = "0.1.1" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" + +[[package]] +name = "smallvec" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "strsim" @@ -533,9 +700,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.14" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef" +checksum = "bf9d950ef167e25e0bdb073cf1d68e9ad2795ac826f2f3f59647817cf23c0bfa" dependencies = [ "clap", "lazy_static", @@ -544,9 +711,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.7" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a" +checksum = "134d838a2c9943ac3125cf6df165eda53493451b719f3255b2a26b85f772d0ba" dependencies = [ "heck", "proc-macro-error 1.0.2", @@ -577,13 +744,19 @@ dependencies = [ "syn", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand", "redox_syscall", @@ -611,6 +784,26 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "thiserror" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.0.1" @@ -620,6 +813,81 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "tracing" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" +dependencies = [ + "cfg-if 1.0.0", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ca517f43f0fb96e0c3072ed5c275fe5eece87e8cb52f4a77b69226d3b1c9df8" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "tracing-log" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb65ea441fbb84f9f6748fd496cf7f63ec9af5bca94dd86456978d055e8eb28b" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cbe87a2fa7e35900ce5de20220a582a9483a7063811defce79d7cbd59d4cfe" +dependencies = [ + "ansi_term 0.12.1", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + [[package]] name = "udev" version = "0.4.0" @@ -693,3 +961,9 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wyz" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" diff --git a/rust-src/mount/Cargo.toml b/rust-src/mount/Cargo.toml index 4fd0d49..d48d4f7 100644 --- a/rust-src/mount/Cargo.toml +++ b/rust-src/mount/Cargo.toml @@ -1,34 +1,30 @@ [package] name = "bcachefs-mount" -version = "0.1.0" -authors = ["Yuxuan Shui "] +version = "0.3.1" +authors = ["Yuxuan Shui ", "Kayla Firestack "] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -log = "0.4" +tracing = "0.1.26" +tracing-log = "0.1.2" +tracing-subscriber = "0.2.20" +tracing-attributes = "0.1.15" clap = { version = "2.33", features = [ "wrap_help" ] } -env_logger = { version = "0.7", default-features = false } anyhow = "1.0" -udev = "0.4" -uuid = "0.8" libc = "0.2.69" -gag = "0.1" -bitfield = "0.13" -memoffset = "0.5" +uuid = "0.8" +udev = "0.4" +gag = "1.0.0" getset = "0.1" itertools = "0.9" -structopt = "0.3" +structopt = "0.3.23" parse-display = "0.1" errno = "0.2" either = "1.5" rpassword = "4" +camino = "1.0.5" +bch_bindgen = { path = "../bch_bindgen" } byteorder = "1.3" -[lib] -crate-type = ["staticlib"] - -[build-dependencies] -pkg-config = "0.3" -bindgen = { version = "0.53", default-features = false } diff --git a/rust-src/mount/README.md b/rust-src/mount/README.md new file mode 100644 index 0000000..e4700f6 --- /dev/null +++ b/rust-src/mount/README.md @@ -0,0 +1,62 @@ +Usage +===== + +``` +bcachefs-mount 0.1.0 +Mount a bcachefs filesystem by its UUID + +USAGE: + bcachefs-mount [OPTIONS] + +FLAGS: + -h, --help + Prints help information + + -V, --version + Prints version information + + +OPTIONS: + -o + Mount options [default: ] + + -p, --password + Where the password would be loaded from. + + Possible values are: "fail" - don't ask for password, fail if filesystem is encrypted; "wait" - wait for + password to become available before mounting; "ask" - prompt the user for password; [default: fail] + +ARGS: + + External UUID of the bcachefs filesystem + + + Where the filesystem should be mounted +``` + +Caveats +======= + +* `--password ask` is not yet implemented, but you can use `--password wait`, and load the key with `bcachefs unlock`. + +Build +===== + +```sh +$ git submodule update --init --recursive +$ cargo build --release +``` + +Binary will be built in `target/release/bcachefs-mount` + +Dependencies: + +* rust +* blkid +* uuid +* liburcu +* libsodium +* zlib +* liblz4 +* libzstd +* libkeyutils diff --git a/rust-src/mount/build.rs b/rust-src/mount/build.rs deleted file mode 100644 index 6542889..0000000 --- a/rust-src/mount/build.rs +++ /dev/null @@ -1,67 +0,0 @@ -fn main() { - use std::path::PathBuf; - use std::process::Command; - - let out_dir: PathBuf = std::env::var_os("OUT_DIR").unwrap().into(); - let top_dir: PathBuf = std::env::var_os("CARGO_MANIFEST_DIR").unwrap().into(); - let libbcachefs_inc_dir = std::env::var("LIBBCACHEFS_INCLUDE") - .unwrap_or_else(|_| top_dir.join("libbcachefs").display().to_string()); - let libbcachefs_inc_dir = std::path::Path::new(&libbcachefs_inc_dir); - println!("{}", libbcachefs_inc_dir.display()); - - let libbcachefs_dir = top_dir.join("libbcachefs").join("libbcachefs"); - let bindings = bindgen::builder() - .header(top_dir - .join("src") - .join("libbcachefs_wrapper.h") - .display() - .to_string()) - .clang_arg(format!( - "-I{}", - libbcachefs_inc_dir.join("include").display() - )) - .clang_arg(format!("-I{}", libbcachefs_inc_dir.display())) - .clang_arg("-DZSTD_STATIC_LINKING_ONLY") - .clang_arg("-DNO_BCACHEFS_FS") - .clang_arg("-D_GNU_SOURCE") - .derive_debug(false) - .derive_default(true) - .default_enum_style(bindgen::EnumVariation::Rust { - non_exhaustive: true, - }) - .whitelist_function("bch2_read_super") - .whitelist_function("bch2_sb_field_.*") - .whitelist_function("bch2_chacha_encrypt_key") - .whitelist_function("derive_passphrase") - .whitelist_function("request_key") - .whitelist_function("add_key") - .whitelist_function("keyctl_search") - .whitelist_var("BCH_.*") - .whitelist_var("KEY_SPEC_.*") - .whitelist_type("bch_kdf_types") - .whitelist_type("bch_sb_field_.*") - .whitelist_type("bch_encrypted_key") - .whitelist_type("nonce") - .rustified_enum("bch_kdf_types") - .opaque_type("gendisk") - .opaque_type("bkey") - .generate() - .unwrap(); - bindings.write_to_file(out_dir.join("bcachefs.rs")).unwrap(); - - let keyutils = pkg_config::probe_library("libkeyutils").unwrap(); - let bindings = bindgen::builder() - .header(top_dir - .join("src") - .join("keyutils_wrapper.h") - .display() - .to_string()) - .clang_args( - keyutils.include_paths - .iter() - .map(|p| format!("-I{}", p.display())), - ) - .generate() - .unwrap(); - bindings.write_to_file(out_dir.join("keyutils.rs")).unwrap(); -} diff --git a/rust-src/mount/default.nix b/rust-src/mount/default.nix index 84c046b..dab7db7 100644 --- a/rust-src/mount/default.nix +++ b/rust-src/mount/default.nix @@ -27,8 +27,8 @@ in { LIBCLANG_PATH BINDGEN_EXTRA_CLANG_ARGS; - preFixup = '' - ln $out/bin/mount-bcachefs $out/bin/mount.bcachefs + postInstall = '' + ln $out/bin/${cargo.package.name} $out/bin/mount.bcachefs ln -s $out/bin $out/sbin ''; # -isystem ${llvmPackages.libclang.lib}/lib/clang/${lib.getVersion llvmPackages.libclang}/include"; diff --git a/rust-src/mount/module.nix b/rust-src/mount/module.nix new file mode 100644 index 0000000..b62aa7d --- /dev/null +++ b/rust-src/mount/module.nix @@ -0,0 +1,54 @@ +## Mirrors: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/tasks/filesystems/bcachefs.nix +## with changes to use flakes and import mount.bcachefs +{ config, lib, pkgs, utils, ... }: + +with lib; + +let + + bootFs = filterAttrs (n: fs: (fs.fsType == "bcachefs") && (utils.fsNeededForBoot fs)) config.fileSystems; + cfg = config.filesystems.bcachefs; +in + +{ + options.filesystems.bcachefs.packages.tools = lib.mkOption { + description = "Which package to use to link in the bcachefs tools package"; + default = pkgs.bcachefs.tools; + type = lib.types.package; + }; + options.filesystems.bcachefs.packages.mount = lib.mkOption { + description = "Which package to use to link in the bcachefs mount package"; + default = pkgs.bcachefs.mount; + type = lib.types.package; + }; + options.filesystems.bcachefs.packages.kernelPackages = lib.mkOption { + description = "Which package to use to link in the kernel package to use"; + default = pkgs.bcachefs.kernelPackages; + type = lib.types.attrs; + + }; + + config = mkIf (elem "bcachefs" config.boot.supportedFilesystems) (mkMerge [ + { + system.fsPackages = [ cfg.packages.tools cfg.packages.mount ]; + + # use kernel package with bcachefs support until it's in mainline + boot.kernelPackages = cfg.packages.kernelPackages; + } + + (mkIf ((elem "bcachefs" config.boot.initrd.supportedFilesystems) || (bootFs != {})) { + # chacha20 and poly1305 are required only for decryption attempts + boot.initrd.availableKernelModules = [ "sha256" "chacha20" "poly1305" ]; + boot.initrd.kernelModules = [ "bcachefs" ]; + + boot.initrd.extraUtilsCommands = '' + copy_bin_and_libs ${cfg.packages.tools}/bin/bcachefs + copy_bin_and_libs ${cfg.packages.mount}/bin/mount.bcachefs + ''; + boot.initrd.extraUtilsCommandsTest = '' + $out/bin/bcachefs version + $out/bin/mount.bcachefs --version + ''; + }) + ]); +} diff --git a/rust-src/mount/rustfmt.toml b/rust-src/mount/rustfmt.toml new file mode 100644 index 0000000..a2b7f32 --- /dev/null +++ b/rust-src/mount/rustfmt.toml @@ -0,0 +1,2 @@ +max_width=120 +hard_tabs = true diff --git a/rust-src/mount/src/filesystem.rs b/rust-src/mount/src/filesystem.rs index 36af8c0..b1575c2 100644 --- a/rust-src/mount/src/filesystem.rs +++ b/rust-src/mount/src/filesystem.rs @@ -19,11 +19,103 @@ pub struct FileSystem { #[getset(get = "pub")] devices: Vec, } +impl std::fmt::Debug for FileSystem { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("FileSystem") + .field("uuid", &self.uuid) + .field("encrypted", &self.encrypted) + .field("devices", &self.device_string()) + .finish() + } +} +use std::fmt; +impl std::fmt::Display for FileSystem { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let devs = self.device_string(); + write!( + f, + "{:?}: locked?={lock} ({}) ", + self.uuid, + devs, + lock = self.encrypted + ) + } +} + +impl FileSystem { + pub(crate) fn new(sb: bcachefs::bch_sb_handle) -> Self { + Self { + uuid: sb.sb().uuid(), + encrypted: sb.sb().crypt().is_some(), + sb: sb, + devices: Vec::new(), + } + } + + pub fn device_string(&self) -> String { + use itertools::Itertools; + self.devices.iter().map(|d| d.display()).join(":") + } + + pub fn mount( + &self, + target: impl AsRef, + options: impl AsRef, + ) -> anyhow::Result<()> { + tracing::info_span!("mount").in_scope(|| { + let src = self.device_string(); + let (data, mountflags) = parse_mount_options(options); + // let fstype = c_str!("bcachefs"); + + tracing::info!(msg="mounting bcachefs filesystem", target=%target.as_ref().display()); + mount_inner(src, target, "bcachefs", mountflags, data) + }) + } +} + +fn mount_inner( + src: String, + target: impl AsRef, + fstype: &str, + mountflags: u64, + data: Option, +) -> anyhow::Result<()> { + use std::{ + ffi::{c_void, CString}, + os::{raw::c_char, unix::ffi::OsStrExt}, + }; + + // bind the CStrings to keep them alive + let src = CString::new(src)?; + let target = CString::new(target.as_ref().as_os_str().as_bytes())?; + let data = data.map(CString::new).transpose()?; + let fstype = CString::new(fstype)?; + + // convert to pointers for ffi + let src = src.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; + let target = target.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; + let data = data.as_ref().map_or(std::ptr::null(), |data| { + data.as_c_str().to_bytes_with_nul().as_ptr() as *const c_void + }); + let fstype = fstype.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; + + let ret = {let _entered = tracing::info_span!("libc::mount").entered(); + tracing::info!("mounting filesystem"); + // REQUIRES: CAP_SYS_ADMIN + unsafe { libc::mount(src, target, fstype, mountflags, data) } + }; + match ret { + 0 => Ok(()), + _ => Err(crate::ErrnoError(errno::errno()).into()), + } +} /// Parse a comma-separated mount options and split out mountflags and filesystem /// specific options. +#[tracing_attributes::instrument(skip(options))] fn parse_mount_options(options: impl AsRef) -> (Option, u64) { use either::Either::*; + tracing::debug!(msg="parsing mount options", options=?options.as_ref()); let (opts, flags) = options .as_ref() .split(",") @@ -63,112 +155,54 @@ fn parse_mount_options(options: impl AsRef) -> (Option, u64) { ) } -impl FileSystem { - pub(crate) fn new(sb: bcachefs::bch_sb_handle) -> Self { - Self { - uuid: sb.sb().uuid(), - encrypted: sb.sb().crypt().is_some(), - sb: sb, - devices: vec![], - } - } - - pub fn mount( - &self, - target: impl AsRef, - options: impl AsRef, - ) -> anyhow::Result<()> { - use itertools::Itertools; - use std::ffi::c_void; - use std::os::raw::c_char; - use std::os::unix::ffi::OsStrExt; - let src = self.devices.iter().map(|d| d.display()).join(":"); - let (data, mountflags) = parse_mount_options(options); - let fstype = c_str!("bcachefs"); - - let src = std::ffi::CString::new(src)?; // bind the CString to keep it alive - let target = std::ffi::CString::new(target.as_ref().as_os_str().as_bytes())?; // ditto - let data = data.map(|data| std::ffi::CString::new(data)).transpose()?; // ditto - - let src = src.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; - let target = target.as_c_str().to_bytes_with_nul().as_ptr() as *const c_char; - let data = data.as_ref().map_or(std::ptr::null(), |data| { - data.as_c_str().to_bytes_with_nul().as_ptr() as *const c_void - }); - - let ret = unsafe { libc::mount(src, target, fstype, mountflags, data) }; - if ret == 0 { - Ok(()) - } else { - Err(crate::ErrnoError(errno::errno()).into()) - } - } -} - -use crate::bcachefs; +use bch_bindgen::bcachefs; use std::collections::HashMap; use uuid::Uuid; + +#[tracing_attributes::instrument] pub fn probe_filesystems() -> anyhow::Result> { - use std::os::unix::ffi::OsStrExt; + tracing::trace!("enumerating udev devices"); let mut udev = udev::Enumerator::new()?; - let mut fss = HashMap::new(); - udev.match_subsystem("block")?; - - { - // Stop libbcachefs from spamming the output - let _gag = gag::Gag::stdout().unwrap(); - for dev in udev.scan_devices()? { - if let Some(p) = dev.devnode() { - let path = - std::ffi::CString::new(p.as_os_str().as_bytes()).unwrap(); - let result = unsafe { - let mut opts = std::mem::MaybeUninit::zeroed(); - let mut sb = std::mem::MaybeUninit::zeroed(); - let ret = bcachefs::bch2_read_super( - path.as_ptr(), - opts.as_mut_ptr(), - sb.as_mut_ptr(), - ); - if ret == -libc::EACCES { - Err(std::io::Error::new( - std::io::ErrorKind::PermissionDenied, - "no permission", - )) - } else if ret != 0 { - Err(std::io::Error::new( - std::io::ErrorKind::Other, - "failed to read super", - )) - } else { - Ok((opts.assume_init(), sb.assume_init())) - } - }; - match result { - Ok((_, sb)) => match fss.get_mut(&sb.sb().uuid()) { - None => { - let mut fs = FileSystem::new(sb); - fs.devices.push(p.to_owned()); - fss.insert(fs.uuid, fs); - } - Some(fs) => { - fs.devices.push(p.to_owned()); - } - }, - Err(e) if e.kind() - != std::io::ErrorKind::PermissionDenied => - { - () - } - e @ Err(_) => { - e?; - } - } - } - } - // Flush stdout so buffered output don't get printed after we remove the gag - unsafe { - libc::fflush(stdout); + + udev.match_subsystem("block")?; // find kernel block devices + + let mut fs_map = HashMap::new(); + let devresults = + udev.scan_devices()? + .into_iter() + .filter_map(|dev| dev.devnode().map(ToOwned::to_owned)); + + for pathbuf in devresults { + match get_super_block_uuid(&pathbuf)? { + + Ok((uuid_key, superblock)) => { + let fs = fs_map.entry(uuid_key).or_insert_with(|| { + tracing::info!(msg="found bcachefs pool", uuid=?uuid_key); + FileSystem::new(superblock) + }); + + fs.devices.push(pathbuf); + }, + + Err(e) => { tracing::debug!(inner2_error=?e);} } } - Ok(fss) + + + tracing::info!(msg = "found filesystems", count = fs_map.len()); + Ok(fs_map) +} + +// #[tracing_attributes::instrument(skip(dev, fs_map))] +fn get_super_block_uuid(path: &std::path::Path) -> std::io::Result> { + let sb = bch_bindgen::rs::read_super(&path)?; + let super_block = match sb { + Err(e) => { return Ok(Err(e)); } + Ok(sb) => sb, + }; + + let uuid = (&super_block).sb().uuid(); + tracing::debug!(found="bcachefs superblock", devnode=?path, ?uuid); + + Ok(Ok((uuid, super_block))) } diff --git a/rust-src/mount/src/key.rs b/rust-src/mount/src/key.rs index 6769f52..91c92d1 100644 --- a/rust-src/mount/src/key.rs +++ b/rust-src/mount/src/key.rs @@ -1,12 +1,11 @@ -use log::info; +use tracing::info; fn check_for_key(key_name: &std::ffi::CStr) -> anyhow::Result { - use crate::keyutils::{self, keyctl_search}; + use bch_bindgen::keyutils::{self, keyctl_search}; let key_name = key_name.to_bytes_with_nul().as_ptr() as *const _; let key_type = c_str!("logon"); - let key_id = - unsafe { keyctl_search(keyutils::KEY_SPEC_USER_KEYRING, key_type, key_name, 0) }; + let key_id = unsafe { keyctl_search(keyutils::KEY_SPEC_USER_KEYRING, key_type, key_name, 0) }; if key_id > 0 { info!("Key has became avaiable"); Ok(true) @@ -31,9 +30,9 @@ fn wait_for_key(uuid: &uuid::Uuid) -> anyhow::Result<()> { const BCH_KEY_MAGIC: &str = "bch**key"; use crate::filesystem::FileSystem; fn ask_for_key(fs: &FileSystem) -> anyhow::Result<()> { - use crate::bcachefs::{self, bch2_chacha_encrypt_key, bch_encrypted_key, bch_key}; use anyhow::anyhow; use byteorder::{LittleEndian, ReadBytesExt}; + use bch_bindgen::bcachefs::{self, bch2_chacha_encrypt_key, bch_encrypted_key, bch_key}; use std::os::raw::c_char; let key_name = std::ffi::CString::new(format!("bcachefs:{}", fs.uuid())).unwrap(); @@ -62,19 +61,18 @@ fn ask_for_key(fs: &FileSystem) -> anyhow::Result<()> { ) }; if ret != 0 { - Err(anyhow!("chache decryption failure")) + Err(anyhow!("chacha decryption failure")) } else if key.magic != bch_key_magic { Err(anyhow!("failed to verify the password")) } else { let key_type = c_str!("logon"); let ret = unsafe { - crate::keyutils::add_key( + bch_bindgen::keyutils::add_key( key_type, - key_name.as_c_str().to_bytes_with_nul() as *const _ - as *const c_char, + key_name.as_c_str().to_bytes_with_nul() as *const _ as *const c_char, &output as *const _ as *const _, std::mem::size_of::() as u64, - crate::keyutils::KEY_SPEC_USER_KEYRING, + bch_bindgen::keyutils::KEY_SPEC_USER_KEYRING, ) }; if ret == -1 { @@ -85,9 +83,12 @@ fn ask_for_key(fs: &FileSystem) -> anyhow::Result<()> { } } -pub(crate) fn prepare_key(fs: &FileSystem, password: crate::KeyLocation) -> anyhow::Result<()> { +#[tracing_attributes::instrument] +pub fn prepare_key(fs: &FileSystem, password: crate::KeyLocation) -> anyhow::Result<()> { use crate::KeyLocation::*; use anyhow::anyhow; + + tracing::info!(msg = "checking if key exists for filesystem"); match password { Fail => Err(anyhow!("no key available")), Wait => Ok(wait_for_key(fs.uuid())?), diff --git a/rust-src/mount/src/lib.rs b/rust-src/mount/src/lib.rs index 751eab3..4e918e1 100644 --- a/rust-src/mount/src/lib.rs +++ b/rust-src/mount/src/lib.rs @@ -1,12 +1,24 @@ -use structopt::StructOpt; use anyhow::anyhow; +use structopt::StructOpt; + +pub mod err { + pub enum GError { + Unknown{ + message: std::borrow::Cow<'static, String> + } + } + pub type GResult =::core::result::Result< ::core::result::Result, OE>; + pub type Result = GResult; +} #[macro_export] macro_rules! c_str { ($lit:expr) => { - unsafe { std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr() as *const std::os::raw::c_char) - .to_bytes_with_nul() - .as_ptr() as *const std::os::raw::c_char } + unsafe { + std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr() as *const std::os::raw::c_char) + .to_bytes_with_nul() + .as_ptr() as *const std::os::raw::c_char + } }; } @@ -20,171 +32,60 @@ impl std::fmt::Display for ErrnoError { impl std::error::Error for ErrnoError {} #[derive(Debug)] -pub(crate) enum KeyLocation { +pub enum KeyLocation { Fail, Wait, Ask, } -impl std::str::FromStr for KeyLocation { +#[derive(Debug)] +pub struct KeyLoc(pub Option); +impl std::ops::Deref for KeyLoc { + type Target = Option; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl std::str::FromStr for KeyLoc { type Err = anyhow::Error; fn from_str(s: &str) -> anyhow::Result { - use anyhow::anyhow; + // use anyhow::anyhow; match s { - "fail" => Ok(Self::Fail), - "wait" => Ok(Self::Wait), - "ask" => Ok(Self::Ask), - _ => Err(anyhow!("invalid password option")) + "" => Ok(KeyLoc(None)), + "fail" => Ok(KeyLoc(Some(KeyLocation::Fail))), + "wait" => Ok(KeyLoc(Some(KeyLocation::Wait))), + "ask" => Ok(KeyLoc(Some(KeyLocation::Ask))), + _ => Err(anyhow!("invalid password option")), } } } #[derive(StructOpt, Debug)] /// Mount a bcachefs filesystem by its UUID. -struct Options { +pub struct Options { /// Where the password would be loaded from. /// /// Possible values are: /// "fail" - don't ask for password, fail if filesystem is encrypted; /// "wait" - wait for password to become available before mounting; /// "ask" - prompt the user for password; - #[structopt(short, long, default_value = "fail")] - key_location: KeyLocation, + #[structopt(short, long, default_value = "")] + pub key_location: KeyLoc, /// External UUID of the bcachefs filesystem - uuid: uuid::Uuid, + pub uuid: uuid::Uuid, /// Where the filesystem should be mounted. If not set, then the filesystem /// won't actually be mounted. But all steps preceeding mounting the /// filesystem (e.g. asking for passphrase) will still be performed. - mountpoint: Option, + pub mountpoint: Option, /// Mount options #[structopt(short, default_value = "")] - options: String, -} - -mod filesystem; -mod key; -mod keyutils { - #![allow(non_upper_case_globals)] - #![allow(non_camel_case_types)] - #![allow(non_snake_case)] - #![allow(unused)] - - include!(concat!(env!("OUT_DIR"), "/keyutils.rs")); + pub options: String, } -mod bcachefs { - #![allow(non_upper_case_globals)] - #![allow(non_camel_case_types)] - #![allow(non_snake_case)] - #![allow(unused)] - - include!(concat!(env!("OUT_DIR"), "/bcachefs.rs")); +pub mod filesystem; +pub mod key; - use bitfield::bitfield; - bitfield! { - pub struct bch_scrypt_flags(u64); - pub N, _: 15, 0; - pub R, _: 31, 16; - pub P, _: 47, 32; - } - bitfield! { - pub struct bch_crypt_flags(u64); - TYPE, _: 4, 0; - } - use memoffset::offset_of; - impl bch_sb_field_crypt { - pub fn scrypt_flags(&self) -> Option { - let t = bch_crypt_flags(self.flags); - if t.TYPE() != bch_kdf_types::BCH_KDF_SCRYPT as u64 { - None - } else { - Some(bch_scrypt_flags(self.kdf_flags)) - } - } - pub fn key(&self) -> &bch_encrypted_key { - &self.key - } - } - impl bch_sb { - pub fn crypt(&self) -> Option<&bch_sb_field_crypt> { - unsafe { - let ptr = bch2_sb_field_get( - self as *const _ as *mut _, - bch_sb_field_type::BCH_SB_FIELD_crypt, - ) as *const u8; - if ptr.is_null() { - None - } else { - let offset = offset_of!(bch_sb_field_crypt, field); - Some(&*((ptr.sub(offset)) as *const _)) - } - } - } - pub fn uuid(&self) -> uuid::Uuid { - uuid::Uuid::from_bytes(self.user_uuid.b) - } - - /// Get the nonce used to encrypt the superblock - pub fn nonce(&self) -> nonce { - use byteorder::{ReadBytesExt, LittleEndian}; - let mut internal_uuid = &self.uuid.b[..]; - let dword1 = internal_uuid.read_u32::().unwrap(); - let dword2 = internal_uuid.read_u32::().unwrap(); - nonce { d: [0, 0, dword1, dword2] } - } - } - impl bch_sb_handle { - pub fn sb(&self) -> &bch_sb { - unsafe { &*self.sb } - } - } -} - -fn main_inner() -> anyhow::Result<()> { - use itertools::Itertools; - use log::{info, trace}; - - env_logger::init(); - let opt = Options::from_args(); - trace!("{:?}", opt); - - let fss = filesystem::probe_filesystems()?; - info!("Found {} bcachefs filesystems: ", fss.len()); - for fs in fss.values() { - info!( - "{} ({}): {}", - fs.uuid(), - if fs.encrypted() { - "encrypted" - } else { - "unencrypted" - }, - fs.devices().iter().map(|d| d.display()).join(" ") - ); - } - - if let Some(fs) = fss.get(&opt.uuid) { - if fs.encrypted() { - info!("Making sure key is loaded for this filesystem"); - key::prepare_key(&fs, opt.key_location)?; - } - - if let Some(p) = opt.mountpoint { - fs.mount(&p, &opt.options) - } else { - Ok(()) - } - } else { - Err(anyhow!("Filesystem {} is not found", opt.uuid)) - } -} - -#[no_mangle] -pub extern "C" fn main() { - if let Err(e) = main_inner() { - println!("Error: {:?}", e); - } -} +// pub fn mnt_in_use() diff --git a/rust-src/mount/src/main.rs b/rust-src/mount/src/main.rs new file mode 100644 index 0000000..92b6917 --- /dev/null +++ b/rust-src/mount/src/main.rs @@ -0,0 +1,63 @@ +fn main() { + // convert existing log statements to tracing events + // tracing_log::LogTracer::init().expect("logtracer init failed!"); + // format tracing log data to env_logger like stdout + tracing_subscriber::fmt::init(); + + if let Err(e) = crate::main_inner() { + tracing::error!(fatal_error = ?e); + } +} + + + +#[tracing_attributes::instrument("main")] +pub fn main_inner() -> anyhow::Result<()> { + use structopt::StructOpt; + use bcachefs_mount::{Options, filesystem, key}; + unsafe { + libc::setvbuf( + filesystem::stdout, + std::ptr::null_mut(), + libc::_IONBF, + 0, + ); + // libc::fflush(filesystem::stdout); + } + let opt = Options::from_args(); + + + tracing::trace!(?opt); + + let fss = filesystem::probe_filesystems()?; + let fs = fss + .get(&opt.uuid) + .ok_or_else(|| anyhow::anyhow!("filesystem was not found"))?; + + tracing::info!(msg="found filesystem", %fs); + if fs.encrypted() { + let key = opt + .key_location + .0 + .ok_or_else(|| anyhow::anyhow!("no keyoption specified for locked filesystem"))?; + + key::prepare_key(&fs, key)?; + } + + let mountpoint = opt + .mountpoint + .ok_or_else(|| anyhow::anyhow!("mountpoint option was not specified"))?; + + fs.mount(&mountpoint, &opt.options)?; + + Ok(()) +} + +#[cfg(test)] +mod test { + // use insta::assert_debug_snapshot; + // #[test] + // fn snapshot_testing() { + // insta::assert_debug_snapshot!(); + // } +} -- 2.39.2