diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c9252b448e..d3424da565 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2863,6 +2863,7 @@ virStorageFileGetMetadata; virStorageFileGetMetadataFromBuf; virStorageFileGetMetadataFromFD; virStorageFileGetMetadataInternal; +virStorageFileGetNPIVKey; virStorageFileGetRelativeBackingPath; virStorageFileGetSCSIKey; virStorageFileGetUniqueIdentifier; diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index a2f0670e50..d83d84fcf5 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -1492,6 +1492,85 @@ int virStorageFileGetSCSIKey(const char *path, #endif +#ifdef WITH_UDEV +/* virStorageFileGetNPIVKey + * @path: Path to the NPIV device + * @key: Unique key to be returned + * + * Using a udev specific function, query the @path to get and return a + * unique @key for the caller to use. Unlike the GetSCSIKey method, an + * NPIV LUN is uniquely identified by its ID_TARGET_PORT value. + * + * Returns: + * 0 On success, with the @key filled in or @key=NULL if the + * returned output string didn't have the data we need to + * formulate a unique key value + * -1 When WITH_UDEV is undefined and a system error is reported + * -2 When WITH_UDEV is defined, but calling virCommandRun fails + */ +# define ID_SERIAL "ID_SERIAL=" +# define ID_TARGET_PORT "ID_TARGET_PORT=" +int +virStorageFileGetNPIVKey(const char *path, + char **key) +{ + int status; + VIR_AUTOFREE(char *) outbuf = NULL; + const char *serial; + const char *port; + virCommandPtr cmd = virCommandNewArgList("/lib/udev/scsi_id", + "--replace-whitespace", + "--whitelisted", + "--export", + "--device", path, + NULL + ); + int ret = -2; + + *key = NULL; + + /* Run the program and capture its output */ + virCommandSetOutputBuffer(cmd, &outbuf); + if (virCommandRun(cmd, &status) < 0) + goto cleanup; + + /* Explicitly check status == 0, rather than passing NULL + * to virCommandRun because we don't want to raise an actual + * error in this scenario, just return a NULL key. + */ + if (status == 0 && *outbuf && + (serial = strstr(outbuf, ID_SERIAL)) && + (port = strstr(outbuf, ID_TARGET_PORT))) { + char *tmp; + + serial += strlen(ID_SERIAL); + port += strlen(ID_TARGET_PORT); + + if ((tmp = strchr(serial, '\n'))) + *tmp = '\0'; + + if ((tmp = strchr(port, '\n'))) + *tmp = '\0'; + + if (*serial != '\0' && *port != '\0') + ignore_value(virAsprintf(key, "%s_PORT%s", serial, port)); + } + + ret = 0; + + cleanup: + virCommandFree(cmd); + + return ret; +} +#else +int virStorageFileGetNPIVKey(const char *path, + char **key ATTRIBUTE_UNUSED) +{ + return -1; +} +#endif + /** * virStorageFileParseBackingStoreStr: * @str: backing store specifier string to parse diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index 03837e9e58..d6eaaa28c6 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -392,6 +392,8 @@ int virStorageFileGetLVMKey(const char *path, int virStorageFileGetSCSIKey(const char *path, char **key, bool ignoreError); +int virStorageFileGetNPIVKey(const char *path, + char **key); void virStorageAuthDefFree(virStorageAuthDefPtr def); virStorageAuthDefPtr virStorageAuthDefCopy(const virStorageAuthDef *src);