2 * libefiboot - library for the manipulation of EFI boot variables
3 * Copyright 2012-2015 Red Hat, Inc.
4 * Copyright (C) 2001 Dell Computer Corporation <Matt_Domsch@dell.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of the
9 * License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see
18 * <http://www.gnu.org/licenses/>.
22 #include "fix_coverity.h"
29 #include <linux/ethtool.h>
30 #include <linux/version.h>
31 #include <linux/sockios.h>
33 #include <scsi/scsi.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38 #include <sys/sysmacros.h>
39 #include <sys/types.h>
40 #include <sys/param.h>
47 find_parent_devpath(const char * const child, char **parent)
53 /* strip leading /dev/ */
54 node = strrchr(child, '/');
59 /* look up full path symlink */
60 ret = sysfs_readlink(&linkbuf, "class/block/%s", node);
61 if (ret < 0 || !linkbuf)
65 node = strrchr(linkbuf, '/');
71 node = strrchr(linkbuf, '/');
77 /* write out new path */
78 ret = asprintf(parent, "/dev/%s", node);
86 set_part_name(struct device *dev, const char * const fmt, ...)
96 rc = vasprintf(&dev->part_name, fmt, ap);
101 efi_error("could not allocate memory");
107 reset_part_name(struct device *dev)
112 if (dev->part_name) {
113 free(dev->part_name);
114 dev->part_name = NULL;
120 if (dev->probes[dev->n_probes]->make_part_name) {
121 part = dev->probes[dev->n_probes]->make_part_name(dev);
122 dev->part_name = part;
125 rc = asprintf(&dev->part_name, "%s%d",
126 dev->disk_name, dev->part);
128 efi_error("could not allocate memory");
134 set_part(struct device *dev, int value)
138 if (dev->part == value)
142 rc = reset_part_name(dev);
144 efi_error("reset_part_name() failed");
150 set_disk_name(struct device *dev, const char * const fmt, ...)
157 rc = vasprintf(&dev->disk_name, fmt, ap);
162 efi_error("could not allocate memory");
168 set_disk_and_part_name(struct device *dev)
171 * results are like such:
172 * maj:min -> ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART
175 char *ultimate = pathseg(dev->link, -1);
176 char *penultimate = pathseg(dev->link, -2);
177 char *approximate = pathseg(dev->link, -3);
178 char *proximate = pathseg(dev->link, -4);
181 debug(DEBUG, "dev->disk_name:%p dev->part_name:%p", dev->disk_name, dev->part_name);
182 debug(DEBUG, "dev->part:%d", dev->part);
183 debug(DEBUG, "ultimate:\"%s\"", ultimate ? : "");
184 debug(DEBUG, "penultimate:\"%s\"", penultimate ? : "");
185 debug(DEBUG, "approximate:\"%s\"", approximate ? : "");
186 debug(DEBUG, "proximate:\"%s\"", proximate ? : "");
188 if (ultimate && penultimate &&
189 ((proximate && !strcmp(proximate, "nvme")) ||
190 (approximate && !strcmp(approximate, "block")))) {
192 * 259:1 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1/nvme0n1p1
193 * 8:1 -> ../../devices/pci0000:00/0000:00:17.0/ata2/host1/target1:0:0/1:0:0:0/block/sda/sda1
194 * 8:33 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
195 * 252:1 -> ../../devices/pci0000:00/0000:00:07.0/virtio2/block/vda/vda1
196 * 259:3 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s/pmem11s1
198 set_disk_name(dev, "%s", penultimate);
199 set_part_name(dev, "%s", ultimate);
200 debug(DEBUG, "disk:%s part:%s", penultimate, ultimate);
201 } else if (ultimate && approximate && !strcmp(approximate, "nvme")) {
203 * 259:0 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1
205 set_disk_name(dev, "%s", ultimate);
206 set_part_name(dev, "%sp%d", ultimate, dev->part);
207 debug(DEBUG, "disk:%s part:%sp%d", ultimate, ultimate, dev->part);
208 } else if (ultimate && penultimate && !strcmp(penultimate, "block")) {
210 * 253:0 -> ../../devices/virtual/block/dm-0 (... I guess)
211 * 8:0 -> ../../devices/pci0000:00/0000:00:17.0/ata2/host1/target1:0:0/1:0:0:0/block/sda
212 * 11:0 -> ../../devices/pci0000:00/0000:00:11.5/ata3/host2/target2:0:0/2:0:0:0/block/sr0
213 * 8:32 -> ../../devices/pci0000:00/0000:00:01.0/0000:01:00.0/host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc
214 * 252:0 -> ../../devices/pci0000:00/0000:00:07.0/virtio2/block/vda
215 * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region9/btt9.0/block/pmem9s
216 * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region11/btt11.0/block/pmem11s
218 set_disk_name(dev, "%s", ultimate);
219 set_part_name(dev, "%s%d", ultimate, dev->part);
220 debug(DEBUG, "disk:%s part:%s%d", ultimate, ultimate, dev->part);
221 } else if (ultimate && approximate && !strcmp(approximate, "mtd")) {
223 * 31:0 -> ../../devices/platform/1e000000.palmbus/1e000b00.spi/spi_master/spi32766/spi32766.0/mtd/mtd0/mtdblock0
225 set_disk_name(dev, "%s", ultimate);
226 debug(DEBUG, "disk:%s", ultimate);
232 static struct dev_probe *dev_probes[] = {
234 * pmem needs to be before PCI, so if it provides root it'll
252 supports_iface(struct dev_probe *probe, enum interface_type iftype)
254 for (unsigned int i = 0; probe->iftypes[i] != unknown; i++)
255 if (probe->iftypes[i] == iftype)
261 device_free(struct device *dev)
277 if (dev->acpi_root.acpi_hid_str)
278 free(dev->acpi_root.acpi_hid_str);
279 if (dev->acpi_root.acpi_uid_str)
280 free(dev->acpi_root.acpi_uid_str);
281 if (dev->acpi_root.acpi_cid_str)
282 free(dev->acpi_root.acpi_cid_str);
284 if (dev->interface_type == network) {
289 free(dev->disk_name);
291 free(dev->part_name);
294 for (unsigned int i = 0; i < dev->n_pci_devs; i++)
295 if (dev->pci_dev[i].driverlink)
296 free(dev->pci_dev[i].driverlink);
301 memset(dev, 0, sizeof(*dev));
306 *device_get(int fd, int partition)
309 char *linkbuf = NULL, *tmpbuf = NULL;
310 unsigned int i, n = 0;
313 size_t nmemb = (sizeof(dev_probes)
314 / sizeof(dev_probes[0])) + 1;
316 dev = calloc(1, sizeof(*dev));
318 efi_error("could not allocate %zd bytes", sizeof(*dev));
322 dev->part = partition;
323 debug(DEBUG, "partition:%d dev->part:%d", partition, dev->part);
324 dev->probes = calloc(nmemb, sizeof(struct dev_probe *));
326 efi_error("could not allocate %zd bytes",
327 nmemb * sizeof(struct dev_probe *));
331 rc = fstat(fd, &dev->stat);
333 efi_error("fstat(%d) failed", fd);
337 dev->pci_root.pci_domain = 0xffff;
338 dev->pci_root.pci_bus = 0xff;
340 if (S_ISBLK(dev->stat.st_mode)) {
341 dev->major = major(dev->stat.st_rdev);
342 dev->minor = minor(dev->stat.st_rdev);
343 } else if (S_ISREG(dev->stat.st_mode)) {
344 dev->major = major(dev->stat.st_dev);
345 dev->minor = minor(dev->stat.st_dev);
347 efi_error("device is not a block device or regular file");
351 rc = sysfs_readlink(&linkbuf, "dev/block/%"PRIu64":%"PRIu32,
352 dev->major, dev->minor);
353 if (rc < 0 || !linkbuf) {
354 efi_error("readlink of /sys/dev/block/%"PRIu64":%"PRIu32" failed",
355 dev->major, dev->minor);
359 dev->link = strdup(linkbuf);
361 efi_error("strdup(\"%s\") failed", linkbuf);
364 debug(DEBUG, "dev->link: %s", dev->link);
366 if (dev->part == -1) {
367 rc = read_sysfs_file(&tmpbuf, "dev/block/%s/partition", dev->link);
368 if (rc < 0 || !tmpbuf) {
369 efi_error("device has no /partition node; not a partition");
371 rc = sscanf((char *)tmpbuf, "%d\n", &dev->part);
373 efi_error("couldn't parse partition number for %s", tmpbuf);
377 rc = set_disk_and_part_name(dev);
379 efi_error("could not set disk and partition names");
382 debug(DEBUG, "dev->disk_name: %s", dev->disk_name);
383 debug(DEBUG, "dev->part_name: %s", dev->part_name);
385 rc = sysfs_readlink(&tmpbuf, "block/%s/device", dev->disk_name);
386 if (rc < 0 || !tmpbuf) {
387 efi_error("readlink of /sys/block/%s/device failed",
392 dev->device = strdup(tmpbuf);
394 efi_error("strdup(\"%s\") failed", tmpbuf);
398 rc = sysfs_readlink(&tmpbuf, "block/%s/device/driver", dev->disk_name);
399 if (rc < 0 || !tmpbuf) {
400 if (errno == ENOENT) {
402 * nvme, for example, will have nvme0n1/device point
403 * at nvme0, and we need to look for device/driver
406 rc = sysfs_readlink(&tmpbuf,
407 "block/%s/device/device/driver",
410 if (rc < 0 || !tmpbuf) {
411 efi_error("readlink of /sys/block/%s/device/driver failed",
417 linkbuf = pathseg(tmpbuf, -1);
419 efi_error("could not get segment -1 of \"%s\"", tmpbuf);
423 dev->driver = strdup(linkbuf);
425 efi_error("strdup(\"%s\") failed", linkbuf);
429 const char *current = dev->link;
430 bool needs_root = true;
432 debug(DEBUG, "searching for device nodes in %s", dev->link);
433 for (i = 0; dev_probes[i] && dev_probes[i]->parse; i++) {
434 struct dev_probe *probe = dev_probes[i];
437 if (!needs_root && (probe->flags & DEV_PROVIDES_ROOT)) {
438 debug(DEBUG, "not testing %s because flags is 0x%x", probe->name, probe->flags);
442 debug(DEBUG, "trying %s", probe->name);
443 pos = probe->parse(dev, current, dev->link);
445 efi_error("parsing %s failed", probe->name);
447 } else if (pos == 0) {
450 debug(DEBUG, "%s matched %s", probe->name, current);
452 if (probe->flags & DEV_PROVIDES_HD || probe->flags & DEV_PROVIDES_ROOT)
454 dev->probes[n++] = dev_probes[i];
456 debug(DEBUG, "current:%s", current);
458 if (!*current || !strncmp(current, "block/", 6))
462 if (dev->interface_type == unknown) {
463 efi_error("unknown storage interface");
475 make_blockdev_path(uint8_t *buf, ssize_t size, struct device *dev)
479 debug(DEBUG, "entry buf:%p size:%zd", buf, size);
481 for (unsigned int i = 0; dev->probes[i] &&
482 dev->probes[i]->parse; i++) {
483 struct dev_probe *probe = dev->probes[i];
489 sz = probe->create(dev, buf + off, size ? size - off : 0, 0);
491 efi_error("could not create %s device path",
498 debug(DEBUG, "= %zd", off);
504 make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname)
507 struct ethtool_drvinfo drvinfo = { 0, };
509 ssize_t ret = -1, sz, off = 0;
510 char busname[PATH_MAX+1] = "";
513 memset(&dev, 0, sizeof (dev));
514 dev.interface_type = network;
515 dev.ifname = strdupa(ifname);
520 * find the device link, which looks like:
521 * ../../devices/$PCI_STUFF/net/$IFACE
523 rc = sysfs_readlink(&dev.link, "class/net/%s", ifname);
524 if (rc < 0 || !dev.link)
527 memset(&ifr, 0, sizeof (ifr));
528 strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
529 ifr.ifr_name[IF_NAMESIZE-1] = '\0';
530 drvinfo.cmd = ETHTOOL_GDRVINFO;
531 ifr.ifr_data = (caddr_t)&drvinfo;
533 fd = socket(AF_INET, SOCK_DGRAM, 0);
537 rc = ioctl(fd, SIOCETHTOOL, &ifr);
541 strncpy(busname, drvinfo.bus_info, PATH_MAX);
543 rc = ioctl(fd, SIOCGIFHWADDR, &ifr);
547 sz = pci_parser.create(&dev, buf, size, off);
552 sz = efidp_make_mac_addr(buf+off, size?size-off:0,
553 ifr.ifr_ifru.ifru_hwaddr.sa_family,
554 (uint8_t *)ifr.ifr_ifru.ifru_hwaddr.sa_data,
555 sizeof(ifr.ifr_ifru.ifru_hwaddr.sa_data));
567 /************************************************************
570 * - filedes is an open file descriptor, suitable for reading
573 * sector size, or 512.
574 ************************************************************/
576 get_sector_size(int filedes)
578 int rc, sector_size = 512;
580 rc = ioctl(filedes, BLKSSZGET, §or_size);