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