Not really guessing, it returns host name of the scsi host which has smallest unique_id. --- src/libvirt_private.syms | 1 + src/util/virutil.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/virutil.h | 4 ++ tests/utiltest.c | 27 +++++++++++ 4 files changed, 154 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 27fb0b5..ec85079 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1948,6 +1948,7 @@ virGetUserDirectory; virGetUserID; virGetUserName; virGetUserRuntimeDirectory; +virGuessStableScsiHostName; virHexToBin; virIndexToDiskName; virIsCapableFCHost; diff --git a/src/util/virutil.c b/src/util/virutil.c index a80574f..7f36e27 100644 --- a/src/util/virutil.c +++ b/src/util/virutil.c @@ -2256,6 +2256,120 @@ cleanup: } return ret; } + +static int +virGuessStableScsiHostNameCallback(const char *fpath, + void *opaque) +{ + const char *filename = opaque; + char *p = NULL; + + p = strrchr(fpath, '/'); + p++; + + if (STREQ(p, filename)) + return 0; + return -1; +} + +/** + * virGuessStableScsiHostName: + * @sysfs_prefix: The directory path where starts to traverse, defaults + * to SYSFS_BUS_PCI_DEVICES. + * @addr: The parent's PCI address + * + * Returns the host name (e.g. host10) of the scsi host whose parent + * has address @addr, and "unique_id" has the smallest value on success. + * Or NULL on failure. + */ +char * +virGuessStableScsiHostName(const char *sysfs_prefix, + const char *address) +{ + const char *prefix = sysfs_prefix ? sysfs_prefix : SYSFS_BUS_PCI_DEVICES; + unsigned int flags = 0; + char **paths = NULL; + int npaths = 0; + char *smallest_path = NULL; + unsigned int smallest; + char *dir = NULL; + char *buf = NULL; + char *p1 = NULL; + char *p2 = NULL; + char *ret = NULL; + int i; + + const char *filename = "unique_id"; + + if (virAsprintf(&dir, "%s/%s", prefix, address) < 0) { + virReportOOMError(); + return NULL; + } + + flags |= (VIR_TRAVERSE_DIRECTORY_IGNORE_HIDDEN_FILES | + VIR_TRAVERSE_DIRECTORY_FALL_THROUGH); + + if ((npaths = virTraverseDirectory(dir, 4, flags, + virGuessStableScsiHostNameCallback, + NULL, (void *)filename, &paths)) < 0) + goto cleanup; + + smallest_path = paths[0]; + if (virFileReadAll(paths[0], 1024, &buf) < 0) + goto cleanup; + + if ((p1 = strchr(buf, '\n'))) + *p1 = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &smallest) < 0) + goto cleanup; + + VIR_FREE(buf); + buf = NULL; + + for (i = 0; i < npaths; i++) { + unsigned int rc; + + if (virFileReadAll(paths[i], 1024, &buf) < 0) + goto cleanup; + + if ((p1 = strchr(buf, '\n'))) + *p1 = '\0'; + + if (virStrToLong_ui(buf, NULL, 10, &rc) < 0) + goto cleanup; + + if (rc < smallest) + smallest_path = paths[i]; + + VIR_FREE(buf); + buf = NULL; + } + + if (!(p1 = strstr(smallest_path, "scsi_host"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Unexpected path '%s' for PCI address " + "'%s' unique_id '%u'"), smallest_path, + address, smallest); + goto cleanup; + } + + p1 += strlen("scsi_host"); + p2 = strrchr(p1, '/'); + + if (VIR_STRNDUP(ret, p1 + 1, p2 - p1 -1) < 0) + goto cleanup; + +cleanup: + VIR_FREE(dir); + VIR_FREE(buf); + if (npaths > 0) { + for (i = 0; i < npaths; i++) + VIR_FREE(paths[i]); + VIR_FREE(paths); + } + return ret; +} #else int virReadFCHost(const char *sysfs_prefix ATTRIBUTE_UNUSED, @@ -2326,6 +2440,14 @@ virParseStableScsiHostAddress(const char *sysfs_prefix, virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); return NULL; } + +char * +virGuessStableScsiHostName(const char *sysfs_prefix, + const char *address) +{ + virReportSystemError(ENOSYS, "%s", _("Not supported on this platform")); + return NULL; +} #endif /* __linux__ */ /** diff --git a/src/util/virutil.h b/src/util/virutil.h index 2747cf1..10b3f6f 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -226,7 +226,11 @@ char *virFindPCIDeviceByVPD(const char *sysfs_prefix, char *virParseStableScsiHostAddress(const char *sysfs_prefix, const char *address, unsigned int unique_id) + ATTRIBUTE_NONNULL(2); +char * +virGuessStableScsiHostName(const char *sysfs_prefix, + const char *address) ATTRIBUTE_NONNULL(2); #endif /* __VIR_UTIL_H__ */ diff --git a/tests/utiltest.c b/tests/utiltest.c index d567ecc..0cfcead 100644 --- a/tests/utiltest.c +++ b/tests/utiltest.c @@ -226,6 +226,32 @@ cleanup: } static int +testGuessStableScsiHostName(const void *data ATTRIBUTE_UNUSED) +{ + const char *addr = "0000:00:1f.2"; + char *dir = NULL; + char *rc = NULL; + int ret = -1; + + if (virAsprintf(&dir, "%s/%s", TEST_SYSFS, "bus/pci/devices") < 0) { + virReportOOMError(); + return -1; + } + + if (!(rc = virGuessStableScsiHostName(dir, addr))) + goto cleanup; + + if (STRNEQ(rc, "host2")) + goto cleanup; + + ret = 0; +cleanup: + VIR_FREE(dir); + VIR_FREE(rc); + return ret; +} + +static int testStringPad(const void *data ATTRIBUTE_UNUSED) { const char *str = "1ff2"; @@ -278,6 +304,7 @@ mymain(void) DO_TEST(ParseVersionString); DO_TEST(FindPCIDeviceByVPD); DO_TEST(ParseStableScsiHostAddress); + DO_TEST(GuessStableScsiHostName); DO_TEST(StringPad); cleanup: -- 1.8.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list