COL_RAND,
COL_PKNAME,
COL_HCTL,
+ COL_TRANSPORT,
};
/* column names */
[COL_DZERO] = { "DISC-ZERO", 1, TT_FL_RIGHT, N_("discard zeroes data") },
[COL_WWN] = { "WWN", 18, 0, N_("unique storage identifier") },
[COL_HCTL] = { "HCTL", 10, 0, N_("Host:Channel:Target:Lun for SCSI") },
+ [COL_TRANSPORT] = { "TRAN", 6, 0, N_("device transport type") },
};
struct lsblk {
return 1;
}
+static char *_sysfs_host_string(const char *type, int host, const char *attr)
+{
+ char path[PATH_MAX], tmp[64] = {0};
+ int fd, r;
+
+ if (snprintf(path, sizeof(path), "/sys/class/%s_host/host%d/%s",
+ type, host, attr) < 0)
+ return NULL;
+ if ((fd = open(path, O_RDONLY)) < 0)
+ return NULL;
+ r = read(fd, tmp, sizeof(tmp));
+ close(fd);
+
+ if (r <= 0)
+ return NULL;
+
+ return xstrdup(tmp);
+}
+
+static int _sysfs_host_exists(const char *type, int host)
+{
+ char buf[PATH_MAX];
+ struct stat st;
+
+ if (snprintf(buf, sizeof(buf), "/sys/class/%s_host/host%d",
+ type, host) < 0)
+ return 0;
+
+ if (!stat(buf, &st) && S_ISDIR(st.st_mode))
+ return 1;
+
+ return 0;
+}
+
+static int _sysfs_scsi_attr_exists(const char *attr, int h, int c, int t, int l)
+{
+ char buf[PATH_MAX];
+ struct stat st;
+
+ if (snprintf(buf, sizeof(buf), "/sys/bus/scsi/devices/%d:%d:%d:%d/%s",
+ h, c, t, l, attr) < 0)
+ return 0;
+
+ if (!stat(buf, &st))
+ return 1;
+
+ return 0;
+}
+
+static int _sysfs_scsi_path_contains(const char *pattern, int h, int c, int t, int l)
+{
+ char buf[PATH_MAX], linkc[PATH_MAX];
+ struct stat st;
+
+ if (snprintf(buf, sizeof(buf), "/sys/bus/scsi/devices/%d:%d:%d:%d",
+ h, c, t, l) < 0)
+ return 0;
+
+ if (stat(buf, &st) || readlink(buf, linkc, sizeof(linkc)) <= 0)
+ return 0;
+
+ if (strstr(linkc, pattern))
+ return 1;
+
+ return 0;
+}
+
+/* Thanks to lsscsi code for idea of detection logic used here */
+static char *get_transport(struct blkdev_cxt *cxt)
+{
+ int host, channel, target, lun;
+ char *attr;
+
+ if (!get_hctl(cxt, &host, &channel, &target, &lun))
+ return NULL;
+
+ /* SPI - Serial Peripheral Interface */
+ if (_sysfs_host_exists("spi", host))
+ return xstrdup("spi");
+
+ /* FC/FCoE - Fibre Channel / Fibre Channel over Ethernet */
+ if (_sysfs_host_exists("fc", host)) {
+ if (!(attr = _sysfs_host_string("fc", host, "symbolic_name")))
+ return NULL;
+ if (strstr(attr, " over "))
+ return xstrdup("fcoe");
+ return xstrdup("fc");
+ }
+
+ /* SAS - Serial Attached SCSI */
+ if (_sysfs_host_exists("sas", host))
+ return xstrdup("sas");
+
+ if (_sysfs_scsi_attr_exists("sas_device", host, channel, target, lun))
+ return xstrdup("sas");
+
+ /* SBP - Serial Bus Protocol (FireWire) */
+ if (_sysfs_scsi_attr_exists("ieee1394_id", host, channel, target, lun))
+ return xstrdup("sbp");
+
+ /* iSCSI */
+ if (_sysfs_host_exists("iscsi", host))
+ return xstrdup("iscsi");
+
+ /* USB - Universal Serial Bus */
+ if (_sysfs_scsi_path_contains("usb", host, channel, target, lun))
+ return xstrdup("usb");
+
+ /* ATA, SATA */
+ if (_sysfs_host_exists("scsi", host)) {
+ if (!(attr = _sysfs_host_string("scsi", host, "proc_name")))
+ return NULL;
+ if (!strncmp(attr, "ahci", 4) ||
+ !strncmp(attr, "sata", 4))
+ return xstrdup("sata");
+
+ if (strstr(attr, "ata"))
+ return xstrdup("ata");
+ return NULL;
+ }
+
+ return NULL;
+}
+
#define is_parsable(_l) (((_l)->tt->flags & TT_FL_RAW) || \
((_l)->tt->flags & TT_FL_EXPORT))
}
break;
}
+ case COL_TRANSPORT:
+ p = get_transport(cxt);
+ if (p)
+ tt_line_set_data(ln, col, p);
+ break;
case COL_DALIGN:
p = sysfs_strdup(&cxt->sysfs, "discard_alignment");
if (cxt->discard && p)