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>
46 set_disk_and_part_name(struct disk_info *info)
51 rc = sysfs_readlink(&linkbuf, "dev/block/%"PRIu64":%"PRIu32,
52 info->major, info->minor);
53 if (rc < 0 || !linkbuf)
57 ultimate = strrchr(linkbuf, '/');
66 penultimate = strrchr(linkbuf, '/');
74 * If there's a better way to figure this out, it'd be good, because
75 * I don't want to have to change this for every new disk type...
77 if (!strncmp(ultimate, "pmem", 4)) {
78 if (!info->disk_name) {
79 info->disk_name = strdup(ultimate);
83 } else if (!strcmp(penultimate, "block")) {
84 if (!info->disk_name) {
85 info->disk_name = strdup(ultimate);
89 if (!info->part_name) {
90 rc = asprintf(&info->part_name, "%s%d", info->disk_name,
96 if (!info->disk_name) {
97 info->disk_name = strdup(penultimate);
101 if (!info->part_name) {
102 info->part_name = strdup(ultimate);
103 if (!info->part_name)
112 get_partition_number(const char *devpath)
114 struct stat statbuf = { 0, };
116 unsigned int maj, min;
118 uint8_t *partbuf = NULL; /* XXX this is wrong and the code below will be wrong */
121 rc = stat(devpath, &statbuf);
123 efi_error("couldn't stat %s\n", devpath);
127 if (!S_ISBLK(statbuf.st_mode)) {
128 efi_error("%s is not a block device\n", devpath);
133 maj = major(statbuf.st_rdev);
134 min = minor(statbuf.st_rdev);
136 rc = sysfs_readlink(&linkbuf, "dev/block/%u:%u", maj, min);
137 if (rc < 0 || !linkbuf) {
138 efi_error("couldn't get partition number for %u:%u", maj, min);
142 rc = read_sysfs_file(&partbuf, "dev/block/%s/partition", linkbuf);
144 efi_error("couldn't get partition number for %s", linkbuf);
145 /* This isn't strictly an error for e.g. nvdimm pmem devices */
149 rc = sscanf((char *)partbuf, "%d\n", &ret);
151 efi_error("couldn't get partition number for %s", partbuf);
158 find_parent_devpath(const char * const child, char **parent)
164 /* strip leading /dev/ */
165 node = strrchr(child, '/');
170 /* look up full path symlink */
171 ret = sysfs_readlink(&linkbuf, "class/block/%s", node);
172 if (ret < 0 || !linkbuf)
176 node = strrchr(linkbuf, '/');
182 node = strrchr(linkbuf, '/');
188 /* write out new path */
189 ret = asprintf(parent, "/dev/%s", node);
198 sysfs_test_pmem(const char *buf)
200 char *driverbuf = NULL;
203 rc = sysfs_readlink(&driverbuf,
204 "dev/block/%s/device/driver", buf);
205 if (rc < 0 || !driverbuf)
208 char *driver = strrchr(driverbuf, '/');
209 if (!driver || !*driver)
212 if (!strcmp(driver, "nd_pmem"))
218 sysfs_test_sata(const char *buf, ssize_t size)
220 if (!strncmp(buf, "ata", MIN(size, 3)))
226 sysfs_test_sas(const char *buf, ssize_t size)
230 struct stat statbuf = { 0, };
236 newbuf = strndupa(buf, size+1);
242 rc = sscanf(newbuf, "host%d/%n", &host, &sz);
244 return (errno == 0) ? 0 : -1;
246 rc = asprintfa(&path, "/sys/class/scsi_host/host%d/host_sas_address",
251 rc = stat(path, &statbuf);
258 sysfs_sata_get_port_info(uint32_t print_id, struct disk_info *info)
265 d = opendir("/sys/class/ata_device/");
267 efi_error("opendir failed on /sys/class/ata_device/");
271 while ((de = readdir(d)) != NULL) {
272 uint32_t found_print_id;
274 uint32_t found_devno = 0;
276 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
280 rc = sscanf(de->d_name, "dev%d.%d.%d", &found_print_id,
281 &found_pmp, &found_devno);
282 if (rc < 2 || rc > 3) {
286 } else if (found_print_id != print_id) {
288 } else if (rc == 3) {
290 * the kernel doesn't't ever tell us the SATA PMPN
291 * sentinal value, it'll give us devM.N instead of
292 * devM.N.O in that case instead.
294 if (found_pmp > 0x7fff) {
299 info->sata_info.ata_devno = 0;
300 info->sata_info.ata_pmp = found_pmp;
302 } else if (rc == 2) {
303 info->sata_info.ata_devno = 0;
304 info->sata_info.ata_pmp = 0xffff;
310 rc = read_sysfs_file(&buf, "class/ata_port/ata%d/port_no",
312 if (rc <= 0 || buf == NULL)
315 rc = sscanf((char *)buf, "%d", &info->sata_info.ata_port);
320 * ata_port numbers are 1-indexed from libata in the kernel, but
321 * they're 0-indexed in the spec. For maximal confusion.
323 if (info->sata_info.ata_port == 0) {
327 info->sata_info.ata_port -= 1;
333 /* pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
335 * device -> ../../../btt12.1
336 * device/uuid: 0cee166e-dd56-4bc2-99d2-2544b69025b8
337 * 259:0 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
339 * pmem12.1s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
341 * device -> ../../../btt12.2
342 * device/uuid: 78d94521-91f7-47db-b3a7-51b764281940
343 * 259:1 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.2/block/pmem12.1s
345 * pmem12.2 -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
347 * device -> ../../../pfn12.1
348 * device/uuid: 829c5205-89a5-4581-9819-df7d7754c622
349 * 259:2 -> ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/pfn12.1/block/pmem12.2
352 sysfs_parse_pmem(uint8_t *buf, ssize_t size, ssize_t *off,
353 const char *pbuf, ssize_t psize UNUSED,
354 ssize_t *poff UNUSED, struct disk_info *info)
356 uint8_t *filebuf = NULL;
359 rc = read_sysfs_file(&filebuf,
360 "class/block/%s/device/uuid", pbuf);
361 if ((rc < 0 && errno == ENOENT) || filebuf == NULL)
364 rc = efi_str_to_guid((char *)filebuf, &info->nvdimm_label);
368 /* UUIDs are stored opposite Endian from GUIDs, so our normal GUID
369 * parser is giving us the wrong thing; swizzle those bytes around.
371 swizzle_guid_to_uuid(&info->nvdimm_label);
373 *off = efidp_make_nvdimm(buf, size, &info->nvdimm_label);
378 sysfs_parse_sata(uint8_t *buf, ssize_t size, ssize_t *off,
379 const char *pbuf, ssize_t psize, ssize_t *poff,
380 struct disk_info *info)
391 uint32_t scsi_device;
392 uint32_t scsi_target;
397 newpbuf = strndupa(pbuf, psize+1);
400 newpbuf[psize] = '\0';
402 /* find the ata info:
403 * ata1/host0/target0:0:0/
406 rc = sscanf(newpbuf, "ata%d/host%d/target%d:%d:%d/%n",
407 &print_id, &scsi_bus, &scsi_device, &scsi_target, &scsi_lun,
413 /* find the emulated scsi bits (and ignore them)
416 uint32_t dummy0, dummy1, dummy2;
418 rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n", &dummy0, &dummy1,
419 &dummy2, &dummy3, &psz);
427 char *disk_name = NULL;
428 char *part_name = NULL;
430 rc = sscanf(newpbuf+*poff, "block/%m[^/]%n/%m[^/]%n", &disk_name, &psz,
433 rc = asprintf(&part_name, "%s%d", disk_name, info->part);
440 } else if (rc != 2) {
447 info->sata_info.scsi_bus = scsi_bus;
448 info->sata_info.scsi_device = scsi_device;
449 info->sata_info.scsi_target = scsi_target;
450 info->sata_info.scsi_lun = scsi_lun;
452 rc = sysfs_sata_get_port_info(print_id, info);
459 /* check the original of this; it's guaranteed in our copy */
460 if (pbuf[*poff] != '\0') {
467 info->disk_name = disk_name;
468 info->part_name = part_name;
469 if (info->interface_type == interface_type_unknown)
470 info->interface_type = sata;
472 if (info->interface_type == ata) {
473 *off = efidp_make_atapi(buf, size, info->sata_info.ata_port,
474 info->sata_info.ata_pmp,
475 info->sata_info.ata_devno);
477 *off = efidp_make_sata(buf, size, info->sata_info.ata_port,
478 info->sata_info.ata_pmp,
479 info->sata_info.ata_devno);
485 sysfs_parse_sas(uint8_t *buf, ssize_t size, ssize_t *off,
486 const char *pbuf, ssize_t psize, ssize_t *poff,
487 struct disk_info *info)
491 uint8_t *filebuf = NULL;
492 uint64_t sas_address;
496 newpbuf = strndupa(pbuf, psize+1);
499 newpbuf[psize] = '\0';
505 * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
507 uint32_t tosser0, tosser1, tosser2;
509 /* ignore a bunch of stuff
511 * or host4/port-4:0:0
513 rc = sscanf(newpbuf+*poff, "host%d/port-%d:%d%n", &tosser0, &tosser1,
520 rc = sscanf(pbuf+*poff, ":%d%n", &tosser0, &psz);
521 if (rc != 0 && rc != 1)
527 * or /end_device-4:0:0
528 * awesomely these are the exact same fields that go into port-blah,
529 * but we don't care for now about any of them anyway.
531 rc = sscanf(newpbuf+*poff, "/end_device-%d:%d%n", &tosser0, &tosser1,
538 rc = sscanf(newpbuf+*poff, ":%d%n", &tosser0, &psz);
539 if (rc != 0 && rc != 1)
547 rc = sscanf(newpbuf+*poff, "/target%d:%d:%"PRIu64"/%n", &tosser0,
548 &tosser1, &tosser3, &psz);
556 rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n",
557 &info->sas_info.scsi_bus,
558 &info->sas_info.scsi_device,
559 &info->sas_info.scsi_target,
560 &info->sas_info.scsi_lun, &psz);
568 char *disk_name = NULL;
569 char *part_name = NULL;
570 rc = sscanf(newpbuf+*poff, "block/%m[^/]/%m[^/]%n", &disk_name,
576 /* check the original of this; it's guaranteed in our copy */
577 if (pbuf[*poff] != '\0') {
585 * we also need to get the actual sas_address from someplace...
587 rc = read_sysfs_file(&filebuf,
588 "class/block/%s/device/sas_address",
590 if (rc < 0 || filebuf == NULL)
593 rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address);
597 info->sas_info.sas_address = sas_address;
598 info->disk_name = disk_name;
599 info->part_name = part_name;
600 info->interface_type = sas;
602 *off = efidp_make_sas(buf, size, sas_address);
607 make_pci_path(uint8_t *buf, ssize_t size, char *pathstr, ssize_t *pathoff)
614 if (pathstr == NULL || pathoff == NULL || pathstr[0] == '\0') {
621 uint16_t root_domain;
623 uint32_t acpi_hid = 0;
624 uint64_t acpi_uid_int = 0;
626 * find the pci root domain and port; they basically look like:
630 rc = sscanf(pathstr+poff, "pci%hx:%hhx/%n", &root_domain,
636 uint8_t *fbuf = NULL;
637 rc = read_sysfs_file(&fbuf,
638 "devices/pci%04hx:%02hhx/firmware_node/hid",
639 root_domain, root_bus);
640 if (rc < 0 || fbuf == NULL)
644 rc = sscanf((char *)fbuf, "PNP%hx", &tmp16);
647 acpi_hid = EFIDP_EFI_PNP_ID(tmp16);
649 /* Apparently basically nothing can look up a PcieRoot() node,
650 * because they just check _CID. So since _CID for the root pretty
651 * much always has to be PNP0A03 anyway, just use that no matter
654 if (acpi_hid == EFIDP_ACPI_PCIE_ROOT_HID)
655 acpi_hid = EFIDP_ACPI_PCI_ROOT_HID;
660 rc = read_sysfs_file(&fbuf,
661 "devices/pci%04hx:%02hhx/firmware_node/uid",
662 root_domain, root_bus);
663 if ((rc <= 0 && errno != ENOENT) || fbuf == NULL)
666 rc = sscanf((char *)fbuf, "%"PRIu64"\n", &acpi_uid_int);
668 /* kernel uses "%s\n" to print it, so there
669 * should always be some value and a newline... */
670 int l = strlen((char *)buf);
680 sz = efidp_make_acpi_hid_ex(buf+off, size?size-off:0,
681 acpi_hid, 0, 0, "", (char *)fbuf,
684 sz = efidp_make_acpi_hid(buf+off, size?size-off:0,
685 acpi_hid, acpi_uid_int);
691 /* find the pci domain/bus/device/function:
692 * 0000:00:01.0/0000:01:00.0/
693 * ^d ^b ^d ^f (of the last one in the series)
698 uint8_t bus, device, function;
699 rc = sscanf(pathstr+poff, "%hx:%hhx:%hhx.%hhx/%n",
700 &domain, &bus, &device, &function, &psz);
706 sz = efidp_make_pci(buf+off, size?size-off:0, device, function);
719 make_blockdev_path(uint8_t *buf, ssize_t size, struct disk_info *info)
721 char *linkbuf = NULL;
722 char *driverbuf = NULL;
723 ssize_t off=0, sz=0, loff=0;
728 rc = sysfs_readlink(&linkbuf, "dev/block/%"PRIu64":%u",
729 info->major, info->minor);
730 if (rc < 0 || !linkbuf) {
731 efi_error("couldn't read link for /sys/dev/block/%"PRIu64":%u",
732 info->major, info->minor);
737 * the sysfs path basically looks like one of:
738 * ../../devices/pci$PCI_STUFF/$BLOCKDEV_STUFF/block/$DISK/$PART
739 * ../../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
741 rc = sysfs_test_pmem(linkbuf+loff);
743 efi_error("sysfs_test_pmem(\"%s\") failed", linkbuf+loff);
747 info->interface_type = nd_pmem;
748 rc = sysfs_parse_pmem(buf+off, size?size-off:0, &sz,
749 linkbuf+loff, PATH_MAX-off,
759 rc = sscanf(linkbuf+loff, "../../devices/%n", &lsz);
761 efi_error("scanf(\"%s\", %s, &lz) failed",
762 linkbuf+loff, "../../devices/%n");
768 sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
775 tmppath = strdupa(linkbuf);
778 tmppath[loff] = '\0';
779 rc = sysfs_readlink(&driverbuf, "dev/block/%s/driver",
781 if (rc < 0 || !driverbuf)
784 char *driver = strrchr(driverbuf, '/');
785 if (!driver || !*driver)
791 /* /dev/sda as SATA looks like:
792 * /sys/dev/block/8:0 -> ../../devices/pci0000:00/0000:00:1f.2/ata1/host0/target0:0:0/0:0:0:0/block/sda
795 rc = sysfs_test_sata(linkbuf+loff, PATH_MAX-off);
800 rc = sysfs_parse_sata(buf+off, size?size-off:0, &sz,
801 linkbuf+loff, PATH_MAX-off,
811 /* /dev/sdc as SAS looks like:
812 * /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
815 rc = sysfs_test_sas(linkbuf+loff, PATH_MAX-off);
820 rc = sysfs_parse_sas(buf+off, size?size-off:0, &sz,
821 linkbuf+loff, PATH_MAX-off,
826 * clang-analyzer complains about this because they
827 * don't believe in writing code to avoid introducing
845 eb_disk_info_from_fd(int fd, struct disk_info *info)
851 memset(info, 0, sizeof *info);
853 info->pci_root.pci_root_domain = 0xffff;
854 info->pci_root.pci_root_bus = 0xff;
856 memset(&buf, 0, sizeof(struct stat));
857 rc = fstat(fd, &buf);
859 efi_error("fstat() failed: %m");
862 if (S_ISBLK(buf.st_mode)) {
863 info->major = major(buf.st_rdev);
864 info->minor = minor(buf.st_rdev);
865 } else if (S_ISREG(buf.st_mode)) {
866 info->major = major(buf.st_dev);
867 info->minor = minor(buf.st_dev);
869 efi_error("Cannot stat non-block or non-regular file");
873 rc = sysfs_readlink(&driver, "dev/block/%"PRIu64":%"PRIu32"/device/driver",
874 info->major, info->minor);
876 char *last = strrchr(driver, '/');
878 if (!strcmp(last+1, "nd_pmem")) {
879 info->interface_type = nd_pmem;
882 } else if (!strcmp(last+1, "nd_blk")) {
884 info->inteface_type = scsi;
895 make_net_pci_path(uint8_t *buf, ssize_t size, const char * const ifname)
897 char *linkbuf = NULL;
898 ssize_t off=0, sz=0, loff=0;
902 rc = sysfs_readlink(&linkbuf, "class/net/%s", ifname);
903 if (rc < 0 || !linkbuf)
907 * the sysfs path basically looks like:
908 * ../../devices/$PCI_STUFF/net/$IFACE
910 rc = sscanf(linkbuf, "../../devices/%n", &lsz);
916 sz = make_pci_path(buf, size, linkbuf+loff, &tmplsz);
921 * clang-analyzer complains about this because they don't believe in
922 * writing code to avoid introducing bugs later.
930 make_mac_path(uint8_t *buf, ssize_t size, const char * const ifname)
933 struct ethtool_drvinfo drvinfo = { 0, };
935 ssize_t ret = -1, sz, off=0;
936 char busname[PATH_MAX+1] = "";
938 memset(&ifr, 0, sizeof (ifr));
939 strncpy(ifr.ifr_name, ifname, IF_NAMESIZE);
940 ifr.ifr_name[IF_NAMESIZE-1] = '\0';
941 drvinfo.cmd = ETHTOOL_GDRVINFO;
942 ifr.ifr_data = (caddr_t)&drvinfo;
944 fd = socket(AF_INET, SOCK_DGRAM, 0);
948 rc = ioctl(fd, SIOCETHTOOL, &ifr);
952 strncpy(busname, drvinfo.bus_info, PATH_MAX);
954 rc = ioctl(fd, SIOCGIFHWADDR, &ifr);
958 sz = make_net_pci_path(buf, size, ifname);
963 sz = efidp_make_mac_addr(buf+off, size?size-off:0,
964 ifr.ifr_ifru.ifru_hwaddr.sa_family,
965 (uint8_t *)ifr.ifr_ifru.ifru_hwaddr.sa_data,
966 sizeof(ifr.ifr_ifru.ifru_hwaddr.sa_data));
978 /************************************************************
981 * - filedes is an open file descriptor, suitable for reading
984 * sector size, or 512.
985 ************************************************************/
987 get_sector_size(int filedes)
989 int rc, sector_size = 512;
991 rc = ioctl(filedes, BLKSSZGET, §or_size);