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