[libvirt] [PATCH 2/9] virt-admin: Introduce first working skeleton

Michal Privoznik mprivozn at redhat.com
Wed Oct 14 11:25:13 UTC 2015


On 13.10.2015 15:38, Erik Skultety wrote:
> This patch introduces virt-admin client which is based on virsh client,
> but had to reimplement several methods to meet virt-admin specific needs
> or remove unnecessary virsh specific logic.
> ---
>  .gitignore                      |   1 +
>  daemon/libvirtd.c               |   3 +-
>  include/libvirt/libvirt-admin.h |   1 +
>  po/POTFILES.in                  |   1 +
>  src/libvirt-admin.c             |  31 +++
>  src/libvirt_admin_public.syms   |   1 +
>  tools/Makefile.am               |  28 +-
>  tools/virt-admin.c              | 604 ++++++++++++++++++++++++++++++++++++++++
>  tools/virt-admin.h              |  71 +++++
>  9 files changed, 737 insertions(+), 4 deletions(-)
>  create mode 100644 tools/virt-admin.c
>  create mode 100644 tools/virt-admin.h
> 
> diff --git a/.gitignore b/.gitignore
> index 2d52a8f..a776947 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -176,6 +176,7 @@
>  /tools/virt-login-shell
>  /tools/virsh
>  /tools/virsh-*-edit.c
> +/tools/virt-admin
>  /tools/virt-*-validate
>  /tools/virt-sanlock-cleanup
>  /tools/wireshark/src/plugin.c
> diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
> index 250094b..8734f93 100644
> --- a/daemon/libvirtd.c
> +++ b/daemon/libvirtd.c
> @@ -522,8 +522,7 @@ daemonSetupNetworking(virNetServerPtr srv,
>          virNetServerAddService(srv, svcRO, NULL) < 0)
>          goto cleanup;
>  
> -    /* Temporarily disabled */
> -    if (sock_path_adm && false) {
> +    if (sock_path_adm) {
>          VIR_DEBUG("Registering unix socket %s", sock_path_adm);
>          if (!(svcAdm = virNetServerServiceNewUNIX(sock_path_adm,
>                                                    unix_sock_adm_mask,
> diff --git a/include/libvirt/libvirt-admin.h b/include/libvirt/libvirt-admin.h
> index 9997cc2..72671c6 100644
> --- a/include/libvirt/libvirt-admin.h
> +++ b/include/libvirt/libvirt-admin.h
> @@ -52,6 +52,7 @@ virAdmConnectPtr virAdmConnectOpen(const char *name, unsigned int flags);
>  int virAdmConnectClose(virAdmConnectPtr conn);
>  
>  int virAdmConnectRef(virAdmConnectPtr conn);
> +int virAdmConnectIsAlive(virAdmConnectPtr conn);

I'd split new API introduction into a separate commit. But that's not a
show stopper.

>  
>  # ifdef __cplusplus
>  }
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index 0cc5b99..d0840f4 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -270,6 +270,7 @@ tools/virsh-pool.c
>  tools/virsh-secret.c
>  tools/virsh-snapshot.c
>  tools/virsh-volume.c
> +tools/virt-admin.c
>  tools/virt-host-validate-common.c
>  tools/virt-host-validate-lxc.c
>  tools/virt-host-validate-qemu.c
> diff --git a/src/libvirt-admin.c b/src/libvirt-admin.c
> index 5a4fc48..f0824dd 100644
> --- a/src/libvirt-admin.c
> +++ b/src/libvirt-admin.c
> @@ -386,3 +386,34 @@ virAdmConnectRef(virAdmConnectPtr conn)
>  
>      return 0;
>  }
> +
> +/**
> + * virAdmConnectIsAlive:
> + * @conn: connection to admin server
> + *
> + * Decide whether the connection to the admin server is alive or not.
> + * Connection is considered alive if the channel it is running over is not
> + * closed.
> + *
> + * Returns 1, if the connection is alive, 0 if the channel has already
> + * been closed.
> + */
> +int
> +virAdmConnectIsAlive(virAdmConnectPtr conn)
> +{
> +    bool ret;
> +    remoteAdminPrivPtr priv = conn->privateData;
> +
> +    VIR_DEBUG("conn=%p", conn);
> +
> +    virResetLastError();
> +
> +    virObjectLock(priv);
> +    ret = virNetClientIsOpen(priv->client);
> +    virObjectUnlock(priv);
> +
> +    if (ret)
> +        return 1;
> +    else
> +        return 0;
> +}
> diff --git a/src/libvirt_admin_public.syms b/src/libvirt_admin_public.syms
> index d9e3c0b..16cfd42 100644
> --- a/src/libvirt_admin_public.syms
> +++ b/src/libvirt_admin_public.syms
> @@ -15,4 +15,5 @@ LIBVIRT_ADMIN_1.3.0 {
>          virAdmConnectOpen;
>          virAdmConnectClose;
>          virAdmConnectRef;
> +        virAdmConnectIsAlive;
>  };
> diff --git a/tools/Makefile.am b/tools/Makefile.am
> index d5638d9..e68fe84 100644
> --- a/tools/Makefile.am
> +++ b/tools/Makefile.am
> @@ -1,4 +1,4 @@
> -## Copyright (C) 2005-2014 Red Hat, Inc.
> +## Copyright (C) 2005-2015 Red Hat, Inc.
>  ##
>  ## This library is free software; you can redistribute it and/or
>  ## modify it under the terms of the GNU Lesser General Public
> @@ -63,7 +63,7 @@ confdir = $(sysconfdir)/libvirt
>  conf_DATA =
>  
>  bin_SCRIPTS = virt-xml-validate virt-pki-validate
> -bin_PROGRAMS = virsh virt-host-validate
> +bin_PROGRAMS = virsh virt-host-validate virt-admin
>  libexec_SCRIPTS = libvirt-guests.sh
>  
>  if WITH_SANLOCK
> @@ -230,6 +230,30 @@ virsh_CFLAGS =							\
>  		$(PIE_CFLAGS)					\
>  		$(COVERAGE_CFLAGS)				\
>  		$(LIBXML_CFLAGS)
> +
> +virt_admin_SOURCES =					\
> +		virt-admin.c virt-admin.h		\
> +		$(NULL)
> +
> +virt_admin_LDFLAGS =					\
> +		$(AM_LDFLAGS)					\
> +		$(COVERAGE_LDFLAGS)				\
> +		$(NULL)
> +virt_admin_LDADD =						\
> +		$(STATIC_BINARIES)				\
> +		$(PIE_LDFLAGS)					\
> +		../src/libvirt.la				\
> +		../src/libvirt-admin.la			\
> +		../gnulib/lib/libgnu.la			\
> +		libvirt_shell.la				\
> +		$(LIBXML_LIBS)					\
> +		$(NULL)
> +virt_admin_CFLAGS =						\
> +		$(WARN_CFLAGS)					\
> +		$(PIE_CFLAGS)					\
> +		$(COVERAGE_CFLAGS)				\
> +		$(LIBXML_CFLAGS)				\
> +		$(READLINE_CFLAGS)
>  BUILT_SOURCES =
>  
>  if WITH_WIN_ICON
> diff --git a/tools/virt-admin.c b/tools/virt-admin.c
> new file mode 100644
> index 0000000..4964e3d
> --- /dev/null
> +++ b/tools/virt-admin.c
> @@ -0,0 +1,604 @@
> +/*
> + * virt-admin.c: a shell to exercise the libvirt admin API
> + *
> + * Copyright (C) 2015 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Daniel Veillard <veillard at redhat.com>
> + * Karel Zak <kzak at redhat.com>
> + * Daniel P. Berrange <berrange at redhat.com>

I did not know that Karel or Daniel contributed to the new file ...

> + */
> +
> +#include <config.h>
> +#include "virt-admin.h"
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <stdarg.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <getopt.h>
> +#include <sys/time.h>
> +#include <fcntl.h>
> +#include <locale.h>
> +#include <time.h>
> +#include <limits.h>
> +#include <sys/stat.h>
> +#include <inttypes.h>
> +#include <signal.h>

This seems like a lot of includes ...

> +
> +#if WITH_READLINE
> +# include <readline/readline.h>
> +# include <readline/history.h>
> +#endif
> +
> +#include "internal.h"
> +#include "virerror.h"
> +#include "virbuffer.h"
> +#include "viralloc.h"
> +#include <libvirt/libvirt-qemu.h>
> +#include <libvirt/libvirt-lxc.h>

We are certainly not going to need libvirt-qemu nor libvirt-lxc here.

> +#include "virfile.h"
> +#include "configmake.h"
> +#include "virthread.h"
> +#include "virtypedparam.h"
> +#include "virstring.h"
> +
> +/* Gnulib doesn't guarantee SA_SIGINFO support.  */
> +#ifndef SA_SIGINFO
> +# define SA_SIGINFO 0
> +#endif
> +
> +#define VIRT_ADMIN_PROMPT "virt-admin # "
> +
> +#define vshAdmDisconnect(ctl, conn) vshAdmDisconnectInternal(ctl, &conn);
> +
> +static char *progname;
> +
> +static const vshCmdGrp cmdGroups[];
> +static const vshClientHooks hooks;
> +
> +/*
> + * Detection of disconnections and automatic reconnection support
> + */
> +static int disconnected; /* we may have been disconnected */

This is used as boolean. s/int/bool/.

> +
> +static virAdmConnectPtr
> +vshAdmConnect(vshControl *ctl, unsigned int flags)
> +{
> +    vshAdmControlPtr priv = ctl->privData;
> +
> +    priv->conn = virAdmConnectOpen(ctl->connname, flags);
> +
> +    if (!priv->conn) {
> +        if (priv->wantReconnect)
> +            vshError(ctl, "%s", _("Failed to reconnect to the admin server"));
> +        else
> +            vshError(ctl, "%s", _("Failed to connect to the admin server"));
> +        return NULL;
> +    } else {
> +        if (priv->wantReconnect)
> +            vshPrint(ctl, "%s\n", _("Reconnected to the admin server"));
> +        else
> +            vshPrint(ctl, "%s\n", _("Connected to the admin server"));
> +    }
> +
> +    return priv->conn;
> +}
> +
> +static int
> +vshAdmDisconnectInternal(vshControl *ctl, virAdmConnectPtr *conn)
> +{
> +    int ret = 0;
> +
> +    if (!*conn)
> +        return ret;
> +
> +    ret = virAdmConnectClose(*conn);
> +    if (ret < 0)
> +        vshError(ctl, "%s", _("Failed to disconnect from the admin server"));
> +    else if (ret > 0)
> +        vshError(ctl, "%s", _("One or more references were leaked after "
> +                              "disconnect from the hypervisor"));
> +    *conn = NULL;
> +    return ret;
> +}
> +
> +/*
> + * vshAdmReconnect:
> + *
> + * Reconnect to a daemon's admin server
> + *
> + */
> +static void
> +vshAdmReconnect(vshControl *ctl)
> +{
> +    vshAdmControlPtr priv = ctl->privData;
> +    if (priv->conn || disconnected)
> +        priv->wantReconnect = true;
> +
> +    vshAdmDisconnect(ctl, priv->conn);
> +    priv->conn = vshAdmConnect(ctl, 0);
> +
> +    priv->wantReconnect = false;
> +    disconnected = 0;
> +}
> +
> +/* ---------------
> + * Command Connect
> + * ---------------
> + */
> +
> +static const vshCmdOptDef opts_connect[] = {
> +    {.name = "name",
> +     .type = VSH_OT_STRING,
> +     .flags = VSH_OFLAG_EMPTY_OK,
> +     .help = N_("daemon's admin server connection URI")
> +    },
> +    {.name = NULL}
> +};
> +
> +static const vshCmdInfo info_connect[] = {
> +    {.name = "help",
> +     .data = N_("(re)connect to daemon's admin server")
> +    },
> +    {.name = "desc",
> +     .data = N_("Connect to daemon's administrating server. Note that having "
> +                "an invalid or no connection causes the 'connect' command to be "
> +                "automatically invoked using the default URI when a command "
> +                "which requires an active connection is executed.")
> +    },
> +    {.name = NULL}
> +};
> +
> +static bool
> +cmdConnect(vshControl *ctl, const vshCmd *cmd)
> +{
> +    const char *name = NULL;
> +    vshAdmControlPtr priv = ctl->privData;
> +
> +    VIR_FREE(ctl->connname);
> +    if (vshCommandOptStringReq(ctl, cmd, "name", &name) < 0)
> +        return false;
> +
> +    ctl->connname = vshStrdup(ctl, name);
> +
> +    vshAdmReconnect(ctl);
> +    if (!priv->conn)
> +        return false;
> +
> +    return true;
> +}
> +
> +static void *
> +vshAdmConnectionHandler(vshControl *ctl)
> +{
> +    vshAdmControlPtr priv = ctl->privData;
> +
> +    if (!priv->conn || disconnected)
> +        vshAdmReconnect(ctl);
> +
> +    if (!priv->conn || !virAdmConnectIsAlive(priv->conn)) {
> +        vshError(ctl, "%s", _("no valid connection"));
> +        return NULL;
> +    }
> +
> +    return priv->conn;
> +}
> +
> +/*
> + * Initialize connection.
> + */
> +static bool
> +vshAdmInit(vshControl *ctl)
> +{
> +    vshAdmControlPtr priv = ctl->privData;
> +
> +    /* Since we have the commandline arguments parsed, we need to
> +     * reload our initial settings to make debugging and readline
> +     * work properly */
> +    vshInitReload(ctl);
> +
> +    if (priv->conn)
> +        return false;
> +
> +    /* set up the library error handler */
> +    virSetErrorFunc(NULL, vshErrorHandler);
> +
> +    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->connname) {
> +        vshAdmReconnect(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;
> +}
> +
> +static void
> +vshAdmDeinitTimer(int timer ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED)
> +{
> +    /* nothing to be done here */
> +}
> +
> +/*
> + * Deinitialize virt-admin
> + */
> +static bool
> +vshAdmDeinit(vshControl *ctl)
> +{
> +    vshAdmControlPtr priv = ctl->privData;
> +
> +    vshDeinit(ctl);
> +    VIR_FREE(ctl->connname);
> +
> +    if (priv->conn)
> +        vshAdmDisconnect(ctl, priv->conn);
> +
> +    virResetLastError();
> +
> +    if (ctl->eventLoopStarted) {
> +        int timer;
> +
> +        virMutexLock(&ctl->lock);
> +        ctl->quit = true;
> +        /* HACK: Add a dummy timeout to break event loop */
> +        timer = virEventAddTimeout(0, vshAdmDeinitTimer, 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
> +vshAdmUsage(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      daemon admin connection URI\n"
> +                      "    -d | --debug=NUM        debug level [0-4]\n"
> +                      "    -h | --help             this help\n"
> +                      "    -l | --log=FILE         output logging to file\n"
> +                      "    -q | --quiet            quiet mode\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"),
> +                grp->name, grp->keyword);
> +        for (cmd = grp->commands; cmd->name; cmd++) {
> +            if (cmd->flags & VSH_CMD_FLAG_ALIAS)
> +                continue;
> +            fprintf(stdout,
> +                    "    %-30s %s\n", cmd->name,
> +                    _(vshCmddefGetInfo(cmd, "help")));
> +        }
> +        fprintf(stdout, "\n");
> +    }
> +
> +    fprintf(stdout, "%s",
> +            _("\n  (specify help <group> for details about the commands in the group)\n"));
> +    fprintf(stdout, "%s",
> +            _("\n  (specify help <command> for details about the command)\n\n"));
> +    return;
> +}
> +
> +/*
> + * Show version and options compiled in
> + */
> +static void
> +vshAdmShowVersion(vshControl *ctl ATTRIBUTE_UNUSED)
> +{
> +    /* FIXME - list a copyright blurb, as in GNU programs?  */
> +    vshPrint(ctl, _("Virt-admin command line tool of libvirt %s\n"), VERSION);
> +    vshPrint(ctl, _("See web site at %s\n\n"), "http://libvirt.org/");
> +
> +    vshPrint(ctl, "%s", _("Compiled with support for:\n"));
> +    vshPrint(ctl, "\n");
> +    vshPrint(ctl, "%s", _(" Miscellaneous:"));
> +#ifdef WITH_LIBVIRTD
> +    vshPrint(ctl, " Daemon");
> +#endif
> +#ifdef WITH_SECDRIVER_APPARMOR
> +    vshPrint(ctl, " AppArmor");
> +#endif
> +#ifdef WITH_SECDRIVER_SELINUX
> +    vshPrint(ctl, " SELinux");
> +#endif
> +#ifdef ENABLE_DEBUG
> +    vshPrint(ctl, " Debug");
> +#endif
> +#if WITH_READLINE
> +    vshPrint(ctl, " Readline");
> +#endif
> +#ifdef WITH_DRIVER_MODULES
> +    vshPrint(ctl, " Modular");
> +#endif
> +    vshPrint(ctl, "\n");
> +}
> +
> +static bool
> +vshAdmParseArgv(vshControl *ctl, int argc, char **argv)
> +{
> +    int arg, debug;
> +    size_t i;
> +    int longindex = -1;
> +    struct option opt[] = {
> +        {"connect", required_argument, NULL, 'c'},
> +        {"debug", required_argument, NULL, 'd'},
> +        {"help", no_argument, NULL, 'h'},
> +        {"log", required_argument, NULL, 'l'},
> +        {"quiet", no_argument, NULL, 'q'},
> +        {"version", optional_argument, NULL, 'v'},
> +        {NULL, 0, NULL, 0}
> +    };
> +
> +    /* Standard (non-command) options. The leading + ensures that no
> +     * argument reordering takes place, so that command options are
> +     * not confused with top-level virt-admin options. */
> +    while ((arg = getopt_long(argc, argv, "+:c:d:e:h:l:qvV", opt, &longindex)) != -1) {
> +        switch (arg) {
> +        case 'c':
> +            VIR_FREE(ctl->connname);
> +            ctl->connname = vshStrdup(ctl, optarg);
> +            break;
> +        case 'd':
> +            if (virStrToLong_i(optarg, NULL, 10, &debug) < 0) {
> +                vshError(ctl, _("option %s takes a numeric argument"),
> +                         longindex == -1 ? "-d" : "--debug");
> +                exit(EXIT_FAILURE);
> +            }
> +            if (debug < VSH_ERR_DEBUG || debug > VSH_ERR_ERROR)
> +                vshError(ctl, _("ignoring debug level %d out of range [%d-%d]"),
> +                         debug, VSH_ERR_DEBUG, VSH_ERR_ERROR);
> +            else
> +                ctl->debug = debug;
> +            break;
> +        case 'h':
> +            vshAdmUsage();
> +            exit(EXIT_SUCCESS);
> +            break;
> +        case 'l':
> +            vshCloseLogFile(ctl);
> +            ctl->logfile = vshStrdup(ctl, optarg);
> +            vshOpenLogFile(ctl);
> +            break;
> +        case 'q':
> +            ctl->quiet = true;
> +            break;
> +        case 'v':
> +            if (STRNEQ_NULLABLE(optarg, "long")) {
> +                puts(VERSION);
> +                exit(EXIT_SUCCESS);
> +            }
> +            /* fall through */
> +        case 'V':
> +            vshAdmShowVersion(ctl);
> +            exit(EXIT_SUCCESS);
> +        case ':':
> +            for (i = 0; opt[i].name != NULL; i++) {
> +                if (opt[i].val == optopt)
> +                    break;
> +            }
> +            if (opt[i].name)
> +                vshError(ctl, _("option '-%c'/'--%s' requires an argument"),
> +                         optopt, opt[i].name);
> +            else
> +                vshError(ctl, _("option '-%c' requires an argument"), optopt);
> +            exit(EXIT_FAILURE);
> +        case '?':
> +            if (optopt)
> +                vshError(ctl, _("unsupported option '-%c'. See --help."), optopt);
> +            else
> +                vshError(ctl, _("unsupported option '%s'. See --help."), argv[optind - 1]);
> +            exit(EXIT_FAILURE);
> +        default:
> +            vshError(ctl, _("unknown option"));
> +            exit(EXIT_FAILURE);
> +        }
> +        longindex = -1;
> +    }
> +
> +    if (argc == optind) {
> +        ctl->imode = true;
> +    } else {
> +        /* parse command */
> +        ctl->imode = false;
> +        if (argc - optind == 1) {
> +            vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
> +            return vshCommandStringParse(ctl, argv[optind]);
> +        } else {
> +            return vshCommandArgvParse(ctl, argc - optind, argv + optind);
> +        }
> +    }
> +    return true;
> +}
> +
> +static const vshCmdDef vshAdmCmds[] = {
> +    VSH_CMD_CD,
> +    VSH_CMD_ECHO,
> +    VSH_CMD_EXIT,
> +    VSH_CMD_HELP,
> +    VSH_CMD_PWD,
> +    VSH_CMD_QUIT,
> +    {.name = "connect",
> +     .handler = cmdConnect,
> +     .opts = opts_connect,
> +     .info = info_connect,
> +     .flags = VSH_CMD_FLAG_NOCONNECT
> +    },
> +    {.name = NULL}
> +};
> +
> +static const vshCmdGrp cmdGroups[] = {
> +    /*{VIRT_ADMIN_CMD_GRP_MANAGEMENT, "domain", domManagementCmds},
> +    {VIRT_ADMIN_CMD_GRP_MONITORING, "monitor", domMonitoringCmds},*/

Just drop these and introduce when needed.

> +    {VIRT_ADMIN_CMD_GRP_SHELL, "virt-admin", vshAdmCmds},
> +    {NULL, NULL, NULL}
> +};
> +
> +static const vshClientHooks hooks = {
> +    .connHandler = vshAdmConnectionHandler
> +};
> +
> +int
> +main(int argc, char **argv)
> +{
> +    vshControl _ctl, *ctl = &_ctl;
> +    vshAdmControl virtAdminCtl;
> +    const char *defaultConn;
> +    bool ret = true;
> +
> +    memset(ctl, 0, sizeof(vshControl));
> +    memset(&virtAdminCtl, 0, sizeof(vshAdmControl));
> +    ctl->name = "virt-admin";        /* hardcoded name of the binary */
> +    ctl->log_fd = -1;                /* Initialize log file descriptor */
> +    ctl->debug = VSH_DEBUG_DEFAULT;
> +    ctl->hooks = &hooks;
> +
> +    ctl->eventPipe[0] = -1;
> +    ctl->eventPipe[1] = -1;
> +    ctl->eventTimerId = -1;
> +    ctl->privData = &virtAdminCtl;
> +
> +    if (!(progname = strrchr(argv[0], '/')))
> +        progname = argv[0];
> +    else
> +        progname++;
> +    ctl->progname = progname;
> +
> +    if (!setlocale(LC_ALL, "")) {
> +        perror("setlocale");
> +        /* failure to setup locale is not fatal */
> +    }
> +    if (!bindtextdomain(PACKAGE, LOCALEDIR)) {
> +        perror("bindtextdomain");
> +        return EXIT_FAILURE;
> +    }
> +    if (!textdomain(PACKAGE)) {
> +        perror("textdomain");
> +        return EXIT_FAILURE;
> +    }
> +
> +    if (isatty(STDIN_FILENO)) {
> +        ctl->istty = true;
> +
> +#ifndef WIN32
> +        if (tcgetattr(STDIN_FILENO, &ctl->termattr) < 0)
> +            ctl->istty = false;
> +#endif
> +    }
> +
> +    if (virMutexInit(&ctl->lock) < 0) {
> +        vshError(ctl, "%s", _("Failed to initialize mutex"));
> +        return EXIT_FAILURE;
> +    }
> +
> +    if (virInitialize() < 0) {
> +        vshError(ctl, "%s", _("Failed to initialize libvirt"));
> +        return EXIT_FAILURE;
> +    }
> +
> +    virFileActivateDirOverride(argv[0]);
> +
> +    if ((defaultConn = virGetEnvBlockSUID("LIBVIRT_DEFAULT_ADMIN_URI")))
> +        ctl->connname = vshStrdup(ctl, defaultConn);
> +
> +    if (!vshInit(ctl, cmdGroups, NULL))
> +        exit(EXIT_FAILURE);
> +
> +    if (!vshAdmParseArgv(ctl, argc, argv) ||
> +        !vshAdmInit(ctl)) {
> +        vshAdmDeinit(ctl);
> +        exit(EXIT_FAILURE);
> +    }
> +
> +    if (!ctl->imode) {
> +        ret = vshCommandRun(ctl, ctl->cmd);
> +    } else {
> +        /* interactive mode */
> +        if (!ctl->quiet) {
> +            vshPrint(ctl,
> +                     _("Welcome to %s, the administrating virtualization "
> +                       "interactive terminal.\n\n"),
> +                     progname);
> +            vshPrint(ctl, "%s",
> +                     _("Type:  'help' for help with commands\n"
> +                       "       'quit' to quit\n\n"));
> +        }
> +
> +        do {
> +            ctl->cmdstr = vshReadline(ctl, VIRT_ADMIN_PROMPT);
> +            if (ctl->cmdstr == NULL)
> +                break;          /* EOF */
> +            if (*ctl->cmdstr) {
> +#if WITH_READLINE
> +                add_history(ctl->cmdstr);
> +#endif
> +                if (vshCommandStringParse(ctl, ctl->cmdstr))
> +                    vshCommandRun(ctl, ctl->cmd);
> +            }
> +            VIR_FREE(ctl->cmdstr);
> +        } while (ctl->imode);
> +
> +        if (ctl->cmdstr == NULL)
> +            fputc('\n', stdout);        /* line break after alone prompt */
> +    }
> +
> +    vshAdmDeinit(ctl);
> +    exit(ret ? EXIT_SUCCESS : EXIT_FAILURE);
> +}
> diff --git a/tools/virt-admin.h b/tools/virt-admin.h
> new file mode 100644
> index 0000000..962d5bc
> --- /dev/null
> +++ b/tools/virt-admin.h
> @@ -0,0 +1,71 @@
> +/*
> + * virt-admin.h: a shell to exercise the libvirt admin API
> + *
> + * Copyright (C) 2015 Red Hat, Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library.  If not, see
> + * <http://www.gnu.org/licenses/>.
> + *
> + * Daniel Veillard <veillard at redhat.com>
> + * Karel Zak <kzak at redhat.com>
> + * Daniel P. Berrange <berrange at redhat.com>
> + */
> +
> +#ifndef VIRT_ADMIN_H
> +# define VIRT_ADMIN_H
> +
> +# include <stdio.h>
> +# include <stdlib.h>
> +# include <string.h>
> +# include <stdarg.h>
> +# include <unistd.h>
> +# include <sys/stat.h>
> +# include <termios.h>

Again, plenty of includes. Some of them are duplicated in .c some of
them are not needed (e.g. termios.h).

> +
> +# include "internal.h"
> +# include "virerror.h"
> +# include "virthread.h"
> +# include "vsh.h"
> +
> +# define VIR_FROM_THIS VIR_FROM_NONE
> +
> +/*
> + * Command group types
> + */
> +# define VIRT_ADMIN_CMD_GRP_MANAGEMENT   "Daemon/server/client Management"
> +# define VIRT_ADMIN_CMD_GRP_MONITORING   "Daemon/server/client Monitoring"

These ^^ are not used yet.

> +# define VIRT_ADMIN_CMD_GRP_SHELL        "Virt-admin itself"
> +
> +typedef struct _vshAdmControl vshAdmControl;
> +typedef vshAdmControl *vshAdmControlPtr;
> +
> +/*
> + * adminControl
> + */
> +struct _vshAdmControl {
> +    virAdmConnectPtr conn;      /* connection to a daemon's admin server */
> +    bool wantReconnect;
> +    /*bool useGetInfo;            [> must use virDomainGetInfo, since
> +                                   virDomainGetState is not supported <]*/

Er, what? virDomainGetInfo? I believe this is a leftover from copy and
paste. Drop it.

> +};
> +
> +/* Filter flags for various vshCommandOpt*By() functions */
> +typedef enum {
> +    VIRSH_BYID   = (1 << 1),
> +    VIRSH_BYUUID = (1 << 2),
> +    VIRSH_BYNAME = (1 << 3),
> +    VIRSH_BYMAC  = (1 << 4),
> +} vshAdmLookupByFlags;
> +

And again here.

> +#endif /* VIRT_ADMIN_H */
> 

Otherwise looking good. ACK.

Michal




More information about the libvir-list mailing list