diff options
author | Thomas Bertschinger <tahbertschinger@gmail.com> | 2024-01-15 23:41:00 -0700 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2024-01-16 01:46:41 -0500 |
commit | 0a284fc4ffcbb46f0a4b921415ef12a9c75fa05c (patch) | |
tree | 22aa82b7448833713ca975eb3c241f607742fc78 /rust-src/src | |
parent | 249bf7b9d446092e1b744c366b7e8c4563a437f0 (diff) |
convert main() from C to Rust
This moves the main() function from C to Rust. It also updates the name
of the Rust package from "bcachefs-rust" to "bcachefs-tools".
Signed-off-by: Thomas Bertschinger <tahbertschinger@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'rust-src/src')
-rw-r--r-- | rust-src/src/bcachefs.rs | 107 | ||||
-rw-r--r-- | rust-src/src/cmd_completions.rs | 3 | ||||
-rw-r--r-- | rust-src/src/cmd_list.rs | 3 | ||||
-rw-r--r-- | rust-src/src/cmd_main.rs | 34 | ||||
-rw-r--r-- | rust-src/src/cmd_mount.rs | 11 | ||||
-rw-r--r-- | rust-src/src/lib.rs | 13 |
6 files changed, 118 insertions, 53 deletions
diff --git a/rust-src/src/bcachefs.rs b/rust-src/src/bcachefs.rs new file mode 100644 index 00000000..3d7af3d4 --- /dev/null +++ b/rust-src/src/bcachefs.rs @@ -0,0 +1,107 @@ +use std::ffi::CString; + +use bcachefs::cmd_completions::cmd_completions; +use bcachefs::cmd_list::cmd_list; +use bcachefs::cmd_mount::cmd_mount; +use bcachefs::logger::SimpleLogger; +use bch_bindgen::c; + +fn handle_c_command(args: Vec<String>, symlink_cmd: Option<&str>) -> i32 { + let mut argv: Vec<_> = args.clone(); + + let cmd = match symlink_cmd { + Some(s) => s.to_string(), + None => argv.remove(1), + }; + + let argc: i32 = argv.len().try_into().unwrap(); + + let argv: Vec<_> = argv + .iter() + .map(|s| CString::new(s.as_str()).unwrap()) + .collect(); + let argv: Vec<_> = argv.iter().map(|s| s.as_ptr()).collect(); + let argv = argv.as_ptr() as *mut *mut i8; + + // The C functions will mutate argv. It shouldn't be used after this block. + unsafe { + match cmd.as_str() { + "--help" => { + c::bcachefs_usage(); + 0 + }, + "data" => c::data_cmds(argc, argv), + "device" => c::device_cmds(argc, argv), + "dump" => c::cmd_dump(argc, argv), + "format" => c::cmd_format(argc, argv), + "fs" => c::fs_cmds(argc, argv), + "fsck" => c::cmd_fsck(argc, argv), + "list_journal" => c::cmd_list_journal(argc, argv), + "kill_btree_node" => c::cmd_kill_btree_node(argc, argv), + "migrate" => c::cmd_migrate(argc, argv), + "migrate-superblock" => c::cmd_migrate_superblock(argc, argv), + "mkfs" => c::cmd_format(argc, argv), + "remove-passphrase" => c::cmd_remove_passphrase(argc, argv), + "reset-counters" => c::cmd_reset_counters(argc, argv), + "set-option" => c::cmd_set_option(argc, argv), + "set-passphrase" => c::cmd_set_passphrase(argc, argv), + "setattr" => c::cmd_setattr(argc, argv), + "show-super" => c::cmd_show_super(argc, argv), + "subvolume" => c::subvolume_cmds(argc, argv), + "unlock" => c::cmd_unlock(argc, argv), + "version" => c::cmd_version(argc, argv), + + #[cfg(fuse)] + "fusemount" => c::cmd_fusemount(argc, argv), + + _ => { + println!("Unknown command {}", cmd); + c::bcachefs_usage(); + 1 + } + } + } +} + +fn main() { + let args: Vec<String> = std::env::args().collect(); + + let symlink_cmd: Option<&str> = if args[0].contains("mkfs") { + Some("mkfs") + } else if args[0].contains("fsck") { + Some("fsck") + } else if args[0].contains("mount.fuse") { + Some("fusemount") + } else if args[0].contains("mount") { + Some("mount") + } else { + None + }; + + if symlink_cmd.is_none() && args.len() < 2 { + println!("missing command"); + unsafe { c::bcachefs_usage() }; + std::process::exit(1); + } + + unsafe { c::raid_init() }; + + log::set_boxed_logger(Box::new(SimpleLogger)).unwrap(); + log::set_max_level(log::LevelFilter::Warn); + + let cmd = match symlink_cmd { + Some(s) => s, + None => args[1].as_str(), + }; + + let ret = match cmd { + "completions" => cmd_completions(args[1..].to_vec()), + "list" => cmd_list(args[1..].to_vec()), + "mount" => cmd_mount(args, symlink_cmd), + _ => handle_c_command(args, symlink_cmd), + }; + + if ret != 0 { + std::process::exit(1); + } +} diff --git a/rust-src/src/cmd_completions.rs b/rust-src/src/cmd_completions.rs index 3e839fe8..53cdd643 100644 --- a/rust-src/src/cmd_completions.rs +++ b/rust-src/src/cmd_completions.rs @@ -1,6 +1,5 @@ use clap::{Command, CommandFactory, Parser}; use clap_complete::{generate, Generator, Shell}; -use std::ffi::{c_int, OsStr}; use std::io; /// Generate shell completions @@ -13,7 +12,7 @@ fn print_completions<G: Generator>(gen: G, cmd: &mut Command) { generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout()); } -pub fn cmd_completions(argv: Vec<&OsStr>) -> c_int { +pub fn cmd_completions(argv: Vec<String>) -> i32 { let cli = Cli::parse_from(argv); print_completions(cli.shell, &mut super::Cli::command()); 0 diff --git a/rust-src/src/cmd_list.rs b/rust-src/src/cmd_list.rs index fa9c2f2f..cb352916 100644 --- a/rust-src/src/cmd_list.rs +++ b/rust-src/src/cmd_list.rs @@ -9,7 +9,6 @@ use bch_bindgen::btree::BtreeIter; use bch_bindgen::btree::BtreeNodeIter; use bch_bindgen::btree::BtreeIterFlags; use clap::{Parser}; -use std::ffi::{c_int, OsStr}; fn list_keys(fs: &Fs, opt: Cli) -> anyhow::Result<()> { let trans = BtreeTrans::new(fs); @@ -157,7 +156,7 @@ fn cmd_list_inner(opt: Cli) -> anyhow::Result<()> { } } -pub fn cmd_list(argv: Vec<&OsStr>) -> c_int { +pub fn cmd_list(argv: Vec<String>) -> i32 { let opt = Cli::parse_from(argv); colored::control::set_override(opt.colorize); if let Err(e) = cmd_list_inner(opt) { diff --git a/rust-src/src/cmd_main.rs b/rust-src/src/cmd_main.rs deleted file mode 100644 index baedc851..00000000 --- a/rust-src/src/cmd_main.rs +++ /dev/null @@ -1,34 +0,0 @@ -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 - } - } -} diff --git a/rust-src/src/cmd_mount.rs b/rust-src/src/cmd_mount.rs index eccfe6d0..b120c91e 100644 --- a/rust-src/src/cmd_mount.rs +++ b/rust-src/src/cmd_mount.rs @@ -6,7 +6,7 @@ use uuid::Uuid; use std::path::PathBuf; use crate::key; use crate::key::KeyLocation; -use std::ffi::{CString, c_int, c_char, c_void, OsStr}; +use std::ffi::{CString, c_char, c_void}; use std::os::unix::ffi::OsStrExt; fn mount_inner( @@ -223,7 +223,14 @@ fn cmd_mount_inner(opt: Cli) -> anyhow::Result<()> { Ok(()) } -pub fn cmd_mount(argv: Vec<&OsStr>) -> c_int { +pub fn cmd_mount(mut argv: Vec<String>, symlink_cmd: Option<&str>) -> i32 { + // If the bcachefs tool is being called as "bcachefs mount dev ..." (as opposed to via a + // symlink like "/usr/sbin/mount.bcachefs dev ...", then we need to pop the 0th argument + // ("bcachefs") since the CLI parser here expects the device at position 1. + if symlink_cmd.is_none() { + argv.remove(0); + } + let opt = Cli::parse_from(argv); // @TODO : more granular log levels via mount option diff --git a/rust-src/src/lib.rs b/rust-src/src/lib.rs index 026cca49..f8b508dc 100644 --- a/rust-src/src/lib.rs +++ b/rust-src/src/lib.rs @@ -2,7 +2,6 @@ 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; @@ -32,18 +31,6 @@ macro_rules! c_str { }; } -#[macro_export] -macro_rules! transform_c_args { - ($var:ident, $argc:expr, $argv:expr) => { - // TODO: `OsStr::from_bytes` only exists on *nix - use ::std::os::unix::ffi::OsStrExt; - let $var: Vec<_> = (0..$argc) - .map(|i| unsafe { ::std::ffi::CStr::from_ptr(*$argv.add(i as usize)) }) - .map(|i| ::std::ffi::OsStr::from_bytes(i.to_bytes())) - .collect(); - }; -} - #[derive(Debug)] struct ErrnoError(errno::Errno); impl std::fmt::Display for ErrnoError { |