fd_server: use clap's derive
This isn't a clear win, but still seems better than before. We also get
to avoid some string parsing except for --ro-fds.
Bug: 246385183
Test: atest AuthFsHostTest ComposHostTestCases
Change-Id: I8c2627c42b14796c1fa67e3ad32ec948cad6622e
diff --git a/authfs/fd_server/src/main.rs b/authfs/fd_server/src/main.rs
index 5b7a4f4..93a788b 100644
--- a/authfs/fd_server/src/main.rs
+++ b/authfs/fd_server/src/main.rs
@@ -26,12 +26,13 @@
mod fsverity;
use anyhow::{bail, Result};
+use clap::Parser;
use log::debug;
use nix::sys::stat::{umask, Mode};
use rpcbinder::run_rpc_server;
use std::collections::BTreeMap;
use std::fs::File;
-use std::os::unix::io::FromRawFd;
+use std::os::unix::io::{FromRawFd, OwnedFd};
use aidl::{FdConfig, FdService};
use authfs_fsverity_metadata::parse_fsverity_metadata;
@@ -72,86 +73,52 @@
))
}
-fn parse_arg_rw_fds(arg: &str) -> Result<(i32, FdConfig)> {
- let fd = arg.parse::<i32>()?;
- let file = fd_to_owned::<File>(fd)?;
- if file.metadata()?.len() > 0 {
- bail!("File is expected to be empty");
- }
- Ok((fd, FdConfig::ReadWrite(file)))
-}
-
-fn parse_arg_ro_dirs(arg: &str) -> Result<(i32, FdConfig)> {
- let fd = arg.parse::<i32>()?;
- Ok((fd, FdConfig::InputDir(fd_to_owned(fd)?)))
-}
-
-fn parse_arg_rw_dirs(arg: &str) -> Result<(i32, FdConfig)> {
- let fd = arg.parse::<i32>()?;
- Ok((fd, FdConfig::OutputDir(fd_to_owned(fd)?)))
-}
-
+#[derive(Parser)]
struct Args {
- fd_pool: BTreeMap<i32, FdConfig>,
- ready_fd: Option<File>,
+ /// Read-only FD of file, with optional FD of corresponding .fsv_meta, joined with a ':'.
+ /// Example: "1:2", "3".
+ #[clap(long)]
+ ro_fds: Vec<String>,
+
+ /// Read-writable FD of file
+ #[clap(long)]
+ rw_fds: Vec<i32>,
+
+ /// Read-only FD of directory
+ #[clap(long)]
+ ro_dirs: Vec<i32>,
+
+ /// Read-writable FD of directory
+ #[clap(long)]
+ rw_dirs: Vec<i32>,
+
+ /// A pipe FD for signaling the other end once ready
+ #[clap(long)]
+ ready_fd: Option<i32>,
}
-fn parse_args() -> Result<Args> {
- #[rustfmt::skip]
- let matches = clap::App::new("fd_server")
- .arg(clap::Arg::with_name("ro-fds")
- .long("ro-fds")
- .multiple(true)
- .number_of_values(1))
- .arg(clap::Arg::with_name("rw-fds")
- .long("rw-fds")
- .multiple(true)
- .number_of_values(1))
- .arg(clap::Arg::with_name("ro-dirs")
- .long("ro-dirs")
- .multiple(true)
- .number_of_values(1))
- .arg(clap::Arg::with_name("rw-dirs")
- .long("rw-dirs")
- .multiple(true)
- .number_of_values(1))
- .arg(clap::Arg::with_name("ready-fd")
- .long("ready-fd")
- .takes_value(true))
- .get_matches();
-
+/// Convert argument strings and integers to a form that is easier to use and handles ownership.
+fn convert_args(args: Args) -> Result<(BTreeMap<i32, FdConfig>, Option<OwnedFd>)> {
let mut fd_pool = BTreeMap::new();
- if let Some(args) = matches.values_of("ro-fds") {
- for arg in args {
- let (fd, config) = parse_arg_ro_fds(arg)?;
- fd_pool.insert(fd, config);
- }
+ for arg in args.ro_fds {
+ let (fd, config) = parse_arg_ro_fds(&arg)?;
+ fd_pool.insert(fd, config);
}
- if let Some(args) = matches.values_of("rw-fds") {
- for arg in args {
- let (fd, config) = parse_arg_rw_fds(arg)?;
- fd_pool.insert(fd, config);
+ for fd in args.rw_fds {
+ let file = fd_to_owned::<File>(fd)?;
+ if file.metadata()?.len() > 0 {
+ bail!("File is expected to be empty");
}
+ fd_pool.insert(fd, FdConfig::ReadWrite(file));
}
- if let Some(args) = matches.values_of("ro-dirs") {
- for arg in args {
- let (fd, config) = parse_arg_ro_dirs(arg)?;
- fd_pool.insert(fd, config);
- }
+ for fd in args.ro_dirs {
+ fd_pool.insert(fd, FdConfig::InputDir(fd_to_owned(fd)?));
}
- if let Some(args) = matches.values_of("rw-dirs") {
- for arg in args {
- let (fd, config) = parse_arg_rw_dirs(arg)?;
- fd_pool.insert(fd, config);
- }
+ for fd in args.rw_dirs {
+ fd_pool.insert(fd, FdConfig::OutputDir(fd_to_owned(fd)?));
}
- let ready_fd = if let Some(arg) = matches.value_of("ready-fd") {
- let fd = arg.parse::<i32>()?;
- Some(fd_to_owned(fd)?)
- } else {
- None
- };
- Ok(Args { fd_pool, ready_fd })
+ let ready_fd = args.ready_fd.map(fd_to_owned).transpose()?;
+ Ok((fd_pool, ready_fd))
}
fn main() -> Result<()> {
@@ -159,7 +126,8 @@
android_logger::Config::default().with_tag("fd_server").with_min_level(log::Level::Debug),
);
- let args = parse_args()?;
+ let args = Args::parse();
+ let (fd_pool, mut ready_fd) = convert_args(args)?;
// Allow open/create/mkdir from authfs to create with expecting mode. It's possible to still
// use a custom mask on creation, then report the actual file mode back to authfs. But there
@@ -167,9 +135,8 @@
let old_umask = umask(Mode::empty());
debug!("Setting umask to 0 (old: {:03o})", old_umask.bits());
- let service = FdService::new_binder(args.fd_pool).as_binder();
+ let service = FdService::new_binder(fd_pool).as_binder();
debug!("fd_server is starting as a rpc service.");
- let mut ready_fd = args.ready_fd;
let retval = run_rpc_server(service, RPC_SERVICE_PORT, || {
debug!("fd_server is ready");
// Close the ready-fd if we were given one to signal our readiness.