[libvirt] [PATCH v3 3/3] virt-shell: Move generic commands implementation to vsh.c
Erik Skultety
eskultet at redhat.com
Fri Aug 14 13:17:55 UTC 2015
I talked to Martin and Michal about this and I agree with them that
moving the command structures as well as the commands is better idea
than leaving the structures in virsh.c so I'll send a v4 inline patch.
Erik
On 13/08/15 13:39, Erik Skultety wrote:
> Generic commands like 'help', 'cd', 'pwd',etc. can be reused by any
> client, so the clients should profit from this implementation rather
> than providing their own similar implementation (if it's not intensional
> and there's a reason for this)
> ---
> tools/virsh.c | 343 +++++++++++++++-------------------------------------------
> tools/vsh.c | 155 ++++++++++++++++++++++++++
> tools/vsh.h | 7 ++
> 3 files changed, 250 insertions(+), 255 deletions(-)
>
> diff --git a/tools/virsh.c b/tools/virsh.c
> index 2d198cd..e123ea2 100644
> --- a/tools/virsh.c
> +++ b/tools/virsh.c
> @@ -188,79 +188,6 @@ virshReconnect(vshControl *ctl)
> priv->blockJobNoBytes = false;
> }
>
> -
> -/*
> - * "connect" command
> - */
> -static const vshCmdInfo info_connect[] = {
> - {.name = "help",
> - .data = N_("(re)connect to hypervisor")
> - },
> - {.name = "desc",
> - .data = N_("Connect to local hypervisor. This is built-in "
> - "command after shell start up.")
> - },
> - {.name = NULL}
> -};
> -
> -static const vshCmdOptDef opts_connect[] = {
> - {.name = "name",
> - .type = VSH_OT_STRING,
> - .flags = VSH_OFLAG_EMPTY_OK,
> - .help = N_("hypervisor connection URI")
> - },
> - {.name = "readonly",
> - .type = VSH_OT_BOOL,
> - .help = N_("read-only connection")
> - },
> - {.name = NULL}
> -};
> -
> -static bool
> -cmdConnect(vshControl *ctl, const vshCmd *cmd)
> -{
> - bool ro = vshCommandOptBool(cmd, "readonly");
> - const char *name = NULL;
> - virshControlPtr priv = ctl->privData;
> -
> - 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"));
> - priv->conn = NULL;
> - }
> -
> - VIR_FREE(ctl->name);
> - if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
> - return false;
> -
> - ctl->name = vshStrdup(ctl, name);
> -
> - priv->useGetInfo = false;
> - priv->useSnapshotOld = false;
> - priv->blockJobNoBytes = false;
> - priv->readonly = ro;
> -
> - priv->conn = virshConnect(ctl, ctl->name, priv->readonly);
> -
> - if (!priv->conn) {
> - vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
> - return false;
> - }
> -
> - if (virConnectRegisterCloseCallback(priv->conn, virshCatchDisconnect,
> - NULL, NULL) < 0)
> - vshError(ctl, "%s", _("Unable to register disconnect callback"));
> -
> - return true;
> -}
> -
> int virshStreamSink(virStreamPtr st ATTRIBUTE_UNUSED,
> const char *bytes, size_t nbytes, void *opaque)
> {
> @@ -270,13 +197,9 @@ int virshStreamSink(virStreamPtr st ATTRIBUTE_UNUSED,
> }
>
> /* ---------------
> - * Commands
> + * Command Info
> * ---------------
> */
> -
> -/*
> - * "help" command
> - */
> static const vshCmdInfo info_help[] = {
> {.name = "help",
> .data = N_("print help")
> @@ -288,55 +211,6 @@ static const vshCmdInfo info_help[] = {
> {.name = NULL}
> };
>
> -static const vshCmdOptDef opts_help[] = {
> - {.name = "command",
> - .type = VSH_OT_STRING,
> - .help = N_("Prints global help, command specific help, or help for a group of related commands")
> - },
> - {.name = NULL}
> -};
> -
> -static bool
> -cmdHelp(vshControl *ctl, const vshCmd *cmd)
> - {
> - const char *name = NULL;
> -
> - if (vshCommandOptString(ctl, cmd, "command", &name) <= 0) {
> - const vshCmdGrp *grp;
> - const vshCmdDef *def;
> -
> - vshPrint(ctl, "%s", _("Grouped commands:\n\n"));
> -
> - for (grp = cmdGroups; grp->name; grp++) {
> - vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
> - grp->keyword);
> -
> - for (def = grp->commands; def->name; def++) {
> - if (def->flags & VSH_CMD_FLAG_ALIAS)
> - continue;
> - vshPrint(ctl, " %-30s %s\n", def->name,
> - _(vshCmddefGetInfo(def, "help")));
> - }
> -
> - vshPrint(ctl, "\n");
> - }
> -
> - return true;
> - }
> -
> - if (vshCmddefSearch(name)) {
> - return vshCmddefHelp(ctl, name);
> - } else if (vshCmdGrpSearch(name)) {
> - return vshCmdGrpHelp(ctl, name);
> - } else {
> - vshError(ctl, _("command or command group '%s' doesn't exist"), name);
> - return false;
> - }
> -}
> -
> -/*
> - * "cd" command
> - */
> static const vshCmdInfo info_cd[] = {
> {.name = "help",
> .data = N_("change the current directory")
> @@ -347,45 +221,6 @@ static const vshCmdInfo info_cd[] = {
> {.name = NULL}
> };
>
> -static const vshCmdOptDef opts_cd[] = {
> - {.name = "dir",
> - .type = VSH_OT_STRING,
> - .help = N_("directory to switch to (default: home or else root)")
> - },
> - {.name = NULL}
> -};
> -
> -static bool
> -cmdCd(vshControl *ctl, const vshCmd *cmd)
> -{
> - const char *dir = NULL;
> - char *dir_malloced = NULL;
> - bool ret = true;
> - char ebuf[1024];
> -
> - if (!ctl->imode) {
> - vshError(ctl, "%s", _("cd: command valid only in interactive mode"));
> - return false;
> - }
> -
> - if (vshCommandOptString(ctl, cmd, "dir", &dir) <= 0)
> - dir = dir_malloced = virGetUserDirectory();
> - if (!dir)
> - dir = "/";
> -
> - if (chdir(dir) == -1) {
> - vshError(ctl, _("cd: %s: %s"),
> - virStrerror(errno, ebuf, sizeof(ebuf)), dir);
> - ret = false;
> - }
> -
> - VIR_FREE(dir_malloced);
> - return ret;
> -}
> -
> -/*
> - * "pwd" command
> - */
> static const vshCmdInfo info_pwd[] = {
> {.name = "help",
> .data = N_("print the current directory")
> @@ -396,29 +231,6 @@ static const vshCmdInfo info_pwd[] = {
> {.name = NULL}
> };
>
> -static bool
> -cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
> -{
> - char *cwd;
> - bool ret = true;
> - char ebuf[1024];
> -
> - cwd = getcwd(NULL, 0);
> - if (!cwd) {
> - vshError(ctl, _("pwd: cannot get current directory: %s"),
> - virStrerror(errno, ebuf, sizeof(ebuf)));
> - ret = false;
> - } else {
> - vshPrint(ctl, _("%s\n"), cwd);
> - VIR_FREE(cwd);
> - }
> -
> - return ret;
> -}
> -
> -/*
> - * "echo" command
> - */
> static const vshCmdInfo info_echo[] = {
> {.name = "help",
> .data = N_("echo arguments")
> @@ -429,6 +241,47 @@ static const vshCmdInfo info_echo[] = {
> {.name = NULL}
> };
>
> +static const vshCmdInfo info_quit[] = {
> + {.name = "help",
> + .data = N_("quit this interactive terminal")
> + },
> + {.name = "desc",
> + .data = ""
> + },
> + {.name = NULL}
> +};
> +
> +static const vshCmdInfo info_connect[] = {
> + {.name = "help",
> + .data = N_("(re)connect to hypervisor")
> + },
> + {.name = "desc",
> + .data = N_("Connect to local hypervisor. This is built-in "
> + "command after shell start up.")
> + },
> + {.name = NULL}
> +};
> +
> +/* ---------------
> + * Command Opts
> + * ---------------
> + */
> +static const vshCmdOptDef opts_help[] = {
> + {.name = "command",
> + .type = VSH_OT_STRING,
> + .help = N_("Prints global help, command specific help, or help for a group of related commands")
> + },
> + {.name = NULL}
> +};
> +
> +static const vshCmdOptDef opts_cd[] = {
> + {.name = "dir",
> + .type = VSH_OT_STRING,
> + .help = N_("directory to switch to (default: home or else root)")
> + },
> + {.name = NULL}
> +};
> +
> static const vshCmdOptDef opts_echo[] = {
> {.name = "shell",
> .type = VSH_OT_BOOL,
> @@ -453,80 +306,61 @@ static const vshCmdOptDef opts_echo[] = {
> {.name = NULL}
> };
>
> -/* Exists mainly for debugging virsh, but also handy for adding back
> - * quotes for later evaluation.
> - */
> +static const vshCmdOptDef opts_connect[] = {
> + {.name = "name",
> + .type = VSH_OT_STRING,
> + .flags = VSH_OFLAG_EMPTY_OK,
> + .help = N_("hypervisor connection URI")
> + },
> + {.name = "readonly",
> + .type = VSH_OT_BOOL,
> + .help = N_("read-only connection")
> + },
> + {.name = NULL}
> +};
> +
> static bool
> -cmdEcho(vshControl *ctl, const vshCmd *cmd)
> +cmdConnect(vshControl *ctl, const vshCmd *cmd)
> {
> - bool shell = false;
> - bool xml = false;
> - int count = 0;
> - const vshCmdOpt *opt = NULL;
> - char *arg;
> - virBuffer buf = VIR_BUFFER_INITIALIZER;
> -
> - if (vshCommandOptBool(cmd, "shell"))
> - shell = true;
> - if (vshCommandOptBool(cmd, "xml"))
> - xml = true;
> -
> - while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
> - char *str;
> - virBuffer xmlbuf = VIR_BUFFER_INITIALIZER;
> -
> - arg = opt->data;
> -
> - if (count)
> - virBufferAddChar(&buf, ' ');
> -
> - if (xml) {
> - virBufferEscapeString(&xmlbuf, "%s", arg);
> - if (virBufferError(&xmlbuf)) {
> - vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
> - return false;
> - }
> - str = virBufferContentAndReset(&xmlbuf);
> - } else {
> - str = vshStrdup(ctl, arg);
> - }
> + bool ro = vshCommandOptBool(cmd, "readonly");
> + const char *name = NULL;
> + virshControlPtr priv = ctl->privData;
>
> - if (shell)
> - virBufferEscapeShell(&buf, str);
> - else
> - virBufferAdd(&buf, str, -1);
> - count++;
> - VIR_FREE(str);
> + 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"));
> + priv->conn = NULL;
> }
>
> - if (virBufferError(&buf)) {
> - vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
> + VIR_FREE(ctl->connname);
> + if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
> + return false;
> +
> + ctl->connname = vshStrdup(ctl, name);
> +
> + priv->useGetInfo = false;
> + priv->useSnapshotOld = false;
> + priv->blockJobNoBytes = false;
> + priv->readonly = ro;
> +
> + priv->conn = virshConnect(ctl, ctl->connname, priv->readonly);
> +
> + if (!priv->conn) {
> + vshError(ctl, "%s", _("Failed to connect to the hypervisor"));
> return false;
> }
> - arg = virBufferContentAndReset(&buf);
> - if (arg)
> - vshPrint(ctl, "%s", arg);
> - VIR_FREE(arg);
> - return true;
> -}
>
> -/*
> - * "quit" command
> - */
> -static const vshCmdInfo info_quit[] = {
> - {.name = "help",
> - .data = N_("quit this interactive terminal")
> - },
> - {.name = "desc",
> - .data = ""
> - },
> - {.name = NULL}
> -};
> + if (virConnectRegisterCloseCallback(priv->conn, virshCatchDisconnect,
> + NULL, NULL) < 0)
> + vshError(ctl, "%s", _("Unable to register disconnect callback"));
>
> -static bool
> -cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
> -{
> - ctl->imode = false;
> return true;
> }
>
> @@ -535,7 +369,6 @@ cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
> * ---------------
> */
>
> -
> static bool
> virshConnectionUsability(vshControl *ctl, virConnectPtr conn)
> {
> diff --git a/tools/vsh.c b/tools/vsh.c
> index 043d0fb..084cac5 100644
> --- a/tools/vsh.c
> +++ b/tools/vsh.c
> @@ -2748,3 +2748,158 @@ vshDeinit(vshControl *ctl)
> vshReadlineDeinit(ctl);
> vshCloseLogFile(ctl);
> }
> +
> +/* -----------------------------------------------
> + * Generic commands available to use by any client
> + * -----------------------------------------------
> + */
> +
> +bool
> +cmdHelp(vshControl *ctl, const vshCmd *cmd)
> + {
> + const char *name = NULL;
> +
> + if (vshCommandOptString(ctl, cmd, "command", &name) <= 0) {
> + const vshCmdGrp *grp;
> + const vshCmdDef *def;
> +
> + vshPrint(ctl, "%s", _("Grouped commands:\n\n"));
> +
> + for (grp = cmdGroups; grp->name; grp++) {
> + vshPrint(ctl, _(" %s (help keyword '%s'):\n"), grp->name,
> + grp->keyword);
> +
> + for (def = grp->commands; def->name; def++) {
> + if (def->flags & VSH_CMD_FLAG_ALIAS)
> + continue;
> + vshPrint(ctl, " %-30s %s\n", def->name,
> + _(vshCmddefGetInfo(def, "help")));
> + }
> +
> + vshPrint(ctl, "\n");
> + }
> +
> + return true;
> + }
> +
> + if (vshCmddefSearch(name)) {
> + return vshCmddefHelp(ctl, name);
> + } else if (vshCmdGrpSearch(name)) {
> + return vshCmdGrpHelp(ctl, name);
> + } else {
> + vshError(ctl, _("command or command group '%s' doesn't exist"), name);
> + return false;
> + }
> +}
> +
> +bool
> +cmdCd(vshControl *ctl, const vshCmd *cmd)
> +{
> + const char *dir = NULL;
> + char *dir_malloced = NULL;
> + bool ret = true;
> + char ebuf[1024];
> +
> + if (!ctl->imode) {
> + vshError(ctl, "%s", _("cd: command valid only in interactive mode"));
> + return false;
> + }
> +
> + if (vshCommandOptString(ctl, cmd, "dir", &dir) <= 0)
> + dir = dir_malloced = virGetUserDirectory();
> + if (!dir)
> + dir = "/";
> +
> + if (chdir(dir) == -1) {
> + vshError(ctl, _("cd: %s: %s"),
> + virStrerror(errno, ebuf, sizeof(ebuf)), dir);
> + ret = false;
> + }
> +
> + VIR_FREE(dir_malloced);
> + return ret;
> +}
> +
> +/* Exists mainly for debugging virsh, but also handy for adding back
> + * quotes for later evaluation.
> + */
> +bool
> +cmdEcho(vshControl *ctl, const vshCmd *cmd)
> +{
> + bool shell = false;
> + bool xml = false;
> + int count = 0;
> + const vshCmdOpt *opt = NULL;
> + char *arg;
> + virBuffer buf = VIR_BUFFER_INITIALIZER;
> +
> + if (vshCommandOptBool(cmd, "shell"))
> + shell = true;
> + if (vshCommandOptBool(cmd, "xml"))
> + xml = true;
> +
> + while ((opt = vshCommandOptArgv(ctl, cmd, opt))) {
> + char *str;
> + virBuffer xmlbuf = VIR_BUFFER_INITIALIZER;
> +
> + arg = opt->data;
> +
> + if (count)
> + virBufferAddChar(&buf, ' ');
> +
> + if (xml) {
> + virBufferEscapeString(&xmlbuf, "%s", arg);
> + if (virBufferError(&xmlbuf)) {
> + vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
> + return false;
> + }
> + str = virBufferContentAndReset(&xmlbuf);
> + } else {
> + str = vshStrdup(ctl, arg);
> + }
> +
> + if (shell)
> + virBufferEscapeShell(&buf, str);
> + else
> + virBufferAdd(&buf, str, -1);
> + count++;
> + VIR_FREE(str);
> + }
> +
> + if (virBufferError(&buf)) {
> + vshPrint(ctl, "%s", _("Failed to allocate XML buffer"));
> + return false;
> + }
> + arg = virBufferContentAndReset(&buf);
> + if (arg)
> + vshPrint(ctl, "%s", arg);
> + VIR_FREE(arg);
> + return true;
> +}
> +
> +bool
> +cmdPwd(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
> +{
> + char *cwd;
> + bool ret = true;
> + char ebuf[1024];
> +
> + cwd = getcwd(NULL, 0);
> + if (!cwd) {
> + vshError(ctl, _("pwd: cannot get current directory: %s"),
> + virStrerror(errno, ebuf, sizeof(ebuf)));
> + ret = false;
> + } else {
> + vshPrint(ctl, _("%s\n"), cwd);
> + VIR_FREE(cwd);
> + }
> +
> + return ret;
> +}
> +
> +bool
> +cmdQuit(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
> +{
> + ctl->imode = false;
> + return true;
> +}
> diff --git a/tools/vsh.h b/tools/vsh.h
> index 19862d0..cbc3455 100644
> --- a/tools/vsh.h
> +++ b/tools/vsh.h
> @@ -363,6 +363,13 @@ int vshEventStart(vshControl *ctl, int timeout_ms);
> void vshEventTimeout(int timer, void *opaque);
> int vshEventWait(vshControl *ctl);
>
> +/* generic commands */
> +bool cmdHelp(vshControl *ctl, const vshCmd *cmd);
> +bool cmdCd(vshControl *ctl, const vshCmd *cmd);
> +bool cmdEcho(vshControl *ctl, const vshCmd *cmd);
> +bool cmdPwd(vshControl *ctl, const vshCmd *cmd);
> +bool cmdQuit(vshControl *ctl, const vshCmd *cmd);
> +
> /* readline */
> char * vshReadline(vshControl *ctl, const char *prompt);
>
>
More information about the libvir-list
mailing list