--- /dev/null
+/*
+ * libefiboot - library for the manipulation of EFI boot variables
+ * Copyright 2012-2018 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "fix_coverity.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "efiboot.h"
+
+/*
+ * support for SAS devices
+ *
+ * /sys/dev/block/$major:$minor looks like:
+ * 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
+ * 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
+ *
+ * /sys/dev/block/8:32/device looks like:
+ * DUNNO. But I suspect it's: ../../../4:0:0:0
+ *
+ * These things are also things in this case:
+ * /sys/class/scsi_host/host4/host_sas_address
+ * /sys/class/block/sdc/device/sas_address
+ *
+ * I'm not sure at the moment if they're the same or not.
+ */
+static ssize_t
+parse_sas(struct device *dev, const char *current)
+{
+ struct stat statbuf = { 0, };
+ int rc;
+ uint32_t scsi_host, scsi_bus, scsi_device, scsi_target;
+ uint64_t scsi_lun;
+ ssize_t pos;
+ uint8_t *filebuf = NULL;
+ uint64_t sas_address;
+
+ debug(DEBUG, "entry");
+
+ pos = parse_scsi_link(current, &scsi_host,
+ &scsi_bus, &scsi_device,
+ &scsi_target, &scsi_lun);
+ /*
+ * If we can't parse the scsi data, it isn't a sas device, so return 0
+ * not error.
+ */
+ if (pos < 0)
+ return 0;
+
+ /*
+ * Make sure it has the actual /SAS/ bits before we continue
+ * validating all this junk.
+ */
+ rc = sysfs_stat(&statbuf,
+ "class/scsi_host/host%d/host_sas_address",
+ scsi_host);
+ /*
+ * If we can't parse the scsi data, it isn't a /SAS/ device, so return
+ * 0 not error. Later errors mean it is an ata device, but we can't
+ * parse it right, so they return -1.
+ */
+ if (rc < 0)
+ return 0;
+
+ /*
+ * we also need to get the actual sas_address from someplace...
+ */
+ rc = read_sysfs_file(&filebuf,
+ "class/block/%s/device/sas_address",
+ dev->disk_name);
+ if (rc < 0 || filebuf == NULL)
+ return -1;
+
+ rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address);
+ if (rc != 1)
+ return -1;
+
+ dev->sas_info.sas_address = sas_address;
+
+ dev->scsi_info.scsi_bus = scsi_bus;
+ dev->scsi_info.scsi_device = scsi_device;
+ dev->scsi_info.scsi_target = scsi_target;
+ dev->scsi_info.scsi_lun = scsi_lun;
+ dev->interface_type = sas;
+ return pos;
+}
+
+static ssize_t
+dp_create_sas(struct device *dev,
+ uint8_t *buf, ssize_t size, ssize_t off)
+{
+ ssize_t sz;
+
+ debug(DEBUG, "entry");
+
+ sz = efidp_make_sas(buf + off, size ? size - off : 0,
+ dev->sas_info.sas_address);
+
+ return sz;
+}
+
+enum interface_type sas_iftypes[] = { sas, unknown };
+
+struct dev_probe HIDDEN sas_parser = {
+ .name = "sas",
+ .iftypes = sas_iftypes,
+ .flags = DEV_PROVIDES_HD,
+ .parse = parse_sas,
+ .create = dp_create_sas,
+};
return 0;
}
-static int
-sysfs_test_sas(const char *buf, ssize_t size)
-{
- int rc;
- char *path;
- struct stat statbuf = { 0, };
- char *newbuf;
-
- int host;
- int sz;
-
- newbuf = strndupa(buf, size+1);
- if (!newbuf)
- return -1;
- newbuf[size] = '\0';
-
- errno = 0;
- rc = sscanf(newbuf, "host%d/%n", &host, &sz);
- if (rc < 1)
- return (errno == 0) ? 0 : -1;
-
- rc = asprintfa(&path, "/sys/class/scsi_host/host%d/host_sas_address",
- host);
- if (rc < 0)
- return -1;
-
- rc = stat(path, &statbuf);
- if (rc >= 0)
- return 1;
- return 0;
-}
-
/* pmem12s -> ../devices/LNXSYSTM:00/LNXSYBUS:00/ACPI0012:00/ndbus0/region12/btt12.1/block/pmem12s
* dev: 259:0
* device -> ../../../btt12.1
}
static ssize_t
-sysfs_parse_sas(uint8_t *buf, ssize_t size, ssize_t *off,
- const char *pbuf, ssize_t psize, ssize_t *poff,
- struct disk_info *info)
-{
- int rc;
- int psz = 0;
- uint8_t *filebuf = NULL;
- uint64_t sas_address;
-
- char *newpbuf;
-
- newpbuf = strndupa(pbuf, psize+1);
- if (!newpbuf)
- return -1;
- newpbuf[psize] = '\0';
-
- *poff = 0;
- *off = 0;
-
- /* buf is:
- * host4/port-4:0/end_device-4:0/target4:0:0/4:0:0:0/block/sdc/sdc1
- */
- uint32_t tosser0, tosser1, tosser2;
-
- /* ignore a bunch of stuff
- * host4/port-4:0
- * or host4/port-4:0:0
- */
- rc = sscanf(newpbuf+*poff, "host%d/port-%d:%d%n", &tosser0, &tosser1,
- &tosser2, &psz);
- if (rc != 3)
- return -1;
- *poff += psz;
-
- psz = 0;
- rc = sscanf(pbuf+*poff, ":%d%n", &tosser0, &psz);
- if (rc != 0 && rc != 1)
- return -1;
- *poff += psz;
-
- /* next:
- * /end_device-4:0
- * or /end_device-4:0:0
- * awesomely these are the exact same fields that go into port-blah,
- * but we don't care for now about any of them anyway.
- */
- rc = sscanf(newpbuf+*poff, "/end_device-%d:%d%n", &tosser0, &tosser1,
- &psz);
- if (rc != 2)
- return -1;
- *poff += psz;
-
- psz = 0;
- rc = sscanf(newpbuf+*poff, ":%d%n", &tosser0, &psz);
- if (rc != 0 && rc != 1)
- return -1;
- *poff += psz;
-
- /* now:
- * /target4:0:0/
- */
- uint64_t tosser3;
- rc = sscanf(newpbuf+*poff, "/target%d:%d:%"PRIu64"/%n", &tosser0,
- &tosser1, &tosser3, &psz);
- if (rc != 3)
- return -1;
- *poff += psz;
-
- /* now:
- * %d:%d:%d:%llu/
- */
- rc = sscanf(newpbuf+*poff, "%d:%d:%d:%"PRIu64"/%n",
- &info->sas_info.scsi_bus,
- &info->sas_info.scsi_device,
- &info->sas_info.scsi_target,
- &info->sas_info.scsi_lun, &psz);
- if (rc != 4)
- return -1;
- *poff += psz;
-
- /* what's left is:
- * block/sdc/sdc1
- */
- char *disk_name = NULL;
- char *part_name = NULL;
- rc = sscanf(newpbuf+*poff, "block/%m[^/]/%m[^/]%n", &disk_name,
- &part_name, &psz);
- if (rc != 2)
- return -1;
- *poff += psz;
-
- /* check the original of this; it's guaranteed in our copy */
- if (pbuf[*poff] != '\0') {
- free(disk_name);
- free(part_name);
- errno = EINVAL;
- return -1;
- }
-
- /*
- * we also need to get the actual sas_address from someplace...
- */
- rc = read_sysfs_file(&filebuf,
- "class/block/%s/device/sas_address",
- disk_name);
- if (rc < 0 || filebuf == NULL)
- return -1;
-
- rc = sscanf((char *)filebuf, "%"PRIx64, &sas_address);
- if (rc != 1)
- return -1;
-
- info->sas_info.sas_address = sas_address;
- info->disk_name = disk_name;
- info->part_name = part_name;
- info->interface_type = sas;
-
- *off = efidp_make_sas(buf, size, sas_address);
- return *off;
-}
-
-static ssize_t
make_pci_path(uint8_t *buf, ssize_t size, char *pathstr, ssize_t *pathoff)
{
ssize_t off=0, sz=0;
}
- /* /dev/sdc as SAS looks like:
- * /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
- */
- if (!found) {
- rc = sysfs_test_sas(linkbuf+loff, PATH_MAX-off);
- if (rc < 0)
- return -1;
- else if (rc > 0) {
- ssize_t linksz=0;
- rc = sysfs_parse_sas(buf+off, size?size-off:0, &sz,
- linkbuf+loff, PATH_MAX-off,
- &linksz, info);
- if (rc < 0)
- return -1;
- /*
- * clang-analyzer complains about this because they
- * don't believe in writing code to avoid introducing
- * bugs later.
- */
- // loff += linksz;
- off += sz;
- found = 1;
- }
- }
-
if (!found) {
errno = ENOENT;
return -1;