vm: Use Structopt for parsing command line arguments

Test: adb shell /apex/com.android.virt/bin/vm --help
Change-Id: I1c19f6f3d0ef3f78cd1c8a52fbce6a09affe08fe
diff --git a/vm/Android.bp b/vm/Android.bp
index 5089e39..248af4d 100644
--- a/vm/Android.bp
+++ b/vm/Android.bp
@@ -14,6 +14,7 @@
         "libenv_logger",
         "liblibc",
         "liblog_rust",
+        "libstructopt",
     ],
     apex_available: [
         "com.android.virt",
diff --git a/vm/src/main.rs b/vm/src/main.rs
index 96ec649..34031f7 100644
--- a/vm/src/main.rs
+++ b/vm/src/main.rs
@@ -20,29 +20,36 @@
 use android_system_virtmanager::binder::{
     get_interface, ParcelFileDescriptor, ProcessState, Strong,
 };
-use anyhow::{bail, Context, Error};
+use anyhow::{Context, Error};
 // TODO: Import these via android_system_virtmanager::binder once https://r.android.com/1619403 is
 // submitted.
 use binder::{DeathRecipient, IBinder};
-use std::env;
 use std::fs::File;
 use std::io;
 use std::os::unix::io::{AsRawFd, FromRawFd};
-use std::process::exit;
+use std::path::PathBuf;
+use structopt::clap::AppSettings;
+use structopt::StructOpt;
 use sync::AtomicFlag;
 
 const VIRT_MANAGER_BINDER_SERVICE_IDENTIFIER: &str = "android.system.virtmanager";
 
+#[derive(StructOpt)]
+#[structopt(no_version, global_settings = &[AppSettings::DisableVersion])]
+enum Opt {
+    /// Run a virtual machine
+    Run {
+        /// Path to VM config JSON
+        #[structopt(parse(from_os_str))]
+        config: PathBuf,
+    },
+    /// List running virtual machines
+    List,
+}
+
 fn main() -> Result<(), Error> {
     env_logger::init();
-
-    let args: Vec<_> = env::args().collect();
-    if args.len() < 2 {
-        eprintln!("Usage:");
-        eprintln!("  {} run <vm_config.json>", args[0]);
-        eprintln!("  {} list", args[0]);
-        exit(1);
-    }
+    let opt = Opt::from_args();
 
     // We need to start the thread pool for Binder to work properly, especially link_to_death.
     ProcessState::start_thread_pool();
@@ -50,15 +57,15 @@
     let virt_manager = get_interface(VIRT_MANAGER_BINDER_SERVICE_IDENTIFIER)
         .context("Failed to find Virt Manager service")?;
 
-    match args[1].as_ref() {
-        "run" if args.len() == 3 => command_run(virt_manager, &args[2]),
-        "list" if args.len() == 2 => command_list(virt_manager),
-        command => bail!("Invalid command '{}' or wrong number of arguments", command),
+    match opt {
+        Opt::Run { config } => command_run(virt_manager, &config),
+        Opt::List => command_list(virt_manager),
     }
 }
 
 /// Run a VM from the given configuration file.
-fn command_run(virt_manager: Strong<dyn IVirtManager>, config_filename: &str) -> Result<(), Error> {
+fn command_run(virt_manager: Strong<dyn IVirtManager>, config_path: &PathBuf) -> Result<(), Error> {
+    let config_filename = config_path.to_str().context("Failed to parse VM config path")?;
     let stdout_file = ParcelFileDescriptor::new(duplicate_stdout()?);
     let vm =
         virt_manager.startVm(config_filename, Some(&stdout_file)).context("Failed to start VM")?;