[libvirt] [PATCH 04/13] virsh: remove generic data, only client specific are kept

Erik Skultety eskultet at redhat.com
Mon Jun 29 15:37:38 UTC 2015


The very opposite action to removing client specific data from vsh.
As all the generic methods/structures/variables have been moved to vsh,
there's no need for them in virsh.
---
 tools/virsh.c | 2393 ++++-----------------------------------------------------
 tools/virsh.h |  428 -----------
 tools/vsh.c   |    2 +-
 3 files changed, 140 insertions(+), 2683 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index f293d0f..9280b40 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -25,7 +25,6 @@
 #include <config.h>
 #include "virsh.h"
 
-#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -41,7 +40,6 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <inttypes.h>
-#include <strings.h>
 #include <signal.h>
 
 #if WITH_READLINE
@@ -85,59 +83,6 @@ static char *progname;
 
 static const vshCmdGrp cmdGroups[];
 
-/* Bypass header poison */
-#undef strdup
-
-void *
-_vshMalloc(vshControl *ctl, size_t size, const char *filename, int line)
-{
-    char *x;
-
-    if (VIR_ALLOC_N(x, size) == 0)
-        return x;
-    vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
-             filename, line, (int) size);
-    exit(EXIT_FAILURE);
-}
-
-void *
-_vshCalloc(vshControl *ctl, size_t nmemb, size_t size, const char *filename,
-           int line)
-{
-    char *x;
-
-    if (!xalloc_oversized(nmemb, size) &&
-        VIR_ALLOC_N(x, nmemb * size) == 0)
-        return x;
-    vshError(ctl, _("%s: %d: failed to allocate %d bytes"),
-             filename, line, (int) (size*nmemb));
-    exit(EXIT_FAILURE);
-}
-
-char *
-_vshStrdup(vshControl *ctl, const char *s, const char *filename, int line)
-{
-    char *x;
-
-    if (VIR_STRDUP(x, s) >= 0)
-        return x;
-    vshError(ctl, _("%s: %d: failed to allocate %lu bytes"),
-             filename, line, (unsigned long)strlen(s));
-    exit(EXIT_FAILURE);
-}
-
-/* Poison the raw allocating identifiers in favor of our vsh variants.  */
-#define strdup use_vshStrdup_instead_of_strdup
-
-int
-vshNameSorter(const void *a, const void *b)
-{
-    const char **sa = (const char**)a;
-    const char **sb = (const char**)b;
-
-    return vshStrcasecmp(*sa, *sb);
-}
-
 double
 virshPrettyCapacity(unsigned long long val, const char **unit)
 {
@@ -913,25 +858,10 @@ cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
 }
 
 /* ---------------
- * Utils for work with command definition
+ * Utils for work with runtime commands data
  * ---------------
  */
-const char *
-vshCmddefGetInfo(const vshCmdDef * cmd, const char *name)
-{
-    const vshCmdInfo *info;
-
-    for (info = cmd->info; info && info->name; info++) {
-        if (STREQ(info->name, name))
-            return info->data;
-    }
-    return NULL;
-}
 
-/* Validate that the options associated with cmd can be parsed.  */
-static int
-vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg,
-                  uint32_t *opts_required)
 /*
  * virshCommandOptTimeoutToMs:
  * @ctl virsh control structure
@@ -945,2253 +875,211 @@ vshCmddefOptParse(const vshCmdDef *cmd, uint32_t *opts_need_arg,
 int
 virshCommandOptTimeoutToMs(vshControl *ctl, const vshCmd *cmd, int *timeout)
 {
-    size_t i;
-    bool optional = false;
-
-    *opts_need_arg = 0;
-    *opts_required = 0;
-
-    if (!cmd->opts)
-        return 0;
-
-    for (i = 0; cmd->opts[i].name; i++) {
-        const vshCmdOptDef *opt = &cmd->opts[i];
-
-        if (i > 31)
-            return -1; /* too many options */
-        if (opt->type == VSH_OT_BOOL) {
-            optional = true;
-            if (opt->flags & VSH_OFLAG_REQ)
-                return -1; /* bool options can't be mandatory */
-            continue;
-        }
-        if (opt->type == VSH_OT_ALIAS) {
-            size_t j;
-            char *name = (char *)opt->help; /* cast away const */
-            char *p;
-
-            if (opt->flags || !opt->help)
-                return -1; /* alias options are tracked by the original name */
-            if ((p = strchr(name, '=')) &&
-                VIR_STRNDUP(name, name, p - name) < 0)
-                return -1;
-            for (j = i + 1; cmd->opts[j].name; j++) {
-                if (STREQ(name, cmd->opts[j].name) &&
-                    cmd->opts[j].type != VSH_OT_ALIAS)
-                    break;
-            }
-            if (name != opt->help) {
-                VIR_FREE(name);
-                /* If alias comes with value, replacement must not be bool */
-                if (cmd->opts[j].type == VSH_OT_BOOL)
-                    return -1;
-            }
-            if (!cmd->opts[j].name)
-                return -1; /* alias option must map to a later option name */
-            continue;
-        }
-        if (opt->flags & VSH_OFLAG_REQ_OPT) {
-            if (opt->flags & VSH_OFLAG_REQ)
-                *opts_required |= 1 << i;
-            else
-                optional = true;
-            continue;
-        }
+    int ret;
+    unsigned int utimeout;
 
-        *opts_need_arg |= 1 << i;
-        if (opt->flags & VSH_OFLAG_REQ) {
-            if (optional && opt->type != VSH_OT_ARGV)
-                return -1; /* mandatory options must be listed first */
-            *opts_required |= 1 << i;
-        } else {
-            optional = true;
-        }
+    if ((ret = vshCommandOptUInt(ctl, cmd, "timeout", &utimeout)) <= 0)
+        return ret;
 
-        if (opt->type == VSH_OT_ARGV && cmd->opts[i + 1].name)
-            return -1; /* argv option must be listed last */
+    /* Ensure that the timeout is not zero and that we can convert
+     * it from seconds to milliseconds without overflowing. */
+    if (utimeout == 0 || utimeout > INT_MAX / 1000) {
+        vshError(ctl,
+                 _("Numeric value '%u' for <%s> option is malformed or out of range"),
+                 utimeout,
+                 "timeout");
+        ret = -1;
+    } else {
+        *timeout = ((int) utimeout) * 1000;
     }
-    return 0;
+
+    return ret;
 }
 
-static vshCmdOptDef helpopt = {
-    .name = "help",
-    .type = VSH_OT_BOOL,
-    .help = N_("print help for this function")
-};
-static const vshCmdOptDef *
-vshCmddefGetOption(vshControl *ctl, const vshCmdDef *cmd, const char *name,
-                   uint32_t *opts_seen, int *opt_index, char **optstr)
 static bool
 virshConnectionUsability(vshControl *ctl, virConnectPtr conn)
 {
-    size_t i;
-    const vshCmdOptDef *ret = NULL;
-    char *alias = NULL;
-
-    if (STREQ(name, helpopt.name))
-        return &helpopt;
-
-    for (i = 0; cmd->opts && cmd->opts[i].name; i++) {
-        const vshCmdOptDef *opt = &cmd->opts[i];
-
-        if (STREQ(opt->name, name)) {
-            if (opt->type == VSH_OT_ALIAS) {
-                char *value;
-
-                /* Two types of replacements:
-                   opt->help = "string": straight replacement of name
-                   opt->help = "string=value": treat boolean flag as
-                   alias of option and its default value */
-                sa_assert(!alias);
-                if (VIR_STRDUP(alias, opt->help) < 0)
-                    goto cleanup;
-                name = alias;
-                if ((value = strchr(name, '='))) {
-                    *value = '\0';
-                    if (*optstr) {
-                        vshError(ctl, _("invalid '=' after option --%s"),
-                                 opt->name);
-                        goto cleanup;
-                    }
-                    if (VIR_STRDUP(*optstr, value + 1) < 0)
-                        goto cleanup;
-                }
-                continue;
-            }
-            if ((*opts_seen & (1 << i)) && opt->type != VSH_OT_ARGV) {
-                vshError(ctl, _("option --%s already seen"), name);
-                goto cleanup;
-            }
-            *opts_seen |= 1 << i;
-            *opt_index = i;
-            ret = opt;
-            goto cleanup;
-        }
+    if (!conn ||
+        virConnectIsAlive(conn) == 0) {
+        vshError(ctl, "%s", _("no valid connection"));
+        return false;
     }
 
-    if (STRNEQ(cmd->name, "help")) {
-        vshError(ctl, _("command '%s' doesn't support option --%s"),
-                 cmd->name, name);
-    }
- cleanup:
-    VIR_FREE(alias);
-    return ret;
+    /* The connection is considered dead only if
+     * virConnectIsAlive() successfuly says so.
+     */
+    vshResetLibvirtError();
+
+    return true;
 }
 
-static const vshCmdOptDef *
-vshCmddefGetData(const vshCmdDef *cmd, uint32_t *opts_need_arg,
-                 uint32_t *opts_seen)
 {
-    size_t i;
-    const vshCmdOptDef *opt;
 
-    if (!*opts_need_arg)
-        return NULL;
 
-    /* Grab least-significant set bit */
-    i = ffs(*opts_need_arg) - 1;
-    opt = &cmd->opts[i];
-    if (opt->type != VSH_OT_ARGV)
-        *opts_need_arg &= ~(1 << i);
-    *opts_seen |= 1 << i;
-    return opt;
 }
 
-/*
- * Checks for required options
+/* ---------------
+ * Misc utils
+ * ---------------
  */
-static int
-vshCommandCheckOpts(vshControl *ctl, const vshCmd *cmd, uint32_t opts_required,
-                    uint32_t opts_seen)
 int
 virshDomainState(vshControl *ctl, virDomainPtr dom, int *reason)
 {
-    const vshCmdDef *def = cmd->def;
-    size_t i;
-
-    opts_required &= ~opts_seen;
-    if (!opts_required)
-        return 0;
+    virDomainInfo info;
+    virshControlPtr priv = ctl->privData;
 
-    for (i = 0; def->opts[i].name; i++) {
-        if (opts_required & (1 << i)) {
-            const vshCmdOptDef *opt = &def->opts[i];
+    if (reason)
+        *reason = -1;
 
-            vshError(ctl,
-                     opt->type == VSH_OT_DATA || opt->type == VSH_OT_ARGV ?
-                     _("command '%s' requires <%s> option") :
-                     _("command '%s' requires --%s option"),
-                     def->name, opt->name);
+    if (!priv->useGetInfo) {
+        int state;
+        if (virDomainGetState(dom, &state, reason, 0) < 0) {
+            virErrorPtr err = virGetLastError();
+            if (err && err->code == VIR_ERR_NO_SUPPORT)
+                priv->useGetInfo = true;
+            else
+                return -1;
+        } else {
+            return state;
         }
     }
-    return -1;
+
+    /* fall back to virDomainGetInfo if virDomainGetState is not supported */
+    if (virDomainGetInfo(dom, &info) < 0)
+        return -1;
+    else
+        return info.state;
 }
 
-const vshCmdDef *
-vshCmddefSearch(const char *cmdname)
 /*
  * Initialize connection.
  */
 static bool
 virshInit(vshControl *ctl)
 {
-    const vshCmdGrp *g;
-    const vshCmdDef *c;
-
-    for (g = cmdGroups; g->name; g++) {
-        for (c = g->commands; c->name; c++) {
-            if (STREQ(c->name, cmdname))
-                return c;
-        }
-    }
+    virshControlPtr priv = ctl->privData;
 
-    return NULL;
-}
+    /* Since we have the commandline arguments parsed, we need to
+     * re-initialize all the debugging to make it work properly */
+    vshInitDebug(ctl);
 
-const vshCmdGrp *
-vshCmdGrpSearch(const char *grpname)
-{
-    const vshCmdGrp *g;
+    if (priv->conn)
+        return false;
 
-    for (g = cmdGroups; g->name; g++) {
-        if (STREQ(g->name, grpname) || STREQ(g->keyword, grpname))
-            return g;
-    }
+    /* set up the library error handler */
+    virSetErrorFunc(NULL, vshErrorHandler);
 
-    return NULL;
-}
+    if (virEventRegisterDefaultImpl() < 0)
+        return false;
 
-bool
-vshCmdGrpHelp(vshControl *ctl, const char *grpname)
-{
-    const vshCmdGrp *grp = vshCmdGrpSearch(grpname);
-    const vshCmdDef *cmd = NULL;
+    if (virThreadCreate(&ctl->eventLoop, true, vshEventLoop, ctl) < 0)
+        return false;
+    ctl->eventLoopStarted = true;
 
-    if (!grp) {
-        vshError(ctl, _("command group '%s' doesn't exist"), grpname);
+    if ((ctl->eventTimerId = virEventAddTimeout(-1, vshEventTimeout, ctl,
+                                                NULL)) < 0)
         return false;
-    } else {
-        vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
-                 grp->keyword);
 
-        for (cmd = grp->commands; cmd->name; cmd++) {
-            if (cmd->flags & VSH_CMD_FLAG_ALIAS)
-                continue;
-            vshPrint(ctl, "    %-30s %s\n", cmd->name,
-                     _(vshCmddefGetInfo(cmd, "help")));
+    if (ctl->name) {
+        virshReconnect(ctl);
+        /* Connecting to a named connection must succeed, but we delay
+         * connecting to the default connection until we need it
+         * (since the first command might be 'connect' which allows a
+         * non-default connection, or might be 'help' which needs no
+         * connection).
+         */
+        if (!priv->conn) {
+            vshReportError(ctl);
+            return false;
         }
     }
 
     return true;
 }
 
-bool
-vshCmddefHelp(vshControl *ctl, const char *cmdname)
 static void
 virshDeinitTimer(int timer ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED)
 {
-    const vshCmdDef *def = vshCmddefSearch(cmdname);
-
-    if (!def) {
-        vshError(ctl, _("command '%s' doesn't exist"), cmdname);
-        return false;
-    } else {
-        /* Don't translate desc if it is "".  */
-        const char *desc = vshCmddefGetInfo(def, "desc");
-        const char *help = _(vshCmddefGetInfo(def, "help"));
-        char buf[256];
-        uint32_t opts_need_arg;
-        uint32_t opts_required;
-        bool shortopt = false; /* true if 'arg' works instead of '--opt arg' */
-
-        if (vshCmddefOptParse(def, &opts_need_arg, &opts_required)) {
-            vshError(ctl, _("internal error: bad options in command: '%s'"),
-                     def->name);
-            return false;
-        }
-
-        fputs(_("  NAME\n"), stdout);
-        fprintf(stdout, "    %s - %s\n", def->name, help);
-
-        fputs(_("\n  SYNOPSIS\n"), stdout);
-        fprintf(stdout, "    %s", def->name);
-        if (def->opts) {
-            const vshCmdOptDef *opt;
-            for (opt = def->opts; opt->name; opt++) {
-                const char *fmt = "%s";
-                switch (opt->type) {
-                case VSH_OT_BOOL:
-                    fmt = "[--%s]";
-                    break;
-                case VSH_OT_INT:
-                    /* xgettext:c-format */
-                    fmt = ((opt->flags & VSH_OFLAG_REQ) ? "<%s>"
-                           : _("[--%s <number>]"));
-                    if (!(opt->flags & VSH_OFLAG_REQ_OPT))
-                        shortopt = true;
-                    break;
-                case VSH_OT_STRING:
-                    /* xgettext:c-format */
-                    fmt = _("[--%s <string>]");
-                    if (!(opt->flags & VSH_OFLAG_REQ_OPT))
-                        shortopt = true;
-                    break;
-                case VSH_OT_DATA:
-                    fmt = ((opt->flags & VSH_OFLAG_REQ) ? "<%s>" : "[<%s>]");
-                    if (!(opt->flags & VSH_OFLAG_REQ_OPT))
-                        shortopt = true;
-                    break;
-                case VSH_OT_ARGV:
-                    /* xgettext:c-format */
-                    if (shortopt) {
-                        fmt = (opt->flags & VSH_OFLAG_REQ)
-                            ? _("{[--%s] <string>}...")
-                            : _("[[--%s] <string>]...");
-                    } else {
-                        fmt = (opt->flags & VSH_OFLAG_REQ) ? _("<%s>...")
-                            : _("[<%s>]...");
-                    }
-                    break;
-                case VSH_OT_ALIAS:
-                    /* aliases are intentionally undocumented */
-                    continue;
-                }
-                fputc(' ', stdout);
-                fprintf(stdout, fmt, opt->name);
-            }
-        }
-        fputc('\n', stdout);
-
-        if (desc[0]) {
-            /* Print the description only if it's not empty.  */
-            fputs(_("\n  DESCRIPTION\n"), stdout);
-            fprintf(stdout, "    %s\n", _(desc));
-        }
-
-        if (def->opts && def->opts->name) {
-            const vshCmdOptDef *opt;
-            fputs(_("\n  OPTIONS\n"), stdout);
-            for (opt = def->opts; opt->name; opt++) {
-                switch (opt->type) {
-                case VSH_OT_BOOL:
-                    snprintf(buf, sizeof(buf), "--%s", opt->name);
-                    break;
-                case VSH_OT_INT:
-                    snprintf(buf, sizeof(buf),
-                             (opt->flags & VSH_OFLAG_REQ) ? _("[--%s] <number>")
-                             : _("--%s <number>"), opt->name);
-                    break;
-                case VSH_OT_STRING:
-                    /* OT_STRING should never be VSH_OFLAG_REQ */
-                    if (opt->flags & VSH_OFLAG_REQ) {
-                        vshError(ctl,
-                                 _("internal error: bad options in command: '%s'"),
-                                 def->name);
-                        return false;
-                    }
-                    snprintf(buf, sizeof(buf), _("--%s <string>"), opt->name);
-                    break;
-                case VSH_OT_DATA:
-                    /* OT_DATA should always be VSH_OFLAG_REQ */
-                    if (!(opt->flags & VSH_OFLAG_REQ)) {
-                        vshError(ctl,
-                                 _("internal error: bad options in command: '%s'"),
-                                 def->name);
-                        return false;
-                    }
-                    snprintf(buf, sizeof(buf), _("[--%s] <string>"),
-                             opt->name);
-                    break;
-                case VSH_OT_ARGV:
-                    snprintf(buf, sizeof(buf),
-                             shortopt ? _("[--%s] <string>") : _("<%s>"),
-                             opt->name);
-                    break;
-                case VSH_OT_ALIAS:
-                    continue;
-                }
-
-                fprintf(stdout, "    %-15s  %s\n", buf, _(opt->help));
-            }
-        }
-        fputc('\n', stdout);
-    }
-    return true;
+    /* nothing to be done here */
 }
 
-/* ---------------
- * Utils for work with runtime commands data
- * ---------------
+/*
+ * Deinitialize virsh
  */
-static void
-vshCommandOptFree(vshCmdOpt * arg)
 static bool
 virshDeinit(vshControl *ctl)
 {
-    vshCmdOpt *a = arg;
+    virshControlPtr priv = ctl->privData;
 
-    while (a) {
-        vshCmdOpt *tmp = a;
+    vshReadlineDeinit(ctl);
+    vshCloseLogFile(ctl);
+    VIR_FREE(ctl->name);
+    if (priv->conn) {
+        int ret;
+        virConnectUnregisterCloseCallback(priv->conn, virshCatchDisconnect);
+        ret = virConnectClose(priv->conn);
+        if (ret < 0)
+            vshError(ctl, "%s", _("Failed to disconnect from the hypervisor"));
+        else if (ret > 0)
+            vshError(ctl, "%s", _("One or more references were leaked after "
+                                  "disconnect from the hypervisor"));
+    }
+    virResetLastError();
 
-        a = a->next;
+    if (ctl->eventLoopStarted) {
+        int timer;
 
-        VIR_FREE(tmp->data);
-        VIR_FREE(tmp);
-    }
-}
+        virMutexLock(&ctl->lock);
+        ctl->quit = true;
+        /* HACK: Add a dummy timeout to break event loop */
+        timer = virEventAddTimeout(0, virshDeinitTimer, NULL, NULL);
+        virMutexUnlock(&ctl->lock);
 
-static void
-vshCommandFree(vshCmd *cmd)
-{
-    vshCmd *c = cmd;
+        virThreadJoin(&ctl->eventLoop);
 
-    while (c) {
-        vshCmd *tmp = c;
+        if (timer != -1)
+            virEventRemoveTimeout(timer);
 
-        c = c->next;
+        if (ctl->eventTimerId != -1)
+            virEventRemoveTimeout(ctl->eventTimerId);
 
-        if (tmp->opts)
-            vshCommandOptFree(tmp->opts);
-        VIR_FREE(tmp);
+        ctl->eventLoopStarted = false;
     }
-}
 
-/**
- * vshCommandOpt:
- * @cmd: parsed command line to search
- * @name: option name to search for
- * @opt: result of the search
- * @needData: true if option must be non-boolean
- *
- * Look up an option passed to CMD by NAME.  Returns 1 with *OPT set
- * to the option if found, 0 with *OPT set to NULL if the name is
- * valid and the option is not required, -1 with *OPT set to NULL if
- * the option is required but not present, and assert if NAME is not
- * valid (which indicates a programming error).  No error messages are
- * issued if a value is returned.
- */
-static int
-vshCommandOpt(const vshCmd *cmd, const char *name, vshCmdOpt **opt,
-              bool needData)
-{
-    vshCmdOpt *candidate = cmd->opts;
-    const vshCmdOptDef *valid = cmd->def->opts;
-    int ret = 0;
-
-    /* See if option is valid and/or required.  */
-    *opt = NULL;
-    while (valid) {
-        assert(valid->name);
-        if (STREQ(name, valid->name))
-            break;
-        valid++;
-    }
-    assert(!needData || valid->type != VSH_OT_BOOL);
-    if (valid->flags & VSH_OFLAG_REQ)
-        ret = -1;
+    virMutexDestroy(&ctl->lock);
 
-    /* See if option is present on command line.  */
-    while (candidate) {
-        if (STREQ(candidate->def->name, name)) {
-            *opt = candidate;
-            ret = 1;
-            break;
-        }
-        candidate = candidate->next;
-    }
-    return ret;
+    return true;
 }
 
-/**
- * vshCommandOptInt:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Convert option to int.
- * On error, a message is displayed.
- *
- * Return value:
- * >0 if option found and valid (@value updated)
- * 0 if option not found and not required (@value untouched)
- * <0 in all other cases (@value untouched)
+/*
+ * Print usage
  */
-int
-vshCommandOptInt(vshControl *ctl, const vshCmd *cmd,
-                 const char *name, int *value)
+static void
+virshUsage(void)
 {
-    vshCmdOpt *arg;
-    int ret;
-
-    if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
-        return ret;
+    const vshCmdGrp *grp;
+    const vshCmdDef *cmd;
 
-    if ((ret = virStrToLong_i(arg->data, NULL, 10, value)) < 0)
-        vshError(ctl,
-                 _("Numeric value '%s' for <%s> option is malformed or out of range"),
-                 arg->data, name);
-    else
-        ret = 1;
-
-    return ret;
-}
-
-static int
-vshCommandOptUIntInternal(vshControl *ctl,
-                          const vshCmd *cmd,
-                          const char *name,
-                          unsigned int *value,
-                          bool wrap)
-{
-    vshCmdOpt *arg;
-    int ret;
-
-    if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
-        return ret;
-
-    if (wrap)
-        ret = virStrToLong_ui(arg->data, NULL, 10, value);
-    else
-        ret = virStrToLong_uip(arg->data, NULL, 10, value);
-    if (ret < 0)
-        vshError(ctl,
-                 _("Numeric value '%s' for <%s> option is malformed or out of range"),
-                 arg->data, name);
-    else
-        ret = 1;
-
-    return ret;
-}
-
-/**
- * vshCommandOptUInt:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Convert option to unsigned int, reject negative numbers
- * See vshCommandOptInt()
- */
-int
-vshCommandOptUInt(vshControl *ctl, const vshCmd *cmd,
-                  const char *name, unsigned int *value)
-{
-    return vshCommandOptUIntInternal(ctl, cmd, name, value, false);
-}
-
-/**
- * vshCommandOptUIntWrap:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Convert option to unsigned int, wraps negative numbers to positive
- * See vshCommandOptInt()
- */
-int
-vshCommandOptUIntWrap(vshControl *ctl, const vshCmd *cmd,
-                      const char *name, unsigned int *value)
-{
-    return vshCommandOptUIntInternal(ctl, cmd, name, value, true);
-}
-
-static int
-vshCommandOptULInternal(vshControl *ctl,
-                        const vshCmd *cmd,
-                        const char *name,
-                        unsigned long *value,
-                        bool wrap)
-{
-    vshCmdOpt *arg;
-    int ret;
-
-    if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
-        return ret;
-
-    if (wrap)
-        ret = virStrToLong_ul(arg->data, NULL, 10, value);
-    else
-        ret = virStrToLong_ulp(arg->data, NULL, 10, value);
-    if (ret < 0)
-        vshError(ctl,
-                 _("Numeric value '%s' for <%s> option is malformed or out of range"),
-                 arg->data, name);
-    else
-        ret = 1;
-
-    return ret;
-}
-
-/*
- * vshCommandOptUL:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Convert option to unsigned long
- * See vshCommandOptInt()
- */
-int
-vshCommandOptUL(vshControl *ctl, const vshCmd *cmd,
-                const char *name, unsigned long *value)
-{
-    return vshCommandOptULInternal(ctl, cmd, name, value, false);
-}
-
-/**
- * vshCommandOptULWrap:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Convert option to unsigned long, wraps negative numbers to positive
- * See vshCommandOptInt()
- */
-int
-vshCommandOptULWrap(vshControl *ctl, const vshCmd *cmd,
-                    const char *name, unsigned long *value)
-{
-    return vshCommandOptULInternal(ctl, cmd, name, value, true);
-}
-
-/**
- * vshCommandOptString:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Returns option as STRING
- * Return value:
- * >0 if option found and valid (@value updated)
- * 0 if option not found and not required (@value untouched)
- * <0 in all other cases (@value untouched)
- */
-int
-vshCommandOptString(vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd,
-                    const char *name, const char **value)
-{
-    vshCmdOpt *arg;
-    int ret;
-
-    if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
-        return ret;
-
-    if (!*arg->data && !(arg->def->flags & VSH_OFLAG_EMPTY_OK))
-        return -1;
-    *value = arg->data;
-    return 1;
-}
-
-/**
- * vshCommandOptStringReq:
- * @ctl virsh control structure
- * @cmd command structure
- * @name option name
- * @value result (updated to NULL or the option argument)
- *
- * Gets a option argument as string.
- *
- * Returns 0 on success or when the option is not present and not
- * required, *value is set to the option argument. On error -1 is
- * returned and error message printed.
- */
-int
-vshCommandOptStringReq(vshControl *ctl,
-                       const vshCmd *cmd,
-                       const char *name,
-                       const char **value)
-{
-    vshCmdOpt *arg;
-    int ret;
-    const char *error = NULL;
-
-    /* clear out the value */
-    *value = NULL;
-
-    ret = vshCommandOpt(cmd, name, &arg, true);
-    /* option is not required and not present */
-    if (ret == 0)
-        return 0;
-    /* this should not be propagated here, just to be sure */
-    if (ret == -1)
-        error = N_("Mandatory option not present");
-    else if (!*arg->data && !(arg->def->flags & VSH_OFLAG_EMPTY_OK))
-        error = N_("Option argument is empty");
-
-    if (error) {
-        vshError(ctl, _("Failed to get option '%s': %s"), name, _(error));
-        return -1;
-    }
-
-    *value = arg->data;
-    return 0;
-}
-
-/**
- * vshCommandOptLongLong:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Returns option as long long
- * See vshCommandOptInt()
- */
-int
-vshCommandOptLongLong(vshControl *ctl, const vshCmd *cmd,
-                      const char *name, long long *value)
-{
-    vshCmdOpt *arg;
-    int ret;
-
-    if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
-        return ret;
-
-    if ((ret = virStrToLong_ll(arg->data, NULL, 10, value)) < 0)
-        vshError(ctl,
-                 _("Numeric value '%s' for <%s> option is malformed or out of range"),
-                 arg->data, name);
-    else
-        ret = 1;
-
-    return ret;
-}
-
-static int
-vshCommandOptULongLongInternal(vshControl *ctl,
-                               const vshCmd *cmd,
-                               const char *name,
-                               unsigned long long *value,
-                               bool wrap)
-{
-    vshCmdOpt *arg;
-    int ret;
-
-    if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
-        return ret;
-
-    if (wrap)
-        ret = virStrToLong_ull(arg->data, NULL, 10, value);
-    else
-        ret = virStrToLong_ullp(arg->data, NULL, 10, value);
-    if (ret < 0)
-        vshError(ctl,
-                 _("Numeric value '%s' for <%s> option is malformed or out of range"),
-                 arg->data, name);
-    else
-        ret = 1;
-
-    return ret;
-}
-
-/**
- * vshCommandOptULongLong:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Returns option as long long, rejects negative numbers
- * See vshCommandOptInt()
- */
-int
-vshCommandOptULongLong(vshControl *ctl, const vshCmd *cmd,
-                       const char *name, unsigned long long *value)
-{
-    return vshCommandOptULongLongInternal(ctl, cmd, name, value, false);
-}
-
-/**
- * vshCommandOptULongLongWrap:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- *
- * Returns option as long long, wraps negative numbers to positive
- * See vshCommandOptInt()
- */
-int
-vshCommandOptULongLongWrap(vshControl *ctl, const vshCmd *cmd,
-                           const char *name, unsigned long long *value)
-{
-    return vshCommandOptULongLongInternal(ctl, cmd, name, value, true);
-}
-
-/**
- * vshCommandOptScaledInt:
- * @ctl virsh control structure
- * @cmd command reference
- * @name option name
- * @value result
- * @scale default of 1 or 1024, if no suffix is present
- * @max maximum value permitted
- *
- * Returns option as long long, scaled according to suffix
- * See vshCommandOptInt()
- */
-int
-vshCommandOptScaledInt(vshControl *ctl, const vshCmd *cmd,
-                       const char *name, unsigned long long *value,
-                       int scale, unsigned long long max)
-{
-    vshCmdOpt *arg;
-    char *end;
-    int ret;
-
-    if ((ret = vshCommandOpt(cmd, name, &arg, true)) <= 0)
-        return ret;
-    if (virStrToLong_ullp(arg->data, &end, 10, value) < 0 ||
-        virScaleInteger(value, end, scale, max) < 0)
-    {
-        vshError(ctl,
-                 _("Numeric value '%s' for <%s> option is malformed or out of range"),
-                 arg->data, name);
-        ret = -1;
-    } else {
-        ret = 1;
-    }
-
-    return ret;
-}
-
-
-/**
- * vshCommandOptBool:
- * @cmd command reference
- * @name option name
- *
- * Returns true/false if the option exists.  Note that this does NOT
- * validate whether the option is actually boolean, or even whether
- * name is legal; so that this can be used to probe whether a data
- * option is present without actually using that data.
- */
-bool
-vshCommandOptBool(const vshCmd *cmd, const char *name)
-{
-    vshCmdOpt *dummy;
-
-    return vshCommandOpt(cmd, name, &dummy, false) == 1;
-}
-
-/**
- * vshCommandOptArgv:
- * @ctl virsh control structure
- * @cmd command reference
- * @opt starting point for the search
- *
- * Returns the next argv argument after OPT (or the first one if OPT
- * is NULL), or NULL if no more are present.
- *
- * Requires that a VSH_OT_ARGV option be last in the
- * list of supported options in CMD->def->opts.
- */
-const vshCmdOpt *
-vshCommandOptArgv(vshControl *ctl ATTRIBUTE_UNUSED, const vshCmd *cmd,
-                  const vshCmdOpt *opt)
-{
-    opt = opt ? opt->next : cmd->opts;
-
-    while (opt) {
-        if (opt->def->type == VSH_OT_ARGV)
-            return opt;
-        opt = opt->next;
-    }
-    return NULL;
-}
-
-/*
- * vshCommandOptTimeoutToMs:
- * @ctl virsh control structure
- * @cmd command reference
- * @timeout result
- *
- * Parse an optional --timeout parameter in seconds, but store the
- * value of the timeout in milliseconds.
- * See vshCommandOptInt()
- */
-int
-vshCommandOptTimeoutToMs(vshControl *ctl, const vshCmd *cmd, int *timeout)
-{
-    int ret;
-    unsigned int utimeout;
-
-    if ((ret = vshCommandOptUInt(ctl, cmd, "timeout", &utimeout)) <= 0)
-        return ret;
-
-    /* Ensure that the timeout is not zero and that we can convert
-     * it from seconds to milliseconds without overflowing. */
-    if (utimeout == 0 || utimeout > INT_MAX / 1000) {
-        vshError(ctl,
-                 _("Numeric value '%u' for <%s> option is malformed or out of range"),
-                 utimeout,
-                 "timeout");
-        ret = -1;
-    } else {
-        *timeout = ((int) utimeout) * 1000;
-    }
-
-    return ret;
-}
-
-static bool
-vshConnectionUsability(vshControl *ctl, virConnectPtr conn)
-{
-    if (!conn ||
-        virConnectIsAlive(conn) == 0) {
-        vshError(ctl, "%s", _("no valid connection"));
-        return false;
-    }
-
-    /* The connection is considered dead only if
-     * virConnectIsAlive() successfuly says so.
-     */
-    vshResetLibvirtError();
-
-    return true;
-}
-
-/*
- * Executes command(s) and returns return code from last command
- */
-static bool
-vshCommandRun(vshControl *ctl, const vshCmd *cmd)
-{
-    bool ret = true;
-
-    while (cmd) {
-        struct timeval before, after;
-        bool enable_timing = ctl->timing;
-
-        if ((ctl->conn == NULL || disconnected) &&
-            !(cmd->def->flags & VSH_CMD_FLAG_NOCONNECT))
-            vshReconnect(ctl);
-
-        if (enable_timing)
-            GETTIMEOFDAY(&before);
-
-        if ((cmd->def->flags & VSH_CMD_FLAG_NOCONNECT) ||
-            vshConnectionUsability(ctl, ctl->conn)) {
-            ret = cmd->def->handler(ctl, cmd);
-        } else {
-            /* connection is not usable, return error */
-            ret = false;
-        }
-
-        if (enable_timing)
-            GETTIMEOFDAY(&after);
-
-        /* try to automatically catch disconnections */
-        if (!ret &&
-            ((last_error != NULL) &&
-             (((last_error->code == VIR_ERR_SYSTEM_ERROR) &&
-               (last_error->domain == VIR_FROM_REMOTE)) ||
-              (last_error->code == VIR_ERR_RPC) ||
-              (last_error->code == VIR_ERR_NO_CONNECT) ||
-              (last_error->code == VIR_ERR_INVALID_CONN))))
-            disconnected++;
-
-        if (!ret)
-            vshReportError(ctl);
-
-        if (STREQ(cmd->def->name, "quit") ||
-            STREQ(cmd->def->name, "exit"))        /* hack ... */
-            return ret;
-
-        if (enable_timing) {
-            double diff_ms = (((after.tv_sec - before.tv_sec) * 1000.0) +
-                              ((after.tv_usec - before.tv_usec) / 1000.0));
-
-            vshPrint(ctl, _("\n(Time: %.3f ms)\n\n"), diff_ms);
-        } else {
-            vshPrintExtra(ctl, "\n");
-        }
-        cmd = cmd->next;
-    }
-    return ret;
-}
-
-/* ---------------
- * Command parsing
- * ---------------
- */
-
-typedef enum {
-    VSH_TK_ERROR, /* Failed to parse a token */
-    VSH_TK_ARG, /* Arbitrary argument, might be option or empty */
-    VSH_TK_SUBCMD_END, /* Separation between commands */
-    VSH_TK_END /* No more commands */
-} vshCommandToken;
-
-typedef struct _vshCommandParser vshCommandParser;
-struct _vshCommandParser {
-    vshCommandToken(*getNextArg)(vshControl *, vshCommandParser *,
-                                 char **);
-    /* vshCommandStringGetArg() */
-    char *pos;
-    /* vshCommandArgvGetArg() */
-    char **arg_pos;
-    char **arg_end;
-};
-
-static bool
-vshCommandParse(vshControl *ctl, vshCommandParser *parser)
-{
-    char *tkdata = NULL;
-    vshCmd *clast = NULL;
-    vshCmdOpt *first = NULL;
-
-    if (ctl->cmd) {
-        vshCommandFree(ctl->cmd);
-        ctl->cmd = NULL;
-    }
-
-    while (1) {
-        vshCmdOpt *last = NULL;
-        const vshCmdDef *cmd = NULL;
-        vshCommandToken tk;
-        bool data_only = false;
-        uint32_t opts_need_arg = 0;
-        uint32_t opts_required = 0;
-        uint32_t opts_seen = 0;
-
-        first = NULL;
-
-        while (1) {
-            const vshCmdOptDef *opt = NULL;
-
-            tkdata = NULL;
-            tk = parser->getNextArg(ctl, parser, &tkdata);
-
-            if (tk == VSH_TK_ERROR)
-                goto syntaxError;
-            if (tk != VSH_TK_ARG) {
-                VIR_FREE(tkdata);
-                break;
-            }
-
-            if (cmd == NULL) {
-                /* first token must be command name */
-                if (!(cmd = vshCmddefSearch(tkdata))) {
-                    vshError(ctl, _("unknown command: '%s'"), tkdata);
-                    goto syntaxError;   /* ... or ignore this command only? */
-                }
-                if (vshCmddefOptParse(cmd, &opts_need_arg,
-                                      &opts_required) < 0) {
-                    vshError(ctl,
-                             _("internal error: bad options in command: '%s'"),
-                             tkdata);
-                    goto syntaxError;
-                }
-                VIR_FREE(tkdata);
-            } else if (data_only) {
-                goto get_data;
-            } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
-                       c_isalnum(tkdata[2])) {
-                char *optstr = strchr(tkdata + 2, '=');
-                int opt_index = 0;
-
-                if (optstr) {
-                    *optstr = '\0'; /* convert the '=' to '\0' */
-                    optstr = vshStrdup(ctl, optstr + 1);
-                }
-                /* Special case 'help' to ignore all spurious options */
-                if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
-                                               &opts_seen, &opt_index,
-                                               &optstr))) {
-                    VIR_FREE(optstr);
-                    if (STREQ(cmd->name, "help"))
-                        continue;
-                    goto syntaxError;
-                }
-                VIR_FREE(tkdata);
-
-                if (opt->type != VSH_OT_BOOL) {
-                    /* option data */
-                    if (optstr)
-                        tkdata = optstr;
-                    else
-                        tk = parser->getNextArg(ctl, parser, &tkdata);
-                    if (tk == VSH_TK_ERROR)
-                        goto syntaxError;
-                    if (tk != VSH_TK_ARG) {
-                        vshError(ctl,
-                                 _("expected syntax: --%s <%s>"),
-                                 opt->name,
-                                 opt->type ==
-                                 VSH_OT_INT ? _("number") : _("string"));
-                        goto syntaxError;
-                    }
-                    if (opt->type != VSH_OT_ARGV)
-                        opts_need_arg &= ~(1 << opt_index);
-                } else {
-                    tkdata = NULL;
-                    if (optstr) {
-                        vshError(ctl, _("invalid '=' after option --%s"),
-                                 opt->name);
-                        VIR_FREE(optstr);
-                        goto syntaxError;
-                    }
-                }
-            } else if (tkdata[0] == '-' && tkdata[1] == '-' &&
-                       tkdata[2] == '\0') {
-                data_only = true;
-                continue;
-            } else {
- get_data:
-                /* Special case 'help' to ignore spurious data */
-                if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
-                                             &opts_seen)) &&
-                     STRNEQ(cmd->name, "help")) {
-                    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, VSH_ERR_INFO, "%s: %s(%s): %s\n",
-                         cmd->name,
-                         opt->name,
-                         opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
-                         opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
-            }
-        }
-
-        /* command parsed -- allocate new struct for the command */
-        if (cmd) {
-            vshCmd *c = vshMalloc(ctl, sizeof(vshCmd));
-            vshCmdOpt *tmpopt = first;
-
-            /* if we encountered --help, replace parsed command with
-             * 'help <cmdname>' */
-            for (tmpopt = first; tmpopt; tmpopt = tmpopt->next) {
-                if (STRNEQ(tmpopt->def->name, "help"))
-                    continue;
-
-                vshCommandOptFree(first);
-                first = vshMalloc(ctl, sizeof(vshCmdOpt));
-                first->def = &(opts_help[0]);
-                first->data = vshStrdup(ctl, cmd->name);
-                first->next = NULL;
-
-                cmd = vshCmddefSearch("help");
-                opts_required = 0;
-                opts_seen = 0;
-                break;
-            }
-
-            c->opts = first;
-            c->def = cmd;
-            c->next = NULL;
-
-            if (vshCommandCheckOpts(ctl, c, opts_required, opts_seen) < 0) {
-                VIR_FREE(c);
-                goto syntaxError;
-            }
-
-            if (!ctl->cmd)
-                ctl->cmd = c;
-            if (clast)
-                clast->next = c;
-            clast = c;
-        }
-
-        if (tk == VSH_TK_END)
-            break;
-    }
-
-    return true;
-
- syntaxError:
-    if (ctl->cmd) {
-        vshCommandFree(ctl->cmd);
-        ctl->cmd = NULL;
-    }
-    if (first)
-        vshCommandOptFree(first);
-    VIR_FREE(tkdata);
-    return false;
-}
-
-/* --------------------
- * Command argv parsing
- * --------------------
- */
-
-static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
-vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
-{
-    if (parser->arg_pos == parser->arg_end) {
-        *res = NULL;
-        return VSH_TK_END;
-    }
-
-    *res = vshStrdup(ctl, *parser->arg_pos);
-    parser->arg_pos++;
-    return VSH_TK_ARG;
-}
-
-static bool
-vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
-{
-    vshCommandParser parser;
-
-    if (nargs <= 0)
-        return false;
-
-    parser.arg_pos = argv;
-    parser.arg_end = argv + nargs;
-    parser.getNextArg = vshCommandArgvGetArg;
-    return vshCommandParse(ctl, &parser);
-}
-
-/* ----------------------
- * Command string parsing
- * ----------------------
- */
-
-static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
-vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
-{
-    bool single_quote = false;
-    bool double_quote = false;
-    int sz = 0;
-    char *p = parser->pos;
-    char *q = vshStrdup(ctl, p);
-
-    *res = q;
-
-    while (*p && (*p == ' ' || *p == '\t'))
-        p++;
-
-    if (*p == '\0')
-        return VSH_TK_END;
-    if (*p == ';') {
-        parser->pos = ++p;             /* = \0 or begin of next command */
-        return VSH_TK_SUBCMD_END;
-    }
-
-    while (*p) {
-        /* end of token is blank space or ';' */
-        if (!double_quote && !single_quote &&
-            (*p == ' ' || *p == '\t' || *p == ';'))
-            break;
-
-        if (!double_quote && *p == '\'') { /* single quote */
-            single_quote = !single_quote;
-            p++;
-            continue;
-        } else if (!single_quote && *p == '\\') { /* escape */
-            /*
-             * The same as the bash, a \ in "" is an escaper,
-             * but a \ in '' is not an escaper.
-             */
-            p++;
-            if (*p == '\0') {
-                vshError(ctl, "%s", _("dangling \\"));
-                return VSH_TK_ERROR;
-            }
-        } else if (!single_quote && *p == '"') { /* double quote */
-            double_quote = !double_quote;
-            p++;
-            continue;
-        }
-
-        *q++ = *p++;
-        sz++;
-    }
-    if (double_quote) {
-        vshError(ctl, "%s", _("missing \""));
-        return VSH_TK_ERROR;
-    }
-
-    *q = '\0';
-    parser->pos = p;
-    return VSH_TK_ARG;
-}
-
-static bool
-vshCommandStringParse(vshControl *ctl, char *cmdstr)
-{
-    vshCommandParser parser;
-
-    if (cmdstr == NULL || *cmdstr == '\0')
-        return false;
-
-    parser.pos = cmdstr;
-    parser.getNextArg = vshCommandStringGetArg;
-    return vshCommandParse(ctl, &parser);
-}
-
-/* ---------------
- * Misc utils
- * ---------------
- */
-int
-vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason)
-{
-    virDomainInfo info;
-
-    if (reason)
-        *reason = -1;
-
-    if (!ctl->useGetInfo) {
-        int state;
-        if (virDomainGetState(dom, &state, reason, 0) < 0) {
-            virErrorPtr err = virGetLastError();
-            if (err && err->code == VIR_ERR_NO_SUPPORT)
-                ctl->useGetInfo = true;
-            else
-                return -1;
-        } else {
-            return state;
-        }
-    }
-
-    /* fall back to virDomainGetInfo if virDomainGetState is not supported */
-    if (virDomainGetInfo(dom, &info) < 0)
-        return -1;
-    else
-        return info.state;
-}
-
-/* Return a non-NULL string representation of a typed parameter; exit
- * if we are out of memory.  */
-char *
-vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
-{
-    int ret = 0;
-    char *str = NULL;
-
-    switch (item->type) {
-    case VIR_TYPED_PARAM_INT:
-        ret = virAsprintf(&str, "%d", item->value.i);
-        break;
-
-    case VIR_TYPED_PARAM_UINT:
-        ret = virAsprintf(&str, "%u", item->value.ui);
-        break;
-
-    case VIR_TYPED_PARAM_LLONG:
-        ret = virAsprintf(&str, "%lld", item->value.l);
-        break;
-
-    case VIR_TYPED_PARAM_ULLONG:
-        ret = virAsprintf(&str, "%llu", item->value.ul);
-        break;
-
-    case VIR_TYPED_PARAM_DOUBLE:
-        ret = virAsprintf(&str, "%f", item->value.d);
-        break;
-
-    case VIR_TYPED_PARAM_BOOLEAN:
-        str = vshStrdup(ctl, item->value.b ? _("yes") : _("no"));
-        break;
-
-    case VIR_TYPED_PARAM_STRING:
-        str = vshStrdup(ctl, item->value.s);
-        break;
-
-    default:
-        vshError(ctl, _("unimplemented parameter type %d"), item->type);
-    }
-
-    if (ret < 0) {
-        vshError(ctl, "%s", _("Out of memory"));
-        exit(EXIT_FAILURE);
-    }
-    return str;
-}
-
-void
-vshDebug(vshControl *ctl, int level, const char *format, ...)
-{
-    va_list ap;
-    char *str;
-
-    /* Aligning log levels to that of libvirt.
-     * Traces with levels >=  user-specified-level
-     * gets logged into file
-     */
-    if (level < ctl->debug)
-        return;
-
-    va_start(ap, format);
-    vshOutputLogFile(ctl, level, format, ap);
-    va_end(ap);
-
-    va_start(ap, format);
-    if (virVasprintf(&str, format, ap) < 0) {
-        /* Skip debug messages on low memory */
-        va_end(ap);
-        return;
-    }
-    va_end(ap);
-    fputs(str, stdout);
-    VIR_FREE(str);
-}
-
-void
-vshPrintExtra(vshControl *ctl, const char *format, ...)
-{
-    va_list ap;
-    char *str;
-
-    if (ctl && ctl->quiet)
-        return;
-
-    va_start(ap, format);
-    if (virVasprintf(&str, format, ap) < 0) {
-        vshError(ctl, "%s", _("Out of memory"));
-        va_end(ap);
-        return;
-    }
-    va_end(ap);
-    fputs(str, stdout);
-    VIR_FREE(str);
-}
-
-
-bool
-vshTTYIsInterruptCharacter(vshControl *ctl ATTRIBUTE_UNUSED,
-                           const char chr ATTRIBUTE_UNUSED)
-{
-#ifndef WIN32
-    if (ctl->istty &&
-        ctl->termattr.c_cc[VINTR] == chr)
-        return true;
-#endif
-
-    return false;
-}
-
-
-bool
-vshTTYAvailable(vshControl *ctl)
-{
-    return ctl->istty;
-}
-
-
-int
-vshTTYDisableInterrupt(vshControl *ctl ATTRIBUTE_UNUSED)
-{
-#ifndef WIN32
-    struct termios termset = ctl->termattr;
-
-    if (!ctl->istty)
-        return -1;
-
-    /* check if we need to set the terminal */
-    if (termset.c_cc[VINTR] == _POSIX_VDISABLE)
-        return 0;
-
-    termset.c_cc[VINTR] = _POSIX_VDISABLE;
-    termset.c_lflag &= ~ICANON;
-
-    if (tcsetattr(STDIN_FILENO, TCSANOW, &termset) < 0)
-        return -1;
-#endif
-
-    return 0;
-}
-
-
-int
-vshTTYRestore(vshControl *ctl ATTRIBUTE_UNUSED)
-{
-#ifndef WIN32
-    if (!ctl->istty)
-        return 0;
-
-    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &ctl->termattr) < 0)
-        return -1;
-#endif
-
-    return 0;
-}
-
-
-#if !defined(WIN32) && !defined(HAVE_CFMAKERAW)
-/* provide fallback in case cfmakeraw isn't available */
-static void
-cfmakeraw(struct termios *attr)
-{
-    attr->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
-                         | INLCR | IGNCR | ICRNL | IXON);
-    attr->c_oflag &= ~OPOST;
-    attr->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
-    attr->c_cflag &= ~(CSIZE | PARENB);
-    attr->c_cflag |= CS8;
-}
-#endif /* !WIN32 && !HAVE_CFMAKERAW */
-
-
-int
-vshTTYMakeRaw(vshControl *ctl ATTRIBUTE_UNUSED,
-              bool report_errors ATTRIBUTE_UNUSED)
-{
-#ifndef WIN32
-    struct termios rawattr = ctl->termattr;
-    char ebuf[1024];
-
-    if (!ctl->istty) {
-        if (report_errors) {
-            vshError(ctl, "%s",
-                     _("unable to make terminal raw: console isn't a tty"));
-        }
-
-        return -1;
-    }
-
-    cfmakeraw(&rawattr);
-
-    if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &rawattr) < 0) {
-        if (report_errors)
-            vshError(ctl, _("unable to set tty attributes: %s"),
-                     virStrerror(errno, ebuf, sizeof(ebuf)));
-        return -1;
-    }
-#endif
-
-    return 0;
-}
-
-
-void
-vshError(vshControl *ctl, const char *format, ...)
-{
-    va_list ap;
-    char *str;
-
-    if (ctl != NULL) {
-        va_start(ap, format);
-        vshOutputLogFile(ctl, VSH_ERR_ERROR, format, ap);
-        va_end(ap);
-    }
-
-    /* Most output is to stdout, but if someone ran virsh 2>&1, then
-     * printing to stderr will not interleave correctly with stdout
-     * unless we flush between every transition between streams.  */
-    fflush(stdout);
-    fputs(_("error: "), stderr);
-
-    va_start(ap, format);
-    /* We can't recursively call vshError on an OOM situation, so ignore
-       failure here. */
-    ignore_value(virVasprintf(&str, format, ap));
-    va_end(ap);
-
-    fprintf(stderr, "%s\n", NULLSTR(str));
-    fflush(stderr);
-    VIR_FREE(str);
-}
-
-
-static void
-vshEventLoop(void *opaque)
-{
-    vshControl *ctl = opaque;
-
-    while (1) {
-        bool quit;
-        virMutexLock(&ctl->lock);
-        quit = ctl->quit;
-        virMutexUnlock(&ctl->lock);
-
-        if (quit)
-            break;
-
-        if (virEventRunDefaultImpl() < 0)
-            vshReportError(ctl);
-    }
-}
-
-
-/*
- * Helpers for waiting for a libvirt event.
- */
-
-/* We want to use SIGINT to cancel a wait; but as signal handlers
- * don't have an opaque argument, we have to use static storage.  */
-static int vshEventFd = -1;
-static struct sigaction vshEventOldAction;
-
-
-/* Signal handler installed in vshEventStart, removed in vshEventCleanup.  */
-static void
-vshEventInt(int sig ATTRIBUTE_UNUSED,
-            siginfo_t *siginfo ATTRIBUTE_UNUSED,
-            void *context ATTRIBUTE_UNUSED)
-{
-    char reason = VSH_EVENT_INTERRUPT;
-    if (vshEventFd >= 0)
-        ignore_value(safewrite(vshEventFd, &reason, 1));
-}
-
-
-/* Event loop handler used to limit length of waiting for any other event. */
-static void
-vshEventTimeout(int timer ATTRIBUTE_UNUSED,
-                void *opaque)
-{
-    vshControl *ctl = opaque;
-    char reason = VSH_EVENT_TIMEOUT;
-
-    if (ctl->eventPipe[1] >= 0)
-        ignore_value(safewrite(ctl->eventPipe[1], &reason, 1));
-}
-
-
-/**
- * vshEventStart:
- * @ctl virsh command struct
- * @timeout_ms max wait time in milliseconds, or 0 for indefinite
- *
- * Set up a wait for a libvirt event.  The wait can be canceled by
- * SIGINT or by calling vshEventDone() in your event handler.  If
- * @timeout_ms is positive, the wait will also end if the timeout
- * expires.  Call vshEventWait() to block the main thread (the event
- * handler runs in the event loop thread).  When done (including if
- * there was an error registering for an event), use vshEventCleanup()
- * to quit waiting.  Returns 0 on success, -1 on failure.  */
-int
-vshEventStart(vshControl *ctl, int timeout_ms)
-{
-    struct sigaction action;
-
-    assert(ctl->eventPipe[0] == -1 && ctl->eventPipe[1] == -1 &&
-           vshEventFd == -1 && ctl->eventTimerId >= 0);
-    if (pipe2(ctl->eventPipe, O_CLOEXEC) < 0) {
-        char ebuf[1024];
-
-        vshError(ctl, _("failed to create pipe: %s"),
-                 virStrerror(errno, ebuf, sizeof(ebuf)));
-        return -1;
-    }
-    vshEventFd = ctl->eventPipe[1];
-
-    action.sa_sigaction = vshEventInt;
-    action.sa_flags = SA_SIGINFO;
-    sigemptyset(&action.sa_mask);
-    sigaction(SIGINT, &action, &vshEventOldAction);
-
-    if (timeout_ms)
-        virEventUpdateTimeout(ctl->eventTimerId, timeout_ms);
-
-    return 0;
-}
-
-
-/**
- * vshEventDone:
- * @ctl virsh command struct
- *
- * Call this from an event callback to let the main thread quit
- * blocking on further events.
- */
-void
-vshEventDone(vshControl *ctl)
-{
-    char reason = VSH_EVENT_DONE;
-
-    if (ctl->eventPipe[1] >= 0)
-        ignore_value(safewrite(ctl->eventPipe[1], &reason, 1));
-}
-
-
-/**
- * vshEventWait:
- * @ctl virsh command struct
- *
- * Call this in the main thread after calling vshEventStart() then
- * registering for one or more events.  This call will block until
- * SIGINT, the timeout registered at the start, or until one of your
- * event handlers calls vshEventDone().  Returns an enum VSH_EVENT_*
- * stating how the wait concluded, or -1 on error.
- */
-int
-vshEventWait(vshControl *ctl)
-{
-    char buf;
-    int rv;
-
-    assert(ctl->eventPipe[0] >= 0);
-    while ((rv = read(ctl->eventPipe[0], &buf, 1)) < 0 && errno == EINTR);
-    if (rv != 1) {
-        char ebuf[1024];
-
-        if (!rv)
-            errno = EPIPE;
-        vshError(ctl, _("failed to determine loop exit status: %s"),
-                 virStrerror(errno, ebuf, sizeof(ebuf)));
-        return -1;
-    }
-    return buf;
-}
-
-
-/**
- * vshEventCleanup:
- * @ctl virsh command struct
- *
- * Call at the end of any function that has used vshEventStart(), to
- * tear down any remaining SIGINT or timeout handlers.
- */
-void
-vshEventCleanup(vshControl *ctl)
-{
-    if (vshEventFd >= 0) {
-        sigaction(SIGINT, &vshEventOldAction, NULL);
-        vshEventFd = -1;
-    }
-    VIR_FORCE_CLOSE(ctl->eventPipe[0]);
-    VIR_FORCE_CLOSE(ctl->eventPipe[1]);
-    virEventUpdateTimeout(ctl->eventTimerId, -1);
-}
-
-
-/*
- * Initialize debug settings.
- */
-static void
-vshInitDebug(vshControl *ctl)
-{
-    const char *debugEnv;
-
-    if (ctl->debug == VSH_DEBUG_DEFAULT) {
-        /* log level not set from commandline, check env variable */
-        debugEnv = virGetEnvAllowSUID("VIRSH_DEBUG");
-        if (debugEnv) {
-            int debug;
-            if (virStrToLong_i(debugEnv, NULL, 10, &debug) < 0 ||
-                debug < VSH_ERR_DEBUG || debug > VSH_ERR_ERROR) {
-                vshError(ctl, "%s",
-                         _("VIRSH_DEBUG not set with a valid numeric value"));
-            } else {
-                ctl->debug = debug;
-            }
-        }
-    }
-
-    if (ctl->logfile == NULL) {
-        /* log file not set from cmdline */
-        debugEnv = virGetEnvBlockSUID("VIRSH_LOG_FILE");
-        if (debugEnv && *debugEnv) {
-            ctl->logfile = vshStrdup(ctl, debugEnv);
-            vshOpenLogFile(ctl);
-        }
-    }
-}
-
-/*
- * Initialize connection.
- */
-static bool
-vshInit(vshControl *ctl)
-{
-    /* Since we have the commandline arguments parsed, we need to
-     * re-initialize all the debugging to make it work properly */
-    vshInitDebug(ctl);
-
-    if (ctl->conn)
-        return false;
-
-    /* set up the library error handler */
-    virSetErrorFunc(NULL, virshErrorHandler);
-
-    if (virEventRegisterDefaultImpl() < 0)
-        return false;
-
-    if (virThreadCreate(&ctl->eventLoop, true, vshEventLoop, ctl) < 0)
-        return false;
-    ctl->eventLoopStarted = true;
-
-    if ((ctl->eventTimerId = virEventAddTimeout(-1, vshEventTimeout, ctl,
-                                                NULL)) < 0)
-        return false;
-
-    if (ctl->name) {
-        vshReconnect(ctl);
-        /* Connecting to a named connection must succeed, but we delay
-         * connecting to the default connection until we need it
-         * (since the first command might be 'connect' which allows a
-         * non-default connection, or might be 'help' which needs no
-         * connection).
-         */
-        if (!ctl->conn) {
-            vshReportError(ctl);
-            return false;
-        }
-    }
-
-    return true;
-}
-
-#define LOGFILE_FLAGS (O_WRONLY | O_APPEND | O_CREAT | O_SYNC)
-
-/**
- * vshOpenLogFile:
- *
- * Open log file.
- */
-void
-vshOpenLogFile(vshControl *ctl)
-{
-    if (ctl->logfile == NULL)
-        return;
-
-    if ((ctl->log_fd = open(ctl->logfile, LOGFILE_FLAGS, FILE_MODE)) < 0) {
-        vshError(ctl, "%s",
-                 _("failed to open the log file. check the log file path"));
-        exit(EXIT_FAILURE);
-    }
-}
-
-/**
- * vshOutputLogFile:
- *
- * Outputting an error to log file.
- */
-void
-vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format,
-                 va_list ap)
-{
-    virBuffer buf = VIR_BUFFER_INITIALIZER;
-    char *str = NULL;
-    size_t len;
-    const char *lvl = "";
-    time_t stTime;
-    struct tm stTm;
-
-    if (ctl->log_fd == -1)
-        return;
-
-    /**
-     * create log format
-     *
-     * [YYYY.MM.DD HH:MM:SS SIGNATURE PID] LOG_LEVEL message
-    */
-    time(&stTime);
-    localtime_r(&stTime, &stTm);
-    virBufferAsprintf(&buf, "[%d.%02d.%02d %02d:%02d:%02d %s %d] ",
-                      (1900 + stTm.tm_year),
-                      (1 + stTm.tm_mon),
-                      stTm.tm_mday,
-                      stTm.tm_hour,
-                      stTm.tm_min,
-                      stTm.tm_sec,
-                      SIGN_NAME,
-                      (int) getpid());
-    switch (log_level) {
-        case VSH_ERR_DEBUG:
-            lvl = LVL_DEBUG;
-            break;
-        case VSH_ERR_INFO:
-            lvl = LVL_INFO;
-            break;
-        case VSH_ERR_NOTICE:
-            lvl = LVL_INFO;
-            break;
-        case VSH_ERR_WARNING:
-            lvl = LVL_WARNING;
-            break;
-        case VSH_ERR_ERROR:
-            lvl = LVL_ERROR;
-            break;
-        default:
-            lvl = LVL_DEBUG;
-            break;
-    }
-    virBufferAsprintf(&buf, "%s ", lvl);
-    virBufferVasprintf(&buf, msg_format, ap);
-    virBufferAddChar(&buf, '\n');
-
-    if (virBufferError(&buf))
-        goto error;
-
-    str = virBufferContentAndReset(&buf);
-    len = strlen(str);
-    if (len > 1 && str[len - 2] == '\n') {
-        str[len - 1] = '\0';
-        len--;
-    }
-
-    /* write log */
-    if (safewrite(ctl->log_fd, str, len) < 0)
-        goto error;
-
-    VIR_FREE(str);
-    return;
-
- error:
-    vshCloseLogFile(ctl);
-    vshError(ctl, "%s", _("failed to write the log file"));
-    virBufferFreeAndReset(&buf);
-    VIR_FREE(str);
-}
-
-/**
- * vshCloseLogFile:
- *
- * Close log file.
- */
-void
-vshCloseLogFile(vshControl *ctl)
-{
-    char ebuf[1024];
-
-    /* log file close */
-    if (VIR_CLOSE(ctl->log_fd) < 0) {
-        vshError(ctl, _("%s: failed to write log file: %s"),
-                 ctl->logfile ? ctl->logfile : "?",
-                 virStrerror(errno, ebuf, sizeof(ebuf)));
-    }
-
-    if (ctl->logfile) {
-        VIR_FREE(ctl->logfile);
-        ctl->logfile = NULL;
-    }
-}
-
-#if WITH_READLINE
-
-/* -----------------
- * Readline stuff
- * -----------------
- */
-
-/*
- * Generator function for command completion.  STATE lets us
- * know whether to start from scratch; without any state
- * (i.e. STATE == 0), then we start at the top of the list.
- */
-static char *
-vshReadlineCommandGenerator(const char *text, int state)
-{
-    static int grp_list_index, cmd_list_index, len;
-    const char *name;
-    const vshCmdGrp *grp;
-    const vshCmdDef *cmds;
-
-    if (!state) {
-        grp_list_index = 0;
-        cmd_list_index = 0;
-        len = strlen(text);
-    }
-
-    grp = cmdGroups;
-
-    /* Return the next name which partially matches from the
-     * command list.
-     */
-    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. */
-    return NULL;
-}
-
-static char *
-vshReadlineOptionsGenerator(const char *text, int state)
-{
-    static int list_index, len;
-    static const vshCmdDef *cmd;
-    const char *name;
-
-    if (!state) {
-        /* determine command name */
-        char *p;
-        char *cmdname;
-
-        if (!(p = strchr(rl_line_buffer, ' ')))
-            return NULL;
-
-        cmdname = vshCalloc(NULL, (p - rl_line_buffer) + 1, 1);
-        memcpy(cmdname, rl_line_buffer, p - rl_line_buffer);
-
-        cmd = vshCmddefSearch(cmdname);
-        list_index = 0;
-        len = strlen(text);
-        VIR_FREE(cmdname);
-    }
-
-    if (!cmd)
-        return NULL;
-
-    if (!cmd->opts)
-        return NULL;
-
-    while ((name = cmd->opts[list_index].name)) {
-        const vshCmdOptDef *opt = &cmd->opts[list_index];
-        char *res;
-
-        list_index++;
-
-        if (opt->type == VSH_OT_DATA || opt->type == VSH_OT_ARGV)
-            /* ignore non --option */
-            continue;
-
-        if (len > 2) {
-            if (STRNEQLEN(name, text + 2, len - 2))
-                continue;
-        }
-        res = vshMalloc(NULL, strlen(name) + 3);
-        snprintf(res, strlen(name) + 3,  "--%s", name);
-        return res;
-    }
-
-    /* If no names matched, then return NULL. */
-    return NULL;
-}
-
-static char **
-vshReadlineCompletion(const char *text, int start,
-                      int end ATTRIBUTE_UNUSED)
-{
-    char **matches = (char **) NULL;
-
-    if (start == 0)
-        /* command name generator */
-        matches = rl_completion_matches(text, vshReadlineCommandGenerator);
-    else
-        /* commands options */
-        matches = rl_completion_matches(text, vshReadlineOptionsGenerator);
-    return matches;
-}
-
-# define VIRSH_HISTSIZE_MAX 500000
-
-static int
-vshReadlineInit(vshControl *ctl)
-{
-    char *userdir = NULL;
-    int max_history = 500;
-    const char *histsize_str;
-
-    /* Allow conditional parsing of the ~/.inputrc file.
-     * Work around ancient readline 4.1 (hello Mac OS X),
-     * which declared it as 'char *' instead of 'const char *'.
-     */
-    rl_readline_name = (char *) "virsh";
-
-    /* Tell the completer that we want a crack first. */
-    rl_attempted_completion_function = vshReadlineCompletion;
-
-    /* Limit the total size of the history buffer */
-    if ((histsize_str = virGetEnvBlockSUID("VIRSH_HISTSIZE"))) {
-        if (virStrToLong_i(histsize_str, NULL, 10, &max_history) < 0) {
-            vshError(ctl, "%s", _("Bad $VIRSH_HISTSIZE value."));
-            VIR_FREE(userdir);
-            return -1;
-        } else if (max_history > VIRSH_HISTSIZE_MAX || max_history < 0) {
-            vshError(ctl, _("$VIRSH_HISTSIZE value should be between 0 and %d"),
-                     VIRSH_HISTSIZE_MAX);
-            VIR_FREE(userdir);
-            return -1;
-        }
-    }
-    stifle_history(max_history);
-
-    /* Prepare to read/write history from/to the $XDG_CACHE_HOME/virsh/history file */
-    userdir = virGetUserCacheDirectory();
-
-    if (userdir == NULL) {
-        vshError(ctl, "%s", _("Could not determine home directory"));
-        return -1;
-    }
-
-    if (virAsprintf(&ctl->historydir, "%s/virsh", userdir) < 0) {
-        vshError(ctl, "%s", _("Out of memory"));
-        VIR_FREE(userdir);
-        return -1;
-    }
-
-    if (virAsprintf(&ctl->historyfile, "%s/history", ctl->historydir) < 0) {
-        vshError(ctl, "%s", _("Out of memory"));
-        VIR_FREE(userdir);
-        return -1;
-    }
-
-    VIR_FREE(userdir);
-
-    read_history(ctl->historyfile);
-
-    return 0;
-}
-
-static void
-vshReadlineDeinit(vshControl *ctl)
-{
-    if (ctl->historyfile != NULL) {
-        if (virFileMakePathWithMode(ctl->historydir, 0755) < 0 &&
-            errno != EEXIST) {
-            char ebuf[1024];
-            vshError(ctl, _("Failed to create '%s': %s"),
-                     ctl->historydir, virStrerror(errno, ebuf, sizeof(ebuf)));
-        } else {
-            write_history(ctl->historyfile);
-        }
-    }
-
-    VIR_FREE(ctl->historydir);
-    VIR_FREE(ctl->historyfile);
-}
-
-static char *
-vshReadline(vshControl *ctl ATTRIBUTE_UNUSED, const char *prompt)
-{
-    return readline(prompt);
-}
-
-#else /* !WITH_READLINE */
-
-static int
-vshReadlineInit(vshControl *ctl ATTRIBUTE_UNUSED)
-{
-    /* empty */
-    return 0;
-}
-
-static void
-vshReadlineDeinit(vshControl *ctl ATTRIBUTE_UNUSED)
-{
-    /* empty */
-}
-
-static char *
-vshReadline(vshControl *ctl, const char *prompt)
-{
-    char line[1024];
-    char *r;
-    int len;
-
-    fputs(prompt, stdout);
-    r = fgets(line, sizeof(line), stdin);
-    if (r == NULL) return NULL; /* EOF */
-
-    /* Chomp trailing \n */
-    len = strlen(r);
-    if (len > 0 && r[len-1] == '\n')
-        r[len-1] = '\0';
-
-    return vshStrdup(ctl, r);
-}
-
-#endif /* !WITH_READLINE */
-
-static void
-vshDeinitTimer(int timer ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED)
-{
-    /* nothing to be done here */
-}
-
-/*
- * Deinitialize virsh
- */
-static bool
-vshDeinit(vshControl *ctl)
-{
-    vshReadlineDeinit(ctl);
-    vshCloseLogFile(ctl);
-    VIR_FREE(ctl->name);
-    if (ctl->conn) {
-        int ret;
-        virConnectUnregisterCloseCallback(ctl->conn, vshCatchDisconnect);
-        ret = virConnectClose(ctl->conn);
-        if (ret < 0)
-            vshError(ctl, "%s", _("Failed to disconnect from the hypervisor"));
-        else if (ret > 0)
-            vshError(ctl, "%s", _("One or more references were leaked after "
-                                  "disconnect from the hypervisor"));
-    }
-    virResetLastError();
-
-    if (ctl->eventLoopStarted) {
-        int timer;
-
-        virMutexLock(&ctl->lock);
-        ctl->quit = true;
-        /* HACK: Add a dummy timeout to break event loop */
-        timer = virEventAddTimeout(0, virshDeinitTimer, NULL, NULL);
-        virMutexUnlock(&ctl->lock);
-
-        virThreadJoin(&ctl->eventLoop);
-
-        if (timer != -1)
-            virEventRemoveTimeout(timer);
-
-        if (ctl->eventTimerId != -1)
-            virEventRemoveTimeout(ctl->eventTimerId);
-
-        ctl->eventLoopStarted = false;
-    }
-
-    virMutexDestroy(&ctl->lock);
-
-    return true;
-}
-
-/*
- * Print usage
- */
-static void
-virshUsage(void)
-{
-    const vshCmdGrp *grp;
-    const vshCmdDef *cmd;
-
-    fprintf(stdout, _("\n%s [options]... [<command_string>]"
-                      "\n%s [options]... <command> [args...]\n\n"
-                      "  options:\n"
-                      "    -c | --connect=URI      hypervisor connection URI\n"
-                      "    -d | --debug=NUM        debug level [0-4]\n"
-                      "    -e | --escape <char>    set escape sequence for console\n"
-                      "    -h | --help             this help\n"
-                      "    -k | --keepalive-interval=NUM\n"
-                      "                            keepalive interval in seconds, 0 for disable\n"
-                      "    -K | --keepalive-count=NUM\n"
-                      "                            number of possible missed keepalive messages\n"
-                      "    -l | --log=FILE         output logging to file\n"
-                      "    -q | --quiet            quiet mode\n"
-                      "    -r | --readonly         connect readonly\n"
-                      "    -t | --timing           print timing information\n"
-                      "    -v                      short version\n"
-                      "    -V                      long version\n"
-                      "         --version[=TYPE]   version, TYPE is short or long (default short)\n"
-                      "  commands (non interactive mode):\n\n"), progname, progname);
+    fprintf(stdout, _("\n%s [options]... [<command_string>]"
+                      "\n%s [options]... <command> [args...]\n\n"
+                      "  options:\n"
+                      "    -c | --connect=URI      hypervisor connection URI\n"
+                      "    -d | --debug=NUM        debug level [0-4]\n"
+                      "    -e | --escape <char>    set escape sequence for console\n"
+                      "    -h | --help             this help\n"
+                      "    -k | --keepalive-interval=NUM\n"
+                      "                            keepalive interval in seconds, 0 for disable\n"
+                      "    -K | --keepalive-count=NUM\n"
+                      "                            number of possible missed keepalive messages\n"
+                      "    -l | --log=FILE         output logging to file\n"
+                      "    -q | --quiet            quiet mode\n"
+                      "    -r | --readonly         connect readonly\n"
+                      "    -t | --timing           print timing information\n"
+                      "    -v                      short version\n"
+                      "    -V                      long version\n"
+                      "         --version[=TYPE]   version, TYPE is short or long (default short)\n"
+                      "  commands (non interactive mode):\n\n"), progname,
+            progname);
 
     for (grp = cmdGroups; grp->name; grp++) {
         fprintf(stdout, _(" %s (help keyword '%s')\n"),
@@ -3641,15 +1529,11 @@ main(int argc, char **argv)
 
     virFileActivateDirOverride(argv[0]);
 
-    if (!(progname = strrchr(argv[0], '/')))
-        progname = argv[0];
-    else
-        progname++;
-
     if ((defaultConn = virGetEnvBlockSUID("VIRSH_DEFAULT_CONNECT_URI")))
         ctl->name = vshStrdup(ctl, defaultConn);
 
-    vshInitDebug(ctl);
+    if (vshInit(ctl, &hooks, cmdGroups) < 0)
+        exit(EXIT_FAILURE);
 
     if (!virshParseArgv(ctl, argc, argv) ||
         !virshInit(ctl)) {
@@ -3676,7 +1560,8 @@ main(int argc, char **argv)
         }
 
         do {
-            const char *prompt = ctl->readonly ? VSH_PROMPT_RO : VSH_PROMPT_RW;
+            const char *prompt = virshCtl.readonly ? VIRSH_PROMPT_RO
+                : VIRSH_PROMPT_RW;
             ctl->cmdstr =
                 vshReadline(ctl, prompt);
             if (ctl->cmdstr == NULL)
diff --git a/tools/virsh.h b/tools/virsh.h
index 945eb23..15a938e 100644
--- a/tools/virsh.h
+++ b/tools/virsh.h
@@ -44,141 +44,9 @@
 
 # define VIR_FROM_THIS VIR_FROM_NONE
 
-# define GETTIMEOFDAY(T) gettimeofday(T, NULL)
-
-# define VSH_MATCH(FLAG) (flags & (FLAG))
-
-/**
- * The log configuration
- */
-# define MSG_BUFFER    4096
-# define SIGN_NAME     "virsh"
-# define DIR_MODE      (S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)  /* 0755 */
-# define FILE_MODE     (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)                                /* 0644 */
-# define LOCK_MODE     (S_IWUSR | S_IRUSR)                                                    /* 0600 */
-# define LVL_DEBUG     "DEBUG"
-# define LVL_INFO      "INFO"
-# define LVL_NOTICE    "NOTICE"
-# define LVL_WARNING   "WARNING"
-# define LVL_ERROR     "ERROR"
-
-/**
- * vshErrorLevel:
- *
- * Indicates the level of a log message
- */
-typedef enum {
-    VSH_ERR_DEBUG = 0,
-    VSH_ERR_INFO,
-    VSH_ERR_NOTICE,
-    VSH_ERR_WARNING,
-    VSH_ERR_ERROR
-} vshErrorLevel;
-
-# define VSH_DEBUG_DEFAULT VSH_ERR_ERROR
-
-/*
- * virsh command line grammar:
- *
- *    command_line    =     <command>\n | <command>; <command>; ...
- *
- *    command         =    <keyword> <option> [--] <data>
- *
- *    option          =     <bool_option> | <int_option> | <string_option>
- *    data            =     <string>
- *
- *    bool_option     =     --optionname
- *    int_option      =     --optionname <number> | --optionname=<number>
- *    string_option   =     --optionname <string> | --optionname=<string>
- *
- *    keyword         =     [a-zA-Z][a-zA-Z-]*
- *    number          =     [0-9]+
- *    string          =     ('[^']*'|"([^\\"]|\\.)*"|([^ \t\n\\'"]|\\.))+
- *
- */
-
-/*
- * vshCmdOptType - command option type
- */
-typedef enum {
-    VSH_OT_BOOL,     /* optional boolean option */
-    VSH_OT_STRING,   /* optional string option */
-    VSH_OT_INT,      /* optional or mandatory int option */
-    VSH_OT_DATA,     /* string data (as non-option) */
-    VSH_OT_ARGV,     /* remaining arguments */
-    VSH_OT_ALIAS,    /* alternate spelling for a later argument */
-} vshCmdOptType;
-
 /*
  * Command group types
  */
-
-/*
- * Command Option Flags
- */
-enum {
-    VSH_OFLAG_NONE     = 0,        /* without flags */
-    VSH_OFLAG_REQ      = (1 << 0), /* option required */
-    VSH_OFLAG_EMPTY_OK = (1 << 1), /* empty string option allowed */
-    VSH_OFLAG_REQ_OPT  = (1 << 2), /* --optionname required */
-};
-
-/* forward declarations */
-typedef struct _vshCmd vshCmd;
-typedef struct _vshCmdDef vshCmdDef;
-typedef struct _vshCmdGrp vshCmdGrp;
-typedef struct _vshCmdInfo vshCmdInfo;
-typedef struct _vshCmdOpt vshCmdOpt;
-typedef struct _vshCmdOptDef vshCmdOptDef;
-typedef struct _vshControl vshControl;
-typedef struct _vshCtrlData vshCtrlData;
-
-typedef char **(*vshCompleter)(unsigned int flags);
-
-/*
- * vshCmdInfo -- name/value pair for information about command
- *
- * Commands should have at least the following names:
- * "help" - short description of command
- * "desc" - description of command, or empty string
- */
-struct _vshCmdInfo {
-    const char *name;           /* name of information, or NULL for list end */
-    const char *data;           /* non-NULL information */
-};
-
-/*
- * vshCmdOptDef - command option definition
- */
-struct _vshCmdOptDef {
-    const char *name;           /* the name of option, or NULL for list end */
-    vshCmdOptType type;         /* option type */
-    unsigned int flags;         /* flags */
-    const char *help;           /* non-NULL help string; or for VSH_OT_ALIAS
-                                 * the name of a later public option */
-    vshCompleter completer;         /* option completer */
-    unsigned int completer_flags;   /* option completer flags */
-};
-
-/*
- * vshCmdOpt - command options
- *
- * After parsing a command, all arguments to the command have been
- * collected into a list of these objects.
- */
-struct _vshCmdOpt {
-    const vshCmdOptDef *def;    /* non-NULL pointer to option definition */
-    char *data;                 /* allocated data, or NULL for bool option */
-    vshCmdOpt *next;
-};
-
-/*
- * Command Usage Flags
- */
-enum {
-    VSH_CMD_FLAG_NOCONNECT = (1 << 0),  /* no prior connection needed */
-    VSH_CMD_FLAG_ALIAS     = (1 << 1),  /* command is an alias */
-};
 # define VIRSH_CMD_GRP_DOM_MANAGEMENT   "Domain Management"
 # define VIRSH_CMD_GRP_DOM_MONITORING   "Domain Monitoring"
 # define VIRSH_CMD_GRP_STORAGE_POOL     "Storage Pool"
@@ -192,175 +60,26 @@ enum {
 # define VIRSH_CMD_GRP_HOST_AND_HV      "Host and Hypervisor"
 # define VIRSH_CMD_GRP_VIRSH            "Virsh itself"
 
-/*
- * vshCmdDef - command definition
- */
-struct _vshCmdDef {
-    const char *name;           /* name of command, or NULL for list end */
-    bool (*handler) (vshControl *, const vshCmd *);    /* command handler */
-    const vshCmdOptDef *opts;   /* definition of command options */
-    const vshCmdInfo *info;     /* details about command */
-    unsigned int flags;         /* bitwise OR of VSH_CMD_FLAG */
-};
 
-/*
- * vshCmd - parsed command
- */
-struct _vshCmd {
-    const vshCmdDef *def;       /* command definition */
-    vshCmdOpt *opts;            /* list of command arguments */
-    vshCmd *next;      /* next command */
-};
 
 /*
  * vshControl
  */
-    char *name;                 /* connection name */
 struct _virshControl {
     virConnectPtr conn;         /* connection to hypervisor (MAY BE NULL) */
-    vshCmd *cmd;                /* the current command */
-    char *cmdstr;               /* string with command */
-    bool imode;                 /* interactive mode? */
-    bool quiet;                 /* quiet mode */
-    int debug;                  /* print debug messages? */
-    bool timing;                /* print timing info? */
     bool readonly;              /* connect readonly (first time only, not
                                  * during explicit connect command)
                                  */
-    char *logfile;              /* log file name */
-    int log_fd;                 /* log file descriptor */
-    char *historydir;           /* readline history directory name */
-    char *historyfile;          /* readline history file name */
     bool useGetInfo;            /* must use virDomainGetInfo, since
                                    virDomainGetState is not supported */
     bool useSnapshotOld;        /* cannot use virDomainSnapshotGetParent or
                                    virDomainSnapshotNumChildren */
     bool blockJobNoBytes;       /* true if _BANDWIDTH_BYTE blockjob flags
                                    are missing */
-    virThread eventLoop;
-    virMutex lock;
-    bool eventLoopStarted;
-    bool quit;
-    int eventPipe[2];           /* Write-to-self pipe to end waiting for an
-                                 * event to occur */
-    int eventTimerId;           /* id of event loop timeout registration */
-
     const char *escapeChar;     /* String representation of
                                    console escape character */
-
-    int keepalive_interval;     /* Client keepalive interval */
-    int keepalive_count;        /* Client keepalive count */
-
-# ifndef WIN32
-    struct termios termattr;    /* settings of the tty terminal */
-# endif
-    bool istty;                 /* is the terminal a tty */
-};
-
-struct _vshCmdGrp {
-    const char *name;    /* name of group, or NULL for list end */
-    const char *keyword; /* help keyword */
-    const vshCmdDef *commands;
 };
 
-void vshError(vshControl *ctl, const char *format, ...)
-    ATTRIBUTE_FMT_PRINTF(2, 3);
-void vshOpenLogFile(vshControl *ctl);
-void vshOutputLogFile(vshControl *ctl, int log_level, const char *format,
-                      va_list ap)
-    ATTRIBUTE_FMT_PRINTF(3, 0);
-void vshCloseLogFile(vshControl *ctl);
-
-virConnectPtr vshConnect(vshControl *ctl, const char *uri, bool readonly);
-
-const char *vshCmddefGetInfo(const vshCmdDef *cmd, const char *info);
-const vshCmdDef *vshCmddefSearch(const char *cmdname);
-bool vshCmddefHelp(vshControl *ctl, const char *name);
-const vshCmdGrp *vshCmdGrpSearch(const char *grpname);
-bool vshCmdGrpHelp(vshControl *ctl, const char *name);
-
-int vshCommandOptInt(vshControl *ctl, const vshCmd *cmd,
-                     const char *name, int *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptUInt(vshControl *ctl, const vshCmd *cmd,
-                      const char *name, unsigned int *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptUIntWrap(vshControl *ctl, const vshCmd *cmd,
-                          const char *name, unsigned int *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptUL(vshControl *ctl, const vshCmd *cmd,
-                    const char *name, unsigned long *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptULWrap(vshControl *ctl, const vshCmd *cmd,
-                        const char *name, unsigned long *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptString(vshControl *ctl, const vshCmd *cmd,
-                        const char *name, const char **value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptStringReq(vshControl *ctl, const vshCmd *cmd,
-                           const char *name, const char **value)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptLongLong(vshControl *ctl, const vshCmd *cmd,
-                          const char *name, long long *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptULongLong(vshControl *ctl, const vshCmd *cmd,
-                           const char *name, unsigned long long *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptULongLongWrap(vshControl *ctl, const vshCmd *cmd,
-                               const char *name, unsigned long long *value)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-int vshCommandOptScaledInt(vshControl *ctl, const vshCmd *cmd,
-                           const char *name, unsigned long long *value,
-                           int scale, unsigned long long max)
-    ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
-bool vshCommandOptBool(const vshCmd *cmd, const char *name);
-const vshCmdOpt *vshCommandOptArgv(vshControl *ctl, const vshCmd *cmd,
-                                   const vshCmdOpt *opt);
-int vshCommandOptTimeoutToMs(vshControl *ctl, const vshCmd *cmd, int *timeout);
-
-/* Filter flags for various vshCommandOpt*By() functions */
-typedef enum {
-    VSH_BYID   = (1 << 1),
-    VSH_BYUUID = (1 << 2),
-    VSH_BYNAME = (1 << 3),
-    VSH_BYMAC  = (1 << 4),
-} vshLookupByFlags;
-
-/* Given an index, return either the name of that device (non-NULL) or
- * of its parent (NULL if a root).  */
-typedef const char * (*vshTreeLookup)(int devid, bool parent, void *opaque);
-int vshTreePrint(vshControl *ctl, vshTreeLookup lookup, void *opaque,
-                 int num_devices, int devid);
-
-void vshPrintExtra(vshControl *ctl, const char *format, ...)
-    ATTRIBUTE_FMT_PRINTF(2, 3);
-void vshDebug(vshControl *ctl, int level, const char *format, ...)
-    ATTRIBUTE_FMT_PRINTF(3, 4);
-
-/* XXX: add batch support */
-# define vshPrint(_ctl, ...)   vshPrintExtra(NULL, __VA_ARGS__)
-
-/* User visible sort, so we want locale-specific case comparison.  */
-# define vshStrcasecmp(S1, S2) strcasecmp(S1, S2)
-int vshNameSorter(const void *a, const void *b);
-
-int vshDomainState(vshControl *ctl, virDomainPtr dom, int *reason);
-virTypedParameterPtr vshFindTypedParamByName(const char *name,
-                                             virTypedParameterPtr list,
-                                             int count);
-char *vshGetTypedParamValue(vshControl *ctl, virTypedParameterPtr item)
-    ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
-
-char *vshEditWriteToTempFile(vshControl *ctl, const char *doc);
-int vshEditFile(vshControl *ctl, const char *filename);
-char *vshEditReadBackFile(vshControl *ctl, const char *filename);
-int vshAskReedit(vshControl *ctl, const char *msg, bool relax_avail);
-int vshStreamSink(virStreamPtr st, const char *bytes, size_t nbytes,
-                  void *opaque);
-double vshPrettyCapacity(unsigned long long val, const char **unit);
-int vshStringToArray(const char *str, char ***array);
-
 /* Typedefs, function prototypes for job progress reporting.
  * There are used by some long lingering commands like
  * migrate, dump, save, managedsave.
@@ -372,156 +91,9 @@ struct _virshCtrlData {
     virConnectPtr dconn;
 };
 
-/* error handling */
-extern virErrorPtr last_error;
-void vshReportError(vshControl *ctl);
-void vshResetLibvirtError(void);
-void vshSaveLibvirtError(void);
-
-/* terminal modifications */
-bool vshTTYIsInterruptCharacter(vshControl *ctl, const char chr);
-int vshTTYDisableInterrupt(vshControl *ctl);
-int vshTTYRestore(vshControl *ctl);
-int vshTTYMakeRaw(vshControl *ctl, bool report_errors);
-bool vshTTYAvailable(vshControl *ctl);
-
-/* waiting for events */
-enum {
-    VSH_EVENT_INTERRUPT,
-    VSH_EVENT_TIMEOUT,
-    VSH_EVENT_DONE,
-};
-int vshEventStart(vshControl *ctl, int timeout_ms);
-void vshEventDone(vshControl *ctl);
-int vshEventWait(vshControl *ctl);
-void vshEventCleanup(vshControl *ctl);
-
-/* allocation wrappers */
-void *_vshMalloc(vshControl *ctl, size_t sz, const char *filename, int line);
-# define vshMalloc(_ctl, _sz)    _vshMalloc(_ctl, _sz, __FILE__, __LINE__)
-
-void *_vshCalloc(vshControl *ctl, size_t nmemb, size_t sz,
-                 const char *filename, int line);
-# define vshCalloc(_ctl, _nmemb, _sz) \
-    _vshCalloc(_ctl, _nmemb, _sz, __FILE__, __LINE__)
-
-char *_vshStrdup(vshControl *ctl, const char *s, const char *filename,
-                 int line);
-# define vshStrdup(_ctl, _s)    _vshStrdup(_ctl, _s, __FILE__, __LINE__)
-
-/* Poison the raw allocating identifiers in favor of our vsh variants.  */
-# undef malloc
-# undef calloc
-# undef realloc
-# undef strdup
-# define malloc use_vshMalloc_instead_of_malloc
-# define calloc use_vshCalloc_instead_of_calloc
-# define realloc use_vshRealloc_instead_of_realloc
-# define strdup use_vshStrdup_instead_of_strdup
-
-/* Macros to help dealing with mutually exclusive options. */
-
-/* VSH_EXCLUSIVE_OPTIONS_EXPR:
- *
- * @NAME1: String containing the name of the option.
- * @EXPR1: Expression to validate the variable (boolean variable)
- * @NAME2: String containing the name of the option.
- * @EXPR2: Expression to validate the variable (boolean variable)
- *
- * Reject mutually exclusive command options in virsh. Use the
- * provided expression to check the variables.
- *
- * This helper does an early return and therefore it has to be called
- * before anything that would require cleanup.
- */
-# define VSH_EXCLUSIVE_OPTIONS_EXPR(NAME1, EXPR1, NAME2, EXPR2)             \
-    if ((EXPR1) && (EXPR2)) {                                               \
-        vshError(ctl, _("Options --%s and --%s are mutually exclusive"),    \
-                 NAME1, NAME2);                                             \
-        return false;                                                       \
-    }
-
-/* VSH_EXCLUSIVE_OPTIONS:
- *
- * @NAME1: String containing the name of the option.
- * @NAME2: String containing the name of the option.
- *
- * Reject mutually exclusive command options in virsh. Use the
- * vshCommandOptBool call to request them.
- *
- * This helper does an early return and therefore it has to be called
- * before anything that would require cleanup.
- */
-# define VSH_EXCLUSIVE_OPTIONS(NAME1, NAME2)                                \
-    VSH_EXCLUSIVE_OPTIONS_EXPR(NAME1, vshCommandOptBool(cmd, NAME1),        \
-                               NAME2, vshCommandOptBool(cmd, NAME2))
 
-/* VSH_EXCLUSIVE_OPTIONS_VAR:
- *
- * @VARNAME1: Boolean variable containing the value of the option of same name
- * @VARNAME2: Boolean variable containing the value of the option of same name
- *
- * Reject mutually exclusive command options in virsh. Check in variables that
- * contain the value and have same name as the option.
- *
- * This helper does an early return and therefore it has to be called
- * before anything that would require cleanup.
- */
-# define VSH_EXCLUSIVE_OPTIONS_VAR(VARNAME1, VARNAME2)                      \
-    VSH_EXCLUSIVE_OPTIONS_EXPR(#VARNAME1, VARNAME1, #VARNAME2, VARNAME2)
 
-/* Macros to help dealing with required options. */
 
-/* VSH_REQUIRE_OPTION_EXPR:
- *
- * @NAME1: String containing the name of the option.
- * @EXPR1: Expression to validate the variable (boolean variable).
- * @NAME2: String containing the name of required option.
- * @EXPR2: Expression to validate the variable (boolean variable).
- *
- * Check if required command options in virsh was set.  Use the
- * provided expression to check the variables.
- *
- * This helper does an early return and therefore it has to be called
- * before anything that would require cleanup.
- */
-# define VSH_REQUIRE_OPTION_EXPR(NAME1, EXPR1, NAME2, EXPR2)                \
-    do {                                                                    \
-        if ((EXPR1) && !(EXPR2)) {                                          \
-            vshError(ctl, _("Option --%s is required by option --%s"),      \
-                     NAME2, NAME1);                                         \
-            return false;                                                   \
-        }                                                                   \
-    } while (0)
-
-/* VSH_REQUIRE_OPTION:
- *
- * @NAME1: String containing the name of the option.
- * @NAME2: String containing the name of required option.
- *
- * Check if required command options in virsh was set.  Use the
- * vshCommandOptBool call to request them.
- *
- * This helper does an early return and therefore it has to be called
- * before anything that would require cleanup.
- */
-# define VSH_REQUIRE_OPTION(NAME1, NAME2)                                   \
-    VSH_REQUIRE_OPTION_EXPR(NAME1, vshCommandOptBool(cmd, NAME1),           \
-                            NAME2, vshCommandOptBool(cmd, NAME2))
 
-/* VSH_REQUIRE_OPTION_VAR:
- *
- * @VARNAME1: Boolean variable containing the value of the option of same name.
- * @VARNAME2: Boolean variable containing the value of required option of
- *            same name.
- *
- * Check if required command options in virsh was set.  Check in variables
- * that contain the value and have same name as the option.
- *
- * This helper does an early return and therefore it has to be called
- * before anything that would require cleanup.
- */
-# define VSH_REQUIRE_OPTION_VAR(VARNAME1, VARNAME2)                         \
-    VSH_REQUIRE_OPTION_EXPR(#VARNAME1, VARNAME1, #VARNAME2, VARNAME2)
 
 #endif /* VIRSH_H */
diff --git a/tools/vsh.c b/tools/vsh.c
index b1d8dbc..71c8344 100644
--- a/tools/vsh.c
+++ b/tools/vsh.c
@@ -1998,7 +1998,7 @@ vshOutputLogFile(vshControl *ctl, int log_level, const char *msg_format,
                       stTm.tm_hour,
                       stTm.tm_min,
                       stTm.tm_sec,
-                      SIGN_NAME,
+                      ctl->progname,
                       (int) getpid());
     switch (log_level) {
         case VSH_ERR_DEBUG:
-- 
1.9.3




More information about the libvir-list mailing list