Update for API changes

Signed-off-by: Eric Biggers <ebiggers@google.com>
diff --git a/.gitignore b/.gitignore
index 7393bea..256af29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
-fsveritymeasure
-fsverityset
+fsverity
 fsveritysetup.pyc
 tags
 cscope.*
diff --git a/Makefile b/Makefile
index 5cf2c22..36e64f8 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 CFLAGS := -O2 -Wall
-EXE := fsverityset fsveritymeasure
+EXE := fsverity
 
 all:$(EXE)
 
diff --git a/fsverity.c b/fsverity.c
new file mode 100644
index 0000000..931cb07
--- /dev/null
+++ b/fsverity.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fs-verity userspace tool
+ *
+ * Copyright (C) 2018, Google, Inc.
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "fsverity_api.h"
+
+#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
+
+static const struct fsverity_hash_alg {
+	const char *name;
+	int digest_size;
+} fsverity_hash_algs[] = {
+	[FS_VERITY_ALG_SHA256] = {
+		.name = "sha256",
+		.digest_size = 32,
+	},
+	[FS_VERITY_ALG_CRC32] = {
+		.name = "crc32",
+		.digest_size = 4,
+	},
+};
+
+static void show_hash_algs(void)
+{
+	size_t i;
+
+	fprintf(stderr, "Available hash algorithms:");
+	for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
+		if (fsverity_hash_algs[i].name)
+			fprintf(stderr, " %s", fsverity_hash_algs[i].name);
+	}
+	fprintf(stderr, "\n");
+}
+
+static const struct fsverity_hash_alg *find_hash_alg(const char *name)
+{
+	size_t i;
+
+	for (i = 0; i < ARRAY_SIZE(fsverity_hash_algs); i++) {
+		if (fsverity_hash_algs[i].name &&
+		    !strcmp(name, fsverity_hash_algs[i].name))
+			return &fsverity_hash_algs[i];
+	}
+	return NULL;
+}
+
+static int hex2bin_char(char c)
+{
+	if (c >= 'a' && c <= 'f')
+		return 10 + c - 'a';
+	if (c >= 'A' && c <= 'F')
+		return 10 + c - 'A';
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	return -1;
+}
+
+static bool parse_hex_digest(const char *hex, __u8 *bin, size_t bin_len)
+{
+	size_t i;
+
+	if (strlen(hex) != 2 * bin_len)
+		return false;
+
+	for (i = 0; i < bin_len; i++) {
+		int hi = hex2bin_char(hex[i * 2]);
+		int lo = hex2bin_char(hex[i * 2 + 1]);
+
+		if (hi < 0 || lo < 0)
+			return false;
+		bin[i] = (hi << 4) | lo;
+	}
+	return true;
+}
+
+enum {
+	OPT_HASH,
+};
+
+static void usage(void)
+{
+	const char * const usage_str =
+"Usage: fsverity enable FILE\n"
+"       fsverity set_measurement [--hash=HASH] FILE EXPECTED_MEASUREMENT\n"
+"\n"
+"EXPECTED_MEASUREMENT must be given as a hex string.\n"
+"The default HASH algorithm is sha256.\n"
+	;
+	fputs(usage_str, stderr);
+	show_hash_algs();
+	exit(2);
+}
+
+static int fsverity_enable(int argc, char *argv[])
+{
+	int fd;
+
+	if (argc != 2)
+		usage();
+
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Can't open %s: %m\n", argv[1]);
+		return 1;
+	}
+	if (ioctl(fd, FS_IOC_ENABLE_VERITY, NULL)) {
+		fprintf(stderr, "FS_IOC_ENABLE_VERITY: %m\n");
+		return 1;
+	}
+	close(fd);
+	return 0;
+}
+
+static int fsverity_set_measurement(int argc, char *argv[])
+{
+	static const struct option longopts[] = {
+		{"hash", required_argument, NULL, OPT_HASH},
+		{NULL, 0, NULL, 0},
+	};
+	const struct fsverity_hash_alg *alg =
+		&fsverity_hash_algs[FS_VERITY_ALG_SHA256];
+	int c;
+	int fd;
+	struct fsverity_measurement *measurement;
+
+	while ((c = getopt_long(argc, argv, "", longopts, NULL)) != -1) {
+		switch (c) {
+		case OPT_HASH:
+			alg = find_hash_alg(optarg);
+			if (!alg) {
+				fprintf(stderr,
+					"Unknown hash algorithm: '%s'\n",
+					optarg);
+				show_hash_algs();
+				return 2;
+			}
+			break;
+		default:
+			usage();
+		}
+	}
+	argv += optind;
+	argc -= optind;
+
+	if (argc != 2)
+		usage();
+
+	fd = open(argv[0], O_RDONLY);
+	if (fd < 0) {
+		fprintf(stderr, "Can't open %s: %m\n", argv[0]);
+		return 1;
+	}
+
+	measurement = calloc(1, sizeof(*measurement) + alg->digest_size);
+	measurement->digest_algorithm = alg - &fsverity_hash_algs[0];
+	measurement->digest_size = alg->digest_size;
+	if (!parse_hex_digest(argv[1], measurement->digest, alg->digest_size)) {
+		fprintf(stderr,
+			"Invalid EXPECTED_MEASUREMENT hex string.  Expected %u-character hex string for hash algorithm '%s'\n",
+			alg->digest_size * 2, alg->name);
+		return 2;
+	}
+
+	if (ioctl(fd, FS_IOC_SET_VERITY_MEASUREMENT, measurement)) {
+		fprintf(stderr, "FS_IOC_SET_VERITY_MEASUREMENT: %m\n");
+		return 1;
+	}
+	close(fd);
+	return 0;
+}
+
+static const struct {
+	const char *name;
+	int (*func)(int argc, char *argv[]);
+} commands[] = {
+	{ "enable", fsverity_enable },
+	{ "set_measurement", fsverity_set_measurement },
+};
+
+int main(int argc, char *argv[])
+{
+	size_t i;
+
+	if (argc < 2)
+		usage();
+
+	for (i = 0; i < ARRAY_SIZE(commands); i++) {
+		if (!strcmp(argv[1], commands[i].name))
+			return commands[i].func(argc - 1, argv + 1);
+	}
+	usage();
+}
diff --git a/fsverity_api.h b/fsverity_api.h
index db0483f..e4cc960 100644
--- a/fsverity_api.h
+++ b/fsverity_api.h
@@ -1,5 +1,5 @@
-#ifndef _FSVERITY_KERNEL_DEFS_H
-#define _FSVERITY_KERNEL_DEFS_H
+#ifndef _FSVERITY_API_H
+#define _FSVERITY_API_H
 
 #include <linux/limits.h>
 #include <linux/ioctl.h>
@@ -7,38 +7,18 @@
 
 /* file-based verity support */
 
-/*
- * TODO(ebiggers):  What is the purpose of this structure?  It's not actually
- * used for anything.
- */
-struct fsverity_set {
-	__u64 offset;
-	__u64 flags;
+#define FS_VERITY_ALG_SHA256	1
+#define FS_VERITY_ALG_CRC32	2
+
+struct fsverity_measurement {
+	__u16 digest_algorithm;
+	__u16 digest_size;
+	__u32 reserved1;
+	__u64 reserved2[3];
+	__u8 digest[];
 };
 
-/*
- * TODO(ebiggers): why isn't this using the same type code as used in the
- * fsverity_header?
- */
-#define FS_VERITY_ROOT_HASH_ALGO_SHA256	0x0000
+#define FS_IOC_ENABLE_VERITY		_IO('f', 133)
+#define FS_IOC_SET_VERITY_MEASUREMENT	_IOW('f', 134, struct fsverity_measurement)
 
-/*
- * TODO(ebiggers): rename this to 'struct fsverity_measurement' to avoid
- * confusion with the Merkle tree root hash?
- */
-struct fsverity_root_hash {
-	__u32 root_hash_algorithm;
-	__u32 flags;
-	__u8 reserved[4];
-	__u8 root_hash[64];
-};
-
-/*
- * TODO(ebiggers): is there a less confusing name for this?  "measure" makes it
- * sound like it's returning something...
- */
-#define FS_IOC_MEASURE_FSVERITY		_IOW('f', 133, \
-					      struct fsverity_root_hash)
-#define FS_IOC_SET_FSVERITY		_IOW('f', 134, struct fsverity_set)
-
-#endif /* _FSVERITY_KERNEL_DEFS_H */
+#endif /* _FSVERITY_API_H */
diff --git a/fsveritymeasure.c b/fsveritymeasure.c
deleted file mode 100644
index 0be1c25..0000000
--- a/fsveritymeasure.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include "fsverity_api.h"
-
-static void usage(void)
-{
-	fprintf(stderr,
-"Usage: fsveritymeasure FILE EXPECTED_MEASUREMENT\n"
-"\n"
-"EXPECTED_MEASUREMENT must be a 64-character hex string.\n");
-	exit(2);
-}
-
-int main(int args, char *argv[])
-{
-	int fd, i;
-	unsigned int byte;
-	struct fsverity_root_hash measurement = { 0 };
-
-	if (args != 3 || strlen(argv[2]) != 64)
-		usage();
-
-	for (i = 0; i < 32; i++) {
-		if (sscanf(&argv[2][i*2], "%02x", &byte) != 1)
-			usage();
-		measurement.root_hash[i] = byte;
-	}
-	fd = open(argv[1], O_RDONLY);
-	if (fd < 0) {
-		fprintf(stderr, "Can't open %s: %m\n", argv[1]);
-		return 1;
-	}
-	if (ioctl(fd, FS_IOC_MEASURE_FSVERITY, &measurement)) {
-		fprintf(stderr, "FS_IOC_MEASURE_FSVERITY: %m\n");
-		return 1;
-	}
-	close(fd);
-	return 0;
-}
diff --git a/fsverityset.c b/fsverityset.c
deleted file mode 100644
index 6075071..0000000
--- a/fsverityset.c
+++ /dev/null
@@ -1,34 +0,0 @@
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-#include "fsverity_api.h"
-
-static void usage(void)
-{
-	fprintf(stderr, "Usage: fsverityset FILE\n");
-	exit(2);
-}
-
-int main(int args, char *argv[])
-{
-	int fd;
-	struct fsverity_set set = { 0 };
-
-	if (args != 2)
-		usage();
-
-	fd = open(argv[1], O_RDONLY);
-	if (fd < 0) {
-		fprintf(stderr, "Can't open %s: %m\n", argv[1]);
-		return 1;
-	}
-	if (ioctl(fd, FS_IOC_SET_FSVERITY, &set)) {
-		fprintf(stderr, "FS_IOC_SET_FSVERITY: %m\n");
-		return 1;
-	}
-	close(fd);
-	return 0;
-}
diff --git a/fsveritysetup.py b/fsveritysetup.py
index 692304c..282bff7 100755
--- a/fsveritysetup.py
+++ b/fsveritysetup.py
@@ -21,8 +21,8 @@
 FS_VERITY_SALT_SIZE = 8
 FS_VERITY_EXT_ELIDE = 0
 FS_VERITY_EXT_PATCH = 1
-FS_VERITY_ALG_CRC32 = 0
 FS_VERITY_ALG_SHA256 = 1
+FS_VERITY_ALG_CRC32 = 2
 
 
 class CRC32Hash(object):
@@ -68,8 +68,8 @@
 
 
 HASH_ALGORITHMS = [
-    HashAlgorithm(FS_VERITY_ALG_CRC32, 'crc32', 4),
     HashAlgorithm(FS_VERITY_ALG_SHA256, 'sha256', 32),
+    HashAlgorithm(FS_VERITY_ALG_CRC32, 'crc32', 4),
 ]
 
 
diff --git a/full-run-fsverity.sh b/full-run-fsverity.sh
index 14bb3dc..2507f57 100755
--- a/full-run-fsverity.sh
+++ b/full-run-fsverity.sh
@@ -7,8 +7,8 @@
 mount -o loop /root/f2fs.img /mnt/f2fs
 cp /root/output-$1.apk /mnt/f2fs/output-$1.apk
 make
-./fsverityset /mnt/f2fs/output-$1.apk
-./fsveritymeasure /mnt/f2fs/output-$1.apk $2
+./fsverity enable /mnt/f2fs/output-$1.apk
+./fsverity set_measurement /mnt/f2fs/output-$1.apk $2
 sync
 echo 3 > /proc/sys/vm/drop_caches
 dd if=/mnt/f2fs/output-$1.apk of=byte0-$1 count=1 bs=1