1/*-
2 * Copyright (c) 2016 Netflix, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: stable/11/usr.sbin/efidp/efidp.c 332123 2018-04-06 18:10:38Z kevans $");
29
30#include <ctype.h>
31#include <efivar.h>
32#include <efivar-dp.h>
33#include <err.h>
34#include <errno.h>
35#include <getopt.h>
36#include <stddef.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#define MAXSIZE 65536	/* Everyting will be smaller than this, most 1000x smaller */
43
44/* options descriptor */
45static struct option longopts[] = {
46	{ "to-unix",		no_argument,		NULL,	'u' },
47	{ "to-efi",		no_argument,		NULL,	'e' },
48	{ "format",		no_argument,		NULL,	'f' },
49	{ "parse",		no_argument,		NULL,	'p' },
50	{ NULL,			0,			NULL,	0 }
51};
52
53
54static int flag_format, flag_parse, flag_unix, flag_efi;
55
56static void
57usage(void)
58{
59
60	errx(1, "efidp [-efpu]");
61}
62
63static ssize_t
64read_file(int fd, void **rv)
65{
66	uint8_t *retval;
67	size_t len;
68	off_t off;
69	ssize_t red;
70
71	len = MAXSIZE;
72	off = 0;
73	retval = malloc(len);
74	do {
75		red = read(fd, retval + off, len - off);
76		if (red == 0)
77			break;
78		off += red;
79		if (off == (off_t)len)
80			break;
81	} while (1);
82	*rv = retval;
83
84	return off;
85}
86
87static void
88parse_args(int argc, char **argv)
89{
90	int ch;
91
92	while ((ch = getopt_long(argc, argv, "efpu",
93		    longopts, NULL)) != -1) {
94		switch (ch) {
95		case 'e':
96			flag_efi++;
97			break;
98		case 'f':
99			flag_format++;
100			break;
101		case 'p':
102			flag_parse++;
103			break;
104		case 'u':
105			flag_unix++;
106			break;
107		default:
108			usage();
109		}
110	}
111	argc -= optind;
112	argv += optind;
113
114	if (argc >= 1)
115		usage();
116
117	if (flag_parse + flag_format + flag_efi + flag_unix != 1) {
118		warnx("Can only use one of -p (--parse), "
119		    "and -f (--format)");
120		usage();
121	}
122}
123
124static char *
125trim(char *s)
126{
127	char *t;
128
129	while (isspace(*s))
130		s++;
131	t = s + strlen(s) - 1;
132	while (t > s && isspace(*t))
133		*t-- = '\0';
134	return s;
135}
136
137static void
138unix_to_efi(void)
139{
140	char buffer[MAXSIZE];
141	char efi[MAXSIZE];
142	efidp dp;
143	char *walker;
144	int rv;
145
146	dp = NULL;
147	while (fgets(buffer, sizeof(buffer), stdin)) {
148		walker= trim(buffer);
149		free(dp);
150		dp = NULL;
151		rv = efivar_unix_path_to_device_path(walker, &dp);
152		if (rv != 0 || dp == NULL) {
153			errno = rv;
154			warn("Can't convert '%s' to efi", walker);
155			continue;
156		}
157		if (efidp_format_device_path(efi, sizeof(efi),
158		    dp, efidp_size(dp)) < 0) {
159			warnx("Can't format dp for '%s'", walker);
160			continue;
161		}
162		printf("%s\n", efi);
163	}
164	free(dp);
165}
166
167static void
168efi_to_unix(void)
169{
170	char buffer[MAXSIZE];
171	char dpbuf[MAXSIZE];
172	efidp dp;
173	size_t dplen;
174	char *walker, *dev, *relpath, *abspath;
175	int rv;
176
177	dp = (efidp)dpbuf;
178	while (fgets(buffer, sizeof(buffer), stdin)) {
179		walker= trim(buffer);
180		dplen = efidp_parse_device_path(walker, dp, sizeof(dpbuf));
181		rv = efivar_device_path_to_unix_path(dp, &dev, &relpath, &abspath);
182		if (rv == 0)
183			printf("%s:%s %s\n", dev, relpath, abspath);
184		else {
185			errno = rv;
186			warn("Can't convert '%s' to unix", walker);
187		}
188	}
189}
190
191static void
192format(void)
193{
194	char buffer[MAXSIZE];
195	ssize_t fmtlen;
196	ssize_t len;
197	void *data;
198	size_t dplen;
199	const_efidp dp;
200
201	len = read_file(STDIN_FILENO, &data);
202	if (len == -1)
203		err(1, "read");
204	dp = (const_efidp)data;
205	while (len > 0) {
206		dplen = efidp_size(dp);
207		fmtlen = efidp_format_device_path(buffer, sizeof(buffer),
208		    dp, dplen);
209		if (fmtlen > 0)
210			printf("%s\n", buffer);
211		len -= dplen;
212		dp = (const_efidp)((const char *)dp + dplen);
213	}
214	free(data);
215}
216
217static void
218parse(void)
219{
220	char buffer[MAXSIZE];
221	efidp dp;
222	ssize_t dplen;
223	char *walker;
224
225	dplen = MAXSIZE;
226	dp = malloc(dplen);
227	if (dp == NULL)
228		errx(1, "Can't allocate memory.");
229	while (fgets(buffer, sizeof(buffer), stdin)) {
230		walker= trim(buffer);
231		dplen = efidp_parse_device_path(walker, dp, dplen);
232		if (dplen == -1)
233			errx(1, "Can't parse %s", walker);
234		write(STDOUT_FILENO, dp, dplen);
235	}
236	free(dp);
237}
238
239int
240main(int argc, char **argv)
241{
242
243	parse_args(argc, argv);
244	if (flag_unix)
245		efi_to_unix();
246	else if (flag_efi)
247		unix_to_efi();
248	else if (flag_format)
249		format();
250	else if (flag_parse)
251		parse();
252}
253