]> git.sesse.net Git - bcachefs-tools-debian/commitdiff
create common entry point for Rust commands
authorThomas Bertschinger <tahbertschinger@gmail.com>
Mon, 8 Jan 2024 01:36:33 +0000 (18:36 -0700)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 8 Jan 2024 02:38:31 +0000 (21:38 -0500)
The bcachefs sub-commands that are implemented in Rust (completions,
list, and mount) had separate entrypoints and thus had some differences
in behavior.

This introduces a common entry point for the Rust sub-commands. This
reduces duplicate boilerplate code like parsing argv and setting up
logging, and will facilitate converting more sub-commands to Rust in
the future.

An immediate benefit is that this fixes an issue with `bcachefs list`
not reporting errors:

before:

$ bcachefs list /dev/typo
$ echo $?
0

after:

$ bcachefs list /dev/typo
ERROR - bcachefs_rust::cmd_list: Fatal error: "No such file or directory"
$ echo $?
1

Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
bcachefs.c
cmds.h
rust-src/src/cmd_completions.rs
rust-src/src/cmd_list.rs
rust-src/src/cmd_main.rs [new file with mode: 0644]
rust-src/src/cmd_mount.rs
rust-src/src/lib.rs

index e132d916fa73967f2e289b0a42e725f1e7a4e822..7b8d4d648a4bc2ed2ee6b8bf7245304bf7cec24e 100644 (file)
@@ -207,7 +207,7 @@ int main(int argc, char *argv[])
 
 #ifndef BCACHEFS_NO_RUST
        if (strstr(full_cmd, "mount"))
-               return cmd_mount(argc, argv);
+               return rust_main(argc, argv, "mount");
 #endif
 
        setvbuf(stdout, NULL, _IOLBF, 0);
@@ -265,10 +265,6 @@ int main(int argc, char *argv[])
 
        if (!strcmp(cmd, "dump"))
                return cmd_dump(argc, argv);
-#ifndef BCACHEFS_NO_RUST
-       if (!strcmp(cmd, "list"))
-               return cmd_list(argc, argv);
-#endif
        if (!strcmp(cmd, "list_journal"))
                return cmd_list_journal(argc, argv);
        if (!strcmp(cmd, "kill_btree_node"))
@@ -277,10 +273,10 @@ int main(int argc, char *argv[])
        if (!strcmp(cmd, "setattr"))
                return cmd_setattr(argc, argv);
 #ifndef BCACHEFS_NO_RUST
-       if (!strcmp(cmd, "mount"))
-               return cmd_mount(argc, argv);
-    if (strstr(cmd, "completions"))
-        return cmd_completions(argc, argv);
+       if (!strcmp(cmd, "list") ||
+           !strcmp(cmd, "mount") ||
+           !strcmp(cmd, "completions"))
+               return rust_main(argc, argv, cmd);
 #endif
 
 #ifdef BCACHEFS_FUSE
diff --git a/cmds.h b/cmds.h
index 76a7613500db95087a342a926ced55e201a2a8c3..88b03f33bfbcfe501abfa95e5a46d29eaaa8b2b6 100644 (file)
--- a/cmds.h
+++ b/cmds.h
@@ -37,7 +37,6 @@ int cmd_remove_passphrase(int argc, char *argv[]);
 int cmd_fsck(int argc, char *argv[]);
 
 int cmd_dump(int argc, char *argv[]);
-int cmd_list(int argc, char *argv[]);
 int cmd_list_journal(int argc, char *argv[]);
 int cmd_kill_btree_node(int argc, char *argv[]);
 
@@ -54,7 +53,7 @@ int cmd_subvolume_delete(int argc, char *argv[]);
 int cmd_subvolume_snapshot(int argc, char *argv[]);
 
 int cmd_fusemount(int argc, char *argv[]);
-int cmd_mount(int argc, char *argv[]);
-int cmd_completions(int argc, char *argv[]);
+
+int rust_main(int argc, char *argv[], char *cmd);
 
 #endif /* _CMDS_H */
index 51859696e0626af2dd04827a10460d82dd89cfdd..3e839fe82dc9c38730f91b87b4c50acc30f4b1d9 100644 (file)
@@ -1,7 +1,6 @@
-use crate::transform_c_args;
 use clap::{Command, CommandFactory, Parser};
 use clap_complete::{generate, Generator, Shell};
-use std::ffi::{c_char, c_int};
+use std::ffi::{c_int, OsStr};
 use std::io;
 
 /// Generate shell completions
@@ -14,10 +13,7 @@ fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
     generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
 }
 
-#[no_mangle]
-#[allow(clippy::not_unsafe_ptr_arg_deref)]
-pub extern "C" fn cmd_completions(argc: c_int, argv: *const *const c_char) -> c_int {
-    transform_c_args!(argv, argc, argv);
+pub fn cmd_completions(argv: Vec<&OsStr>) -> c_int {
     let cli = Cli::parse_from(argv);
     print_completions(cli.shell, &mut super::Cli::command());
     0
index 5540514e6b42a2cf771bf067a4de017e538673bf..fa9c2f2f8701829b7726a97c7086ca423cbc0419 100644 (file)
@@ -9,8 +9,7 @@ use bch_bindgen::btree::BtreeIter;
 use bch_bindgen::btree::BtreeNodeIter;
 use bch_bindgen::btree::BtreeIterFlags;
 use clap::{Parser};
-use std::ffi::{c_int, c_char};
-use crate::transform_c_args;
+use std::ffi::{c_int, OsStr};
 
 fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> {
     let trans = BtreeTrans::new(fs);
@@ -158,13 +157,13 @@ fn cmd_list_inner(opt: Cli) -> anyhow::Result<()> {
     }
 }
 
-#[no_mangle]
-#[allow(clippy::not_unsafe_ptr_arg_deref)]
-pub extern "C" fn cmd_list(argc: c_int, argv: *const *const c_char) {
-    transform_c_args!(argv, argc, argv);
+pub fn cmd_list(argv: Vec<&OsStr>) -> c_int {
     let opt = Cli::parse_from(argv);
     colored::control::set_override(opt.colorize);
     if let Err(e) = cmd_list_inner(opt) {
         error!("Fatal error: {}", e);
+        1
+    } else {
+        0
     }
 }
diff --git a/rust-src/src/cmd_main.rs b/rust-src/src/cmd_main.rs
new file mode 100644 (file)
index 0000000..baedc85
--- /dev/null
@@ -0,0 +1,34 @@
+use log::{error, LevelFilter};
+use std::ffi::{CStr, c_int, c_char};
+use crate::transform_c_args;
+use crate::logger::SimpleLogger;
+use crate::cmd_completions::cmd_completions;
+use crate::cmd_list::cmd_list;
+use crate::cmd_mount::cmd_mount;
+
+#[no_mangle]
+pub extern "C" fn rust_main(argc: c_int, argv: *const *const c_char, cmd: *const c_char) -> c_int {
+    transform_c_args!(argv, argc, argv);
+
+    log::set_boxed_logger(Box::new(SimpleLogger)).unwrap();
+    log::set_max_level(LevelFilter::Warn);
+
+    let cmd: &CStr = unsafe { CStr::from_ptr(cmd) };
+    let cmd = match cmd.to_str() {
+        Ok(c) => c,
+        Err(e) => {
+            error!("could not parse command: {}", e);
+            return 1;
+        }
+    };
+
+    match cmd {
+        "completions" => cmd_completions(argv),
+        "list" => cmd_list(argv),
+        "mount" => cmd_mount(argv),
+        _ => {
+            error!("unknown command: {}", cmd);
+            1
+        }
+    }
+}
index a75dd21fc39ebf7cf1986d265b9ff96bda13b706..3f8253f5e1f56781a22fdf6ee7cf6b0ccacdd85b 100644 (file)
@@ -4,10 +4,9 @@ use log::{info, debug, error, LevelFilter};
 use clap::{Parser};
 use uuid::Uuid;
 use std::path::PathBuf;
-use crate::{key, transform_c_args};
+use crate::key;
 use crate::key::KeyLocation;
-use crate::logger::SimpleLogger;
-use std::ffi::{CString, c_int, c_char, c_void};
+use std::ffi::{CString, c_int, c_char, c_void, OsStr};
 use std::os::unix::ffi::OsStrExt;
 
 fn mount_inner(
@@ -222,14 +221,9 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> {
     Ok(())
 }
 
-#[no_mangle]
-#[allow(clippy::not_unsafe_ptr_arg_deref)]
-pub extern "C" fn cmd_mount(argc: c_int, argv: *const *const c_char) -> c_int {
-    transform_c_args!(argv, argc, argv);
+pub fn cmd_mount(argv: Vec<&OsStr>) -> c_int {
     let opt = Cli::parse_from(argv);
 
-    log::set_boxed_logger(Box::new(SimpleLogger)).unwrap();
-
     // @TODO : more granular log levels via mount option
     log::set_max_level(match opt.verbose {
         0 => LevelFilter::Warn,
index 64297b41d7dce8d56c6a1bdbb0c6ef7ea74add00..026cca49cbbf4f901ba59c8ed0af6e7d36a7768e 100644 (file)
@@ -2,6 +2,7 @@ use clap::Subcommand;
 
 pub mod key;
 pub mod logger;
+pub mod cmd_main;
 pub mod cmd_mount;
 pub mod cmd_list;
 pub mod cmd_completions;