verity: use key-value args for commandline tool

We could use getopt here, but we'd like the arg format to stay the same between
the kernel module and the userspace tool, and getopt in kernel seems gauche.

BUG=chromium-os:15772
TEST=Adhoc
Built image, booted it. All good.

Change-Id: Id15f69e195bad641d5b8f9c1c0f4536f340355ba
Signed-off-by: Elly Jones <ellyjones@google.com>
Reviewed-on: http://gerrit.chromium.org/gerrit/1739
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
Tested-by: Elly Jones <ellyjones@chromium.org>
diff --git a/verity_main.cc b/verity_main.cc
index 8c059e2..db4d62d 100644
--- a/verity_main.cc
+++ b/verity_main.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
 // Use of this source code is governed by the GPL v2 license that can
 // be found in the LICENSE file.
 //
@@ -15,35 +15,20 @@
 void print_usage(const char *name) {
   fprintf(stderr,
 "Usage:\n"
-"  %s mode depth alg image image_blocks hash_image [root_hexdigest]\n\n"
+"  %s <arg>=<value>...\n"
 "Options:\n"
-"- mode:	May be create or verify\n"
-"		If create, the `hash_image' will be created.\n"
-"		If verify, the `hash_image` will be used to verify `image'.\n"
-"- depth:	Deprecated. Must be `0'.\n"
-"- alg:		Cryptographic hash algorithm to use\n"
-"		Valid values: sha512 sha384 sha256 sha224 sha1 sha\n"
-"			      mdc2 ripemd160 md5 md4 md2\n"
-"		(Algorithm choice depends on your target kernel)\n"
-"- image:	Path to the image to be hashed or verified\n"
-"- image_blocks: number of 4096 byte blocks to hash/verify\n"
-"   If 0, the file size will be used.\n"
-"- hash_image:	Path where a hash image file may be created or read\n"
-"- root_hexdigest:	Digest of the root node (in hex) for verifying\n"
+"  mode              One of 'create' or 'verify'\n"
+"  alg               Hash algorithm to use. One of:\n"
+"                      sha512 sha384 sha256 sha224 sha1 sha\n"
+"                      mdc2 ripemd160 md5 md4 md2\n"
+"  payload           Path to the image to hash\n"
+"  payload_blocks    Size of the image, in blocks (4096 bytes)\n"
+"  hashtree          Path to a hash tree to create or read from\n"
+"  root_hexdigest    Digest of the root node (in hex) for verification\n"
 "\n", name);
 }
 
 typedef enum { VERITY_NONE = 0, VERITY_CREATE, VERITY_VERIFY } verity_mode_t;
-static verity_mode_t parse_mode(const char *mode_s) {
-  if (!strcmp(mode_s, "create")) return VERITY_CREATE;
-  if (!strcmp(mode_s, "verify")) return VERITY_VERIFY;
-  fprintf(stderr, "Unknown mode specified: %s\n", mode_s);
-  return VERITY_NONE;
-}
-
-static unsigned int parse_depth(const char *depth_s) {
-  return (unsigned int)strtoul(depth_s, NULL, 0);
-}
 
 static unsigned int parse_blocks(const char *block_s) {
   return (unsigned int)strtoul(block_s, NULL, 0);
@@ -55,22 +40,55 @@
                          unsigned int image_blocks,
                          const char *hash_path);
 
+void splitarg(char *arg, char **key, char **val) {
+  char *sp = NULL;
+  *key = strtok_r(arg, "=", &sp);
+  *val = strtok_r(NULL, "=", &sp);
+}
+
 int main(int argc, char **argv) {
-  if (argc < 7) {
-    print_usage(argv[0]);
-    return 1;
+  verity_mode_t mode = VERITY_CREATE;
+  const char *alg = NULL;
+  const char *payload = NULL;
+  const char *hashtree = NULL;
+  const char *root_hexdigest = NULL;
+  unsigned int payload_blocks = 0;
+  int i;
+  char *key, *val;
+
+  for (i = 1; i < argc; i++) {
+    splitarg(argv[i], &key, &val);
+    if (!strcmp(key, "alg"))
+      alg = val;
+    else if (!strcmp(key, "payload"))
+      payload = val;
+    else if (!strcmp(key, "payload_blocks"))
+      payload_blocks = parse_blocks(val);
+    else if (!strcmp(key, "hashtree"))
+      hashtree = val;
+    else if (!strcmp(key, "root_hexdigest"))
+      root_hexdigest = val;
+    else if (!strcmp(key, "mode"))
+      // Silently drop the mode for now...
+      ;
+    else {
+      fprintf(stderr, "bogus key: '%s'\n", key);
+      print_usage(argv[0]);
+      return -1;
+    }
   }
 
-  if (parse_depth(argv[2]) != 0) {
-    LOG(FATAL) << "depth must be 0";
+  if (!alg || !payload || !hashtree) {
+    fprintf(stderr, "missing data: %s%s%s\n",
+            alg ? "" : "alg ",
+            payload ? "" : "payload ",
+            hashtree ? "" : "hashtree");
+    print_usage(argv[0]);
     return -1;
   }
 
-  if (parse_mode(argv[1]) == VERITY_CREATE) {
-    return verity_create(argv[3],  // alg
-                         argv[4],  // image_path
-                         parse_blocks(argv[5]),
-                         argv[6]);  // hash path
+  if (mode == VERITY_CREATE) {
+    return verity_create(alg, payload, payload_blocks, hashtree);
   } else {
     LOG(FATAL) << "Verification not done yet";
   }