]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
Add a mount.bcachefs tool
authorYuxuan Shui <yshuiv7@gmail.com>
Mon, 4 May 2020 13:28:38 +0000 (14:28 +0100)
committerYuxuan Shui <yshuiv7@gmail.com>
Tue, 5 May 2020 20:33:40 +0000 (21:33 +0100)
This tool currently has most of the fundmental features implemented.
It can mount a filesystem specified by uuid, it can ask password for an
encrypted filesystem.

There may be some work that needs to be done to make it behave more like
a "mount.*" tool.

Related: #1

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
.travis.yml
Makefile
mount/Cargo.lock [new file with mode: 0644]
mount/Cargo.toml [new file with mode: 0644]
mount/build.rs [new file with mode: 0644]
mount/src/filesystem.rs [new file with mode: 0644]
mount/src/key.rs [new file with mode: 0644]
mount/src/keyutils_wrapper.h [new file with mode: 0644]
mount/src/lib.rs [new file with mode: 0644]
mount/src/libbcachefs_wrapper.h [new file with mode: 0644]

index 5f347ba45bc5e0d05176844e606a572477af4048..3b90b73c27f0c5456c364d211fa431f2c80e0779 100644 (file)
@@ -22,6 +22,7 @@ addons:
             - libsodium-dev
             - liburcu-dev
             - libzstd-dev
+            - libudev-dev
             - uuid-dev
             - zlib1g-dev
 
index 25de546ac5b0ec77bbc67aff765c7db7911e77db..fe8b3fd5c253646f46d0b1ef751ef9eb1e33754c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -39,7 +39,7 @@ ifdef D
        CFLAGS+=-DCONFIG_VALGRIND=y
 endif
 
-PKGCONFIG_LIBS="blkid uuid liburcu libsodium zlib liblz4 libzstd"
+PKGCONFIG_LIBS="blkid uuid liburcu libsodium zlib liblz4 libzstd libudev"
 ifdef BCACHEFS_FUSE
        PKGCONFIG_LIBS+="fuse3 >= 3.7"
        CFLAGS+=-DBCACHEFS_FUSE
@@ -57,7 +57,7 @@ endif
 CFLAGS+=$(PKGCONFIG_CFLAGS)
 LDLIBS+=$(PKGCONFIG_LDLIBS)
 
-LDLIBS+=-lm -lpthread -lrt -lscrypt -lkeyutils -laio
+LDLIBS+=-lm -lpthread -lrt -lscrypt -lkeyutils -laio -ldl
 LDLIBS+=$(EXTRA_LDLIBS)
 
 ifeq ($(PREFIX),/usr)
@@ -69,7 +69,7 @@ else
 endif
 
 .PHONY: all
-all: bcachefs
+all: bcachefs mount.bcachefs
 
 .PHONY: tests
 tests: tests/test_helper
@@ -92,6 +92,16 @@ 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
+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)
+
 tests/test_helper: $(filter ./tests/%.o, $(OBJS))
 
 # If the version string differs from the last build, update the last version
@@ -119,7 +129,8 @@ install: bcachefs
 
 .PHONY: clean
 clean:
-       $(RM) bcachefs tests/test_helper .version $(OBJS) $(DEPS)
+       $(RM) bcachefs mount.bcachefs libbcachefs_mount.a tests/test_helper .version $(OBJS) $(DEPS)
+       $(RM) -rf mount/target
 
 .PHONY: deb
 deb: all
diff --git a/mount/Cargo.lock b/mount/Cargo.lock
new file mode 100644 (file)
index 0000000..77ccbba
--- /dev/null
@@ -0,0 +1,695 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "aho-corasick"
+version = "0.7.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
+
+[[package]]
+name = "bcachefs-mount"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "bindgen",
+ "bitfield",
+ "byteorder",
+ "clap",
+ "either",
+ "env_logger",
+ "errno",
+ "gag",
+ "getset",
+ "itertools",
+ "libc",
+ "log",
+ "memoffset",
+ "parse-display",
+ "pkg-config",
+ "rpassword",
+ "structopt",
+ "udev",
+ "uuid",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.53.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bb26d6a69a335b8cb0e7c7e9775cd5666611dc50a37177c3f2cedcfc040e8c8"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "cfg-if",
+ "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.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "byteorder"
+version = "1.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
+
+[[package]]
+name = "cexpr"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "clang-sys"
+version = "0.29.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe6837df1d5cba2397b835c8530f51723267e16abbf83892e9e5af4f0e5dd10a"
+dependencies = [
+ "glob",
+ "libc",
+]
+
+[[package]]
+name = "clap"
+version = "2.33.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "term_size",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "either"
+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"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b480f641ccf0faf324e20c1d3e53d81b7484c698b42ea677f6907ae4db195371"
+dependencies = [
+ "errno-dragonfly",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "errno-dragonfly"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
+dependencies = [
+ "gcc",
+ "libc",
+]
+
+[[package]]
+name = "gag"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cc0b9f53275dc5fada808f1d2f82e3688a6c14d735633d1590b7be8eb2307b5"
+dependencies = [
+ "libc",
+ "tempfile",
+]
+
+[[package]]
+name = "gcc"
+version = "0.3.55"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
+
+[[package]]
+name = "getrandom"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "getset"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f62a139c59ae846c3964c392f12aac68f1997d1a40e9d3b40a89a4ab553e04a0"
+dependencies = [
+ "proc-macro-error 0.4.12",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "heck"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61565ff7aaace3525556587bd2dc31d4a07071957be715e63ce7b1eccf51a8f4"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "itertools"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
+dependencies = [
+ "either",
+]
+
+[[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.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
+
+[[package]]
+name = "libc"
+version = "0.2.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005"
+
+[[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 = "log"
+version = "0.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
+
+[[package]]
+name = "memoffset"
+version = "0.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "nom"
+version = "5.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b471253da97532da4b61552249c521e01e736071f71c1a4f7ebbfbf0a06aad6"
+dependencies = [
+ "memchr",
+ "version_check",
+]
+
+[[package]]
+name = "parse-display"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "718b422bc6b056b6374f7ffc3b2d9b55180a4af59a089835df1963994676d8b6"
+dependencies = [
+ "lazy_static",
+ "parse-display-derive",
+ "regex",
+]
+
+[[package]]
+name = "parse-display-derive"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7cf2deb364a60cc0f633c1ffe619b42463993c91352ae367010b8420e442655"
+dependencies = [
+ "lazy_static",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "regex-syntax",
+ "syn",
+]
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
+
+[[package]]
+name = "proc-macro-error"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18f33027081eba0a6d8aba6d1b1c3a3be58cbb12106341c2d5759fcd9b5277e7"
+dependencies = [
+ "proc-macro-error-attr 0.4.12",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
+dependencies = [
+ "proc-macro-error-attr 1.0.2",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a5b4b77fdb63c1eca72173d68d24501c54ab1269409f6b672c85deb18af69de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "syn-mid",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "syn-mid",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8872cf6f48eee44265156c111456a700ab3483686b3f96df4cf5481c89157319"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c1f4b0efa5fc5e8ceb705136bfee52cfdb6a4e3509f770b478cd6ed434232a7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom",
+ "libc",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
+
+[[package]]
+name = "regex"
+version = "1.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6020f034922e3194c711b82a627453881bc4682166cabb07134a10c26ba7692"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+ "thread_local",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rpassword"
+version = "4.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99371657d3c8e4d816fb6221db98fa408242b0b53bac08f8676a41f8554fe99f"
+dependencies = [
+ "libc",
+ "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 = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "structopt"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "863246aaf5ddd0d6928dfeb1a9ca65f505599e4e1b399935ef7e75107516b4ef"
+dependencies = [
+ "clap",
+ "lazy_static",
+ "structopt-derive",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d239ca4b13aee7a2142e6795cbd69e457665ff8037aed33b3effdc430d2f927a"
+dependencies = [
+ "heck",
+ "proc-macro-error 1.0.2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "410a7488c0a728c7ceb4ad59b9567eb4053d02e8cc7f5c0e0eeeb39518369213"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "syn-mid"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "term_size"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e4129646ca0ed8f45d09b929036bafad5377103edd06e50bf574b353d2b08d9"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "term_size",
+ "unicode-width",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
+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-segmentation"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+
+[[package]]
+name = "uuid"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11"
+
+[[package]]
+name = "vec_map"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
+
+[[package]]
+name = "version_check"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "winapi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
+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"
diff --git a/mount/Cargo.toml b/mount/Cargo.toml
new file mode 100644 (file)
index 0000000..4fd0d49
--- /dev/null
@@ -0,0 +1,34 @@
+[package]
+name = "bcachefs-mount"
+version = "0.1.0"
+authors = ["Yuxuan Shui <yshuiv7@gmail.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+log = "0.4"
+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"
+getset = "0.1"
+itertools = "0.9"
+structopt = "0.3"
+parse-display = "0.1"
+errno = "0.2"
+either = "1.5"
+rpassword = "4"
+byteorder = "1.3"
+
+[lib]
+crate-type = ["staticlib"]
+
+[build-dependencies]
+pkg-config = "0.3"
+bindgen = { version = "0.53", default-features = false }
diff --git a/mount/build.rs b/mount/build.rs
new file mode 100644 (file)
index 0000000..6542889
--- /dev/null
@@ -0,0 +1,67 @@
+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/mount/src/filesystem.rs b/mount/src/filesystem.rs
new file mode 100644 (file)
index 0000000..36af8c0
--- /dev/null
@@ -0,0 +1,174 @@
+extern "C" {
+       pub static stdout: *mut libc::FILE;
+}
+
+use getset::{CopyGetters, Getters};
+use std::path::PathBuf;
+#[derive(Getters, CopyGetters)]
+pub struct FileSystem {
+       /// External UUID of the bcachefs
+       #[getset(get = "pub")]
+       uuid: uuid::Uuid,
+       /// Whether filesystem is encrypted
+       #[getset(get_copy = "pub")]
+       encrypted: bool,
+       /// Super block
+       #[getset(get = "pub")]
+       sb: bcachefs::bch_sb_handle,
+       /// Member devices for this filesystem
+       #[getset(get = "pub")]
+       devices: Vec<PathBuf>,
+}
+
+/// Parse a comma-separated mount options and split out mountflags and filesystem
+/// specific options.
+fn parse_mount_options(options: impl AsRef<str>) -> (Option<String>, u64) {
+       use either::Either::*;
+       let (opts, flags) = options
+               .as_ref()
+               .split(",")
+               .map(|o| match o {
+                       "dirsync" => Left(libc::MS_DIRSYNC),
+                       "lazytime" => Left(1 << 25), // MS_LAZYTIME
+                       "mand" => Left(libc::MS_MANDLOCK),
+                       "noatime" => Left(libc::MS_NOATIME),
+                       "nodev" => Left(libc::MS_NODEV),
+                       "nodiratime" => Left(libc::MS_NODIRATIME),
+                       "noexec" => Left(libc::MS_NOEXEC),
+                       "nosuid" => Left(libc::MS_NOSUID),
+                       "ro" => Left(libc::MS_RDONLY),
+                       "rw" => Left(0),
+                       "relatime" => Left(libc::MS_RELATIME),
+                       "strictatime" => Left(libc::MS_STRICTATIME),
+                       "sync" => Left(libc::MS_SYNCHRONOUS),
+                       "" => Left(0),
+                       o @ _ => Right(o),
+               })
+               .fold((Vec::new(), 0), |(mut opts, flags), next| match next {
+                       Left(f) => (opts, flags | f),
+                       Right(o) => {
+                               opts.push(o);
+                               (opts, flags)
+                       }
+               });
+
+       use itertools::Itertools;
+       (
+               if opts.len() == 0 {
+                       None
+               } else {
+                       Some(opts.iter().join(","))
+               },
+               flags,
+       )
+}
+
+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<std::path::Path>,
+               options: impl AsRef<str>,
+       ) -> 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 std::collections::HashMap;
+use uuid::Uuid;
+pub fn probe_filesystems() -> anyhow::Result<HashMap<Uuid, FileSystem>> {
+       use std::os::unix::ffi::OsStrExt;
+       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);
+               }
+       }
+       Ok(fss)
+}
diff --git a/mount/src/key.rs b/mount/src/key.rs
new file mode 100644 (file)
index 0000000..6769f52
--- /dev/null
@@ -0,0 +1,96 @@
+use log::info;
+
+fn check_for_key(key_name: &std::ffi::CStr) -> anyhow::Result<bool> {
+       use crate::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) };
+       if key_id > 0 {
+               info!("Key has became avaiable");
+               Ok(true)
+       } else if errno::errno().0 != libc::ENOKEY {
+               Err(crate::ErrnoError(errno::errno()).into())
+       } else {
+               Ok(false)
+       }
+}
+
+fn wait_for_key(uuid: &uuid::Uuid) -> anyhow::Result<()> {
+       let key_name = std::ffi::CString::new(format!("bcachefs:{}", uuid)).unwrap();
+       loop {
+               if check_for_key(&key_name)? {
+                       break Ok(());
+               }
+
+               std::thread::sleep(std::time::Duration::from_secs(1));
+       }
+}
+
+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 std::os::raw::c_char;
+
+       let key_name = std::ffi::CString::new(format!("bcachefs:{}", fs.uuid())).unwrap();
+       if check_for_key(&key_name)? {
+               return Ok(());
+       }
+
+       let bch_key_magic = BCH_KEY_MAGIC.as_bytes().read_u64::<LittleEndian>().unwrap();
+       let crypt = fs.sb().sb().crypt().unwrap();
+       let pass = rpassword::read_password_from_tty(Some("Enter passphrase: "))?;
+       let pass = std::ffi::CString::new(pass.trim_end())?; // bind to keep the CString alive
+       let mut output: bch_key = unsafe {
+               bcachefs::derive_passphrase(
+                       crypt as *const _ as *mut _,
+                       pass.as_c_str().to_bytes_with_nul().as_ptr() as *const _,
+               )
+       };
+
+       let mut key = crypt.key().clone();
+       let ret = unsafe {
+               bch2_chacha_encrypt_key(
+                       &mut output as *mut _,
+                       fs.sb().sb().nonce(),
+                       &mut key as *mut _ as *mut _,
+                       std::mem::size_of::<bch_encrypted_key>() as u64,
+               )
+       };
+       if ret != 0 {
+               Err(anyhow!("chache 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(
+                               key_type,
+                               key_name.as_c_str().to_bytes_with_nul() as *const _
+                                       as *const c_char,
+                               &output as *const _ as *const _,
+                               std::mem::size_of::<bch_key>() as u64,
+                               crate::keyutils::KEY_SPEC_USER_KEYRING,
+                       )
+               };
+               if ret == -1 {
+                       Err(anyhow!("failed to add key to keyring: {}", errno::errno()))
+               } else {
+                       Ok(())
+               }
+       }
+}
+
+pub(crate) fn prepare_key(fs: &FileSystem, password: crate::KeyLocation) -> anyhow::Result<()> {
+       use crate::KeyLocation::*;
+       use anyhow::anyhow;
+       match password {
+               Fail => Err(anyhow!("no key available")),
+               Wait => Ok(wait_for_key(fs.uuid())?),
+               Ask => ask_for_key(fs),
+       }
+}
diff --git a/mount/src/keyutils_wrapper.h b/mount/src/keyutils_wrapper.h
new file mode 100644 (file)
index 0000000..857cee2
--- /dev/null
@@ -0,0 +1 @@
+#include <keyutils.h>
diff --git a/mount/src/lib.rs b/mount/src/lib.rs
new file mode 100644 (file)
index 0000000..751eab3
--- /dev/null
@@ -0,0 +1,190 @@
+use structopt::StructOpt;
+use anyhow::anyhow;
+
+#[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 }
+       };
+}
+
+#[derive(Debug)]
+struct ErrnoError(errno::Errno);
+impl std::fmt::Display for ErrnoError {
+       fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+               self.0.fmt(f)
+       }
+}
+impl std::error::Error for ErrnoError {}
+
+#[derive(Debug)]
+pub(crate) enum KeyLocation {
+       Fail,
+       Wait,
+       Ask,
+}
+
+impl std::str::FromStr for KeyLocation {
+       type Err = anyhow::Error;
+       fn from_str(s: &str) -> anyhow::Result<Self> {
+               use anyhow::anyhow;
+               match s {
+                       "fail" => Ok(Self::Fail),
+                       "wait" => Ok(Self::Wait),
+                       "ask" => Ok(Self::Ask),
+                       _ => Err(anyhow!("invalid password option"))
+               }
+       }
+}
+
+#[derive(StructOpt, Debug)]
+/// Mount a bcachefs filesystem by its UUID.
+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,
+
+       /// External UUID of the bcachefs filesystem
+       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<std::path::PathBuf>,
+
+       /// 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"));
+}
+
+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"));
+
+       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<bch_scrypt_flags> {
+                       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::<LittleEndian>().unwrap();
+                       let dword2 = internal_uuid.read_u32::<LittleEndian>().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);
+       }
+}
diff --git a/mount/src/libbcachefs_wrapper.h b/mount/src/libbcachefs_wrapper.h
new file mode 100644 (file)
index 0000000..fd76a6c
--- /dev/null
@@ -0,0 +1,4 @@
+#include <libbcachefs/super-io.h>
+#include <libbcachefs/checksum.h>
+#include <libbcachefs/bcachefs_format.h>
+#include <crypto.h>