Update for API changes

Signed-off-by: Eric Biggers <ebiggers@google.com>
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();
+}