xref: /openbmc/linux/tools/bootconfig/main.c (revision 272da3279df191f028fd63d1683e5ecd56fcb13b)
1950313ebSMasami Hiramatsu // SPDX-License-Identifier: GPL-2.0
2950313ebSMasami Hiramatsu /*
3950313ebSMasami Hiramatsu  * Boot config tool for initrd image
4950313ebSMasami Hiramatsu  */
5950313ebSMasami Hiramatsu #include <stdio.h>
6950313ebSMasami Hiramatsu #include <stdlib.h>
7950313ebSMasami Hiramatsu #include <sys/types.h>
8950313ebSMasami Hiramatsu #include <sys/stat.h>
9950313ebSMasami Hiramatsu #include <fcntl.h>
10950313ebSMasami Hiramatsu #include <unistd.h>
11950313ebSMasami Hiramatsu #include <string.h>
12950313ebSMasami Hiramatsu #include <errno.h>
13950313ebSMasami Hiramatsu 
14950313ebSMasami Hiramatsu #include <linux/kernel.h>
15950313ebSMasami Hiramatsu #include <linux/bootconfig.h>
16950313ebSMasami Hiramatsu 
17*272da327SMasami Hiramatsu static int xbc_show_value(struct xbc_node *node)
18950313ebSMasami Hiramatsu {
19950313ebSMasami Hiramatsu 	const char *val;
20*272da327SMasami Hiramatsu 	char q;
21950313ebSMasami Hiramatsu 	int i = 0;
22950313ebSMasami Hiramatsu 
23950313ebSMasami Hiramatsu 	xbc_array_for_each_value(node, val) {
24*272da327SMasami Hiramatsu 		if (strchr(val, '"'))
25*272da327SMasami Hiramatsu 			q = '\'';
26*272da327SMasami Hiramatsu 		else
27*272da327SMasami Hiramatsu 			q = '"';
28*272da327SMasami Hiramatsu 		printf("%c%s%c%s", q, val, q, node->next ? ", " : ";\n");
29950313ebSMasami Hiramatsu 		i++;
30950313ebSMasami Hiramatsu 	}
31950313ebSMasami Hiramatsu 	return i;
32950313ebSMasami Hiramatsu }
33950313ebSMasami Hiramatsu 
34950313ebSMasami Hiramatsu static void xbc_show_compact_tree(void)
35950313ebSMasami Hiramatsu {
36950313ebSMasami Hiramatsu 	struct xbc_node *node, *cnode;
37950313ebSMasami Hiramatsu 	int depth = 0, i;
38950313ebSMasami Hiramatsu 
39950313ebSMasami Hiramatsu 	node = xbc_root_node();
40950313ebSMasami Hiramatsu 	while (node && xbc_node_is_key(node)) {
41950313ebSMasami Hiramatsu 		for (i = 0; i < depth; i++)
42950313ebSMasami Hiramatsu 			printf("\t");
43950313ebSMasami Hiramatsu 		cnode = xbc_node_get_child(node);
44950313ebSMasami Hiramatsu 		while (cnode && xbc_node_is_key(cnode) && !cnode->next) {
45950313ebSMasami Hiramatsu 			printf("%s.", xbc_node_get_data(node));
46950313ebSMasami Hiramatsu 			node = cnode;
47950313ebSMasami Hiramatsu 			cnode = xbc_node_get_child(node);
48950313ebSMasami Hiramatsu 		}
49950313ebSMasami Hiramatsu 		if (cnode && xbc_node_is_key(cnode)) {
50950313ebSMasami Hiramatsu 			printf("%s {\n", xbc_node_get_data(node));
51950313ebSMasami Hiramatsu 			depth++;
52950313ebSMasami Hiramatsu 			node = cnode;
53950313ebSMasami Hiramatsu 			continue;
54950313ebSMasami Hiramatsu 		} else if (cnode && xbc_node_is_value(cnode)) {
55950313ebSMasami Hiramatsu 			printf("%s = ", xbc_node_get_data(node));
56*272da327SMasami Hiramatsu 			xbc_show_value(cnode);
57950313ebSMasami Hiramatsu 		} else {
58950313ebSMasami Hiramatsu 			printf("%s;\n", xbc_node_get_data(node));
59950313ebSMasami Hiramatsu 		}
60950313ebSMasami Hiramatsu 
61950313ebSMasami Hiramatsu 		if (node->next) {
62950313ebSMasami Hiramatsu 			node = xbc_node_get_next(node);
63950313ebSMasami Hiramatsu 			continue;
64950313ebSMasami Hiramatsu 		}
65950313ebSMasami Hiramatsu 		while (!node->next) {
66950313ebSMasami Hiramatsu 			node = xbc_node_get_parent(node);
67950313ebSMasami Hiramatsu 			if (!node)
68950313ebSMasami Hiramatsu 				return;
69950313ebSMasami Hiramatsu 			if (!xbc_node_get_child(node)->next)
70950313ebSMasami Hiramatsu 				continue;
71950313ebSMasami Hiramatsu 			depth--;
72950313ebSMasami Hiramatsu 			for (i = 0; i < depth; i++)
73950313ebSMasami Hiramatsu 				printf("\t");
74950313ebSMasami Hiramatsu 			printf("}\n");
75950313ebSMasami Hiramatsu 		}
76950313ebSMasami Hiramatsu 		node = xbc_node_get_next(node);
77950313ebSMasami Hiramatsu 	}
78950313ebSMasami Hiramatsu }
79950313ebSMasami Hiramatsu 
80950313ebSMasami Hiramatsu /* Simple real checksum */
81950313ebSMasami Hiramatsu int checksum(unsigned char *buf, int len)
82950313ebSMasami Hiramatsu {
83950313ebSMasami Hiramatsu 	int i, sum = 0;
84950313ebSMasami Hiramatsu 
85950313ebSMasami Hiramatsu 	for (i = 0; i < len; i++)
86950313ebSMasami Hiramatsu 		sum += buf[i];
87950313ebSMasami Hiramatsu 
88950313ebSMasami Hiramatsu 	return sum;
89950313ebSMasami Hiramatsu }
90950313ebSMasami Hiramatsu 
91950313ebSMasami Hiramatsu #define PAGE_SIZE	4096
92950313ebSMasami Hiramatsu 
93950313ebSMasami Hiramatsu int load_xbc_fd(int fd, char **buf, int size)
94950313ebSMasami Hiramatsu {
95950313ebSMasami Hiramatsu 	int ret;
96950313ebSMasami Hiramatsu 
97950313ebSMasami Hiramatsu 	*buf = malloc(size + 1);
98950313ebSMasami Hiramatsu 	if (!*buf)
99950313ebSMasami Hiramatsu 		return -ENOMEM;
100950313ebSMasami Hiramatsu 
101950313ebSMasami Hiramatsu 	ret = read(fd, *buf, size);
102950313ebSMasami Hiramatsu 	if (ret < 0)
103950313ebSMasami Hiramatsu 		return -errno;
104950313ebSMasami Hiramatsu 	(*buf)[size] = '\0';
105950313ebSMasami Hiramatsu 
106950313ebSMasami Hiramatsu 	return ret;
107950313ebSMasami Hiramatsu }
108950313ebSMasami Hiramatsu 
109950313ebSMasami Hiramatsu /* Return the read size or -errno */
110950313ebSMasami Hiramatsu int load_xbc_file(const char *path, char **buf)
111950313ebSMasami Hiramatsu {
112950313ebSMasami Hiramatsu 	struct stat stat;
113950313ebSMasami Hiramatsu 	int fd, ret;
114950313ebSMasami Hiramatsu 
115950313ebSMasami Hiramatsu 	fd = open(path, O_RDONLY);
116950313ebSMasami Hiramatsu 	if (fd < 0)
117950313ebSMasami Hiramatsu 		return -errno;
118950313ebSMasami Hiramatsu 	ret = fstat(fd, &stat);
119950313ebSMasami Hiramatsu 	if (ret < 0)
120950313ebSMasami Hiramatsu 		return -errno;
121950313ebSMasami Hiramatsu 
122950313ebSMasami Hiramatsu 	ret = load_xbc_fd(fd, buf, stat.st_size);
123950313ebSMasami Hiramatsu 
124950313ebSMasami Hiramatsu 	close(fd);
125950313ebSMasami Hiramatsu 
126950313ebSMasami Hiramatsu 	return ret;
127950313ebSMasami Hiramatsu }
128950313ebSMasami Hiramatsu 
129950313ebSMasami Hiramatsu int load_xbc_from_initrd(int fd, char **buf)
130950313ebSMasami Hiramatsu {
131950313ebSMasami Hiramatsu 	struct stat stat;
132950313ebSMasami Hiramatsu 	int ret;
133950313ebSMasami Hiramatsu 	u32 size = 0, csum = 0, rcsum;
13485c46b78SMasami Hiramatsu 	char magic[BOOTCONFIG_MAGIC_LEN];
13589b74cacSMasami Hiramatsu 	const char *msg;
136950313ebSMasami Hiramatsu 
137950313ebSMasami Hiramatsu 	ret = fstat(fd, &stat);
138950313ebSMasami Hiramatsu 	if (ret < 0)
139950313ebSMasami Hiramatsu 		return -errno;
140950313ebSMasami Hiramatsu 
14185c46b78SMasami Hiramatsu 	if (stat.st_size < 8 + BOOTCONFIG_MAGIC_LEN)
142950313ebSMasami Hiramatsu 		return 0;
143950313ebSMasami Hiramatsu 
14485c46b78SMasami Hiramatsu 	if (lseek(fd, -BOOTCONFIG_MAGIC_LEN, SEEK_END) < 0) {
14585c46b78SMasami Hiramatsu 		pr_err("Failed to lseek: %d\n", -errno);
14685c46b78SMasami Hiramatsu 		return -errno;
14785c46b78SMasami Hiramatsu 	}
14885c46b78SMasami Hiramatsu 	if (read(fd, magic, BOOTCONFIG_MAGIC_LEN) < 0)
14985c46b78SMasami Hiramatsu 		return -errno;
15085c46b78SMasami Hiramatsu 	/* Check the bootconfig magic bytes */
15185c46b78SMasami Hiramatsu 	if (memcmp(magic, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN) != 0)
15285c46b78SMasami Hiramatsu 		return 0;
15385c46b78SMasami Hiramatsu 
15485c46b78SMasami Hiramatsu 	if (lseek(fd, -(8 + BOOTCONFIG_MAGIC_LEN), SEEK_END) < 0) {
15597378001SMasami Hiramatsu 		pr_err("Failed to lseek: %d\n", -errno);
156950313ebSMasami Hiramatsu 		return -errno;
157950313ebSMasami Hiramatsu 	}
158950313ebSMasami Hiramatsu 
159950313ebSMasami Hiramatsu 	if (read(fd, &size, sizeof(u32)) < 0)
160950313ebSMasami Hiramatsu 		return -errno;
161950313ebSMasami Hiramatsu 
162950313ebSMasami Hiramatsu 	if (read(fd, &csum, sizeof(u32)) < 0)
163950313ebSMasami Hiramatsu 		return -errno;
164950313ebSMasami Hiramatsu 
16585c46b78SMasami Hiramatsu 	/* Wrong size error  */
16685c46b78SMasami Hiramatsu 	if (stat.st_size < size + 8 + BOOTCONFIG_MAGIC_LEN) {
16785c46b78SMasami Hiramatsu 		pr_err("bootconfig size is too big\n");
16885c46b78SMasami Hiramatsu 		return -E2BIG;
16985c46b78SMasami Hiramatsu 	}
170950313ebSMasami Hiramatsu 
17185c46b78SMasami Hiramatsu 	if (lseek(fd, stat.st_size - (size + 8 + BOOTCONFIG_MAGIC_LEN),
17285c46b78SMasami Hiramatsu 		  SEEK_SET) < 0) {
17397378001SMasami Hiramatsu 		pr_err("Failed to lseek: %d\n", -errno);
174950313ebSMasami Hiramatsu 		return -errno;
175950313ebSMasami Hiramatsu 	}
176950313ebSMasami Hiramatsu 
177950313ebSMasami Hiramatsu 	ret = load_xbc_fd(fd, buf, size);
178950313ebSMasami Hiramatsu 	if (ret < 0)
179950313ebSMasami Hiramatsu 		return ret;
180950313ebSMasami Hiramatsu 
18185c46b78SMasami Hiramatsu 	/* Wrong Checksum */
182950313ebSMasami Hiramatsu 	rcsum = checksum((unsigned char *)*buf, size);
183950313ebSMasami Hiramatsu 	if (csum != rcsum) {
18497378001SMasami Hiramatsu 		pr_err("checksum error: %d != %d\n", csum, rcsum);
18585c46b78SMasami Hiramatsu 		return -EINVAL;
186950313ebSMasami Hiramatsu 	}
187950313ebSMasami Hiramatsu 
18889b74cacSMasami Hiramatsu 	ret = xbc_init(*buf, &msg, NULL);
18985c46b78SMasami Hiramatsu 	/* Wrong data */
19089b74cacSMasami Hiramatsu 	if (ret < 0) {
19189b74cacSMasami Hiramatsu 		pr_err("parse error: %s.\n", msg);
19285c46b78SMasami Hiramatsu 		return ret;
19389b74cacSMasami Hiramatsu 	}
194950313ebSMasami Hiramatsu 
195950313ebSMasami Hiramatsu 	return size;
196950313ebSMasami Hiramatsu }
197950313ebSMasami Hiramatsu 
198950313ebSMasami Hiramatsu int show_xbc(const char *path)
199950313ebSMasami Hiramatsu {
200950313ebSMasami Hiramatsu 	int ret, fd;
201950313ebSMasami Hiramatsu 	char *buf = NULL;
202950313ebSMasami Hiramatsu 
203950313ebSMasami Hiramatsu 	fd = open(path, O_RDONLY);
204950313ebSMasami Hiramatsu 	if (fd < 0) {
20597378001SMasami Hiramatsu 		pr_err("Failed to open initrd %s: %d\n", path, fd);
206950313ebSMasami Hiramatsu 		return -errno;
207950313ebSMasami Hiramatsu 	}
208950313ebSMasami Hiramatsu 
209950313ebSMasami Hiramatsu 	ret = load_xbc_from_initrd(fd, &buf);
210950313ebSMasami Hiramatsu 	if (ret < 0)
21197378001SMasami Hiramatsu 		pr_err("Failed to load a boot config from initrd: %d\n", ret);
212950313ebSMasami Hiramatsu 	else
213950313ebSMasami Hiramatsu 		xbc_show_compact_tree();
214950313ebSMasami Hiramatsu 
215950313ebSMasami Hiramatsu 	close(fd);
216950313ebSMasami Hiramatsu 	free(buf);
217950313ebSMasami Hiramatsu 
218950313ebSMasami Hiramatsu 	return ret;
219950313ebSMasami Hiramatsu }
220950313ebSMasami Hiramatsu 
221950313ebSMasami Hiramatsu int delete_xbc(const char *path)
222950313ebSMasami Hiramatsu {
223950313ebSMasami Hiramatsu 	struct stat stat;
224950313ebSMasami Hiramatsu 	int ret = 0, fd, size;
225950313ebSMasami Hiramatsu 	char *buf = NULL;
226950313ebSMasami Hiramatsu 
227950313ebSMasami Hiramatsu 	fd = open(path, O_RDWR);
228950313ebSMasami Hiramatsu 	if (fd < 0) {
22997378001SMasami Hiramatsu 		pr_err("Failed to open initrd %s: %d\n", path, fd);
230950313ebSMasami Hiramatsu 		return -errno;
231950313ebSMasami Hiramatsu 	}
232950313ebSMasami Hiramatsu 
233950313ebSMasami Hiramatsu 	size = load_xbc_from_initrd(fd, &buf);
234950313ebSMasami Hiramatsu 	if (size < 0) {
235950313ebSMasami Hiramatsu 		ret = size;
23697378001SMasami Hiramatsu 		pr_err("Failed to load a boot config from initrd: %d\n", ret);
237950313ebSMasami Hiramatsu 	} else if (size > 0) {
238950313ebSMasami Hiramatsu 		ret = fstat(fd, &stat);
239950313ebSMasami Hiramatsu 		if (!ret)
24085c46b78SMasami Hiramatsu 			ret = ftruncate(fd, stat.st_size
24185c46b78SMasami Hiramatsu 					- size - 8 - BOOTCONFIG_MAGIC_LEN);
242950313ebSMasami Hiramatsu 		if (ret)
243950313ebSMasami Hiramatsu 			ret = -errno;
244950313ebSMasami Hiramatsu 	} /* Ignore if there is no boot config in initrd */
245950313ebSMasami Hiramatsu 
246950313ebSMasami Hiramatsu 	close(fd);
247950313ebSMasami Hiramatsu 	free(buf);
248950313ebSMasami Hiramatsu 
249950313ebSMasami Hiramatsu 	return ret;
250950313ebSMasami Hiramatsu }
251950313ebSMasami Hiramatsu 
25289b74cacSMasami Hiramatsu static void show_xbc_error(const char *data, const char *msg, int pos)
25389b74cacSMasami Hiramatsu {
25489b74cacSMasami Hiramatsu 	int lin = 1, col, i;
25589b74cacSMasami Hiramatsu 
25689b74cacSMasami Hiramatsu 	if (pos < 0) {
25789b74cacSMasami Hiramatsu 		pr_err("Error: %s.\n", msg);
25889b74cacSMasami Hiramatsu 		return;
25989b74cacSMasami Hiramatsu 	}
26089b74cacSMasami Hiramatsu 
26189b74cacSMasami Hiramatsu 	/* Note that pos starts from 0 but lin and col should start from 1. */
26289b74cacSMasami Hiramatsu 	col = pos + 1;
26389b74cacSMasami Hiramatsu 	for (i = 0; i < pos; i++) {
26489b74cacSMasami Hiramatsu 		if (data[i] == '\n') {
26589b74cacSMasami Hiramatsu 			lin++;
26689b74cacSMasami Hiramatsu 			col = pos - i;
26789b74cacSMasami Hiramatsu 		}
26889b74cacSMasami Hiramatsu 	}
26989b74cacSMasami Hiramatsu 	pr_err("Parse Error: %s at %d:%d\n", msg, lin, col);
27089b74cacSMasami Hiramatsu 
27189b74cacSMasami Hiramatsu }
27289b74cacSMasami Hiramatsu 
273950313ebSMasami Hiramatsu int apply_xbc(const char *path, const char *xbc_path)
274950313ebSMasami Hiramatsu {
275950313ebSMasami Hiramatsu 	u32 size, csum;
276950313ebSMasami Hiramatsu 	char *buf, *data;
277950313ebSMasami Hiramatsu 	int ret, fd;
27889b74cacSMasami Hiramatsu 	const char *msg;
27989b74cacSMasami Hiramatsu 	int pos;
280950313ebSMasami Hiramatsu 
281950313ebSMasami Hiramatsu 	ret = load_xbc_file(xbc_path, &buf);
282950313ebSMasami Hiramatsu 	if (ret < 0) {
28397378001SMasami Hiramatsu 		pr_err("Failed to load %s : %d\n", xbc_path, ret);
284950313ebSMasami Hiramatsu 		return ret;
285950313ebSMasami Hiramatsu 	}
286950313ebSMasami Hiramatsu 	size = strlen(buf) + 1;
287950313ebSMasami Hiramatsu 	csum = checksum((unsigned char *)buf, size);
288950313ebSMasami Hiramatsu 
289950313ebSMasami Hiramatsu 	/* Prepare xbc_path data */
290950313ebSMasami Hiramatsu 	data = malloc(size + 8);
291950313ebSMasami Hiramatsu 	if (!data)
292950313ebSMasami Hiramatsu 		return -ENOMEM;
293950313ebSMasami Hiramatsu 	strcpy(data, buf);
294950313ebSMasami Hiramatsu 	*(u32 *)(data + size) = size;
295950313ebSMasami Hiramatsu 	*(u32 *)(data + size + 4) = csum;
296950313ebSMasami Hiramatsu 
297950313ebSMasami Hiramatsu 	/* Check the data format */
29889b74cacSMasami Hiramatsu 	ret = xbc_init(buf, &msg, &pos);
299950313ebSMasami Hiramatsu 	if (ret < 0) {
30089b74cacSMasami Hiramatsu 		show_xbc_error(data, msg, pos);
301950313ebSMasami Hiramatsu 		free(data);
302950313ebSMasami Hiramatsu 		free(buf);
30389b74cacSMasami Hiramatsu 
304950313ebSMasami Hiramatsu 		return ret;
305950313ebSMasami Hiramatsu 	}
306950313ebSMasami Hiramatsu 	printf("Apply %s to %s\n", xbc_path, path);
3070f0d0a77SMasami Hiramatsu 	printf("\tNumber of nodes: %d\n", ret);
308950313ebSMasami Hiramatsu 	printf("\tSize: %u bytes\n", (unsigned int)size);
309950313ebSMasami Hiramatsu 	printf("\tChecksum: %d\n", (unsigned int)csum);
310950313ebSMasami Hiramatsu 
311950313ebSMasami Hiramatsu 	/* TODO: Check the options by schema */
312950313ebSMasami Hiramatsu 	xbc_destroy_all();
313950313ebSMasami Hiramatsu 	free(buf);
314950313ebSMasami Hiramatsu 
315950313ebSMasami Hiramatsu 	/* Remove old boot config if exists */
316950313ebSMasami Hiramatsu 	ret = delete_xbc(path);
317950313ebSMasami Hiramatsu 	if (ret < 0) {
31897378001SMasami Hiramatsu 		pr_err("Failed to delete previous boot config: %d\n", ret);
31988426044SYunfeng Ye 		free(data);
320950313ebSMasami Hiramatsu 		return ret;
321950313ebSMasami Hiramatsu 	}
322950313ebSMasami Hiramatsu 
323950313ebSMasami Hiramatsu 	/* Apply new one */
324950313ebSMasami Hiramatsu 	fd = open(path, O_RDWR | O_APPEND);
325950313ebSMasami Hiramatsu 	if (fd < 0) {
32697378001SMasami Hiramatsu 		pr_err("Failed to open %s: %d\n", path, fd);
32788426044SYunfeng Ye 		free(data);
328950313ebSMasami Hiramatsu 		return fd;
329950313ebSMasami Hiramatsu 	}
330950313ebSMasami Hiramatsu 	/* TODO: Ensure the @path is initramfs/initrd image */
331950313ebSMasami Hiramatsu 	ret = write(fd, data, size + 8);
332950313ebSMasami Hiramatsu 	if (ret < 0) {
33397378001SMasami Hiramatsu 		pr_err("Failed to apply a boot config: %d\n", ret);
33488426044SYunfeng Ye 		goto out;
335950313ebSMasami Hiramatsu 	}
33685c46b78SMasami Hiramatsu 	/* Write a magic word of the bootconfig */
33785c46b78SMasami Hiramatsu 	ret = write(fd, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
33885c46b78SMasami Hiramatsu 	if (ret < 0) {
33985c46b78SMasami Hiramatsu 		pr_err("Failed to apply a boot config magic: %d\n", ret);
34088426044SYunfeng Ye 		goto out;
34185c46b78SMasami Hiramatsu 	}
3429d82ccdaSSteven Rostedt (VMware) 	ret = 0;
34388426044SYunfeng Ye out:
344950313ebSMasami Hiramatsu 	close(fd);
345950313ebSMasami Hiramatsu 	free(data);
346950313ebSMasami Hiramatsu 
34788426044SYunfeng Ye 	return ret;
348950313ebSMasami Hiramatsu }
349950313ebSMasami Hiramatsu 
350950313ebSMasami Hiramatsu int usage(void)
351950313ebSMasami Hiramatsu {
352950313ebSMasami Hiramatsu 	printf("Usage: bootconfig [OPTIONS] <INITRD>\n"
353950313ebSMasami Hiramatsu 		" Apply, delete or show boot config to initrd.\n"
354950313ebSMasami Hiramatsu 		" Options:\n"
355950313ebSMasami Hiramatsu 		"		-a <config>: Apply boot config to initrd\n"
356950313ebSMasami Hiramatsu 		"		-d : Delete boot config file from initrd\n\n"
357950313ebSMasami Hiramatsu 		" If no option is given, show current applied boot config.\n");
358950313ebSMasami Hiramatsu 	return -1;
359950313ebSMasami Hiramatsu }
360950313ebSMasami Hiramatsu 
361950313ebSMasami Hiramatsu int main(int argc, char **argv)
362950313ebSMasami Hiramatsu {
363950313ebSMasami Hiramatsu 	char *path = NULL;
364950313ebSMasami Hiramatsu 	char *apply = NULL;
365950313ebSMasami Hiramatsu 	bool delete = false;
366950313ebSMasami Hiramatsu 	int opt;
367950313ebSMasami Hiramatsu 
368950313ebSMasami Hiramatsu 	while ((opt = getopt(argc, argv, "hda:")) != -1) {
369950313ebSMasami Hiramatsu 		switch (opt) {
370950313ebSMasami Hiramatsu 		case 'd':
371950313ebSMasami Hiramatsu 			delete = true;
372950313ebSMasami Hiramatsu 			break;
373950313ebSMasami Hiramatsu 		case 'a':
374950313ebSMasami Hiramatsu 			apply = optarg;
375950313ebSMasami Hiramatsu 			break;
376950313ebSMasami Hiramatsu 		case 'h':
377950313ebSMasami Hiramatsu 		default:
378950313ebSMasami Hiramatsu 			return usage();
379950313ebSMasami Hiramatsu 		}
380950313ebSMasami Hiramatsu 	}
381950313ebSMasami Hiramatsu 
382950313ebSMasami Hiramatsu 	if (apply && delete) {
38397378001SMasami Hiramatsu 		pr_err("Error: You can not specify both -a and -d at once.\n");
384950313ebSMasami Hiramatsu 		return usage();
385950313ebSMasami Hiramatsu 	}
386950313ebSMasami Hiramatsu 
387950313ebSMasami Hiramatsu 	if (optind >= argc) {
38897378001SMasami Hiramatsu 		pr_err("Error: No initrd is specified.\n");
389950313ebSMasami Hiramatsu 		return usage();
390950313ebSMasami Hiramatsu 	}
391950313ebSMasami Hiramatsu 
392950313ebSMasami Hiramatsu 	path = argv[optind];
393950313ebSMasami Hiramatsu 
394950313ebSMasami Hiramatsu 	if (apply)
395950313ebSMasami Hiramatsu 		return apply_xbc(path, apply);
396950313ebSMasami Hiramatsu 	else if (delete)
397950313ebSMasami Hiramatsu 		return delete_xbc(path);
398950313ebSMasami Hiramatsu 
399950313ebSMasami Hiramatsu 	return show_xbc(path);
400950313ebSMasami Hiramatsu }
401