2 * libefiboot - library for the manipulation of EFI boot variables
3 * Copyright 2012-2015 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "fix_coverity.h"
27 #include <netinet/in.h>
28 #include <netinet/ip.h>
31 #include <sys/types.h>
33 #include <sys/socket.h>
37 static int NONNULL(1, 2, 3)
38 find_file(const char * const filepath, char **devicep, char **relpathp)
40 struct stat fsb = { 0, };
44 char linkbuf[PATH_MAX+1] = "";
47 linklen = strlen(filepath);
48 if (linklen > PATH_MAX) {
50 efi_error("filepath length exceeds PATH_MAX");
53 strcpy(linkbuf, filepath);
56 rc = stat(linkbuf, &fsb);
60 if (S_ISLNK(fsb.st_mode)) {
61 char tmp[PATH_MAX+1] = "";
64 l = readlink(linkbuf, tmp, PATH_MAX);
66 efi_error("readlink failed");
77 mounts = fopen("/proc/self/mounts", "r");
79 efi_error("couldn not open /proc/self/mounts");
85 struct stat dsb = { 0, };
88 me = getmntent(mounts);
92 efi_error("could not find mountpoint");
97 if (me->mnt_fsname[0] != '/')
100 rc = stat(me->mnt_fsname, &dsb);
104 efi_error("could not stat mountpoint");
108 if (!S_ISBLK(dsb.st_mode))
111 if (dsb.st_rdev == fsb.st_dev) {
112 ssize_t mntlen = strlen(me->mnt_dir);
113 if (mntlen >= linklen)
115 if (strncmp(linkbuf, me->mnt_dir, mntlen))
117 *devicep = strdup(me->mnt_fsname);
120 efi_error("strdup failed");
123 *relpathp = strdup(linkbuf + mntlen);
128 efi_error("strdup failed");
142 open_disk(struct device *dev, int flags)
144 char *diskpath = NULL;
147 rc = asprintfa(&diskpath, "/dev/%s", dev->disk_name);
149 efi_error("could not allocate buffer");
153 rc = open(diskpath, flags);
155 efi_error("could not open disk");
161 tilt_slashes(char *s)
171 efi_va_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size,
172 const char *devpath, int partition,
174 uint32_t options, va_list ap)
176 ssize_t ret = -1, off = 0, sz;
177 struct device *dev = NULL;
181 debug("partition:%d", partition);
184 memset(buf, '\0', size);
186 fd = open(devpath, O_RDONLY);
188 efi_error("could not open device for ESP");
192 dev = device_get(fd, partition);
194 efi_error("could not get ESP disk info");
201 debug("partition: %d", partition);
202 disk_fd = open_disk(dev,
203 (options & EFIBOOT_OPTIONS_WRITE_SIGNATURE)
204 ? O_RDWR : O_RDONLY);
206 efi_error("could not open disk");
210 if (is_partitioned(disk_fd))
214 debug("is_partitioned(): partition -> %d", partition);
219 set_part(dev, partition);
221 if (partition == 0) {
222 options |= EFIBOOT_ABBREV_NONE;
223 options &= ~(EFIBOOT_ABBREV_HD|
225 EFIBOOT_ABBREV_EDD10);
228 if (options & EFIBOOT_ABBREV_NONE)
229 debug("EFIBOOT_ABBREV_NONE");
230 if (options & EFIBOOT_ABBREV_HD)
231 debug("EFIBOOT_ABBREV_HD");
232 if (options & EFIBOOT_ABBREV_FILE)
233 debug("EFIBOOT_ABBREV_FILE");
234 if (options & EFIBOOT_ABBREV_EDD10)
235 debug("EFIBOOT_ABBREV_EDD10");
237 if (options & EFIBOOT_ABBREV_EDD10) {
241 dev->edd10_devicenum = va_arg(aq, uint32_t);
246 if (!(options & (EFIBOOT_ABBREV_FILE|EFIBOOT_ABBREV_HD)) &&
247 (dev->flags & DEV_ABBREV_ONLY)) {
250 efi_error("Device must use File() or HD() device path");
254 if ((options & EFIBOOT_ABBREV_EDD10)
255 && (!(options & EFIBOOT_ABBREV_FILE)
256 && !(options & EFIBOOT_ABBREV_HD))) {
257 sz = efidp_make_edd10(buf, size, dev->edd10_devicenum);
259 efi_error("could not make EDD 1.0 device path");
263 } else if (!(options & EFIBOOT_ABBREV_FILE)
264 && !(options & EFIBOOT_ABBREV_HD)) {
267 * We're probably on a modern kernel, so just parse the
268 * symlink from /sys/dev/block/$major:$minor and get it
271 sz = make_blockdev_path(buf, size, dev);
273 efi_error("could not create device path");
279 if ((!(options & EFIBOOT_ABBREV_FILE) && dev->part_name) ||
280 ((options & EFIBOOT_ABBREV_HD) && ! dev->part_name)) {
284 disk_fd = open_disk(dev,
285 (options & EFIBOOT_OPTIONS_WRITE_SIGNATURE)
286 ? O_RDWR : O_RDONLY);
288 efi_error("could not open disk");
292 sz = make_hd_dn(buf+off, size?size-off:0,
293 disk_fd, dev->part, options);
298 efi_error("could not make HD() DP node");
304 char *filepath = strdupa(relpath);
305 tilt_slashes(filepath);
306 sz = efidp_make_file(buf+off, size?size-off:0, filepath);
308 efi_error("could not make File() DP node");
313 sz = efidp_make_end_entire(buf+off, size?size-off:0);
315 efi_error("could not make EndEntire DP node");
331 ssize_t NONNULL(3, 5) PUBLIC
332 efi_generate_file_device_path_from_esp(uint8_t *buf, ssize_t size,
333 const char *devpath, int partition,
335 uint32_t options, ...)
341 va_start(ap, options);
342 ret = efi_va_generate_file_device_path_from_esp(buf, size, devpath,
349 efi_error("could not generate File DP from ESP");
354 get_part(char *devpath)
358 struct device *dev = NULL;
360 fd = open(devpath, O_RDONLY);
362 efi_error("could not open device for ESP");
366 dev = device_get(fd, -1);
368 efi_error("could not get ESP disk info");
372 partition = dev->part;
383 ssize_t NONNULL(3) PUBLIC
384 efi_generate_file_device_path(uint8_t *buf, ssize_t size,
385 const char * const filepath,
386 uint32_t options, ...)
390 char *child_devpath = NULL;
391 char *parent_devpath = NULL;
392 char *relpath = NULL;
396 rc = find_file(filepath, &child_devpath, &relpath);
398 efi_error("could not canonicalize fs path");
402 rc = find_parent_devpath(child_devpath, &parent_devpath);
404 efi_error("could not find parent device for file");
407 debug("child_devpath:%s", child_devpath);
409 debug("parent_devpath:%s", parent_devpath);
410 debug("child_devpath:%s", child_devpath);
413 rc = get_part(child_devpath);
415 efi_error("Couldn't get partition number for %s",
419 debug("detected partition:%d", rc);
421 va_start(ap, options);
423 if (!strcmp(parent_devpath, "/dev/block"))
424 ret = efi_va_generate_file_device_path_from_esp(buf, size,
426 relpath, options, ap);
428 ret = efi_va_generate_file_device_path_from_esp(buf, size,
430 relpath, options, ap);
435 efi_error("could not generate File DP from ESP");
441 free(parent_devpath);
448 static ssize_t NONNULL(3, 4, 5, 6)
449 make_ipv4_path(uint8_t *buf, ssize_t size,
450 const char * const local_addr UNUSED,
451 const char * const remote_addr UNUSED,
452 const char * const gateway_addr UNUSED,
453 const char * const netmask UNUSED,
454 uint16_t local_port UNUSED,
455 uint16_t remote_port UNUSED,
456 uint16_t protocol UNUSED,
457 uint8_t addr_origin UNUSED)
462 if (local_addr == NULL || remote_addr == NULL ||
463 gateway_addr == NULL || netmask == NULL) {
468 ret = efidp_make_ipv4(buf, size, 0, 0, 0, 0, 0, 0, 0, 0);
470 efi_error("could not make ipv4 DP node");
474 ssize_t NONNULL(3, 4, 5, 6, 7) PUBLIC
475 efi_generate_ipv4_device_path(uint8_t *buf, ssize_t size,
476 const char * const ifname,
477 const char * const local_addr,
478 const char * const remote_addr,
479 const char * const gateway_addr,
480 const char * const netmask,
482 uint16_t remote_port,
489 sz = make_mac_path(buf, size, ifname);
491 efi_error("could not make MAC DP node");
496 sz = make_ipv4_path(buf+off, size?size-off:0, local_addr, remote_addr,
497 gateway_addr, netmask, local_port, remote_port,
498 protocol, addr_origin);
500 efi_error("could not make IPV4 DP node");
505 sz = efidp_make_end_entire(buf+off, size?size-off:0);
507 efi_error("could not make EndEntire DP node");