On 06/07/2013 01:03 PM, Osier Yang wrote:
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.
It is up to the caller to free the memory returned.
+ */
+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;
+
From here...
+ 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;
...to here isn't necessary... and if you keep it, then the
loop below
goes from 1 to npaths since 0 is already covered...
+
+ 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];
if (!smallest_path || (rc < smallest)) {
smallest_path = paths[i];
smallest = rc
}
The (!smallest_path) is only necessary if you cut as noted above, but
the resetting of smallest to rc would seem to be required in either case.
+
+ VIR_FREE(buf);
+ buf = NULL;
The buf = NULL is superfluous
John
+ }
+
+ 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: