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: > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list