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>
35 #include <sys/ioctl.h>
36 #include <sys/socket.h>
37 #include <sys/sysmacros.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
43 #include <efivar/efivar.h>
44 #include <efivar/efiboot.h>
51 __attribute__((__visibility__ ("hidden")))
52 set_disk_and_part_name(struct disk_info *info)
57 rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%"PRIu32,
58 info->major, info->minor);
59 if (rc < 0 || !linkbuf)
63 ultimate = strrchr(linkbuf, '/');
72 penultimate = strrchr(linkbuf, '/');
80 * If there's a better way to figure this out, it'd be good, because
81 * I don't want to have to change this for every new disk type...
83 if (!strncmp(ultimate, "pmem", 4)) {
84 if (!info->disk_name) {
85 info->disk_name = strdup(ultimate);
89 } else if (!strcmp(penultimate, "block")) {
90 if (!info->disk_name) {
91 info->disk_name = strdup(ultimate);
95 if (!info->part_name) {
96 rc = asprintf(&info->part_name, "%s%d", info->disk_name,
101 } else if (!strncmp(penultimate, "nvme", 4)) {
102 if (!info->disk_name) {
103 info->disk_name = strdup(ultimate);
104 if (!info->disk_name)
107 if (!info->part_name) {
108 rc = asprintf(&info->part_name, "%sp%d",
109 info->disk_name, info->part);
114 if (!info->disk_name) {
115 info->disk_name = strdup(penultimate);
116 if (!info->disk_name)
119 if (!info->part_name) {
120 info->part_name = strdup(ultimate);
121 if (!info->part_name)
130 __attribute__((__visibility__ ("hidden")))
131 get_partition_number(const char *devpath)
133 struct stat statbuf = { 0, };
135 unsigned int maj, min;
140 rc = stat(devpath, &statbuf);
142 efi_error("couldn't stat %s\n", devpath);
146 if (!S_ISBLK(statbuf.st_mode)) {
147 efi_error("%s is not a block device\n", devpath);
152 maj = major(statbuf.st_rdev);
153 min = minor(statbuf.st_rdev);
155 rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%u:%u", maj, min);
156 if (rc < 0 || !linkbuf) {
157 efi_error("couldn't get partition number for %u:%u", maj, min);
161 rc = read_sysfs_file(&partbuf, "/sys/dev/block/%s/partition", linkbuf);
163 efi_error("couldn't get partition number for %s", linkbuf);
164 /* This isn't strictly an error for e.g. nvdimm pmem devices */
168 rc = sscanf((char *)partbuf, "%d\n", &ret);
170 efi_error("couldn't get partition number for %s", partbuf);
177 __attribute__((__visibility__ ("hidden")))
178 find_parent_devpath(const char * const child, char **parent)
184 /* strip leading /dev/ */
185 node = strrchr(child, '/');
190 /* look up full path symlink */
191 ret = sysfs_readlink(&linkbuf, "/sys/class/block/%s", node);
192 if (ret < 0 || !linkbuf)
196 node = strrchr(linkbuf, '/');
202 node = strrchr(linkbuf, '/');
208 /* write out new path */
209 ret = asprintf(parent, "/dev/%s", node);
218 sysfs_test_pmem(const char *buf)
220 char *driverbuf = NULL;
223 rc = sysfs_readlink(&driverbuf,
224 "/sys/dev/block/%s/device/driver", buf);
225 if (rc < 0 || !driverbuf)
228 char *driver = strrchr(driverbuf, '/');
229 if (!driver || !*driver)
232 if (!strcmp(driver, "nd_pmem"))
238 sysfs_test_nvme(const char *buf, ssize_t size)
240 if (!strncmp(buf, "nvme/", MIN(size, 5)))
246 sysfs_test_sata(const char *buf, ssize_t size)
248 if (!strncmp(buf, "ata", MIN(size, 3)))
254 sysfs_test_sas(const char *buf, ssize_t size)
258 struct stat statbuf = { 0, };
264 newbuf = strndupa(buf, size+1);
270 rc = sscanf(newbuf, "host%d/%n", &host, &sz);
272 return (errno == 0) ? 0 : -1;
274 rc = asprintfa(&path, "/sys/class/scsi_host/host%d/host_sas_address",
279 rc = stat(path, &statbuf);
286 sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info)
293 d = opendir("/sys/class/ata_device/");
295 efi_error("opendir failed on /sys/class/ata_device/");
299 while ((de = readdir(d)) != NULL) {
300 uint32_t found_print_id;
302 uint32_t found_devno = 0;
304 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
308 rc = sscanf(de->d_name, "dev%d.%d.%d", &found_print_id,
309 &found_pmp, &found_devno);
310 if (rc < 2 || rc > 3) {
314 } else if (found_print_id != print_id) {
316 } else if (rc == 3) {
318 * the kernel doesn't't ever tell us the SATA PMPN
319 * sentinal value, it'll give us devM.N instead of
320 * devM.N.O in that case instead.
322 if (found_pmp > 0x7fff) {
327 info->sata_info.ata_devno = 0;
328 info->sata_info.ata_pmp = found_pmp;
330 } else if (rc == 2) {
331 info->sata_info.ata_devno = 0;
332 info->sata_info.ata_pmp = 0xffff;
338 rc = read_sysfs_file(&buf, "/sys/class/ata_port/ata%d/port_no",
340 if (rc <= 0 || buf == NULL)
343 rc = sscanf((char *)buf, "%d", &info->sata_info.ata_port);
348 * ata_port numbers are 1-indexed from libata in the kernel, but
349 * they're 0-indexed in the spec. For maximal confusion.
351 if (info->sata_info.ata_port == 0) {
355 info->sata_info.ata_port -= 1;
361 /* pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
363 * device -> ../../../btt12.1
364 * device/uuid: 0cee166e-dd56-4bc2-99d2-2544b69025b8
365 * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
367 * pmem12.1s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
369 * device -> ../../../btt12.2
370 * device/uuid: 78d94521-91f7-47db-b3a7-51b764281940
371 * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
373 * pmem12.2 -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
375 * device -> ../../../pfn12.1
376 * device/uuid: 829c5205-89a5-4581-9819-df7d7754c622
377 * 259:2 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
380 sysfs_parse_pmem(uint8_t *buf, ssize_t size, ssize_t *off,
381 const char *pbuf, ssize_t psize __attribute__((__unused__)),
382 ssize_t *poff __attribute__((__unused__)),
383 struct disk_info *info)
385 uint8_t *filebuf = NULL;
388 rc = read_sysfs_file(&filebuf,
389 "/sys/class/block/%s/device/uuid", pbuf);
390 if ((rc < 0 && errno == ENOENT) || filebuf == NULL)
393 rc = efi_str_to_guid((char *)filebuf, &info->nvdimm_label);
397 /* UUIDs are stored opposite Endian from GUIDs, so our normal GUID
398 * parser is giving us the wrong thing; swizzle those bytes around.
400 swizzle_guid_to_uuid(&info->nvdimm_label);
402 *off = efidp_make_nvdimm(buf, size, &info->nvdimm_label);
407 sysfs_parse_nvme(uint8_t *buf, ssize_t size, ssize_t *off,
408 const char *pbuf, ssize_t psize, ssize_t *poff,
409 struct disk_info *info)
413 uint8_t *filebuf = NULL;
420 newpbuf = strndupa(pbuf, psize+1);
423 newpbuf[psize] = '\0';
432 rc = sscanf(newpbuf, "nvme/nvme%d/nvme%dn%d%n", &tosser0,
433 &ctrl_id, &ns_id, &psz);
438 info->nvme_info.ctrl_id = ctrl_id;
439 info->nvme_info.ns_id = ns_id;
440 info->nvme_info.has_eui = 0;
441 info->interface_type = nvme;
444 * now fish the eui out of sysfs is there is one...
446 rc = read_sysfs_file(&filebuf,
447 "/sys/class/block/nvme%dn%d/eui",
449 if ((rc < 0 && errno == ENOENT) || filebuf == NULL) {
450 rc = read_sysfs_file(&filebuf,
451 "/sys/class/block/nvme%dn%d/device/eui",
454 if (rc >= 0 && filebuf != NULL) {
460 rc = sscanf((char *)filebuf,
461 "%02hhx %02hhx %02hhx %02hhx "
462 "%02hhx %02hhx %02hhx %02hhx",
463 &eui[0], &eui[1], &eui[2], &eui[3],
464 &eui[4], &eui[5], &eui[6], &eui[7]);
469 info->nvme_info.has_eui = 1;
470 memcpy(info->nvme_info.eui, eui, sizeof(eui));
473 *off = efidp_make_nvme(buf, size,
474 info->nvme_info.ns_id,
475 info->nvme_info.has_eui ? info->nvme_info.eui
482 sysfs_parse_sata(uint8_t *buf, ssize_t size, ssize_t *off,
483 const char *pbuf, ssize_t psize, ssize_t *poff,
484 struct disk_info *info)
495 uint32_t scsi_device;
496 uint32_t scsi_target;
501 newpbuf = strndupa(pbuf, psize+1);
504 newpbuf[psize] = '\0';
506 /* find the ata info:
507 * ata1/host0/target0:0:0/
510 rc = sscanf(newpbuf, "ata%d/host%d/target%d:%d:%d/%n",
511 &print_id, &scsi_bus, &scsi_device, &scsi_target, &scsi_lun,
517 /* find the emulated scsi bits (and ignore them)
520 uint32_t dummy0, dummy1, dummy2;
522 rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n", &dummy0, &dummy1,
523 &dummy2, &dummy3, &psz);
531 char *disk_name = NULL;
532 char *part_name = NULL;
534 rc = sscanf(newpbuf+*poff, "block/%m[^/]%n/%m[^/]%n", &disk_name, &psz,
537 rc = asprintf(&part_name, "%s%d", disk_name, info->part);
544 } else if (rc != 2) {
551 info->sata_info.scsi_bus = scsi_bus;
552 info->sata_info.scsi_device = scsi_device;
553 info->sata_info.scsi_target = scsi_target;
554 info->sata_info.scsi_lun = scsi_lun;
556 rc = sysfs_sata_get_port_info(print_id, info);
563 /* check the original of this; it's guaranteed in our copy */
564 if (pbuf[*poff] != '\0') {
571 info->disk_name = disk_name;
572 info->part_name = part_name;
573 if (info->interface_type == interface_type_unknown)
574 info->interface_type = sata;
576 if (info->interface_type == ata) {
577 *off = efidp_make_atapi(buf, size, info->sata_info.ata_port,
578 info->sata_info.ata_pmp,
579 info->sata_info.ata_devno);
581 *off = efidp_make_sata(buf, size, info->sata_info.ata_port,
582 info->sata_info.ata_pmp,
583 info->sata_info.ata_devno);
589 sysfs_parse_sas(uint8_t *buf, ssize_t size, ssize_t *off,
590 const char *pbuf, ssize_t psize, ssize_t *poff,
591 struct disk_info *info)
595 uint8_t *filebuf = NULL;
596 uint64_t sas_address;
600 newpbuf = strndupa(pbuf, psize+1);
603 newpbuf[psize] = '\0';
609 * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
611 uint32_t tosser0, tosser1, tosser2;
613 /* ignore a bunch of stuff
615 * or host4/port-4:0:0
617 rc = sscanf(newpbuf+*poff, "host%d/port-%d:%d%n", &tosser0, &tosser1,
624 rc = sscanf(pbuf+*poff, ":%d%n", &tosser0, &psz);
625 if (rc != 0 && rc != 1)
631 * or /end_device-4:0:0
632 * awesomely these are the exact same fields that go into port-blah,
633 * but we don't care for now about any of them anyway.
635 rc = sscanf(newpbuf+*poff, "/end_device-%d:%d%n", &tosser0, &tosser1,
642 rc = sscanf(newpbuf+*poff, ":%d%n", &tosser0, &psz);
643 if (rc != 0 && rc != 1)
651 rc = sscanf(newpbuf+*poff, "/target%d:%d:%"PRIu64"/%n", &tosser0,
652 &tosser1, &tosser3, &psz);
660 rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n",
661 &info->sas_info.scsi_bus,
662 &info->sas_info.scsi_device,
663 &info->sas_info.scsi_target,
664 &info->sas_info.scsi_lun, &psz);
672 char *disk_name = NULL;
673 char *part_name = NULL;
674 rc = sscanf(newpbuf+*poff, "block/%m[^/]/%m[^/]%n", &disk_name,
680 /* check the original of this; it's guaranteed in our copy */
681 if (pbuf[*poff] != '\0') {
689 * we also need to get the actual sas_address from someplace...
691 rc = read_sysfs_file(&filebuf,
692 "/sys/class/block/%s/device/sas_address",
694 if (rc < 0 || filebuf == NULL)
697 rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address);
701 info->sas_info.sas_address = sas_address;
702 info->disk_name = disk_name;
703 info->part_name = part_name;
704 info->interface_type = sas;
706 *off = efidp_make_sas(buf, size, sas_address);
711 make_pci_path(uint8_t *buf, ssize_t size, char *pathstr, ssize_t *pathoff)
718 if (pathstr == NULL || pathoff == NULL || pathstr[0] == '\0') {
725 uint16_t root_domain;
727 uint32_t acpi_hid = 0;
728 uint64_t acpi_uid_int = 0;
730 * find the pci root domain and port; they basically look like:
734 rc = sscanf(pathstr+poff, "pci%hx:%hhx/%n", &root_domain,
740 uint8_t *fbuf = NULL;
741 rc = read_sysfs_file(&fbuf,
742 "/sys/devices/pci%04hx:%02hhx/firmware_node/hid",
743 root_domain, root_bus);
744 if (rc < 0 || fbuf == NULL)
748 rc = sscanf((char *)fbuf, "PNP%hx", &tmp16);
751 acpi_hid = EFIDP_EFI_PNP_ID(tmp16);
753 /* Apparently basically nothing can look up a PcieRoot() node,
754 * because they just check _CID. So since _CID for the root pretty
755 * much always has to be PNP0A03 anyway, just use that no matter
758 if (acpi_hid == EFIDP_ACPI_PCIE_ROOT_HID)
759 acpi_hid = EFIDP_ACPI_PCI_ROOT_HID;
764 rc = read_sysfs_file(&fbuf,
765 "/sys/devices/pci%04hx:%02hhx/firmware_node/uid",
766 root_domain, root_bus);
767 if ((rc <= 0 && errno != ENOENT) || fbuf == NULL)
770 rc = sscanf((char *)fbuf, "%"PRIu64"\n", &acpi_uid_int);
772 /* kernel uses "%s\n" to print it, so there
773 * should always be some value and a newline... */
774 int l = strlen((char *)buf);
784 sz = efidp_make_acpi_hid_ex(buf+off, size?size-off:0,
785 acpi_hid, 0, 0, "", (char *)fbuf,
788 sz = efidp_make_acpi_hid(buf+off, size?size-off:0,
789 acpi_hid, acpi_uid_int);
795 /* find the pci domain/bus/device/function:
796 * 0000:00:01.0/0000:01:00.0/
797 * ^d ^b ^d ^f (of the last one in the series)
802 uint8_t bus, device, function;
803 rc = sscanf(pathstr+poff, "%hx:%hhx:%hhx.%hhx/%n",
804 &domain, &bus, &device, &function, &psz);
810 sz = efidp_make_pci(buf+off, size?size-off:0, device, function);
823 __attribute__((__visibility__ ("hidden")))
824 make_blockdev_path(uint8_t *buf, ssize_t size, struct disk_info *info)
826 char *linkbuf = NULL;
827 char *driverbuf = NULL;
828 ssize_t off=0, sz=0, loff=0;
833 rc = sysfs_readlink(&linkbuf, "/sys/dev/block/%"PRIu64":%u",
834 info->major, info->minor);
835 if (rc < 0 || !linkbuf) {
836 efi_error("couldn't read link for /sys/dev/block/%"PRIu64":%u",
837 info->major, info->minor);
842 * the sysfs path basically looks like one of:
843 * ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART
844 * ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
846 rc = sysfs_test_pmem(linkbuf+loff);
848 efi_error("sysfs_test_pmem(\"%s\") failed", linkbuf+loff);
852 info->interface_type = nd_pmem;
853 rc = sysfs_parse_pmem(buf+off, size?size-off:0, &sz,
854 linkbuf+loff, PATH_MAX-off,
864 rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz);
866 efi_error("scanf(\"%s\", %s, &lz) failed",
867 linkbuf+loff, "../../devices/%n");
873 sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
880 tmppath = strdupa(linkbuf);
883 tmppath[loff] = '\0';
884 rc = sysfs_readlink(&driverbuf, "/sys/dev/block/%s/driver",
886 if (rc < 0 || !driverbuf)
889 char *driver = strrchr(driverbuf, '/');
890 if (!driver || !*driver)
894 if (!strncmp(driver, "pata_", 5) ||
895 !(strcmp(driver, "ata_piix")))
896 info->interface_type = ata;
900 (info->interface_type == interface_type_unknown ||
901 info->interface_type == atapi ||
902 info->interface_type == usb ||
903 info->interface_type == i1394 ||
904 info->interface_type == fibre ||
905 info->interface_type == i2o ||
906 info->interface_type == md)) {
910 rc = sscanf(linkbuf+loff, "virtio%x/%n", &tosser, &tmpoff);
913 } else if (rc == 1) {
914 info->interface_type = virtblk;
920 /* /dev/nvme0n1 looks like:
921 * /sys/dev/block/259:0 -> ../../devices/pci0000:00/0000:00:1d.0/0000:05:00.0/nvme/nvme0/nvme0n1
924 rc = sysfs_test_nvme(linkbuf+loff, PATH_MAX-off);
929 rc = sysfs_parse_nvme(buf+off, size?size-off:0, &sz,
930 linkbuf+loff, PATH_MAX-off,
940 /* /dev/sda as SATA looks like:
941 * /sys/dev/block/8:0 -> ../../devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
944 rc = sysfs_test_sata(linkbuf+loff, PATH_MAX-off);
949 rc = sysfs_parse_sata(buf+off, size?size-off:0, &sz,
950 linkbuf+loff, PATH_MAX-off,
960 /* /dev/sdc as SAS looks like:
961 * /sys/dev/block/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
964 rc = sysfs_test_sas(linkbuf+loff, PATH_MAX-off);
969 rc = sysfs_parse_sas(buf+off, size?size-off:0, &sz,
970 linkbuf+loff, PATH_MAX-off,
975 * clang-analyzer complains about this because they
976 * don't believe in writing code to avoid introducing
985 if (!found && info->interface_type == scsi) {
988 rc = sysfs_readlink(&linkbuf, "/sys/class/block/%s/device",
990 if (rc < 0 || !linkbuf)
993 rc = sscanf(linkbuf, "../../../%d:%d:%d:%"PRIu64,
994 &info->scsi_info.scsi_bus,
995 &info->scsi_info.scsi_device,
996 &info->scsi_info.scsi_target,
997 &info->scsi_info.scsi_lun);
1001 sz = efidp_make_scsi(buf+off, size?size-off:0,
1002 info->scsi_info.scsi_target,
1003 info->scsi_info.scsi_lun);
1019 __attribute__((__visibility__ ("hidden")))
1020 eb_disk_info_from_fd(int fd, struct disk_info *info)
1026 memset(info, 0, sizeof *info);
1028 info->pci_root.root_pci_domain = 0xffff;
1029 info->pci_root.root_pci_bus = 0xff;
1031 memset(&buf, 0, sizeof(struct stat));
1032 rc = fstat(fd, &buf);
1034 efi_error("fstat() failed: %m");
1037 if (S_ISBLK(buf.st_mode)) {
1038 info->major = major(buf.st_rdev);
1039 info->minor = minor(buf.st_rdev);
1040 } else if (S_ISREG(buf.st_mode)) {
1041 info->major = major(buf.st_dev);
1042 info->minor = minor(buf.st_dev);
1044 efi_error("Cannot stat non-block or non-regular file");
1048 /* IDE disks can have up to 64 partitions, or 6 bits worth,
1049 * and have one bit for the disk number.
1050 * This leaves an extra bit at the top.
1052 if (info->major == 3) {
1053 info->disknum = (info->minor >> 6) & 1;
1054 info->controllernum = (info->major - 3 + 0) + info->disknum;
1055 info->interface_type = ata;
1056 info->part = info->minor & 0x3F;
1058 } else if (info->major == 22) {
1059 info->disknum = (info->minor >> 6) & 1;
1060 info->controllernum = (info->major - 22 + 2) + info->disknum;
1061 info->interface_type = ata;
1062 info->part = info->minor & 0x3F;
1064 } else if (info->major >= 33 && info->major <= 34) {
1065 info->disknum = (info->minor >> 6) & 1;
1066 info->controllernum = (info->major - 33 + 4) + info->disknum;
1067 info->interface_type = ata;
1068 info->part = info->minor & 0x3F;
1070 } else if (info->major >= 56 && info->major <= 57) {
1071 info->disknum = (info->minor >> 6) & 1;
1072 info->controllernum = (info->major - 56 + 8) + info->disknum;
1073 info->interface_type = ata;
1074 info->part = info->minor & 0x3F;
1076 } else if (info->major >= 88 && info->major <= 91) {
1077 info->disknum = (info->minor >> 6) & 1;
1078 info->controllernum = (info->major - 88 + 12) + info->disknum;
1079 info->interface_type = ata;
1080 info->part = info->minor & 0x3F;
1084 /* I2O disks can have up to 16 partitions, or 4 bits worth. */
1085 if (info->major >= 80 && info->major <= 87) {
1086 info->interface_type = i2o;
1087 info->disknum = 16*(info->major-80) + (info->minor >> 4);
1088 info->part = (info->minor & 0xF);
1092 /* SCSI disks can have up to 16 partitions, or 4 bits worth
1093 * and have one bit for the disk number.
1095 if (info->major == 8) {
1096 info->interface_type = scsi;
1097 info->disknum = (info->minor >> 4);
1098 info->part = (info->minor & 0xF);
1100 } else if (info->major >= 65 && info->major <= 71) {
1101 info->interface_type = scsi;
1102 info->disknum = 16*(info->major-64) + (info->minor >> 4);
1103 info->part = (info->minor & 0xF);
1105 } else if (info->major >= 128 && info->major <= 135) {
1106 info->interface_type = scsi;
1107 info->disknum = 16*(info->major-128) + (info->minor >> 4);
1108 info->part = (info->minor & 0xF);
1112 rc = sysfs_readlink(&driver, "/sys/dev/block/%"PRIu64":%"PRIu32"/device/driver",
1113 info->major, info->minor);
1115 char *last = strrchr(driver, '/');
1117 if (!strcmp(last+1, "nd_pmem")) {
1118 info->interface_type = nd_pmem;
1121 } else if (!strcmp(last+1, "nd_blk")) {
1123 info->inteface_type = scsi;
1134 make_net_pci_path(uint8_t *buf, ssize_t size, const char * const ifname)
1136 char *linkbuf = NULL;
1137 ssize_t off=0, sz=0, loff=0;
1141 rc = sysfs_readlink(&linkbuf, "/sys/class/net/%s", ifname);
1142 if (rc < 0 || !linkbuf)
1146 * the sysfs path basically looks like:
1147 * ../../devices/$PCI_STUFF/net/$IFACE
1149 rc = sscanf(linkbuf, "../../devices/%n", &lsz);
1155 sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
1160 * clang-analyzer complains about this because they don't believe in
1161 * writing code to avoid introducing bugs later.
1169 __attribute__((__visibility__ ("hidden")))
1170 make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname)
1173 struct ethtool_drvinfo drvinfo = { 0, };
1175 ssize_t ret = -1, sz, off=0;
1176 char busname[PATH_MAX+1] = "";
1178 memset(&ifr, 0, sizeof (ifr));
1179 strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
1180 ifr.ifr_name[IF_NAMESIZE-1] = '\0';
1181 drvinfo.cmd = ETHTOOL_GDRVINFO;
1182 ifr.ifr_data = (caddr_t)&drvinfo;
1184 fd = socket(AF_INET, SOCK_DGRAM, 0);
1188 rc = ioctl(fd, SIOCETHTOOL, &ifr);
1192 strncpy(busname, drvinfo.bus_info, PATH_MAX);
1194 rc = ioctl(fd, SIOCGIFHWADDR, &ifr);
1198 sz = make_net_pci_path(buf, size, ifname);
1203 sz = efidp_make_mac_addr(buf+off, size?size-off:0,
1204 ifr.ifr_ifru.ifru_hwaddr.sa_family,
1205 (uint8_t *)ifr.ifr_ifru.ifru_hwaddr.sa_data,
1206 sizeof(ifr.ifr_ifru.ifru_hwaddr.sa_data));