/*
* virstoragefile.c: file utility functions for FS storage backend
*
* Copyright (C) 2007-2017 Red Hat, Inc.
* Copyright (C) 2007-2008 Daniel P. Berrange
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*/
#include
#include "virstoragefile.h"
#include "viralloc.h"
#include "virerror.h"
#include "virlog.h"
#include "vircommand.h"
#include "virstring.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
VIR_LOG_INIT("util.storagefile");
#ifdef WITH_UDEV
/* virStorageFileGetSCSIKey
* @path: Path to the SCSI device
* @key: Unique key to be returned
* @ignoreError: Used to not report ENOSYS
*
* Using a udev specific function, query the @path to get and return a
* unique @key for the caller to use.
*
* Returns:
* 0 On success, with the @key filled in or @key=NULL if the
* returned string was empty.
* -1 When WITH_UDEV is undefined and a system error is reported
* -2 When WITH_UDEV is defined, but calling virCommandRun fails
*/
int
virStorageFileGetSCSIKey(const char *path,
char **key,
bool ignoreError G_GNUC_UNUSED)
{
int status;
g_autoptr(virCommand) cmd = NULL;
cmd = virCommandNewArgList("/lib/udev/scsi_id",
"--replace-whitespace",
"--whitelisted",
"--device", path,
NULL
);
*key = NULL;
/* Run the program and capture its output */
virCommandSetOutputBuffer(cmd, key);
if (virCommandRun(cmd, &status) < 0)
return -2;
/* 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 && *key) {
char *nl = strchr(*key, '\n');
if (nl)
*nl = '\0';
}
if (*key && STREQ(*key, ""))
VIR_FREE(*key);
return 0;
}
#else
int virStorageFileGetSCSIKey(const char *path,
char **key G_GNUC_UNUSED,
bool ignoreError)
{
if (!ignoreError)
virReportSystemError(ENOSYS, _("Unable to get SCSI key for %1$s"), path);
return -1;
}
#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;
const char *serial;
const char *port;
g_autofree char *outbuf = NULL;
g_autoptr(virCommand) cmd = NULL;
cmd = virCommandNewArgList("/lib/udev/scsi_id",
"--replace-whitespace",
"--whitelisted",
"--export",
"--device", path,
NULL
);
*key = NULL;
/* Run the program and capture its output */
virCommandSetOutputBuffer(cmd, &outbuf);
if (virCommandRun(cmd, &status) < 0)
return -2;
/* 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')
*key = g_strdup_printf("%s_PORT%s", serial, port);
}
return 0;
}
#else
int virStorageFileGetNPIVKey(const char *path G_GNUC_UNUSED,
char **key G_GNUC_UNUSED)
{
return -1;
}
#endif
/**
* virStorageFileParseBackingStoreStr:
* @str: backing store specifier string to parse
* @target: returns target device portion of the string
* @chainIndex: returns the backing store portion of the string
*
* Parses the backing store specifier string such as vda[1], or sda into
* components and returns them via arguments. If the string did not specify an
* index, 0 is assumed.
*
* Returns 0 on success -1 on error
*/
int
virStorageFileParseBackingStoreStr(const char *str,
char **target,
unsigned int *chainIndex)
{
unsigned int idx = 0;
char *suffix;
g_auto(GStrv) strings = NULL;
*chainIndex = 0;
if (!(strings = g_strsplit(str, "[", 2)))
return -1;
if (strings[0] && strings[1]) {
if (virStrToLong_uip(strings[1], &suffix, 10, &idx) < 0 ||
STRNEQ(suffix, "]"))
return -1;
}
if (target)
*target = g_strdup(strings[0]);
*chainIndex = idx;
return 0;
}