I think this is complete (can't really try it out until the test
driver is running), but have a few questions about it:
1) Does the command set look complete?
2) Do you agree with the naming (using "if-", and following the
libvirt convention for if-create/if-destroy, rather than the fedora
convention (if-up/if-down)?
3) I'm all for eliminating unnecessary copy/paste in code, but the way
that cmdNetworkEdit() and cmdPoolEdit() are created (by
awking/seding virsh.c to create a modified version of the cmdEdit
function that lives in a separate .c which is #included by virsh.c)
seems just a bit convoluted to me. I've made it one step worse for
cmdInterfaceEdit because virInterfaceDefineXML has an extra
argument (flags) that virDomainDefineXML doesn't. What are your
opinions? Should I continue on in the tradition for consistency's
sake (as I've done in this patch), or manually put
cmdInterfaceEdit() directly into virsh.c?
---
src/Makefile.am | 18 +++-
src/virsh.c | 398 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 414 insertions(+), 2 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index d4f7ea1..7601611 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -585,7 +585,7 @@ virsh_LDADD = \
../gnulib/lib/libgnu.la \
$(VIRSH_LIBS)
virsh_CFLAGS = $(COVERAGE_CFLAGS) $(READLINE_CFLAGS) $(NUMACTL_CFLAGS)
-BUILT_SOURCES = virsh-net-edit.c virsh-pool-edit.c libvirt.syms
+BUILT_SOURCES = virsh-net-edit.c virsh-if-edit.c virsh-pool-edit.c libvirt.syms
virsh-net-edit.c: virsh.c Makefile.am
rm -f $@-tmp
@@ -602,6 +602,22 @@ virsh-net-edit.c: virsh.c Makefile.am
rm -f $@
mv $@-tmp $@
+virsh-if-edit.c: virsh.c Makefile.am
+ rm -f $@-tmp
+ echo '/* Automatically generated from: $^ */' > $@-tmp
+ echo 'static int' >> $@-tmp
+ awk '/^cmdEdit/, /^}/' $< \
+ | sed -e 's/domain/interface/g' \
+ -e 's/Domain/Interface/g' \
+ -e 's/cmdEdit/cmdInterfaceEdit/g' \
+ -e 's/dom/iface/g' \
+ -e 's/int flags.*/int flags = 0;/g' \
+ -e 's/DefineXML\(.*\))/DefineXML\1, 0)/' \
+ >> $@-tmp
+ chmod a-w $@-tmp
+ rm -f $@
+ mv $@-tmp $@
+
virsh-pool-edit.c: virsh.c Makefile.am
rm -f $@-tmp
echo '/* Automatically generated from: $^ */' > $@-tmp
diff --git a/src/virsh.c b/src/virsh.c
index f5248d9..6fd090c 100644
--- a/src/virsh.c
+++ b/src/virsh.c
@@ -228,6 +228,7 @@ static int vshCommandOptBool(const vshCmd *cmd, const char *name);
#define VSH_BYID (1 << 1)
#define VSH_BYUUID (1 << 2)
#define VSH_BYNAME (1 << 3)
+#define VSH_BYMAC (1 << 4)
static virDomainPtr vshCommandOptDomainBy(vshControl *ctl, const vshCmd *cmd,
char **name, int flag);
@@ -244,6 +245,14 @@ static virNetworkPtr vshCommandOptNetworkBy(vshControl *ctl, const
vshCmd *cmd,
vshCommandOptNetworkBy(_ctl, _cmd, _name, \
VSH_BYUUID|VSH_BYNAME)
+static virInterfacePtr vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
+ char **name, int flag);
+
+/* default is lookup by Name and MAC */
+#define vshCommandOptInterface(_ctl, _cmd, _name) \
+ vshCommandOptInterfaceBy(_ctl, _cmd, _name, \
+ VSH_BYMAC|VSH_BYNAME)
+
static virStoragePoolPtr vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd,
const char *optname, char **name, int flag);
@@ -2955,6 +2964,325 @@ cmdNetworkUuid(vshControl *ctl, const vshCmd *cmd)
}
+/**************************************************************************/
+/*
+ * "if-list" command
+ */
+static const vshCmdInfo info_interface_list[] = {
+ {"help", gettext_noop("list physical host interfaces")},
+ {"desc", gettext_noop("Returns list of physical host
interfaces.")},
+ {NULL, NULL}
+};
+
+static int
+cmdInterfaceList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
+{
+ int ifCount = 0, i;
+ char **ifNames = NULL;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ ifCount = virConnectNumOfInterfaces(ctl->conn);
+ if (ifCount < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list interfaces"));
+ return FALSE;
+ }
+ if (ifCount) {
+ ifNames = vshMalloc(ctl, sizeof(char *) * ifCount);
+
+ if ((ifCount = virConnectListInterfaces(ctl->conn,
+ ifNames, ifCount)) < 0) {
+ vshError(ctl, FALSE, "%s", _("Failed to list
interfaces"));
+ free(ifNames);
+ return FALSE;
+ }
+
+ qsort(&ifNames[0], ifCount, sizeof(char *), namesorter);
+ }
+
+ vshPrintExtra(ctl, "%-20s %-30s\n", _("Name"), _("MAC
Address"));
+ vshPrintExtra(ctl,
"--------------------------------------------------\n");
+
+ for (i = 0; i < ifCount; i++) {
+ virInterfacePtr iface = virInterfaceLookupByName(ctl->conn, ifNames[i]);
+
+ /* this kind of work with interfaces is not atomic operation */
+ if (!iface) {
+ free(ifNames[i]);
+ continue;
+ }
+
+ vshPrint(ctl, "%-20s %-30s\n",
+ virInterfaceGetName(iface),
+ virInterfaceGetMACString(iface));
+ virInterfaceFree(iface);
+ free(ifNames[i]);
+ }
+ free(ifNames);
+ return TRUE;
+}
+
+/*
+ * "if-name" command
+ */
+static const vshCmdInfo info_interface_name[] = {
+ {"help", gettext_noop("convert an interface MAC address to interface
name")},
+ {"desc", ""},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_name[] = {
+ {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface
mac")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdInterfaceName(vshControl *ctl, const vshCmd *cmd)
+{
+ virInterfacePtr iface;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+ if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
+ VSH_BYMAC)))
+ return FALSE;
+
+ vshPrint(ctl, "%s\n", virInterfaceGetName(iface));
+ virInterfaceFree(iface);
+ return TRUE;
+}
+
+/*
+ * "if-mac" command
+ */
+static const vshCmdInfo info_interface_mac[] = {
+ {"help", gettext_noop("convert an interface name to interface MAC
address")},
+ {"desc", ""},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_mac[] = {
+ {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface
name")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdInterfaceMAC(vshControl *ctl, const vshCmd *cmd)
+{
+ virInterfacePtr iface;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+ if (!(iface = vshCommandOptInterfaceBy(ctl, cmd, NULL,
+ VSH_BYNAME)))
+ return FALSE;
+
+ vshPrint(ctl, "%s\n", virInterfaceGetMACString(iface));
+ virInterfaceFree(iface);
+ return TRUE;
+}
+
+/*
+ * "if-dumpxml" command
+ */
+static const vshCmdInfo info_interface_dumpxml[] = {
+ {"help", gettext_noop("interface information in XML")},
+ {"desc", gettext_noop("Output the physical host interface information
as an XML dump to stdout.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_dumpxml[] = {
+ {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name
or MAC address")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdInterfaceDumpXML(vshControl *ctl, const vshCmd *cmd)
+{
+ virInterfacePtr iface;
+ int ret = TRUE;
+ char *dump;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(iface = vshCommandOptInterface(ctl, cmd, NULL)))
+ return FALSE;
+
+ dump = virInterfaceGetXMLDesc(iface, 0);
+ if (dump != NULL) {
+ printf("%s", dump);
+ free(dump);
+ } else {
+ ret = FALSE;
+ }
+
+ virInterfaceFree(iface);
+ return ret;
+}
+
+/*
+ * "if-define" command
+ */
+static const vshCmdInfo info_interface_define[] = {
+ {"help", gettext_noop("define (but don't start) a physical host
interface from an XML file")},
+ {"desc", gettext_noop("Define a physical host interface.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_define[] = {
+ {"file", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("file containing an
XML interface description")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdInterfaceDefine(vshControl *ctl, const vshCmd *cmd)
+{
+ virInterfacePtr interface;
+ char *from;
+ int found;
+ int ret = TRUE;
+ char *buffer;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ from = vshCommandOptString(cmd, "file", &found);
+ if (!found)
+ return FALSE;
+
+ if (virFileReadAll(from, VIRSH_MAX_XML_FILE, &buffer) < 0)
+ return FALSE;
+
+ interface = virInterfaceDefineXML(ctl->conn, buffer, 0);
+ free (buffer);
+
+ if (interface != NULL) {
+ vshPrint(ctl, _("Interface %s defined from %s\n"),
+ virInterfaceGetName(interface), from);
+ } else {
+ vshError(ctl, FALSE, _("Failed to define interface from %s"), from);
+ ret = FALSE;
+ }
+ return ret;
+}
+
+/*
+ * "if-undefine" command
+ */
+static const vshCmdInfo info_interface_undefine[] = {
+ {"help", gettext_noop("undefine a physical host interface (remove it
from configuration)")},
+ {"desc", gettext_noop("undefine an interface.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_undefine[] = {
+ {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name
or MAC address")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdInterfaceUndefine(vshControl *ctl, const vshCmd *cmd)
+{
+ virInterfacePtr iface;
+ int ret = TRUE;
+ char *name;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
+ return FALSE;
+
+ if (virInterfaceUndefine(iface) == 0) {
+ vshPrint(ctl, _("Interface %s undefined\n"), name);
+ } else {
+ vshError(ctl, FALSE, _("Failed to undefine interface %s"), name);
+ ret = FALSE;
+ }
+
+ virInterfaceFree(iface);
+ return ret;
+}
+
+/*
+ * "if-create" command
+ */
+static const vshCmdInfo info_interface_create[] = {
+ {"help", gettext_noop("create a physical host interface (enable it /
\"if-up\")")},
+ {"desc", gettext_noop("create a physical host interface.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_create[] = {
+ {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name
or MAC address")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdInterfaceCreate(vshControl *ctl, const vshCmd *cmd)
+{
+ virInterfacePtr iface;
+ int ret = TRUE;
+ char *name;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
+ return FALSE;
+
+ if (virInterfaceCreate(iface, 0) == 0) {
+ vshPrint(ctl, _("Interface %s created\n"), name);
+ } else {
+ vshError(ctl, FALSE, _("Failed to create interface %s"), name);
+ ret = FALSE;
+ }
+
+ virInterfaceFree(iface);
+ return ret;
+}
+
+/*
+ * "if-destroy" command
+ */
+static const vshCmdInfo info_interface_destroy[] = {
+ {"help", gettext_noop("destroy a physical host interface (disable it /
\"if-down\")")},
+ {"desc", gettext_noop("destroy a physical host interface.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_destroy[] = {
+ {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name
or MAC address")},
+ {NULL, 0, 0, NULL}
+};
+
+static int
+cmdInterfaceDestroy(vshControl *ctl, const vshCmd *cmd)
+{
+ virInterfacePtr iface;
+ int ret = TRUE;
+ char *name;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ if (!(iface = vshCommandOptInterface(ctl, cmd, &name)))
+ return FALSE;
+
+ if (virInterfaceDestroy(iface, 0) == 0) {
+ vshPrint(ctl, _("Interface %s destroyed\n"), name);
+ } else {
+ vshError(ctl, FALSE, _("Failed to destroy interface %s"), name);
+ ret = FALSE;
+ }
+
+ virInterfaceFree(iface);
+ return ret;
+}
+
+/**************************************************************************/
/*
* "pool-autostart" command
*/
@@ -6059,7 +6387,7 @@ static const vshCmdOptDef opts_edit[] = {
};
/* This function also acts as a template to generate cmdNetworkEdit
- * and cmdPoolEdit functions (below) using a sed script in the Makefile.
+ * cmdInterfaceEdit and cmdPoolEdit functions (below) using a sed script in the
Makefile.
*/
static int
cmdEdit (vshControl *ctl, const vshCmd *cmd)
@@ -6165,6 +6493,23 @@ static const vshCmdOptDef opts_network_edit[] = {
#include "virsh-net-edit.c"
/*
+ * "if-edit" command
+ */
+static const vshCmdInfo info_interface_edit[] = {
+ {"help", gettext_noop("edit XML configuration for a physical host
interface")},
+ {"desc", gettext_noop("Edit the XML configuration for a physical host
interface.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_interface_edit[] = {
+ {"interface", VSH_OT_DATA, VSH_OFLAG_REQ, gettext_noop("interface name
or MAC address")},
+ {NULL, 0, 0, NULL}
+};
+
+/* This is generated from this file by a sed script in the Makefile. */
+#include "virsh-if-edit.c"
+
+/*
* "pool-edit" command
*/
static const vshCmdInfo info_pool_edit[] = {
@@ -6247,6 +6592,17 @@ static const vshCmdDef commands[] = {
{"net-start", cmdNetworkStart, opts_network_start, info_network_start},
{"net-undefine", cmdNetworkUndefine, opts_network_undefine,
info_network_undefine},
{"net-uuid", cmdNetworkUuid, opts_network_uuid, info_network_uuid},
+
+ {"if-list", cmdInterfaceList, NULL, info_interface_list},
+ {"if-name", cmdInterfaceName, opts_interface_name, info_interface_name},
+ {"if-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac},
+ {"if-dumpxml", cmdInterfaceDumpXML, opts_interface_dumpxml,
info_interface_dumpxml},
+ {"if-define", cmdInterfaceDefine, opts_interface_define,
info_interface_define},
+ {"if-undefine", cmdInterfaceUndefine, opts_interface_undefine,
info_interface_undefine},
+ {"if-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit},
+ {"if-create", cmdInterfaceCreate, opts_interface_create,
info_interface_create},
+ {"if-destroy", cmdInterfaceDestroy, opts_interface_destroy,
info_interface_destroy},
+
{"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
{"nodedev-list", cmdNodeListDevices, opts_node_list_devices,
info_node_list_devices},
@@ -6698,6 +7054,46 @@ vshCommandOptNetworkBy(vshControl *ctl, const vshCmd *cmd,
return network;
}
+static virInterfacePtr
+vshCommandOptInterfaceBy(vshControl *ctl, const vshCmd *cmd,
+ char **name, int flag)
+{
+ virInterfacePtr iface = NULL;
+ char *n;
+ const char *optname = "interface";
+ if (!cmd_has_option (ctl, cmd, optname))
+ return NULL;
+
+ if (!(n = vshCommandOptString(cmd, optname, NULL))) {
+ vshError(ctl, FALSE, "%s", _("undefined interface
identifier"));
+ return NULL;
+ }
+
+ vshDebug(ctl, 5, "%s: found option <%s>: %s\n",
+ cmd->def->name, optname, n);
+
+ if (name)
+ *name = n;
+
+ /* try it by MAC */
+ if ((iface == NULL) && (flag & VSH_BYMAC)) {
+ vshDebug(ctl, 5, "%s: <%s> trying as interface MAC\n",
+ cmd->def->name, optname);
+ iface = virInterfaceLookupByMACString(ctl->conn, n);
+ }
+ /* try it by NAME */
+ if ((iface == NULL) && (flag & VSH_BYNAME)) {
+ vshDebug(ctl, 5, "%s: <%s> trying as interface NAME\n",
+ cmd->def->name, optname);
+ iface = virInterfaceLookupByName(ctl->conn, n);
+ }
+
+ if (!iface)
+ vshError(ctl, FALSE, _("failed to get interface '%s'"), n);
+
+ return iface;
+}
+
static virStoragePoolPtr
vshCommandOptPoolBy(vshControl *ctl, const vshCmd *cmd, const char *optname,
char **name, int flag)
--
1.6.0.6