xref: /freebsd/usr.sbin/efidp/efidp.c (revision cab6a39d7b343596a5823e65c0f7b426551ec22d)
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 	size_t dplen;
173 	char *walker, *dev, *relpath, *abspath;
174 	int rv;
175 
176 	dp = (efidp)dpbuf;
177 	while (fgets(buffer, sizeof(buffer), stdin)) {
178 		walker= trim(buffer);
179 		dplen = efidp_parse_device_path(walker, dp, sizeof(dpbuf));
180 		rv = efivar_device_path_to_unix_path(dp, &dev, &relpath, &abspath);
181 		if (rv == 0)
182 			printf("%s:%s %s\n", dev, relpath, abspath);
183 		else {
184 			errno = rv;
185 			warn("Can't convert '%s' to unix", walker);
186 		}
187 	}
188 }
189 
190 static void
191 format(void)
192 {
193 	char buffer[MAXSIZE];
194 	ssize_t fmtlen;
195 	ssize_t len;
196 	void *data;
197 	size_t dplen;
198 	const_efidp dp;
199 
200 	len = read_file(STDIN_FILENO, &data);
201 	if (len == -1)
202 		err(1, "read");
203 	dp = (const_efidp)data;
204 	while (len > 0) {
205 		dplen = efidp_size(dp);
206 		fmtlen = efidp_format_device_path(buffer, sizeof(buffer),
207 		    dp, dplen);
208 		if (fmtlen > 0)
209 			printf("%s\n", buffer);
210 		len -= dplen;
211 		dp = (const_efidp)((const char *)dp + dplen);
212 	}
213 	free(data);
214 }
215 
216 static void
217 parse(void)
218 {
219 	char buffer[MAXSIZE];
220 	efidp dp;
221 	ssize_t dplen;
222 	char *walker;
223 
224 	dplen = MAXSIZE;
225 	dp = malloc(dplen);
226 	if (dp == NULL)
227 		errx(1, "Can't allocate memory.");
228 	while (fgets(buffer, sizeof(buffer), stdin)) {
229 		walker= trim(buffer);
230 		dplen = efidp_parse_device_path(walker, dp, dplen);
231 		if (dplen == -1)
232 			errx(1, "Can't parse %s", walker);
233 		write(STDOUT_FILENO, dp, dplen);
234 	}
235 	free(dp);
236 }
237 
238 int
239 main(int argc, char **argv)
240 {
241 
242 	parse_args(argc, argv);
243 	if (flag_unix)
244 		efi_to_unix();
245 	else if (flag_efi)
246 		unix_to_efi();
247 	else if (flag_format)
248 		format();
249 	else if (flag_parse)
250 		parse();
251 }
252