2012-07-23 15:08:39 +08:00
|
|
|
/*
|
|
|
|
* virsh-nodedev.c: Commands in node device group
|
|
|
|
*
|
2016-01-09 21:36:29 +08:00
|
|
|
* Copyright (C) 2005, 2007-2016 Red Hat, Inc.
|
2012-07-23 15:08:39 +08:00
|
|
|
*
|
|
|
|
* 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
|
2012-09-21 06:30:55 +08:00
|
|
|
* License along with this library. If not, see
|
2012-07-23 15:08:39 +08:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2012-08-21 06:23:10 +08:00
|
|
|
#include <config.h>
|
2022-04-02 18:31:47 +08:00
|
|
|
#include "virsh-completer-nodedev.h"
|
2012-08-21 06:23:10 +08:00
|
|
|
#include "virsh-nodedev.h"
|
2021-09-26 17:44:30 +08:00
|
|
|
#include "virsh-util.h"
|
2012-08-21 06:23:10 +08:00
|
|
|
|
|
|
|
#include "internal.h"
|
2012-12-13 02:06:53 +08:00
|
|
|
#include "viralloc.h"
|
2013-05-10 02:59:04 +08:00
|
|
|
#include "virfile.h"
|
2016-08-09 03:34:21 +08:00
|
|
|
#include "virtime.h"
|
2012-09-17 11:32:53 +08:00
|
|
|
#include "conf/node_device_conf.h"
|
2019-04-01 18:14:26 +08:00
|
|
|
#include "virenum.h"
|
2020-02-17 05:59:28 +08:00
|
|
|
#include "virutil.h"
|
2012-08-21 06:23:10 +08:00
|
|
|
|
2012-07-23 15:08:39 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-create" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_create[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("create a device defined "
|
|
|
|
"by an XML file on the node")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Create a device on the node. Note that this "
|
|
|
|
"command creates devices on the physical host "
|
|
|
|
"that can then be assigned to a virtual machine.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_create[] = {
|
2016-01-09 21:36:29 +08:00
|
|
|
VIRSH_COMMON_OPT_FILE(N_("file containing an XML description "
|
|
|
|
"of the device")),
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceCreate(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) dev = NULL;
|
2012-07-23 15:08:39 +08:00
|
|
|
const char *from = NULL;
|
2021-08-11 21:25:15 +08:00
|
|
|
g_autofree char *buffer = NULL;
|
2021-03-11 15:16:13 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2013-01-22 00:29:14 +08:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
|
|
|
|
virsh: use common namespacing
Convert the exported items in virsh.h to use a common 'vsh' prefix.
* tools/virsh.h (VIRSH_MAX_XML_FILE): Rename...
(VSH_MAX_XML_FILE): ...and parenthesize.
(DIFF_MSEC, CTRL_CLOSE_BRACKET): Delete.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Remove prototype.
(editWriteToTempFile, editFile, editReadBackFile, prettyCapacity)
(virshReportError): Rename...
(vshEditWriteToTempFile, vshEditFile, vshEditReadBackFile)
(vshPrettyCapacity, vshReportError): ...into vsh namespace.
(jobWatchTimeoutFunc): Move to virsh-domain.c.
* tools/virsh.c (vshCommandRun): Inline former DIFF_MSEC.
(main): Inline former CTRL_CLOSE_BRACKET.
(vshUsage, vshInit, vshDeinit, vshParseArgv): Make static.
(prettyCapacity, virshReportError, editWriteToTempFile, editFile):
Fix naming, and adjust usage.
(vshAskReedit, vshCommandRun, vshEventLoop, vshInit): Adjust
usage.
* tools/virsh-domain.c (cmdAttachDevice, cmdCPUCompare)
(cmdCPUBaseline, cmdCreate, cmdDefine, cmdDetachDevice)
(cmdUpdateDevice, cmdDesc, cmdUndefine, cmdStart, cmdVcpucount)
(cmdAttachDevice, cmdDomjobinfo): Likewise.
* tools/virsh-edit.c (do): Likewise.
* tools/virsh-interface.c (cmdInterfaceDefine): Likewise.
* tools/virsh-network.c (cmdNetworkCreate, cmdNetworkDefine):
Likewise.
* tools/virsh-nodedev.c (cmdNodeDeviceCreate): Likewise.
* tools/virsh-nwfilter.c (cmdNWFilterDefine): Likewise.
* tools/virsh-pool.c (cmdPoolCreate, cmdPoolDefine)
(cmdPoolDiscoverSources, cmdPoolList): Likewise.
* tools/virsh-secret.c (cmdSecretDefine): Likewise.
* tools/virsh-snapshot.c (cmdSnapshotCreate, vshSnapshotCreate)
(vshLookupSnapshot, cmdSnapshotEdit, cmdSnapshotCurrent)
(vshGetSnapshotParent): Likewise.
* tools/virsh-volume.c (cmdVolCreate, cmdVolCreateFrom)
(cmdVolInfo, cmdVolList): Likewise.
2012-08-19 12:10:17 +08:00
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
|
|
|
|
2021-09-24 07:49:08 +08:00
|
|
|
if (!(dev = virNodeDeviceCreateXML(priv->conn, buffer, 0))) {
|
2012-07-23 15:08:39 +08:00
|
|
|
vshError(ctl, _("Failed to create node device from %s"), from);
|
2021-09-24 07:49:08 +08:00
|
|
|
return false;
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
|
|
|
|
2021-09-24 07:49:08 +08:00
|
|
|
vshPrintExtra(ctl, _("Node device %s created from %s\n"),
|
|
|
|
virNodeDeviceGetName(dev), from);
|
|
|
|
return true;
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-destroy" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_destroy[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("destroy (stop) a device on the node")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Destroy a device on the node. Note that this "
|
|
|
|
"command destroys devices on the physical host")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_destroy[] = {
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = "name",
|
2013-02-04 22:16:44 +08:00
|
|
|
.type = VSH_OT_ALIAS,
|
|
|
|
.help = "device"
|
|
|
|
},
|
|
|
|
{.name = "device",
|
2013-01-14 22:30:11 +08:00
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 21:44:37 +08:00
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 22:30:11 +08:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
2020-08-18 05:21:48 +08:00
|
|
|
static virNodeDevice*
|
|
|
|
vshFindNodeDevice(vshControl *ctl, const char *value)
|
2012-07-23 15:08:39 +08:00
|
|
|
{
|
|
|
|
virNodeDevicePtr dev = NULL;
|
2021-08-11 21:45:02 +08:00
|
|
|
g_auto(GStrv) arr = NULL;
|
2013-02-04 22:16:44 +08:00
|
|
|
int narr;
|
2021-03-11 15:16:13 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2020-08-18 05:21:48 +08:00
|
|
|
if (strchr(value, ',')) {
|
|
|
|
narr = vshStringToArray(value, &arr);
|
2013-02-04 22:16:44 +08:00
|
|
|
if (narr != 2) {
|
2020-08-18 05:21:48 +08:00
|
|
|
vshError(ctl, _("Malformed device value '%s'"), value);
|
2021-08-12 15:59:20 +08:00
|
|
|
return NULL;
|
2013-02-04 22:16:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!virValidateWWN(arr[0]) || !virValidateWWN(arr[1]))
|
2021-08-12 15:59:20 +08:00
|
|
|
return NULL;
|
2013-02-04 22:16:44 +08:00
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
dev = virNodeDeviceLookupSCSIHostByWWN(priv->conn, arr[0], arr[1], 0);
|
2013-02-04 22:16:44 +08:00
|
|
|
} else {
|
2020-08-18 05:21:48 +08:00
|
|
|
dev = virNodeDeviceLookupByName(priv->conn, value);
|
2013-02-04 22:16:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!dev) {
|
2020-08-18 05:21:48 +08:00
|
|
|
vshError(ctl, "%s '%s'", _("Could not find matching device"), value);
|
2021-08-12 15:59:20 +08:00
|
|
|
return NULL;
|
2013-02-04 22:16:44 +08:00
|
|
|
}
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2020-08-18 05:21:48 +08:00
|
|
|
return dev;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDestroy(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) dev = NULL;
|
2020-08-18 05:21:48 +08:00
|
|
|
const char *device_value = NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev = vshFindNodeDevice(ctl, device_value);
|
|
|
|
if (!dev)
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2020-08-18 05:21:48 +08:00
|
|
|
|
2012-07-23 15:08:39 +08:00
|
|
|
if (virNodeDeviceDestroy(dev) == 0) {
|
2016-08-24 22:14:23 +08:00
|
|
|
vshPrintExtra(ctl, _("Destroyed node device '%s'\n"), device_value);
|
2012-07-23 15:08:39 +08:00
|
|
|
} else {
|
2013-02-04 22:16:44 +08:00
|
|
|
vshError(ctl, _("Failed to destroy node device '%s'"), device_value);
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
|
|
|
|
2021-11-04 22:26:07 +08:00
|
|
|
return true;
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
struct virshNodeList {
|
2012-07-23 15:08:39 +08:00
|
|
|
char **names;
|
|
|
|
char **parents;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const char *
|
2015-06-16 00:53:58 +08:00
|
|
|
virshNodeListLookup(int devid, bool parent, void *opaque)
|
2012-07-23 15:08:39 +08:00
|
|
|
{
|
2015-06-16 00:53:58 +08:00
|
|
|
struct virshNodeList *arrays = opaque;
|
2012-07-23 15:08:39 +08:00
|
|
|
if (parent)
|
|
|
|
return arrays->parents[devid];
|
|
|
|
return arrays->names[devid];
|
|
|
|
}
|
|
|
|
|
2012-09-17 11:32:53 +08:00
|
|
|
static int
|
2015-06-16 00:53:58 +08:00
|
|
|
virshNodeDeviceSorter(const void *a, const void *b)
|
2012-09-17 11:32:53 +08:00
|
|
|
{
|
|
|
|
virNodeDevicePtr *na = (virNodeDevicePtr *) a;
|
|
|
|
virNodeDevicePtr *nb = (virNodeDevicePtr *) b;
|
|
|
|
|
|
|
|
if (*na && !*nb)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!*na)
|
|
|
|
return *nb != NULL;
|
|
|
|
|
|
|
|
return vshStrcasecmp(virNodeDeviceGetName(*na),
|
|
|
|
virNodeDeviceGetName(*nb));
|
|
|
|
}
|
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
struct virshNodeDeviceList {
|
2012-09-17 11:32:53 +08:00
|
|
|
virNodeDevicePtr *devices;
|
|
|
|
size_t ndevices;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
2021-03-11 15:16:13 +08:00
|
|
|
virshNodeDeviceListFree(struct virshNodeDeviceList *list)
|
2012-09-17 11:32:53 +08:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 22:09:33 +08:00
|
|
|
size_t i;
|
2012-09-17 11:32:53 +08:00
|
|
|
|
2013-08-27 19:27:50 +08:00
|
|
|
if (list && list->devices) {
|
2012-09-17 11:32:53 +08:00
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
2021-09-26 17:44:30 +08:00
|
|
|
virshNodeDeviceFree(list->devices[i]);
|
2012-09-17 11:32:53 +08:00
|
|
|
}
|
2021-02-04 03:32:55 +08:00
|
|
|
g_free(list->devices);
|
2012-09-17 11:32:53 +08:00
|
|
|
}
|
2021-02-04 03:32:55 +08:00
|
|
|
g_free(list);
|
2012-09-17 11:32:53 +08:00
|
|
|
}
|
|
|
|
|
2021-03-11 15:16:13 +08:00
|
|
|
static struct virshNodeDeviceList *
|
2015-06-16 00:53:58 +08:00
|
|
|
virshNodeDeviceListCollect(vshControl *ctl,
|
2012-09-17 11:32:53 +08:00
|
|
|
char **capnames,
|
|
|
|
int ncapnames,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
2021-03-11 15:16:13 +08:00
|
|
|
struct virshNodeDeviceList *list = g_new0(struct virshNodeDeviceList, 1);
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 22:09:33 +08:00
|
|
|
size_t i;
|
2012-09-17 11:32:53 +08:00
|
|
|
int ret;
|
|
|
|
virNodeDevicePtr device;
|
|
|
|
bool success = false;
|
|
|
|
size_t deleted = 0;
|
|
|
|
int ndevices = 0;
|
|
|
|
char **names = NULL;
|
2021-03-11 15:16:13 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-09-17 11:32:53 +08:00
|
|
|
|
|
|
|
/* try the list with flags support (0.10.2 and later) */
|
2015-06-16 00:53:58 +08:00
|
|
|
if ((ret = virConnectListAllNodeDevices(priv->conn,
|
2012-09-17 11:32:53 +08:00
|
|
|
&list->devices,
|
|
|
|
flags)) >= 0) {
|
|
|
|
list->ndevices = ret;
|
|
|
|
goto finished;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if the command is actually supported */
|
|
|
|
if (last_error && last_error->code == VIR_ERR_NO_SUPPORT)
|
|
|
|
goto fallback;
|
|
|
|
|
|
|
|
/* there was an error during the call */
|
|
|
|
vshError(ctl, "%s", _("Failed to list node devices"));
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
2014-03-25 14:53:59 +08:00
|
|
|
fallback:
|
2012-09-17 11:32:53 +08:00
|
|
|
/* fall back to old method (0.10.1 and older) */
|
|
|
|
vshResetLibvirtError();
|
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
ndevices = virNodeNumOfDevices(priv->conn, NULL, 0);
|
2012-09-17 11:32:53 +08:00
|
|
|
if (ndevices < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to count node devices"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ndevices == 0)
|
|
|
|
return list;
|
|
|
|
|
2020-10-06 00:50:09 +08:00
|
|
|
names = g_new0(char *, ndevices);
|
2012-09-17 11:32:53 +08:00
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
ndevices = virNodeListDevices(priv->conn, NULL, names, ndevices, 0);
|
2012-09-17 11:32:53 +08:00
|
|
|
if (ndevices < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to list node devices"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-10-06 00:50:09 +08:00
|
|
|
list->devices = g_new0(virNodeDevicePtr, ndevices);
|
2012-09-17 11:32:53 +08:00
|
|
|
list->ndevices = 0;
|
|
|
|
|
|
|
|
/* get the node devices */
|
2013-05-21 15:44:53 +08:00
|
|
|
for (i = 0; i < ndevices; i++) {
|
2015-06-16 00:53:58 +08:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, names[i])))
|
2012-09-17 11:32:53 +08:00
|
|
|
continue;
|
|
|
|
list->devices[list->ndevices++] = device;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* truncate domains that weren't found */
|
|
|
|
deleted = ndevices - list->ndevices;
|
|
|
|
|
|
|
|
if (!capnames)
|
|
|
|
goto finished;
|
|
|
|
|
|
|
|
/* filter the list if the list was acquired by fallback means */
|
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
2021-08-11 21:25:15 +08:00
|
|
|
g_autofree char **caps = NULL;
|
2012-09-17 11:32:53 +08:00
|
|
|
int ncaps = 0;
|
|
|
|
bool match = false;
|
2020-08-03 23:27:58 +08:00
|
|
|
size_t j, k;
|
2012-09-17 11:32:53 +08:00
|
|
|
|
|
|
|
device = list->devices[i];
|
|
|
|
|
|
|
|
if ((ncaps = virNodeDeviceNumOfCaps(device)) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to get capability numbers "
|
|
|
|
"of the device"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2020-10-06 00:50:09 +08:00
|
|
|
caps = g_new0(char *, ncaps);
|
2012-09-17 11:32:53 +08:00
|
|
|
|
|
|
|
if ((ncaps = virNodeDeviceListCaps(device, caps, ncaps)) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Failed to get capability names of the device"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-10-15 20:44:06 +08:00
|
|
|
/* Check if the device's capability matches with provided
|
2012-09-17 11:32:53 +08:00
|
|
|
* capabilities.
|
|
|
|
*/
|
|
|
|
for (j = 0; j < ncaps; j++) {
|
|
|
|
for (k = 0; k < ncapnames; k++) {
|
|
|
|
if (STREQ(caps[j], capnames[k])) {
|
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!match)
|
|
|
|
goto remove_entry;
|
|
|
|
|
|
|
|
/* the device matched all filters, it may stay */
|
|
|
|
continue;
|
|
|
|
|
2014-03-25 14:53:59 +08:00
|
|
|
remove_entry:
|
2012-09-17 11:32:53 +08:00
|
|
|
/* the device has to be removed as it failed one of the filters */
|
2021-09-26 17:44:30 +08:00
|
|
|
g_clear_pointer(&list->devices[i], virshNodeDeviceFree);
|
2012-09-17 11:32:53 +08:00
|
|
|
deleted++;
|
|
|
|
}
|
|
|
|
|
2014-03-25 14:53:59 +08:00
|
|
|
finished:
|
2012-09-17 11:32:53 +08:00
|
|
|
/* sort the list */
|
|
|
|
if (list->devices && list->ndevices)
|
|
|
|
qsort(list->devices, list->ndevices,
|
2015-06-16 00:53:58 +08:00
|
|
|
sizeof(*list->devices), virshNodeDeviceSorter);
|
2012-09-17 11:32:53 +08:00
|
|
|
|
|
|
|
/* truncate the list if filter simulation deleted entries */
|
|
|
|
if (deleted)
|
|
|
|
VIR_SHRINK_N(list->devices, list->ndevices, deleted);
|
|
|
|
|
|
|
|
success = true;
|
|
|
|
|
2014-03-25 14:53:59 +08:00
|
|
|
cleanup:
|
2013-07-11 22:33:29 +08:00
|
|
|
for (i = 0; ndevices != -1 && i < ndevices; i++)
|
2012-09-17 11:32:53 +08:00
|
|
|
VIR_FREE(names[i]);
|
|
|
|
VIR_FREE(names);
|
|
|
|
|
|
|
|
if (!success) {
|
2022-01-29 01:42:45 +08:00
|
|
|
g_clear_pointer(&list, virshNodeDeviceListFree);
|
2012-09-17 11:32:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2012-07-23 15:08:39 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-list" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_list_devices[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("enumerate devices on this host")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = ""
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_list_devices[] = {
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = "tree",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list devices in a tree")
|
|
|
|
},
|
|
|
|
{.name = "cap",
|
|
|
|
.type = VSH_OT_STRING,
|
2019-07-14 17:47:34 +08:00
|
|
|
.completer = virshNodeDeviceCapabilityNameCompleter,
|
2013-01-14 22:30:11 +08:00
|
|
|
.help = N_("capability names, separated by comma")
|
|
|
|
},
|
2020-07-11 03:47:01 +08:00
|
|
|
{.name = "inactive",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list inactive devices")
|
|
|
|
},
|
|
|
|
{.name = "all",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list inactive & active devices")
|
|
|
|
},
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
2019-10-14 20:44:29 +08:00
|
|
|
cmdNodeListDevices(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
2012-07-23 15:08:39 +08:00
|
|
|
{
|
2012-09-17 11:32:53 +08:00
|
|
|
const char *cap_str = NULL;
|
Convert 'int i' to 'size_t i' in tools/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 22:09:33 +08:00
|
|
|
size_t i;
|
2012-07-23 15:08:39 +08:00
|
|
|
bool tree = vshCommandOptBool(cmd, "tree");
|
|
|
|
bool ret = true;
|
2012-09-17 11:32:53 +08:00
|
|
|
unsigned int flags = 0;
|
2021-08-11 21:45:02 +08:00
|
|
|
g_auto(GStrv) caps = NULL;
|
2012-09-17 11:32:53 +08:00
|
|
|
int ncaps = 0;
|
2021-03-11 15:16:13 +08:00
|
|
|
struct virshNodeDeviceList *list = NULL;
|
2012-09-17 11:32:53 +08:00
|
|
|
int cap_type = -1;
|
2020-07-11 03:47:01 +08:00
|
|
|
bool inactive = vshCommandOptBool(cmd, "inactive");
|
|
|
|
bool all = vshCommandOptBool(cmd, "all");
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2015-12-03 20:47:56 +08:00
|
|
|
ignore_value(vshCommandOptStringQuiet(ctl, cmd, "cap", &cap_str));
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2012-09-17 11:32:53 +08:00
|
|
|
if (cap_str) {
|
2013-08-16 00:20:05 +08:00
|
|
|
if ((ncaps = vshStringToArray(cap_str, &caps)) < 0)
|
|
|
|
return false;
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
|
|
|
|
2020-07-11 03:47:01 +08:00
|
|
|
if (all && inactive) {
|
|
|
|
vshError(ctl, "%s", _("Option --all is incompatible with --inactive"));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-07-08 05:29:29 +08:00
|
|
|
if (tree && (cap_str || inactive)) {
|
|
|
|
vshError(ctl, "%s", _("Option --tree is incompatible with --cap and --inactive"));
|
2020-07-11 03:47:01 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-17 11:32:53 +08:00
|
|
|
for (i = 0; i < ncaps; i++) {
|
|
|
|
if ((cap_type = virNodeDevCapTypeFromString(caps[i])) < 0) {
|
|
|
|
vshError(ctl, "%s", _("Invalid capability type"));
|
2013-08-27 19:47:57 +08:00
|
|
|
ret = false;
|
|
|
|
goto cleanup;
|
2012-09-17 11:32:53 +08:00
|
|
|
}
|
|
|
|
|
2017-02-17 23:09:15 +08:00
|
|
|
switch ((virNodeDevCapType) cap_type) {
|
2012-09-17 11:32:53 +08:00
|
|
|
case VIR_NODE_DEV_CAP_SYSTEM:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SYSTEM;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_PCI_DEV:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_PCI_DEV;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_USB_DEV:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_DEV;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_USB_INTERFACE:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_USB_INTERFACE;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_NET:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_NET;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_SCSI_HOST:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_HOST;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_SCSI_TARGET:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_TARGET;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_SCSI:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_STORAGE:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_STORAGE;
|
|
|
|
break;
|
2013-01-08 01:05:28 +08:00
|
|
|
case VIR_NODE_DEV_CAP_FC_HOST:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_FC_HOST;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_VPORTS:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPORTS;
|
|
|
|
break;
|
2013-06-03 18:05:35 +08:00
|
|
|
case VIR_NODE_DEV_CAP_SCSI_GENERIC:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_SCSI_GENERIC;
|
|
|
|
break;
|
2017-02-17 23:09:15 +08:00
|
|
|
case VIR_NODE_DEV_CAP_DRM:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_DRM;
|
|
|
|
break;
|
2017-03-07 00:20:00 +08:00
|
|
|
case VIR_NODE_DEV_CAP_MDEV_TYPES:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_MDEV_TYPES;
|
|
|
|
break;
|
|
|
|
case VIR_NODE_DEV_CAP_MDEV:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_MDEV;
|
|
|
|
break;
|
2021-10-20 16:30:33 +08:00
|
|
|
case VIR_NODE_DEV_CAP_VPD:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_VPD;
|
|
|
|
break;
|
2017-05-22 14:38:22 +08:00
|
|
|
case VIR_NODE_DEV_CAP_CCW_DEV:
|
2017-05-22 14:38:23 +08:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_CCW_DEV;
|
|
|
|
break;
|
2020-09-15 03:11:44 +08:00
|
|
|
case VIR_NODE_DEV_CAP_CSS_DEV:
|
2020-09-15 03:11:45 +08:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_CSS_DEV;
|
|
|
|
break;
|
2020-10-15 01:08:30 +08:00
|
|
|
case VIR_NODE_DEV_CAP_VDPA:
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_VDPA;
|
|
|
|
break;
|
2020-12-04 01:59:33 +08:00
|
|
|
case VIR_NODE_DEV_CAP_AP_CARD:
|
2020-12-04 01:59:37 +08:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_CARD;
|
|
|
|
break;
|
2020-12-04 01:59:35 +08:00
|
|
|
case VIR_NODE_DEV_CAP_AP_QUEUE:
|
2020-12-04 01:59:37 +08:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_QUEUE;
|
|
|
|
break;
|
2020-12-04 01:59:38 +08:00
|
|
|
case VIR_NODE_DEV_CAP_AP_MATRIX:
|
2020-12-04 01:59:40 +08:00
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_CAP_AP_MATRIX;
|
|
|
|
break;
|
2017-02-17 23:09:15 +08:00
|
|
|
case VIR_NODE_DEV_CAP_LAST:
|
2012-09-17 11:32:53 +08:00
|
|
|
break;
|
|
|
|
}
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
2012-09-17 11:32:53 +08:00
|
|
|
|
2020-07-11 03:47:01 +08:00
|
|
|
if (inactive || all)
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_INACTIVE;
|
|
|
|
if (!inactive)
|
|
|
|
flags |= VIR_CONNECT_LIST_NODE_DEVICES_ACTIVE;
|
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
if (!(list = virshNodeDeviceListCollect(ctl, caps, ncaps, flags))) {
|
2012-09-17 11:32:53 +08:00
|
|
|
ret = false;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-07-23 15:08:39 +08:00
|
|
|
if (tree) {
|
2020-10-06 00:50:09 +08:00
|
|
|
char **parents = g_new0(char *, list->ndevices);
|
|
|
|
char **names = g_new0(char *, list->ndevices);
|
2015-06-16 00:53:58 +08:00
|
|
|
struct virshNodeList arrays = { names, parents };
|
2012-09-17 11:32:53 +08:00
|
|
|
|
|
|
|
for (i = 0; i < list->ndevices; i++)
|
2019-10-18 23:24:02 +08:00
|
|
|
names[i] = g_strdup(virNodeDeviceGetName(list->devices[i]));
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2012-09-17 11:32:53 +08:00
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
|
|
|
virNodeDevicePtr dev = list->devices[i];
|
|
|
|
if (STRNEQ(names[i], "computer")) {
|
2019-10-18 23:24:02 +08:00
|
|
|
parents[i] = g_strdup(virNodeDeviceGetParent(dev));
|
2012-07-23 15:08:39 +08:00
|
|
|
} else {
|
|
|
|
parents[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2012-09-17 11:32:53 +08:00
|
|
|
|
2013-05-21 15:44:53 +08:00
|
|
|
for (i = 0; i < list->ndevices; i++) {
|
2012-07-23 15:08:39 +08:00
|
|
|
if (parents[i] == NULL &&
|
2015-06-16 00:53:58 +08:00
|
|
|
vshTreePrint(ctl, virshNodeListLookup, &arrays,
|
2012-09-17 11:32:53 +08:00
|
|
|
list->ndevices, i) < 0)
|
2012-07-23 15:08:39 +08:00
|
|
|
ret = false;
|
|
|
|
}
|
2012-09-17 11:32:53 +08:00
|
|
|
|
2013-05-21 15:44:53 +08:00
|
|
|
for (i = 0; i < list->ndevices; i++)
|
2012-07-23 15:08:39 +08:00
|
|
|
VIR_FREE(parents[i]);
|
|
|
|
VIR_FREE(parents);
|
2012-09-17 11:32:53 +08:00
|
|
|
for (i = 0; i < list->ndevices; i++)
|
|
|
|
VIR_FREE(names[i]);
|
|
|
|
VIR_FREE(names);
|
2012-07-23 15:08:39 +08:00
|
|
|
} else {
|
2012-09-17 11:32:53 +08:00
|
|
|
for (i = 0; i < list->ndevices; i++)
|
|
|
|
vshPrint(ctl, "%s\n", virNodeDeviceGetName(list->devices[i]));
|
|
|
|
}
|
|
|
|
|
2014-03-25 14:53:59 +08:00
|
|
|
cleanup:
|
2015-06-16 00:53:58 +08:00
|
|
|
virshNodeDeviceListFree(list);
|
2012-07-23 15:08:39 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-dumpxml" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_dumpxml[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("node device details in XML")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Output the node device details as an XML dump to stdout.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_dumpxml[] = {
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2013-02-04 22:16:44 +08:00
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
2018-01-12 21:44:37 +08:00
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 22:30:11 +08:00
|
|
|
},
|
2022-06-16 23:29:54 +08:00
|
|
|
{.name = "xpath",
|
|
|
|
.type = VSH_OT_STRING,
|
virsh: Require --xpath for *dumpxml
Historically, the dumpxml command reject any unknown arguments,
for instance:
virsh dumpxml fedora xxx
However, after v8.5.0-rc1~31 the second argument ('xxx') is
treated as an XPath, but it's not that clearly visible.
Therefore, require the --xpath switch, like this:
virsh dumpxml fedora --xpath xxx
Yes, this breaks already released virsh, but I think we can argue
that the pool of users of this particular function is very small.
We also document the argument being mandatory:
dumpxml [--inactive] [--security-info] [--update-cpu] [--migratable]
[--xpath EXPRESSION] [--wrap] domain
The sooner we do this change, the better.
The same applies for other *dumpxml functions (net-dumpxml,
pool-dumpxml, vol-dumpxl to name a few).
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=2103524
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
2022-07-08 18:45:42 +08:00
|
|
|
.flags = VSH_OFLAG_REQ_OPT,
|
2022-06-16 23:29:54 +08:00
|
|
|
.completer = virshCompleteEmpty,
|
|
|
|
.help = N_("xpath expression to filter the XML document")
|
|
|
|
},
|
|
|
|
{.name = "wrap",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("wrap xpath results in an common root element"),
|
|
|
|
},
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDumpXML(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) device = NULL;
|
2021-08-11 21:25:15 +08:00
|
|
|
g_autofree char *xml = NULL;
|
2013-02-04 22:16:44 +08:00
|
|
|
const char *device_value = NULL;
|
2022-06-16 23:29:54 +08:00
|
|
|
bool wrap = vshCommandOptBool(cmd, "wrap");
|
|
|
|
const char *xpath = NULL;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2013-02-04 22:16:44 +08:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
2013-01-22 00:41:14 +08:00
|
|
|
|
2022-06-16 23:29:54 +08:00
|
|
|
if (vshCommandOptStringQuiet(ctl, cmd, "xpath", &xpath) < 0)
|
|
|
|
return false;
|
|
|
|
|
2020-08-18 05:21:48 +08:00
|
|
|
device = vshFindNodeDevice(ctl, device_value);
|
2013-02-04 22:16:44 +08:00
|
|
|
|
2020-08-18 05:21:48 +08:00
|
|
|
if (!device)
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2013-01-22 00:41:14 +08:00
|
|
|
if (!(xml = virNodeDeviceGetXMLDesc(device, 0)))
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2022-06-16 23:29:54 +08:00
|
|
|
return virshDumpXML(ctl, xml, "node-device", xpath, wrap);
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-detach" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_detach[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("detach node device from its device driver")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Detach node device from its device driver before assigning to a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_detach[] = {
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 21:44:37 +08:00
|
|
|
.help = N_("device key"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 22:30:11 +08:00
|
|
|
},
|
2013-04-25 02:22:36 +08:00
|
|
|
{.name = "driver",
|
|
|
|
.type = VSH_OT_STRING,
|
2022-04-02 18:31:47 +08:00
|
|
|
.completer = virshNodeDevicePCIBackendCompleter,
|
2022-04-05 16:38:47 +08:00
|
|
|
.help = N_("pci device assignment backend driver (e.g. 'vfio' or 'xen')")
|
2013-04-25 02:22:36 +08:00
|
|
|
},
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDetach(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
2013-04-25 02:22:36 +08:00
|
|
|
const char *driverName = NULL;
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) device = NULL;
|
2012-07-23 15:08:39 +08:00
|
|
|
bool ret = true;
|
2021-03-11 15:16:13 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2013-01-22 00:29:14 +08:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
2013-01-22 00:41:14 +08:00
|
|
|
|
2015-12-03 20:47:56 +08:00
|
|
|
ignore_value(vshCommandOptStringQuiet(ctl, cmd, "driver", &driverName));
|
2013-04-25 02:22:36 +08:00
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
2013-01-22 00:41:14 +08:00
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-25 02:22:36 +08:00
|
|
|
if (driverName) {
|
|
|
|
/* we must use the newer API that accepts a driverName */
|
|
|
|
if (virNodeDeviceDetachFlags(device, driverName, 0) < 0)
|
|
|
|
ret = false;
|
2012-07-23 15:08:39 +08:00
|
|
|
} else {
|
2013-04-25 02:22:36 +08:00
|
|
|
/* Yes, our (old) public API is misspelled. At least virsh
|
|
|
|
* can accept either spelling. */
|
|
|
|
if (virNodeDeviceDettach(device) < 0)
|
|
|
|
ret = false;
|
2012-07-23 15:08:39 +08:00
|
|
|
}
|
2013-01-22 00:41:14 +08:00
|
|
|
|
2013-04-25 02:22:36 +08:00
|
|
|
if (ret)
|
2016-08-24 22:14:23 +08:00
|
|
|
vshPrintExtra(ctl, _("Device %s detached\n"), name);
|
2013-04-25 02:22:36 +08:00
|
|
|
else
|
|
|
|
vshError(ctl, _("Failed to detach device %s"), name);
|
|
|
|
|
2012-07-23 15:08:39 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-reattach" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_reattach[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("reattach node device to its device driver")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Reattach node device to its device driver once released by the domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_reattach[] = {
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 21:44:37 +08:00
|
|
|
.help = N_("device key"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 22:30:11 +08:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceReAttach(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) device = NULL;
|
2012-07-23 15:08:39 +08:00
|
|
|
bool ret = true;
|
2021-03-11 15:16:13 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2013-01-22 00:29:14 +08:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
2013-01-22 00:41:14 +08:00
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
2013-01-22 00:41:14 +08:00
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNodeDeviceReAttach(device) == 0) {
|
2016-08-24 22:14:23 +08:00
|
|
|
vshPrintExtra(ctl, _("Device %s re-attached\n"), name);
|
2012-07-23 15:08:39 +08:00
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to re-attach device %s"), name);
|
|
|
|
ret = false;
|
|
|
|
}
|
2013-01-22 00:41:14 +08:00
|
|
|
|
2012-07-23 15:08:39 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "nodedev-reset" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_reset[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "help",
|
|
|
|
.data = N_("reset node device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Reset node device before or after assigning to a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_reset[] = {
|
2013-01-14 22:30:11 +08:00
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
2018-01-12 21:44:37 +08:00
|
|
|
.help = N_("device key"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2013-01-14 22:30:11 +08:00
|
|
|
},
|
|
|
|
{.name = NULL}
|
2012-07-23 15:08:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceReset(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) device = NULL;
|
2012-07-23 15:08:39 +08:00
|
|
|
bool ret = true;
|
2021-03-11 15:16:13 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
2012-07-23 15:08:39 +08:00
|
|
|
|
2013-01-22 00:29:14 +08:00
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
2013-01-22 00:41:14 +08:00
|
|
|
|
2015-06-16 00:53:58 +08:00
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
2013-01-22 00:41:14 +08:00
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
2012-07-23 15:08:39 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virNodeDeviceReset(device) == 0) {
|
2016-08-24 22:14:23 +08:00
|
|
|
vshPrintExtra(ctl, _("Device %s reset\n"), name);
|
2012-07-23 15:08:39 +08:00
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to reset device %s"), name);
|
|
|
|
ret = false;
|
|
|
|
}
|
2013-01-22 00:41:14 +08:00
|
|
|
|
2012-07-23 15:08:39 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2012-07-23 15:19:04 +08:00
|
|
|
|
2016-08-09 03:34:21 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-event" command
|
|
|
|
*/
|
2019-01-21 00:04:56 +08:00
|
|
|
VIR_ENUM_DECL(virshNodeDeviceEvent);
|
2016-08-09 03:34:21 +08:00
|
|
|
VIR_ENUM_IMPL(virshNodeDeviceEvent,
|
|
|
|
VIR_NODE_DEVICE_EVENT_LAST,
|
|
|
|
N_("Created"),
|
2020-07-09 23:56:51 +08:00
|
|
|
N_("Deleted"),
|
|
|
|
N_("Defined"),
|
|
|
|
N_("Undefined"));
|
2016-08-09 03:34:21 +08:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
virshNodeDeviceEventToString(int event)
|
|
|
|
{
|
|
|
|
const char *str = virshNodeDeviceEventTypeToString(event);
|
|
|
|
return str ? _(str) : _("unknown");
|
|
|
|
}
|
|
|
|
|
|
|
|
struct virshNodeDeviceEventData {
|
|
|
|
vshControl *ctl;
|
|
|
|
bool loop;
|
|
|
|
bool timestamp;
|
|
|
|
int count;
|
2019-07-14 17:47:34 +08:00
|
|
|
virshNodeDeviceEventCallback *cb;
|
2016-08-09 03:34:21 +08:00
|
|
|
};
|
|
|
|
typedef struct virshNodeDeviceEventData virshNodeDeviceEventData;
|
|
|
|
|
|
|
|
static void
|
2019-10-14 20:44:29 +08:00
|
|
|
vshEventLifecyclePrint(virConnectPtr conn G_GNUC_UNUSED,
|
2016-08-09 03:34:21 +08:00
|
|
|
virNodeDevicePtr dev,
|
|
|
|
int event,
|
2019-10-14 20:44:29 +08:00
|
|
|
int detail G_GNUC_UNUSED,
|
2016-08-09 03:34:21 +08:00
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virshNodeDeviceEventData *data = opaque;
|
|
|
|
|
|
|
|
if (!data->loop && data->count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (data->timestamp) {
|
|
|
|
char timestamp[VIR_TIME_STRING_BUFLEN];
|
|
|
|
|
|
|
|
if (virTimeStringNowRaw(timestamp) < 0)
|
|
|
|
timestamp[0] = '\0';
|
|
|
|
|
|
|
|
vshPrint(data->ctl, _("%s: event 'lifecycle' for node device %s: %s\n"),
|
|
|
|
timestamp,
|
|
|
|
virNodeDeviceGetName(dev), virshNodeDeviceEventToString(event));
|
|
|
|
} else {
|
|
|
|
vshPrint(data->ctl, _("event 'lifecycle' for node device %s: %s\n"),
|
|
|
|
virNodeDeviceGetName(dev), virshNodeDeviceEventToString(event));
|
|
|
|
}
|
|
|
|
|
|
|
|
data->count++;
|
|
|
|
if (!data->loop)
|
|
|
|
vshEventDone(data->ctl);
|
|
|
|
}
|
|
|
|
|
2016-08-11 23:15:23 +08:00
|
|
|
static void
|
2019-10-14 20:44:29 +08:00
|
|
|
vshEventGenericPrint(virConnectPtr conn G_GNUC_UNUSED,
|
2016-08-11 23:15:23 +08:00
|
|
|
virNodeDevicePtr dev,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
virshNodeDeviceEventData *data = opaque;
|
|
|
|
|
|
|
|
if (!data->loop && data->count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (data->timestamp) {
|
|
|
|
char timestamp[VIR_TIME_STRING_BUFLEN];
|
|
|
|
|
|
|
|
if (virTimeStringNowRaw(timestamp) < 0)
|
|
|
|
timestamp[0] = '\0';
|
|
|
|
|
2016-12-02 04:50:08 +08:00
|
|
|
vshPrint(data->ctl, _("%s: event '%s' for node device %s\n"),
|
2016-08-11 23:15:23 +08:00
|
|
|
timestamp,
|
|
|
|
data->cb->name,
|
|
|
|
virNodeDeviceGetName(dev));
|
|
|
|
} else {
|
|
|
|
vshPrint(data->ctl, _("event '%s' for node device %s\n"),
|
|
|
|
data->cb->name,
|
|
|
|
virNodeDeviceGetName(dev));
|
|
|
|
}
|
|
|
|
|
|
|
|
data->count++;
|
|
|
|
if (!data->loop)
|
|
|
|
vshEventDone(data->ctl);
|
|
|
|
}
|
|
|
|
|
2019-07-14 17:47:34 +08:00
|
|
|
virshNodeDeviceEventCallback virshNodeDeviceEventCallbacks[] = {
|
2016-08-11 23:15:23 +08:00
|
|
|
{ "lifecycle",
|
|
|
|
VIR_NODE_DEVICE_EVENT_CALLBACK(vshEventLifecyclePrint), },
|
|
|
|
{ "update", vshEventGenericPrint, }
|
|
|
|
};
|
2020-01-09 18:39:55 +08:00
|
|
|
G_STATIC_ASSERT(VIR_NODE_DEVICE_EVENT_ID_LAST == G_N_ELEMENTS(virshNodeDeviceEventCallbacks));
|
2016-08-11 23:15:23 +08:00
|
|
|
|
|
|
|
|
2016-08-09 03:34:21 +08:00
|
|
|
static const vshCmdInfo info_node_device_event[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Node Device Events")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("List event types, or wait for node device events to occur")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_event[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_STRING,
|
2018-01-12 21:44:37 +08:00
|
|
|
.help = N_("filter by node device name"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
2016-08-09 03:34:21 +08:00
|
|
|
},
|
|
|
|
{.name = "event",
|
|
|
|
.type = VSH_OT_STRING,
|
2019-07-14 17:47:34 +08:00
|
|
|
.completer = virshNodeDeviceEventNameCompleter,
|
2016-08-09 03:34:21 +08:00
|
|
|
.help = N_("which event type to wait for")
|
|
|
|
},
|
|
|
|
{.name = "loop",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("loop until timeout or interrupt, rather than one-shot")
|
|
|
|
},
|
|
|
|
{.name = "timeout",
|
|
|
|
.type = VSH_OT_INT,
|
|
|
|
.help = N_("timeout seconds")
|
|
|
|
},
|
|
|
|
{.name = "list",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("list valid event types")
|
|
|
|
},
|
|
|
|
{.name = "timestamp",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("show timestamp for each printed event")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceEvent(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) dev = NULL;
|
2016-08-09 03:34:21 +08:00
|
|
|
bool ret = false;
|
|
|
|
int eventId = -1;
|
|
|
|
int timeout = 0;
|
|
|
|
virshNodeDeviceEventData data;
|
|
|
|
const char *eventName = NULL;
|
|
|
|
const char *device_value = NULL;
|
|
|
|
int event;
|
2021-03-11 15:16:13 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
2016-08-09 03:34:21 +08:00
|
|
|
|
|
|
|
if (vshCommandOptBool(cmd, "list")) {
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < VIR_NODE_DEVICE_EVENT_ID_LAST; i++)
|
2019-07-14 17:47:34 +08:00
|
|
|
vshPrint(ctl, "%s\n", virshNodeDeviceEventCallbacks[i].name);
|
2016-08-09 03:34:21 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "event", &eventName) < 0)
|
|
|
|
return false;
|
|
|
|
if (!eventName) {
|
2016-09-06 19:14:34 +08:00
|
|
|
vshError(ctl, "%s", _("either --list or --event <type> is required"));
|
2016-08-09 03:34:21 +08:00
|
|
|
return false;
|
|
|
|
}
|
2016-08-11 23:15:23 +08:00
|
|
|
|
|
|
|
for (event = 0; event < VIR_NODE_DEVICE_EVENT_ID_LAST; event++)
|
2019-07-14 17:47:34 +08:00
|
|
|
if (STREQ(eventName, virshNodeDeviceEventCallbacks[event].name))
|
2016-08-11 23:15:23 +08:00
|
|
|
break;
|
|
|
|
if (event == VIR_NODE_DEVICE_EVENT_ID_LAST) {
|
2016-08-09 03:34:21 +08:00
|
|
|
vshError(ctl, _("unknown event type %s"), eventName);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
data.ctl = ctl;
|
|
|
|
data.loop = vshCommandOptBool(cmd, "loop");
|
|
|
|
data.timestamp = vshCommandOptBool(cmd, "timestamp");
|
|
|
|
data.count = 0;
|
2019-07-14 17:47:34 +08:00
|
|
|
data.cb = &virshNodeDeviceEventCallbacks[event];
|
2016-08-09 03:34:21 +08:00
|
|
|
if (vshCommandOptTimeoutToMs(ctl, cmd, &timeout) < 0)
|
|
|
|
return false;
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (device_value) {
|
|
|
|
if (!(dev = virNodeDeviceLookupByName(priv->conn, device_value))) {
|
|
|
|
vshError(ctl, "%s '%s'",
|
|
|
|
_("Could not find matching device"), device_value);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (vshEventStart(ctl, timeout) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if ((eventId = virConnectNodeDeviceEventRegisterAny(priv->conn, dev, event,
|
2016-08-11 23:15:23 +08:00
|
|
|
data.cb->cb,
|
2016-08-09 03:34:21 +08:00
|
|
|
&data, NULL)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
switch (vshEventWait(ctl)) {
|
|
|
|
case VSH_EVENT_INTERRUPT:
|
|
|
|
vshPrint(ctl, "%s", _("event loop interrupted\n"));
|
|
|
|
break;
|
|
|
|
case VSH_EVENT_TIMEOUT:
|
|
|
|
vshPrint(ctl, "%s", _("event loop timed out\n"));
|
|
|
|
break;
|
|
|
|
case VSH_EVENT_DONE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
vshPrint(ctl, _("events received: %d\n"), data.count);
|
|
|
|
if (data.count)
|
|
|
|
ret = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
vshEventCleanup(ctl);
|
|
|
|
if (eventId >= 0 &&
|
|
|
|
virConnectNodeDeviceEventDeregisterAny(priv->conn, eventId) < 0)
|
|
|
|
ret = false;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-14 05:56:48 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-undefine" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_undefine[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Undefine an inactive node device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Undefines the configuration for an inactive node device")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_undefine[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceUndefine(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) dev = NULL;
|
2020-07-14 05:56:48 +08:00
|
|
|
const char *device_value = NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev = vshFindNodeDevice(ctl, device_value);
|
|
|
|
|
|
|
|
if (!dev)
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2020-07-14 05:56:48 +08:00
|
|
|
|
2021-11-08 23:09:48 +08:00
|
|
|
if (virNodeDeviceUndefine(dev, 0) < 0) {
|
2020-07-14 05:56:48 +08:00
|
|
|
vshError(ctl, _("Failed to undefine node device '%s'"), device_value);
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2020-07-14 05:56:48 +08:00
|
|
|
}
|
|
|
|
|
2021-11-08 23:09:48 +08:00
|
|
|
vshPrintExtra(ctl, _("Undefined node device '%s'\n"), device_value);
|
2021-11-04 22:26:07 +08:00
|
|
|
return true;
|
2020-07-14 05:56:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-14 05:40:47 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-define" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_define[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Define a device by an xml file on a node")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Defines a persistent device on the node that can be "
|
|
|
|
"assigned to a domain. The device must be started before "
|
|
|
|
"it can be assigned to a domain.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_define[] = {
|
|
|
|
VIRSH_COMMON_OPT_FILE(N_("file containing an XML description "
|
|
|
|
"of the device")),
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceDefine(vshControl *ctl, const vshCmd *cmd G_GNUC_UNUSED)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) dev = NULL;
|
2020-07-14 05:40:47 +08:00
|
|
|
const char *from = NULL;
|
2021-08-11 21:25:15 +08:00
|
|
|
g_autofree char *buffer = NULL;
|
2020-07-14 05:40:47 +08:00
|
|
|
virshControl *priv = ctl->privData;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "file", &from) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (virFileReadAll(from, VSH_MAX_XML_FILE, &buffer) < 0)
|
|
|
|
return false;
|
|
|
|
|
2021-09-24 07:49:08 +08:00
|
|
|
if (!(dev = virNodeDeviceDefineXML(priv->conn, buffer, 0))) {
|
2020-07-14 05:40:47 +08:00
|
|
|
vshError(ctl, _("Failed to define node device from '%s'"), from);
|
2021-09-24 07:49:08 +08:00
|
|
|
return false;
|
2020-07-14 05:40:47 +08:00
|
|
|
}
|
|
|
|
|
2021-09-24 07:49:08 +08:00
|
|
|
vshPrintExtra(ctl, _("Node device '%s' defined from '%s'\n"),
|
|
|
|
virNodeDeviceGetName(dev), from);
|
|
|
|
return true;
|
2020-07-14 05:40:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-10 05:05:41 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-start" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_start[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("Start an inactive node device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Starts an inactive node device that was previously defined")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_start[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("device name"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceStart(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
|
|
|
const char *name = NULL;
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) device = NULL;
|
2020-07-10 05:05:41 +08:00
|
|
|
bool ret = true;
|
|
|
|
virshControl *priv = ctl->privData;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!(device = virNodeDeviceLookupByName(priv->conn, name))) {
|
|
|
|
vshError(ctl, _("Could not find matching device '%s'"), name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-04-09 23:50:03 +08:00
|
|
|
if (virNodeDeviceCreate(device, 0) == 0) {
|
2020-07-10 05:05:41 +08:00
|
|
|
vshPrintExtra(ctl, _("Device %s started\n"), name);
|
|
|
|
} else {
|
|
|
|
vshError(ctl, _("Failed to start device %s"), name);
|
|
|
|
ret = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-28 05:20:13 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-autostart" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_autostart[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("autostart a defined node device")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Configure a node device to be automatically started at boot.")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_autostart[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
|
|
|
},
|
|
|
|
{.name = "disable",
|
|
|
|
.type = VSH_OT_BOOL,
|
|
|
|
.help = N_("disable autostarting")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceAutostart(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) dev = NULL;
|
2021-05-28 05:20:13 +08:00
|
|
|
const char *name = NULL;
|
|
|
|
int autostart;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &name) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
dev = vshFindNodeDevice(ctl, name);
|
|
|
|
|
2021-11-04 22:26:07 +08:00
|
|
|
if (!dev)
|
|
|
|
return false;
|
2021-05-28 05:20:13 +08:00
|
|
|
|
|
|
|
autostart = !vshCommandOptBool(cmd, "disable");
|
|
|
|
|
|
|
|
if (virNodeDeviceSetAutostart(dev, autostart) < 0) {
|
|
|
|
if (autostart)
|
|
|
|
vshError(ctl, _("failed to mark device %s as autostarted"), name);
|
|
|
|
else
|
|
|
|
vshError(ctl, _("failed to unmark device %s as autostarted"), name);
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2021-05-28 05:20:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (autostart)
|
|
|
|
vshPrintExtra(ctl, _("Device %s marked as autostarted\n"), name);
|
|
|
|
else
|
|
|
|
vshPrintExtra(ctl, _("Device %s unmarked as autostarted\n"), name);
|
|
|
|
|
2021-11-04 22:26:07 +08:00
|
|
|
return true;
|
2021-05-28 05:20:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-03 04:27:41 +08:00
|
|
|
/*
|
|
|
|
* "nodedev-info" command
|
|
|
|
*/
|
|
|
|
static const vshCmdInfo info_node_device_info[] = {
|
|
|
|
{.name = "help",
|
|
|
|
.data = N_("node device information")
|
|
|
|
},
|
|
|
|
{.name = "desc",
|
|
|
|
.data = N_("Returns basic information about the node device")
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const vshCmdOptDef opts_node_device_info[] = {
|
|
|
|
{.name = "device",
|
|
|
|
.type = VSH_OT_DATA,
|
|
|
|
.flags = VSH_OFLAG_REQ,
|
|
|
|
.help = N_("device name or wwn pair in 'wwnn,wwpn' format"),
|
|
|
|
.completer = virshNodeDeviceNameCompleter,
|
|
|
|
},
|
|
|
|
{.name = NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
cmdNodeDeviceInfo(vshControl *ctl, const vshCmd *cmd)
|
|
|
|
{
|
2021-09-26 17:44:30 +08:00
|
|
|
g_autoptr(virshNodeDevice) device = NULL;
|
2021-06-03 04:27:41 +08:00
|
|
|
const char *device_value = NULL;
|
|
|
|
int autostart;
|
|
|
|
const char *parent = NULL;
|
|
|
|
|
|
|
|
if (vshCommandOptStringReq(ctl, cmd, "device", &device_value) < 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
device = vshFindNodeDevice(ctl, device_value);
|
|
|
|
|
|
|
|
if (!device)
|
2021-11-04 22:26:07 +08:00
|
|
|
return false;
|
2021-06-03 04:27:41 +08:00
|
|
|
|
|
|
|
parent = virNodeDeviceGetParent(device);
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("Name:"), virNodeDeviceGetName(device));
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("Parent:"), parent ? parent : "");
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("Active:"), virNodeDeviceIsActive(device) ?
|
|
|
|
_("yes") : _("no"));
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("Persistent:"),
|
|
|
|
virNodeDeviceIsPersistent(device) ? _("yes") : _("no"));
|
|
|
|
if (virNodeDeviceGetAutostart(device, &autostart) < 0)
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("Autostart:"), _("no autostart"));
|
|
|
|
else
|
|
|
|
vshPrint(ctl, "%-15s %s\n", _("Autostart:"), autostart ? _("yes") : _("no"));
|
|
|
|
|
2021-11-04 22:26:07 +08:00
|
|
|
return true;
|
2021-06-03 04:27:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-08-21 06:23:10 +08:00
|
|
|
const vshCmdDef nodedevCmds[] = {
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = "nodedev-create",
|
|
|
|
.handler = cmdNodeDeviceCreate,
|
|
|
|
.opts = opts_node_device_create,
|
|
|
|
.info = info_node_device_create,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-destroy",
|
|
|
|
.handler = cmdNodeDeviceDestroy,
|
|
|
|
.opts = opts_node_device_destroy,
|
|
|
|
.info = info_node_device_destroy,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-detach",
|
|
|
|
.handler = cmdNodeDeviceDetach,
|
|
|
|
.opts = opts_node_device_detach,
|
|
|
|
.info = info_node_device_detach,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-dettach",
|
2016-09-07 23:30:48 +08:00
|
|
|
.flags = VSH_CMD_FLAG_ALIAS,
|
|
|
|
.alias = "nodedev-detach"
|
2013-02-07 23:25:10 +08:00
|
|
|
},
|
|
|
|
{.name = "nodedev-dumpxml",
|
|
|
|
.handler = cmdNodeDeviceDumpXML,
|
|
|
|
.opts = opts_node_device_dumpxml,
|
|
|
|
.info = info_node_device_dumpxml,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-list",
|
|
|
|
.handler = cmdNodeListDevices,
|
|
|
|
.opts = opts_node_list_devices,
|
|
|
|
.info = info_node_list_devices,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-reattach",
|
|
|
|
.handler = cmdNodeDeviceReAttach,
|
|
|
|
.opts = opts_node_device_reattach,
|
|
|
|
.info = info_node_device_reattach,
|
|
|
|
.flags = 0
|
|
|
|
},
|
|
|
|
{.name = "nodedev-reset",
|
|
|
|
.handler = cmdNodeDeviceReset,
|
|
|
|
.opts = opts_node_device_reset,
|
|
|
|
.info = info_node_device_reset,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2016-08-09 03:34:21 +08:00
|
|
|
{.name = "nodedev-event",
|
|
|
|
.handler = cmdNodeDeviceEvent,
|
|
|
|
.opts = opts_node_device_event,
|
|
|
|
.info = info_node_device_event,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-07-14 05:40:47 +08:00
|
|
|
{.name = "nodedev-define",
|
|
|
|
.handler = cmdNodeDeviceDefine,
|
|
|
|
.opts = opts_node_device_define,
|
|
|
|
.info = info_node_device_define,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-07-14 05:56:48 +08:00
|
|
|
{.name = "nodedev-undefine",
|
|
|
|
.handler = cmdNodeDeviceUndefine,
|
|
|
|
.opts = opts_node_device_undefine,
|
|
|
|
.info = info_node_device_undefine,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2020-07-10 05:05:41 +08:00
|
|
|
{.name = "nodedev-start",
|
|
|
|
.handler = cmdNodeDeviceStart,
|
|
|
|
.opts = opts_node_device_start,
|
|
|
|
.info = info_node_device_start,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2021-05-28 05:20:13 +08:00
|
|
|
{.name = "nodedev-autostart",
|
|
|
|
.handler = cmdNodeDeviceAutostart,
|
|
|
|
.opts = opts_node_device_autostart,
|
|
|
|
.info = info_node_device_autostart,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2021-06-03 04:27:41 +08:00
|
|
|
{.name = "nodedev-info",
|
|
|
|
.handler = cmdNodeDeviceInfo,
|
|
|
|
.opts = opts_node_device_info,
|
|
|
|
.info = info_node_device_info,
|
|
|
|
.flags = 0
|
|
|
|
},
|
2013-02-07 23:25:10 +08:00
|
|
|
{.name = NULL}
|
2012-07-23 15:19:04 +08:00
|
|
|
};
|