[libvirt] [PATCH V2] virsh: rework command parsing
by Lai Jiangshan
Old virsh command parsing mashes all the args back into a string and
miss the quotes, this patch fixes it. It is also needed for introducing
qemu-monitor-command which is very useful.
This patch split the command-parsing into 2 phrases:
1) parse command string and make it into <args, argv> style arguments.
2) parse <args, argv> style arguments and make it into vshCmd structure.
The first step is needed when we use virsh as a shell.
And the usage was changed:
old:
virsh [options] [commands]
new:
virsh [options]... [<command_name> args...]
virsh [options]... <command_string>
So we still support commands like:
# virsh "define D.xml; dumpxml D"
"define D.xml; dumpxml D" was parsed as a commands-string.
and support commands like:
# virsh qemu-monitor-command f13guest "info cpus"
we will not mash them into a string, we just skip the step 1 parsing
and goto the step 2 parsing directly.
But we don't support the command like:
# virsh "define D.xml; dumpxml" D
"define D.xml; dumpxml" was parsed as a command-name, but we have no such command-name.
Misc changed behavior:
1) support escape '\'
2) a better quoting support, the following commands are now supported:
virsh # dumpxml --"update-cpu" vm1
virsh # dumpxml --update-cpu vm"1"
3) better handling the boolean options, in old code the following commands are equivalent:
virsh # dumpxml --update-cpu=vm1
virsh # dumpxml --update-cpu vm1
after this patch applied, the first one will become illegal.
The idea of this patch is from Daniel P. Berrange.
changed from V1:
changed the usage as Eric Blake suggested.
Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
virsh.c | 351 ++++++++++++++++++++++++++++++----------------------------------
1 file changed, 170 insertions(+), 181 deletions(-)
--- libvirt-0.8.4.old/tools/virsh.c 2010-09-10 20:47:06.000000000 +0800
+++ libvirt-0.8.4/tools/virsh.c 2010-09-16 17:13:55.000000000 +0800
@@ -10162,90 +10162,166 @@ vshCommandRun(vshControl *ctl, const vsh
* Command string parsing
* ---------------
*/
-#define VSH_TK_ERROR -1
-#define VSH_TK_NONE 0
-#define VSH_TK_OPTION 1
-#define VSH_TK_DATA 2
-#define VSH_TK_END 3
-static int
-vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
+static char *
+vshCmdStrGetArg(vshControl *ctl, char *str, char **end, int *last_arg)
{
- int tk = VSH_TK_NONE;
- int quote = FALSE;
- int sz = 0;
+ int quote = 0;
char *p = str;
- char *tkstr = NULL;
+ char *argstr = NULL;
+ char *res = NULL;
*end = NULL;
+ *last_arg = 0;
while (p && *p && (*p == ' ' || *p == '\t'))
p++;
if (p == NULL || *p == '\0')
- return VSH_TK_END;
+ return NULL;
+
if (*p == ';') {
- *end = ++p; /* = \0 or begin of next command */
- return VSH_TK_END;
+ *end = p + 1; /* = \0 or begin of next command */
+ return NULL;
}
+
+ res = argstr = p;
while (*p) {
- /* end of token is blank space or ';' */
- if ((quote == FALSE && (*p == ' ' || *p == '\t')) || *p == ';')
+ if (*p == '\\') { /* escape */
+ p++;
+ if (*p == '\0')
+ break;
+ } else if (*p == '"') { /* quote */
+ quote = !quote;
+ p++;
+ continue;
+ } else if ((!quote && (*p == ' ' || *p == '\t')) || *p == ';')
break;
- /* end of option name could be '=' */
- if (tk == VSH_TK_OPTION && *p == '=') {
- p++; /* skip '=' */
- break;
- }
+ *argstr++ = *p++;
+ }
+
+ if (*p != '\0') {
+ if (*p == ';')
+ *last_arg = 1;
+ *end = p + 1; /* skip the \0 braught by *argstr = '\0' */
+ } else
+ *end = p;
+ *argstr = '\0';
+
+ if (quote) {
+ vshError(ctl, "%s", _("missing \""));
+ return NULL;
+ }
+
+ return res;
+}
- if (tk == VSH_TK_NONE) {
- if (*p == '-' && *(p + 1) == '-' && *(p + 2)
+static vshCmd *
+vshCommandParseArgv(vshControl *ctl, int args, char *argv[])
+{
+ vshCmdOpt *first = NULL, *last = NULL;
+ const vshCmdDef *cmd;
+ vshCmd *c;
+ int i;
+ int data_ct = 0;
+
+ if (!(cmd = vshCmddefSearch(argv[0]))) {
+ vshError(ctl, _("unknown command: '%s'"), argv[0]);
+ goto syntaxError; /* ... or ignore this command only? */
+ }
+
+ for (i = 1; i < args; i++) {
+ vshCmdOpt *arg;
+ const vshCmdOptDef *opt;
+ char *p, *q;
+
+ p = vshStrdup(ctl, argv[i]);
+ if (*p == '-' && *(p + 1) == '-' && *(p + 2)
&& c_isalnum(*(p + 2))) {
- tk = VSH_TK_OPTION;
- p += 2;
- } else {
- tk = VSH_TK_DATA;
- if (*p == '"') {
- quote = TRUE;
- p++;
- } else {
- quote = FALSE;
+ q = strchr(p + 2, '=');
+ if (q) {
+ *q = '\0';
+ q = vshStrdup(ctl, q + 1);
+ }
+
+ if (!(opt = vshCmddefGetOption(cmd, p + 2))) {
+ vshError(ctl,
+ _("command '%s' doesn't support option --%s"),
+ cmd->name, p);
+ VIR_FREE(p);
+ VIR_FREE(q);
+ goto syntaxError;
+ }
+ VIR_FREE(p);
+
+ if (opt->type == VSH_OT_BOOL) {
+ if (q) {
+ vshError(ctl, _("invalid '=' after option --%s"),
+ opt->name);
+ VIR_FREE(q);
+ goto syntaxError;
}
+ } else if (!q) {
+ i++;
+ if (i == args) {
+ vshError(ctl,
+ _("expected syntax: --%s <%s>"),
+ opt->name,
+ opt->type ==
+ VSH_OT_INT ? _("number") : _("string"));
+ goto syntaxError;
+ }
+ q = vshStrdup(ctl, argv[i]);
+ }
+ } else {
+ q = p;
+ if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
+ vshError(ctl, _("unexpected data '%s'"), q);
+ VIR_FREE(q);
+ goto syntaxError;
}
- tkstr = p; /* begin of token */
- } else if (quote && *p == '"') {
- quote = FALSE;
- p++;
- break; /* end of "..." token */
}
- p++;
- sz++;
+
+ arg = vshMalloc(ctl, sizeof(vshCmdOpt));
+ arg->def = opt;
+ arg->data = q;
+ arg->next = NULL;
+
+ if (!first)
+ first = arg;
+ if (last)
+ last->next = arg;
+ last = arg;
+
+ vshDebug(ctl, 4, "%s: %s(%s): %s\n", cmd->name, opt->name,
+ arg->data != p ? _("OPTION") : _("DATA"), arg->data);
}
- if (quote) {
- vshError(ctl, "%s", _("missing \""));
- return VSH_TK_ERROR;
+
+ c = vshMalloc(ctl, sizeof(vshCmd));
+
+ c->opts = first;
+ c->def = cmd;
+ c->next = NULL;
+
+ if (!vshCommandCheckOpts(ctl, c)) {
+ VIR_FREE(c);
+ goto syntaxError;
}
- if (tkstr == NULL || *tkstr == '\0' || p == NULL)
- return VSH_TK_END;
- if (sz == 0)
- return VSH_TK_END;
-
- *res = vshMalloc(ctl, sz + 1);
- memcpy(*res, tkstr, sz);
- *(*res + sz) = '\0';
+ return c;
- *end = p;
- return tk;
+syntaxError:
+ if (first)
+ vshCommandOptFree(first);
+ return NULL;
}
+
static int
vshCommandParse(vshControl *ctl, char *cmdstr)
{
char *str;
- char *tkdata = NULL;
vshCmd *clast = NULL;
- vshCmdOpt *first = NULL;
if (ctl->cmd) {
vshCommandFree(ctl->cmd);
@@ -10257,130 +10333,42 @@ vshCommandParse(vshControl *ctl, char *c
str = cmdstr;
while (str && *str) {
- vshCmdOpt *last = NULL;
- const vshCmdDef *cmd = NULL;
- int tk = VSH_TK_NONE;
- int data_ct = 0;
-
- first = NULL;
-
- while (tk != VSH_TK_END) {
- char *end = NULL;
- const vshCmdOptDef *opt = NULL;
-
- tkdata = NULL;
-
- /* get token */
- tk = vshCommandGetToken(ctl, str, &end, &tkdata);
-
- str = end;
-
- if (tk == VSH_TK_END) {
- VIR_FREE(tkdata);
- break;
- }
- if (tk == VSH_TK_ERROR)
+ vshCmd *c;
+ int args = 0;
+ char *argv[20];
+ char *arg;
+ int last_arg = 0;
+
+ while ((arg = vshCmdStrGetArg(ctl, str, &str, &last_arg)) != NULL) {
+ if (args == sizeof(argv) / sizeof(argv[0])) {
+ vshError(ctl, _("too many args"));
goto syntaxError;
-
- if (cmd == NULL) {
- /* first token must be command name */
- if (tk != VSH_TK_DATA) {
- vshError(ctl,
- _("unexpected token (command name): '%s'"),
- tkdata);
- goto syntaxError;
- }
- if (!(cmd = vshCmddefSearch(tkdata))) {
- vshError(ctl, _("unknown command: '%s'"), tkdata);
- goto syntaxError; /* ... or ignore this command only? */
- }
- VIR_FREE(tkdata);
- } else if (tk == VSH_TK_OPTION) {
- if (!(opt = vshCmddefGetOption(cmd, tkdata))) {
- vshError(ctl,
- _("command '%s' doesn't support option --%s"),
- cmd->name, tkdata);
- goto syntaxError;
- }
- VIR_FREE(tkdata); /* option name */
-
- if (opt->type != VSH_OT_BOOL) {
- /* option data */
- tk = vshCommandGetToken(ctl, str, &end, &tkdata);
- str = end;
- if (tk == VSH_TK_ERROR)
- goto syntaxError;
- if (tk != VSH_TK_DATA) {
- vshError(ctl,
- _("expected syntax: --%s <%s>"),
- opt->name,
- opt->type ==
- VSH_OT_INT ? _("number") : _("string"));
- goto syntaxError;
- }
- }
- } else if (tk == VSH_TK_DATA) {
- if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
- vshError(ctl, _("unexpected data '%s'"), tkdata);
- goto syntaxError;
- }
- }
- if (opt) {
- /* save option */
- vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
-
- arg->def = opt;
- arg->data = tkdata;
- arg->next = NULL;
- tkdata = NULL;
-
- if (!first)
- first = arg;
- if (last)
- last->next = arg;
- last = arg;
-
- vshDebug(ctl, 4, "%s: %s(%s): %s\n",
- cmd->name,
- opt->name,
- tk == VSH_TK_OPTION ? _("OPTION") : _("DATA"),
- arg->data);
}
- if (!str)
+ argv[args++] = arg;
+ if (last_arg)
break;
}
+ if (args == 0)
+ continue;
- /* command parsed -- allocate new struct for the command */
- if (cmd) {
- vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
-
- c->opts = first;
- c->def = cmd;
- c->next = NULL;
-
- if (!vshCommandCheckOpts(ctl, c)) {
- VIR_FREE(c);
- goto syntaxError;
- }
-
- if (!ctl->cmd)
- ctl->cmd = c;
- if (clast)
- clast->next = c;
- clast = c;
- }
+ c = vshCommandParseArgv(ctl, args, argv);
+ if (!c)
+ goto syntaxError;
+
+ if (!ctl->cmd)
+ ctl->cmd = c;
+ if (clast)
+ clast->next = c;
+ clast = c;
}
return TRUE;
- syntaxError:
+syntaxError:
if (ctl->cmd) {
vshCommandFree(ctl->cmd);
ctl->cmd = NULL;
}
- if (first)
- vshCommandOptFree(first);
- VIR_FREE(tkdata);
return FALSE;
}
@@ -10939,7 +10927,8 @@ static void
vshUsage(void)
{
const vshCmdDef *cmd;
- fprintf(stdout, _("\n%s [options] [commands]\n\n"
+ fprintf(stdout, _("\n%s [options]... [<command_name> args...]"
+ "\n%s [options]... <command_string>\n\n"
" options:\n"
" -c | --connect <uri> hypervisor connection URI\n"
" -r | --readonly connect readonly\n"
@@ -10949,7 +10938,7 @@ vshUsage(void)
" -t | --timing print timing information\n"
" -l | --log <file> output logging to file\n"
" -v | --version program version\n\n"
- " commands (non interactive mode):\n"), progname);
+ " commands (non interactive mode):\n"), progname, progname);
for (cmd = commands; cmd->name; cmd++)
fprintf(stdout,
@@ -11069,25 +11058,25 @@ vshParseArgv(vshControl *ctl, int argc,
if (argc > end) {
/* parse command */
- char *cmdstr;
- int sz = 0, ret;
+ int ret = TRUE;
ctl->imode = FALSE;
- for (i = end; i < argc; i++)
- sz += strlen(argv[i]) + 1; /* +1 is for blank space between items */
-
- cmdstr = vshCalloc(ctl, sz + 1, 1);
-
- for (i = end; i < argc; i++) {
- strncat(cmdstr, argv[i], sz);
- sz -= strlen(argv[i]);
- strncat(cmdstr, " ", sz--);
+ if (argc - end == 1) {
+ char *cmdstr = vshStrdup(ctl, argv[end]);
+ vshDebug(ctl, 2, "commands: \"%s\"\n", cmdstr);
+ ret = vshCommandParse(ctl, cmdstr);
+ VIR_FREE(cmdstr);
+ } else {
+ if (ctl->cmd) {
+ vshCommandFree(ctl->cmd);
+ ctl->cmd = NULL;
+ }
+ ctl->cmd = vshCommandParseArgv(ctl, argc - end, argv + end);
+ if (!ctl->cmd)
+ ret = FALSE;
}
- vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
- ret = vshCommandParse(ctl, cmdstr);
- VIR_FREE(cmdstr);
return ret;
}
return TRUE;
14 years, 1 month
[libvirt] [PATCH] [V1] virsh: Categorize commands into groups for virsh help output
by Osier Yang
Change the virsh help out. The new output of "virsh help" and
"virsh --help" will be like:
Secret:
secret-define define or modify a secret from an XML file
secret-dumpxml secret attributes in XML
secret-set-value set a secret value
secret-get-value Output a secret value
secret-undefine undefine a secret
secret-list list secrets
Snapshot:
snapshot-create Create a snapshot
snapshot-current Get the current snapshot
snapshot-delete Delete a domain snapshot
snapshot-dumpxml Dump XML for a domain snapshot
snapshot-list List snapshots for a domain
snapshot-revert Revert a domain to a snapshot
Also support output help information of specified command group, e.g.
% ./tools/virsh help "Network Filter"
Network Filter:
nwfilter-define define or update a network filter from an XML file
nwfilter-undefine undefine a network filter
nwfilter-dumpxml network filter information in XML
nwfilter-list list network filters
nwfilter-edit edit XML configuration for a network filter
* tools/virsh.c:
- introduce new struct "vshCmdGrp" and macros to define the groups.
- split previous array "commands" into small arrays which are orgnized
by group
- changed some functions, such as "vshCmdDefSearch"
- the modifications doesn't affect tests
* TODO:
- the output format is still not nice, need improved.
- the category of groups probly not reasonable and need improved.
- need to update virsh.pod.
- PO files.
- do enough testing to ensure it doesn't break anything, because virsh
is so important for end-users. :-)
- not sure if it's fine of group name contains space, Because it need
user to quote the whole group name when input. Probly we need some
abstract group names for user.
---
tools/virsh.c | 370 ++++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 260 insertions(+), 110 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index b485eff..ee7fef6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -127,6 +127,22 @@ typedef enum {
} vshCmdOptType;
/*
+ * Command group types
+ */
+#define VSH_CMD_GRP_DOM_MANAGEMENT "Domain Management"
+#define VSH_CMD_GRP_DOM_MONITORING "Domain Monitoring"
+#define VSH_CMD_GRP_STORAGE_POOL "Storage Pool"
+#define VSH_CMD_GRP_STORAGE_VOL "Storage Volume"
+#define VSH_CMD_GRP_NETWORK "Networking"
+#define VSH_CMD_GRP_NODEDEV "Node Device"
+#define VSH_CMD_GRP_IFACE "Interface"
+#define VSH_CMD_GRP_NWFILTER "Network Filter"
+#define VSH_CMD_GRP_SECRET "Secret"
+#define VSH_CMD_GRP_SNAPSHOT "Snapshot"
+#define VSH_CMD_GRP_HOST_AND_HV "Host and Hypervisor"
+#define VSH_CMD_GRP_VIRSH "Virsh Itself"
+
+/*
* Command Option Flags
*/
#define VSH_OFLAG_NONE 0 /* without flags */
@@ -203,8 +219,12 @@ typedef struct __vshControl {
char *historyfile; /* readline history file name */
} __vshControl;
+typedef struct vshCmdGrp {
+ const char *name;
+ const vshCmdDef *commands;
+} vshCmdGrp;
-static const vshCmdDef commands[];
+static const vshCmdGrp cmdGroups[];
static void vshError(vshControl *ctl, const char *format, ...)
ATTRIBUTE_FMT_PRINTF(2, 3);
@@ -219,7 +239,9 @@ static int vshParseArgv(vshControl *ctl, int argc, char **argv);
static const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info);
static const vshCmdDef *vshCmddefSearch(const char *cmdname);
+static const vshCmdGrp *vshCmdGrpSearch(const char *grpname);
static int vshCmddefHelp(vshControl *ctl, const char *name);
+static int vshCmdGrpHelp(vshControl *ctl, const char *name);
static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found);
@@ -548,18 +570,37 @@ static const vshCmdOptDef opts_help[] = {
static int
cmdHelp(vshControl *ctl, const vshCmd *cmd)
{
- const char *cmdname = vshCommandOptString(cmd, "command", NULL);
+ const vshCmdDef *c;
+ const vshCmdGrp *g;
+ const char *name = vshCommandOptString(cmd, "command", NULL);
- if (!cmdname) {
+ if (!name) {
+ const vshCmdGrp *grp;
const vshCmdDef *def;
- vshPrint(ctl, "%s", _("Commands:\n\n"));
- for (def = commands; def->name; def++)
- vshPrint(ctl, " %-15s %s\n", def->name,
- _(vshCmddefGetInfo(def, "help")));
+ vshPrint(ctl, "%s", _("Grouped commands:\n\n"));
+
+ for (grp = cmdGroups; grp->name; grp++) {
+ vshPrint(ctl, " %s:\n", grp->name);
+
+ for (def = grp->commands; def->name; def++)
+ vshPrint(ctl, " %-30s %s\n", def->name,
+ _(vshCmddefGetInfo(def, "help")));
+
+ vshPrint(ctl, "\n");
+ }
+
return TRUE;
}
- return vshCmddefHelp(ctl, cmdname);
+
+ if ((c = vshCmddefSearch(name))) {
+ return vshCmddefHelp(ctl, name);
+ } else if ((g = vshCmdGrpSearch(name))) {
+ return vshCmdGrpHelp(ctl, name);
+ } else {
+ vshError(ctl, _("command or command group '%s' doesn't exist"), name);
+ return FALSE;
+ }
}
/*
@@ -9807,27 +9848,17 @@ cleanup:
return ret;
}
-/*
- * Commands
- */
-static const vshCmdDef commands[] = {
- {"help", cmdHelp, opts_help, info_help},
+static const vshCmdDef domManagementCmds[] = {
{"attach-device", cmdAttachDevice, opts_attach_device, info_attach_device},
{"attach-disk", cmdAttachDisk, opts_attach_disk, info_attach_disk},
{"attach-interface", cmdAttachInterface, opts_attach_interface, info_attach_interface},
{"autostart", cmdAutostart, opts_autostart, info_autostart},
- {"capabilities", cmdCapabilities, NULL, info_capabilities},
-#ifndef WIN32
- {"cd", cmdCd, opts_cd, info_cd},
-#endif
- {"connect", cmdConnect, opts_connect, info_connect},
#ifndef WIN32
{"console", cmdConsole, opts_console, info_console},
#endif
{"cpu-baseline", cmdCPUBaseline, opts_cpu_baseline, info_cpu_baseline},
{"cpu-compare", cmdCPUCompare, opts_cpu_compare, info_cpu_compare},
{"create", cmdCreate, opts_create, info_create},
- {"start", cmdStart, opts_start, info_start},
{"destroy", cmdDestroy, opts_destroy, info_destroy},
{"detach-device", cmdDetachDevice, opts_detach_device, info_detach_device},
{"detach-disk", cmdDetachDisk, opts_detach_disk, info_detach_disk},
@@ -9835,15 +9866,9 @@ static const vshCmdDef commands[] = {
{"define", cmdDefine, opts_define, info_define},
{"domid", cmdDomid, opts_domid, info_domid},
{"domuuid", cmdDomuuid, opts_domuuid, info_domuuid},
- {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
{"domjobinfo", cmdDomjobinfo, opts_domjobinfo, info_domjobinfo},
{"domjobabort", cmdDomjobabort, opts_domjobabort, info_domjobabort},
{"domname", cmdDomname, opts_domname, info_domname},
- {"domstate", cmdDomstate, opts_domstate, info_domstate},
- {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
- {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat},
- {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat},
- {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo},
{"domxml-from-native", cmdDomXMLFromNative, opts_domxmlfromnative, info_domxmlfromnative},
{"domxml-to-native", cmdDomXMLToNative, opts_domxmltonative, info_domxmltonative},
{"dumpxml", cmdDumpXML, opts_dumpxml, info_dumpxml},
@@ -9855,11 +9880,85 @@ static const vshCmdDef commands[] = {
opts_find_storage_pool_sources_as, info_find_storage_pool_sources_as},
{"freecell", cmdFreecell, opts_freecell, info_freecell},
{"hostname", cmdHostname, NULL, info_hostname},
- {"list", cmdList, opts_list, info_list},
{"maxvcpus", cmdMaxvcpus, opts_maxvcpus, info_maxvcpus},
{"migrate", cmdMigrate, opts_migrate, info_migrate},
{"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime},
+ {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave},
+ {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, info_managedsaveremove},
+ {"reboot", cmdReboot, opts_reboot, info_reboot},
+ {"restore", cmdRestore, opts_restore, info_restore},
+ {"resume", cmdResume, opts_resume, info_resume},
+ {"save", cmdSave, opts_save, info_save},
+ {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo},
+ {"start", cmdStart, opts_start, info_start},
+ {"dump", cmdDump, opts_dump, info_dump},
+ {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
+ {"setmem", cmdSetmem, opts_setmem, info_setmem},
+ {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
+ {"memtune", cmdMemtune, opts_memtune, info_memtune},
+ {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
+ {"suspend", cmdSuspend, opts_suspend, info_suspend},
+ {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},
+ {"undefine", cmdUndefine, opts_undefine, info_undefine},
+ {"update-device", cmdUpdateDevice, opts_update_device, info_update_device},
+ {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount},
+ {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
+ {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
+ {"version", cmdVersion, NULL, info_version},
+ {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
+ {NULL, NULL, NULL, NULL}
+};
+
+static const vshCmdDef domMonitoringCmds[] = {
+ {"dominfo", cmdDominfo, opts_dominfo, info_dominfo},
+ {"domstate", cmdDomstate, opts_domstate, info_domstate},
+ {"domblkstat", cmdDomblkstat, opts_domblkstat, info_domblkstat},
+ {"domifstat", cmdDomIfstat, opts_domifstat, info_domifstat},
+ {"dommemstat", cmdDomMemStat, opts_dommemstat, info_dommemstat},
+ {"domblkinfo", cmdDomblkinfo, opts_domblkinfo, info_domblkinfo},
+ {"list", cmdList, opts_list, info_list},
+ {NULL, NULL, NULL, NULL}
+};
+
+static const vshCmdDef storagePoolCmds[] = {
+ {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
+ {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
+ {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create},
+ {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as},
+ {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define},
+ {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as},
+ {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy},
+ {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete},
+ {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml},
+ {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit},
+ {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info},
+ {"pool-list", cmdPoolList, opts_pool_list, info_pool_list},
+ {"pool-name", cmdPoolName, opts_pool_name, info_pool_name},
+ {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh},
+ {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start},
+ {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine},
+ {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid},
+ {NULL, NULL, NULL, NULL}
+};
+
+static const vshCmdDef storageVolCmds[] = {
+ {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
+ {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from},
+ {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
+ {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone},
+ {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete},
+ {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe},
+ {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml},
+ {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info},
+ {"vol-list", cmdVolList, opts_vol_list, info_vol_list},
+ {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool},
+ {"vol-path", cmdVolPath, opts_vol_path, info_vol_path},
+ {"vol-name", cmdVolName, opts_vol_name, info_vol_name},
+ {"vol-key", cmdVolKey, opts_vol_key, info_vol_key},
+ {NULL, NULL, NULL, NULL}
+};
+static const vshCmdDef networkCmds[] = {
{"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart},
{"net-create", cmdNetworkCreate, opts_network_create, info_network_create},
{"net-define", cmdNetworkDefine, opts_network_define, info_network_define},
@@ -9871,7 +9970,22 @@ 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},
+ {NULL, NULL, NULL, NULL}
+};
+static const vshCmdDef nodedevCmds[] = {
+ {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
+ {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices},
+ {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml},
+ {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach},
+ {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach},
+ {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset},
+ {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
+ {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},
+ {NULL, NULL, NULL, NULL}
+};
+
+static const vshCmdDef ifaceCmds[] = {
{"iface-list", cmdInterfaceList, opts_interface_list, info_interface_list},
{"iface-name", cmdInterfaceName, opts_interface_name, info_interface_name},
{"iface-mac", cmdInterfaceMAC, opts_interface_mac, info_interface_mac},
@@ -9881,104 +9995,78 @@ static const vshCmdDef commands[] = {
{"iface-edit", cmdInterfaceEdit, opts_interface_edit, info_interface_edit},
{"iface-start", cmdInterfaceStart, opts_interface_start, info_interface_start},
{"iface-destroy", cmdInterfaceDestroy, opts_interface_destroy, info_interface_destroy},
+ {NULL, NULL, NULL, NULL}
+};
- {"managedsave", cmdManagedSave, opts_managedsave, info_managedsave},
- {"managedsave-remove", cmdManagedSaveRemove, opts_managedsaveremove, info_managedsaveremove},
-
- {"nodeinfo", cmdNodeinfo, NULL, info_nodeinfo},
-
- {"nodedev-list", cmdNodeListDevices, opts_node_list_devices, info_node_list_devices},
- {"nodedev-dumpxml", cmdNodeDeviceDumpXML, opts_node_device_dumpxml, info_node_device_dumpxml},
- {"nodedev-dettach", cmdNodeDeviceDettach, opts_node_device_dettach, info_node_device_dettach},
- {"nodedev-reattach", cmdNodeDeviceReAttach, opts_node_device_reattach, info_node_device_reattach},
- {"nodedev-reset", cmdNodeDeviceReset, opts_node_device_reset, info_node_device_reset},
- {"nodedev-create", cmdNodeDeviceCreate, opts_node_device_create, info_node_device_create},
- {"nodedev-destroy", cmdNodeDeviceDestroy, opts_node_device_destroy, info_node_device_destroy},
-
+static const vshCmdDef nwfilterCmds[] = {
{"nwfilter-define", cmdNWFilterDefine, opts_nwfilter_define, info_nwfilter_define},
{"nwfilter-undefine", cmdNWFilterUndefine, opts_nwfilter_undefine, info_nwfilter_undefine},
{"nwfilter-dumpxml", cmdNWFilterDumpXML, opts_nwfilter_dumpxml, info_nwfilter_dumpxml},
{"nwfilter-list", cmdNWFilterList, opts_nwfilter_list, info_nwfilter_list},
{"nwfilter-edit", cmdNWFilterEdit, opts_nwfilter_edit, info_nwfilter_edit},
+ {NULL, NULL, NULL, NULL}
+};
- {"pool-autostart", cmdPoolAutostart, opts_pool_autostart, info_pool_autostart},
- {"pool-build", cmdPoolBuild, opts_pool_build, info_pool_build},
- {"pool-create", cmdPoolCreate, opts_pool_create, info_pool_create},
- {"pool-create-as", cmdPoolCreateAs, opts_pool_X_as, info_pool_create_as},
- {"pool-define", cmdPoolDefine, opts_pool_define, info_pool_define},
- {"pool-define-as", cmdPoolDefineAs, opts_pool_X_as, info_pool_define_as},
- {"pool-destroy", cmdPoolDestroy, opts_pool_destroy, info_pool_destroy},
- {"pool-delete", cmdPoolDelete, opts_pool_delete, info_pool_delete},
- {"pool-dumpxml", cmdPoolDumpXML, opts_pool_dumpxml, info_pool_dumpxml},
- {"pool-edit", cmdPoolEdit, opts_pool_edit, info_pool_edit},
- {"pool-info", cmdPoolInfo, opts_pool_info, info_pool_info},
- {"pool-list", cmdPoolList, opts_pool_list, info_pool_list},
- {"pool-name", cmdPoolName, opts_pool_name, info_pool_name},
- {"pool-refresh", cmdPoolRefresh, opts_pool_refresh, info_pool_refresh},
- {"pool-start", cmdPoolStart, opts_pool_start, info_pool_start},
- {"pool-undefine", cmdPoolUndefine, opts_pool_undefine, info_pool_undefine},
- {"pool-uuid", cmdPoolUuid, opts_pool_uuid, info_pool_uuid},
-
+static const vshCmdDef secretCmds[] = {
{"secret-define", cmdSecretDefine, opts_secret_define, info_secret_define},
{"secret-dumpxml", cmdSecretDumpXML, opts_secret_dumpxml, info_secret_dumpxml},
{"secret-set-value", cmdSecretSetValue, opts_secret_set_value, info_secret_set_value},
{"secret-get-value", cmdSecretGetValue, opts_secret_get_value, info_secret_get_value},
{"secret-undefine", cmdSecretUndefine, opts_secret_undefine, info_secret_undefine},
{"secret-list", cmdSecretList, NULL, info_secret_list},
+ {NULL, NULL, NULL, NULL}
+};
-
+static const vshCmdDef virshCmds[] = {
#ifndef WIN32
{"pwd", cmdPwd, NULL, info_pwd},
#endif
{"quit", cmdQuit, NULL, info_quit},
{"exit", cmdQuit, NULL, info_quit},
- {"reboot", cmdReboot, opts_reboot, info_reboot},
- {"restore", cmdRestore, opts_restore, info_restore},
- {"resume", cmdResume, opts_resume, info_resume},
- {"save", cmdSave, opts_save, info_save},
- {"schedinfo", cmdSchedinfo, opts_schedinfo, info_schedinfo},
- {"dump", cmdDump, opts_dump, info_dump},
- {"shutdown", cmdShutdown, opts_shutdown, info_shutdown},
- {"setmem", cmdSetmem, opts_setmem, info_setmem},
- {"setmaxmem", cmdSetmaxmem, opts_setmaxmem, info_setmaxmem},
- {"memtune", cmdMemtune, opts_memtune, info_memtune},
- {"setvcpus", cmdSetvcpus, opts_setvcpus, info_setvcpus},
- {"suspend", cmdSuspend, opts_suspend, info_suspend},
- {"ttyconsole", cmdTTYConsole, opts_ttyconsole, info_ttyconsole},
- {"undefine", cmdUndefine, opts_undefine, info_undefine},
- {"update-device", cmdUpdateDevice, opts_update_device, info_update_device},
- {"uri", cmdURI, NULL, info_uri},
-
- {"vol-create", cmdVolCreate, opts_vol_create, info_vol_create},
- {"vol-create-from", cmdVolCreateFrom, opts_vol_create_from, info_vol_create_from},
- {"vol-create-as", cmdVolCreateAs, opts_vol_create_as, info_vol_create_as},
- {"vol-clone", cmdVolClone, opts_vol_clone, info_vol_clone},
- {"vol-delete", cmdVolDelete, opts_vol_delete, info_vol_delete},
- {"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe},
- {"vol-dumpxml", cmdVolDumpXML, opts_vol_dumpxml, info_vol_dumpxml},
- {"vol-info", cmdVolInfo, opts_vol_info, info_vol_info},
- {"vol-list", cmdVolList, opts_vol_list, info_vol_list},
- {"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool},
- {"vol-path", cmdVolPath, opts_vol_path, info_vol_path},
- {"vol-name", cmdVolName, opts_vol_name, info_vol_name},
- {"vol-key", cmdVolKey, opts_vol_key, info_vol_key},
-
- {"vcpucount", cmdVcpucount, opts_vcpucount, info_vcpucount},
- {"vcpuinfo", cmdVcpuinfo, opts_vcpuinfo, info_vcpuinfo},
- {"vcpupin", cmdVcpupin, opts_vcpupin, info_vcpupin},
- {"version", cmdVersion, NULL, info_version},
- {"vncdisplay", cmdVNCDisplay, opts_vncdisplay, info_vncdisplay},
+ {"help", cmdHelp, opts_help, info_help},
+#ifndef WIN32
+ {"cd", cmdCd, opts_cd, info_cd},
+#endif
+ {"echo", cmdEcho, opts_echo, info_echo},
+ {NULL, NULL, NULL, NULL}
+};
+static const vshCmdDef snapshotCmds[] = {
{"snapshot-create", cmdSnapshotCreate, opts_snapshot_create, info_snapshot_create},
{"snapshot-current", cmdSnapshotCurrent, opts_snapshot_current, info_snapshot_current},
{"snapshot-delete", cmdSnapshotDelete, opts_snapshot_delete, info_snapshot_delete},
{"snapshot-dumpxml", cmdSnapshotDumpXML, opts_snapshot_dumpxml, info_snapshot_dumpxml},
{"snapshot-list", cmdSnapshotList, opts_snapshot_list, info_snapshot_list},
{"snapshot-revert", cmdDomainSnapshotRevert, opts_snapshot_revert, info_snapshot_revert},
+ {NULL, NULL, NULL, NULL}
+};
+static const vshCmdDef hostAndHypervisorCmds[] = {
+ {"capabilities", cmdCapabilities, NULL, info_capabilities},
+ {"connect", cmdConnect, opts_connect, info_connect},
+ {"uri", cmdURI, NULL, info_uri},
+ {"freecell", cmdFreecell, opts_freecell, info_freecell},
+ {"hostname", cmdHostname, NULL, info_hostname},
{NULL, NULL, NULL, NULL}
};
+static const vshCmdGrp cmdGroups[] = {
+ {VSH_CMD_GRP_DOM_MANAGEMENT, domManagementCmds},
+ {VSH_CMD_GRP_DOM_MONITORING, domMonitoringCmds},
+ {VSH_CMD_GRP_STORAGE_POOL, storagePoolCmds},
+ {VSH_CMD_GRP_STORAGE_VOL, storageVolCmds},
+ {VSH_CMD_GRP_NETWORK, networkCmds},
+ {VSH_CMD_GRP_NODEDEV, nodedevCmds},
+ {VSH_CMD_GRP_IFACE, ifaceCmds},
+ {VSH_CMD_GRP_NWFILTER, nwfilterCmds},
+ {VSH_CMD_GRP_SECRET, secretCmds},
+ {VSH_CMD_GRP_SNAPSHOT, snapshotCmds},
+ {VSH_CMD_GRP_HOST_AND_HV, hostAndHypervisorCmds},
+ {VSH_CMD_GRP_VIRSH, virshCmds},
+ {NULL, NULL}
+};
+
+
/* ---------------
* Utils for work with command definition
* ---------------
@@ -10060,15 +10148,54 @@ vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd)
static const vshCmdDef *
vshCmddefSearch(const char *cmdname)
{
+ const vshCmdGrp *g;
const vshCmdDef *c;
- for (c = commands; c->name; c++)
- if (STREQ(c->name, cmdname))
- return c;
+ for (g = cmdGroups; g->name; g++) {
+ for (c = g->commands; c->name; c++) {
+ if(STREQ(c->name, cmdname))
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+static const vshCmdGrp *
+vshCmdGrpSearch(const char *grpname)
+{
+ const vshCmdGrp *g;
+
+ for (g = cmdGroups; g->name; g++) {
+ if(STREQ(g->name, grpname))
+ return g;
+ }
+
return NULL;
}
static int
+vshCmdGrpHelp(vshControl *ctl, const char *grpname)
+{
+ const vshCmdGrp *grp = vshCmdGrpSearch(grpname);
+ const vshCmdDef *cmd = NULL;
+
+ if (!grp) {
+ vshError(ctl, _("command group '%s' doesn't exist"), grpname);
+ return FALSE;
+ } else {
+ vshPrint(ctl, " %s:\n", grp->name);
+
+ for (cmd = grp->commands; cmd->name; cmd++) {
+ vshPrint(ctl, " %-30s %s\n", cmd->name,
+ _(vshCmddefGetInfo(cmd, "help")));
+ }
+ }
+
+ return TRUE;
+}
+
+static int
vshCmddefHelp(vshControl *ctl, const char *cmdname)
{
const vshCmdDef *def = vshCmddefSearch(cmdname);
@@ -11242,25 +11369,40 @@ vshCloseLogFile(vshControl *ctl)
static char *
vshReadlineCommandGenerator(const char *text, int state)
{
- static int list_index, len;
+ static int grp_list_index, cmd_list_index, len;
const char *name;
+ const vshCmdGrp *grp;
+ const vshCmdDef *cmds;
+
+ grp = cmdGroups;
/* If this is a new word to complete, initialize now. This
* includes saving the length of TEXT for efficiency, and
* initializing the index variable to 0.
*/
if (!state) {
- list_index = 0;
+ grp_list_index = 0;
+ cmd_list_index = 0;
len = strlen(text);
}
/* Return the next name which partially matches from the
* command list.
*/
- while ((name = commands[list_index].name)) {
- list_index++;
- if (STREQLEN(name, text, len))
- return vshStrdup(NULL, name);
+ while (grp[grp_list_index].name) {
+ cmds = grp[grp_list_index].commands;
+
+ if (cmds[cmd_list_index].name) {
+ while ((name = cmds[cmd_list_index].name)) {
+ cmd_list_index++;
+
+ if (STREQLEN(name, text, len))
+ return vshStrdup(NULL, name);
+ }
+ } else {
+ cmd_list_index = 0;
+ grp_list_index++;
+ }
}
/* If no names matched, then return NULL. */
@@ -11452,13 +11594,13 @@ vshDeinit(vshControl *ctl)
return TRUE;
}
-/*
- * Print usage
- */
+
static void
vshUsage(void)
{
+ const vshCmdGrp *grp;
const vshCmdDef *cmd;
+
fprintf(stdout, _("\n%s [options]... [<command_string>]"
"\n%s [options]... <command> [args...]\n\n"
" options:\n"
@@ -11470,12 +11612,20 @@ vshUsage(void)
" -t | --timing print timing information\n"
" -l | --log <file> output logging to file\n"
" -v | --version program version\n\n"
- " commands (non interactive mode):\n"), progname, progname);
+ " commands (non interactive mode):\n\n"), progname, progname);
+
+ for (grp = cmdGroups; grp->name; grp++) {
+ fprintf(stdout, " %s:\n", grp->name);
- for (cmd = commands; cmd->name; cmd++)
- fprintf(stdout,
- " %-15s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help")));
+ for (cmd = grp->commands; cmd->name; cmd++)
+ fprintf(stdout,
+ " %-30s %s\n", cmd->name, _(vshCmddefGetInfo(cmd, "help")));
+ fprintf(stdout, "\n");
+ }
+
+ fprintf(stdout, "%s",
+ _("\n (specify help <group> for details about commands in that group)\n\n"));
fprintf(stdout, "%s",
_("\n (specify help <command> for details about the command)\n\n"));
return;
--
1.7.2.3
14 years, 1 month
[libvirt] Idea for a "net-info" command in virsh
by Justin Clift
Hey Osier,
I'm thinking there would be good value for people, if we add a
"net-info" command to virsh, as it seems to be missing.
Something that displays the details for a virtual network, like this:
Name: default
UUID: aaaaa-bbbbb-ccccc-ddddd
State: started
Name on host: virbr0
Persistent: yes
Autostarted: yes
Guest interfaces attached
=========================
Domain Interface UUID
****** *******************
guest1 efef-fgfg-efef-fgfg
abab-cdcd-abab-cdcd
guest2 zzyy-aabb-zzyy-aabb
It's just a rough concept idea, but thought it worth asking if it's your
kind of thing.
What do you think? :)
Regards and best wishes,
Justin Clift
14 years, 1 month
[libvirt] virDomainInterfaceStatsStruct documentation
by arnaud.champion@devatom.fr
?Hi,
I'm working on marshaling virDomainInterfaceStatsStruct for C#, and the document miss the struct member explaination. Can anyone explain me the struct members ?
Regards,
Arnaud
14 years, 1 month
[libvirt] virDomainMemoryStats help
by arnaud.champion@devatom.fr
?Hi,
I need a little help about "virDomainMemoryStats" method.
I'm trying to bind it for csharp, and I don't understand the parameter "stats" of the method.
Should this array be filled with desired memory statistics or is it fully returned by the method ?
Can anyone make a little C sample code that I can understand ?
Regards,
Arnaud
14 years, 1 month
Re: [libvirt] [virt-devel] Idea for a "net-info" command in virsh
by Osier Yang
于 2010年11月04日 16:19, Daniel Veillard 写道:
> On Thu, Nov 04, 2010 at 04:04:31AM -0400, jclift(a)redhat.com wrote:
>> Hey Osier,
>>
>> I'm thinking there would be good value for people, in us adding a "net-info" command to virsh, as it seems to be missing.
>>
>> Something that displays the details for a virtual network, like this:
>>
>> Name: default
>> UUID: aaaaa-bbbbb-ccccc-ddddd
>> State: started
>> Name on host: virbr0
>> Persistent: yes
>> Autostarted: yes
>>
>> Guest interfaces attached
>> ====================
>>
>> Domain Interface UUID
>> ****** **************
>> guest1 efef-fgfg-efef-fgfg
>> abab-cdcd-abab-cdcd
>> guest2 zzyy-aabb-zzyy-aabb
>>
>> It's just a rough concept idea, but thought it worth asking if it's your kind of thing.
Hi Justin,
yeah, it's good thought from my point, would like implement it after
finishing the patch for virsh output.. :-)
>>
>> What do you think? :)
>
> I think this kind of suggestions should go to the upstream list :-)
>
forward to libvir-list for discussing.. :/
- Osier
> Daniel
>
14 years, 1 month
[libvirt] [PATCH] macvtap: convert send / recv function to use libnl
by Stefan Berger
In a second step I am converting the netlink send/receive function to
use libnl.
I tested this with 802.1Qbg profiles and my test server and did not see
a regression.
Caveat: The online documentation of libnl talks about nl_socket_alloc()
but the header file provides nl_handle_alloc() -- this could be a hint
to a possible problem between libnl versions...
http://www.infradead.org/~tgr/libnl/doc/group__socket.html
versus
http://libnl.sourcearchive.com/documentation/1.1/group__socket_gf903c9ea0...
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
src/util/macvtap.c | 89
++++++++++++++++++-----------------------------------
1 file changed, 31 insertions(+), 58 deletions(-)
Index: libvirt-acl/src/util/macvtap.c
===================================================================
--- libvirt-acl.orig/src/util/macvtap.c
+++ libvirt-acl/src/util/macvtap.c
@@ -82,22 +82,6 @@ enum virVirtualPortOp {
};
-static int nlOpen(void)
-{
- int fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (fd < 0)
- virReportSystemError(errno,
- "%s",_("cannot open netlink socket"));
- return fd;
-}
-
-
-static void nlClose(int fd)
-{
- close(fd);
-}
-
-
/**
* nlComm:
* @nlmsg: pointer to netlink message
@@ -111,8 +95,8 @@ static void nlClose(int fd)
* buffer will be returned.
*/
static
-int nlComm(struct nlmsghdr *nlmsg,
- char **respbuf, unsigned int *respbuflen,
+int nlComm(struct nl_msg *nl_msg,
+ unsigned char **respbuf, unsigned int *respbuflen,
int nl_pid)
{
int rc = 0;
@@ -121,24 +105,29 @@ int nlComm(struct nlmsghdr *nlmsg,
.nl_pid = nl_pid,
.nl_groups = 0,
};
- int rcvChunkSize = 1024; // expecting less than that
- int rcvoffset = 0;
ssize_t nbytes;
struct timeval tv = {
.tv_sec = NETLINK_ACK_TIMEOUT_S,
};
fd_set readfds;
- int fd = nlOpen();
+ int fd;
int n;
+ struct nl_handle *nlhandle = nl_handle_alloc();
+ struct nlmsghdr *nlmsg = nlmsg_hdr(nl_msg);
- if (fd < 0)
+ if (!nlhandle)
return -1;
+ if (nl_connect(nlhandle, NETLINK_ROUTE) < 0) {
+ rc = -1;
+ goto err_exit;
+ }
+
+ nlmsg_set_dst(nl_msg, &nladdr);
+
nlmsg->nlmsg_pid = getpid();
- nlmsg->nlmsg_flags |= NLM_F_ACK;
- nbytes = sendto(fd, (void *)nlmsg, nlmsg->nlmsg_len, 0,
- (struct sockaddr *)&nladdr, sizeof(nladdr));
+ nbytes = nl_send_auto_complete(nlhandle, nl_msg);
if (nbytes < 0) {
virReportSystemError(errno,
"%s", _("cannot send to netlink socket"));
@@ -146,6 +135,8 @@ int nlComm(struct nlmsghdr *nlmsg,
goto err_exit;
}
+ fd = nl_socket_get_fd(nlhandle);
+
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
@@ -161,28 +152,9 @@ int nlComm(struct nlmsghdr *nlmsg,
goto err_exit;
}
- while (1) {
- if (VIR_REALLOC_N(*respbuf, rcvoffset+rcvChunkSize) < 0) {
- virReportOOMError();
- rc = -1;
- goto err_exit;
- }
-
- socklen_t addrlen = sizeof(nladdr);
- nbytes = recvfrom(fd, &((*respbuf)[rcvoffset]), rcvChunkSize, 0,
- (struct sockaddr *)&nladdr, &addrlen);
- if (nbytes < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
- virReportSystemError(errno, "%s",
- _("error receiving from netlink socket"));
- rc = -1;
- goto err_exit;
- }
- rcvoffset += nbytes;
- break;
- }
- *respbuflen = rcvoffset;
+ *respbuflen = nl_recv(nlhandle, &nladdr, respbuf, NULL);
+ if (*respbuflen <= 0)
+ rc = -1;
err_exit:
if (rc == -1) {
@@ -191,7 +163,8 @@ err_exit:
*respbuflen = 0;
}
- nlClose(fd);
+ nl_handle_destroy(nlhandle);
+
return rc;
}
@@ -211,7 +184,7 @@ link_add(const char *type,
struct nlmsgerr *err;
struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
int ifindex;
- char *recvbuf = NULL;
+ unsigned char *recvbuf = NULL;
unsigned int recvbuflen;
struct nl_msg *nl_msg;
struct nlattr *linkinfo, *info_data;
@@ -260,7 +233,7 @@ link_add(const char *type,
nla_nest_end(nl_msg, linkinfo);
- if (nlComm(nlmsg_hdr(nl_msg), &recvbuf, &recvbuflen, 0) < 0) {
+ if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) {
rc = -1;
goto err_exit;
}
@@ -332,7 +305,7 @@ link_del(const char *ifname)
struct nlmsghdr *resp;
struct nlmsgerr *err;
struct ifinfomsg ifinfo = { .ifi_family = AF_UNSPEC };
- char *recvbuf = NULL;
+ unsigned char *recvbuf = NULL;
unsigned int recvbuflen;
struct nl_msg *nl_msg;
@@ -349,7 +322,7 @@ link_del(const char *ifname)
if (nla_put(nl_msg, IFLA_IFNAME, strlen(ifname)+1, ifname) < 0)
goto buffer_too_small;
- if (nlComm(nlmsg_hdr(nl_msg), &recvbuf, &recvbuflen, 0) < 0) {
+ if (nlComm(nl_msg, &recvbuf, &recvbuflen, 0) < 0) {
rc = -1;
goto err_exit;
}
@@ -746,7 +719,7 @@ getLldpadPid(void) {
static int
link_dump(bool nltarget_kernel, const char *ifname, int ifindex,
- struct nlattr **tb, char **recvbuf)
+ struct nlattr **tb, unsigned char **recvbuf)
{
int rc = 0;
struct nlmsghdr *resp;
@@ -783,7 +756,7 @@ link_dump(bool nltarget_kernel, const ch
}
}
- if (nlComm(nlmsg_hdr(nl_msg), recvbuf, &recvbuflen, pid) < 0) {
+ if (nlComm(nl_msg, recvbuf, &recvbuflen, pid) < 0) {
rc = -1;
goto err_exit;
}
@@ -869,7 +842,7 @@ ifaceGetNthParent(int ifindex, const cha
{
int rc;
struct nlattr *tb[IFLA_MAX + 1] = { NULL, };
- char *recvbuf = NULL;
+ unsigned char *recvbuf = NULL;
bool end = false;
unsigned int i = 0;
@@ -1029,7 +1002,7 @@ doPortProfileOpSetLink(bool nltarget_ker
.ifi_family = AF_UNSPEC,
.ifi_index = ifindex,
};
- char *recvbuf = NULL;
+ unsigned char *recvbuf = NULL;
unsigned int recvbuflen = 0;
uint32_t pid = 0;
struct nl_msg *nl_msg;
@@ -1140,7 +1113,7 @@ doPortProfileOpSetLink(bool nltarget_ker
}
}
- if (nlComm(nlmsg_hdr(nl_msg), &recvbuf, &recvbuflen, pid) < 0) {
+ if (nlComm(nl_msg, &recvbuf, &recvbuflen, pid) < 0) {
rc = -1;
goto err_exit;
}
@@ -1208,7 +1181,7 @@ doPortProfileOpCommon(bool nltarget_kern
uint8_t op)
{
int rc;
- char *recvbuf = NULL;
+ unsigned char *recvbuf = NULL;
struct nlattr *tb[IFLA_MAX + 1] = { NULL , };
int repeats = STATUS_POLL_TIMEOUT_USEC / STATUS_POLL_INTERVL_USEC;
uint16_t status = 0;
14 years, 1 month
[libvirt] [PATCH] rpm: fix /var/lib/libvirt permissions
by Eric Blake
https://bugzilla.redhat.com/show_bug.cgi?id=649511
Regression of forcing 0700 permissions (which breaks guest startup
because the qemu user can't see /var/lib/libvirt/*.monitor) was
introduced in commit 66823690e, as part of libvirt 0.8.2.
* libvirt.spec.in (%{_localstatedir}/lib/libvirt): Guarantee 755
permissions.
---
Stumbled on this one today when upgrading from F13 to F14, and my
VMs no longer started. Turns out that the upgrade process
reinitializes permissions according to the spec file, and the
spec file has been wrong for a couple of releases now.
libvirt.spec.in | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/libvirt.spec.in b/libvirt.spec.in
index 869b5cc..827b8c5 100644
--- a/libvirt.spec.in
+++ b/libvirt.spec.in
@@ -801,7 +801,7 @@ fi
%dir %{_localstatedir}/run/libvirt/
-%dir %{_localstatedir}/lib/libvirt/
+%dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/
%dir %attr(0711, root, root) %{_localstatedir}/lib/libvirt/images/
%dir %attr(0711, root, root) %{_localstatedir}/lib/libvirt/boot/
%dir %attr(0700, root, root) %{_localstatedir}/cache/libvirt/
@@ -895,7 +895,7 @@ fi
%{_sysconfdir}/rc.d/init.d/libvirt-guests
%config(noreplace) %{_sysconfdir}/sysconfig/libvirt-guests
-%dir %attr(0700, root, root) %{_localstatedir}/lib/libvirt
+%dir %attr(0755, root, root) %{_localstatedir}/lib/libvirt/
%if %{with_sasl}
%config(noreplace) %{_sysconfdir}/sasl2/libvirt.conf
--
1.7.3.2
14 years, 1 month
[libvirt] [PATCH] qemu: record timestamps in qemu guest log
by Osier Yang
Currently only record timestamps for domain start and shutdown, for
domain start, record timestamps before qemu command line, for domain
shutdown, just says it's shutting down.
* src/qemu/qemu_driver.c (qemudStartVMDaemon, qemudShutdownVMDaemon)
---
src/qemu/qemu_driver.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 60 insertions(+), 2 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1eea3a9..89b4d11 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -3828,6 +3828,10 @@ static int qemudStartVMDaemon(virConnectPtr conn,
char ebuf[1024];
char *pidfile = NULL;
int logfile = -1;
+ struct timeval cur_time;
+ struct tm time_info;
+ char timestr[100];
+ char *timestamp;
qemuDomainObjPrivatePtr priv = vm->privateData;
struct qemudHookData hookData;
@@ -4015,7 +4019,27 @@ static int qemudStartVMDaemon(virConnectPtr conn,
goto cleanup;
}
+ gettimeofday(&cur_time, NULL);
+ localtime_r(&cur_time.tv_sec, &time_info);
+
+ strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &time_info);
+
+ if (virAsprintf(×tamp, "%s.%3d: ",
+ timestr, (int) cur_time.tv_usec / 1000) < 0) {
+ VIR_FREE(timestamp);
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (safewrite(logfile, timestamp, strlen(timestamp)) < 0) {
+ VIR_WARN("Unable to write timestamp to logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ }
+
+ VIR_FREE(timestamp);
+
tmp = progenv;
+
while (*tmp) {
if (safewrite(logfile, *tmp, strlen(*tmp)) < 0)
VIR_WARN("Unable to write envv to logfile: %s",
@@ -4166,7 +4190,6 @@ cleanup:
return -1;
}
-
static void qemudShutdownVMDaemon(struct qemud_driver *driver,
virDomainObjPtr vm,
int migrated) {
@@ -4176,6 +4199,42 @@ static void qemudShutdownVMDaemon(struct qemud_driver *driver,
virErrorPtr orig_err;
virDomainDefPtr def;
int i;
+ int logfile = -1;
+ char timestr[100];
+ char *timestamp;
+ char ebuf[1024];
+ struct timeval cur_time;
+ struct tm time_info;
+
+ VIR_DEBUG0("Creating domain log file");
+ if ((logfile = qemudLogFD(driver, vm->def->name)) < 0) {
+ /* To not break the normal domain shutdown process, skip the
+ * timestamp log writing if failed on opening log file. */
+ VIR_WARN("Unable to open logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ } else {
+ gettimeofday(&cur_time, NULL);
+ localtime_r(&cur_time.tv_sec, &time_info);
+
+ strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S", &time_info);
+
+ if (virAsprintf(×tamp, "%s.%3d: shutting down\n",
+ timestr, (int) cur_time.tv_usec / 1000) < 0) {
+ VIR_FREE(timestamp);
+ virReportOOMError();
+ }
+
+ if (close(logfile) < 0)
+ VIR_WARN("Unable to close logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ }
+
+ if (safewrite(logfile, timestamp, strlen(timestamp)) < 0) {
+ VIR_WARN("Unable to write timestamp to logfile: %s",
+ virStrerror(errno, ebuf, sizeof ebuf));
+ }
+
+ VIR_FREE(timestamp);
VIR_DEBUG("Shutting down VM '%s' pid=%d migrated=%d",
vm->def->name, vm->pid, migrated);
@@ -4315,7 +4374,6 @@ retry:
}
}
-
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
virConnectAuthPtr auth ATTRIBUTE_UNUSED,
int flags ATTRIBUTE_UNUSED) {
--
1.7.2.3
14 years, 1 month