[libvirt] [PATCH 3/6] bhyve: implement virConnectDomainXMLFromNative

Roman Bogorodskiy bogorodskiy at gmail.com
Tue Jul 5 00:25:57 UTC 2016


  Fabian Freyer wrote:

> First, remove escaped newlines and split up the string into an argv-list for
> the bhyve and loader commands, respectively. This is done by iterating over the
> string splitting it by newlines, and then re-iterating over each line,
> splitting it by spaces.
> 
> Since this code reuses part of the code of qemu_parse_command.c
> (in bhyveCommandLine2argv), add the appropriate copyright notices.
> 
> Signed-off-by: Fabian Freyer <fabian.freyer at physik.tu-berlin.de>
> ---
>  po/POTFILES.in                  |   1 +
>  src/Makefile.am                 |   2 +
>  src/bhyve/bhyve_driver.c        |  42 +++++++
>  src/bhyve/bhyve_parse_command.c | 267 ++++++++++++++++++++++++++++++++++++++++
>  src/bhyve/bhyve_parse_command.h |  30 +++++
>  5 files changed, 342 insertions(+)
>  create mode 100644 src/bhyve/bhyve_parse_command.c
>  create mode 100644 src/bhyve/bhyve_parse_command.h
> 
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index f44a501..18a651d 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -15,6 +15,7 @@ src/bhyve/bhyve_command.c
>  src/bhyve/bhyve_device.c
>  src/bhyve/bhyve_driver.c
>  src/bhyve/bhyve_monitor.c
> +src/bhyve/bhyve_parse_command.c
>  src/bhyve/bhyve_process.c
>  src/conf/capabilities.c
>  src/conf/cpu_conf.c
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 275bfc7..7af985c 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -912,6 +912,8 @@ BHYVE_DRIVER_SOURCES =						\
>  		bhyve/bhyve_capabilities.h			\
>  		bhyve/bhyve_command.c				\
>  		bhyve/bhyve_command.h				\
> +		bhyve/bhyve_parse_command.c			\
> +		bhyve/bhyve_parse_command.h			\
>  		bhyve/bhyve_device.c				\
>  		bhyve/bhyve_device.h				\
>  		bhyve/bhyve_domain.c				\
> diff --git a/src/bhyve/bhyve_driver.c b/src/bhyve/bhyve_driver.c
> index 8036661..97bba9a 100644
> --- a/src/bhyve/bhyve_driver.c
> +++ b/src/bhyve/bhyve_driver.c
> @@ -57,6 +57,7 @@
>  #include "bhyve_device.h"
>  #include "bhyve_driver.h"
>  #include "bhyve_command.h"
> +#include "bhyve_parse_command.h"
>  #include "bhyve_domain.h"
>  #include "bhyve_process.h"
>  #include "bhyve_capabilities.h"
> @@ -1539,6 +1540,46 @@ bhyveConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
>      return 0;
>  }
> 
> +static char *
> +bhyveConnectDomainXMLFromNative(virConnectPtr conn,
> +                                const char *nativeFormat,
> +                                const char *nativeConfig,
> +                                unsigned int flags)
> +{
> +    char *xml = NULL;
> +    virDomainDefPtr def = NULL;
> +    bhyveConnPtr privconn = conn->privateData;
> +    virCapsPtr capabilities = NULL;
> +    unsigned caps = bhyveDriverGetCaps(conn);
> +
> +    virCheckFlags(0, NULL);
> +
> +    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
> +        goto cleanup;
> +
> +    capabilities = bhyveDriverGetCapabilities(privconn);
> +
> +    if (!capabilities)
> +        goto cleanup;

Nothing to clean up before this point, could be just "return NULL";

> +
> +    if (STRNEQ(nativeFormat, BHYVE_CONFIG_FORMAT_ARGV)) {
> +        virReportError(VIR_ERR_INVALID_ARG,
> +                       _("unsupported config type %s"), nativeFormat);
> +        goto cleanup;
> +    }
> +
> +    def = bhyveParseCommandLineString(nativeConfig, caps, privconn->xmlopt);
> +    if (def == NULL)
> +        goto cleanup;
> +
> +    xml = virDomainDefFormat(def, capabilities, 0);
> +
> +cleanup:

One space required before label.

> +    virObjectUnref(capabilities);
> +    virDomainDefFree(def);
> +    return xml;
> +}
> +
>  static virHypervisorDriver bhyveHypervisorDriver = {
>      .name = "bhyve",
>      .connectOpen = bhyveConnectOpen, /* 1.2.2 */
> @@ -1592,6 +1633,7 @@ static virHypervisorDriver bhyveHypervisorDriver = {
>      .connectIsAlive = bhyveConnectIsAlive, /* 1.3.5 */
>      .connectIsSecure = bhyveConnectIsSecure, /* 1.3.5 */
>      .connectIsEncrypted = bhyveConnectIsEncrypted, /* 1.3.5 */
> +    .connectDomainXMLFromNative = bhyveConnectDomainXMLFromNative, /* 2.0.1 */

This should be 2.1.0.

>  };
> 
> 
> diff --git a/src/bhyve/bhyve_parse_command.c b/src/bhyve/bhyve_parse_command.c
> new file mode 100644
> index 0000000..0c4d3f5
> --- /dev/null
> +++ b/src/bhyve/bhyve_parse_command.c
> @@ -0,0 +1,267 @@
> +/*
> + * bhyve_parse_command.c: Bhyve command parser
> + *
> + * Copyright (C) 2006-2016 Red Hat, Inc.
> + * Copyright (C) 2006 Daniel P. Berrange
> + * Copyright (C) 2016 Fabian Freyer
> + *
> + * 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/>.
> + *
> + * Author: Fabian Freyer <fabian.freyer at physik.tu-berlin.de>
> + */
> +
> +#include <config.h>
> +
> +#include "bhyve_capabilities.h"
> +#include "bhyve_command.h"
> +#include "bhyve_parse_command.h"
> +#include "viralloc.h"
> +#include "virlog.h"
> +#include "virstring.h"
> +#include "virutil.h"
> +#include "c-ctype.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_BHYVE
> +
> +VIR_LOG_INIT("bhyve.bhyve_parse_command");
> +
> +/*
> + * This function takes a string representation of the command line and removes
> + * all newline characters, if they are prefixed by a backslash. The result
> + * should be a string with one command per line.
> + *
> + * NB: command MUST be NULL-Terminated.
> + */
> +static char *
> +bhyveParseCommandLineUnescape(const char *command)
> +{
> +    size_t len = strlen(command);
> +    char *unescaped = NULL;
> +    char *curr_src = NULL;
> +    char *curr_dst = NULL;
> +
> +    /* Since we are only removing characters, allocating a buffer of the same
> +     * size as command shouldn't be a problem here */
> +    if (VIR_ALLOC_N(unescaped, len+1) < 0)
> +        return NULL;
> +
> +    /* Iterate over characters in the command, skipping "\\\n", "\\\r" as well
> +     * as "\\\r\n". */
> +    for (curr_src = (char*) command, curr_dst = unescaped; *curr_src != '\0';
> +        curr_src++, curr_dst++) {
> +        if (*curr_src == '\\') {
> +            switch (*(curr_src + 1)) {
> +                case '\n': /* \LF */
> +                    curr_src++;
> +                    curr_dst--;
> +                    break;
> +                case '\r': /* \CR */
> +                    curr_src++;
> +                    curr_dst--;
> +                    if (*curr_src == '\n') /* \CRLF */
> +                        curr_src++;
> +                    break;
> +                default:
> +                    *curr_dst = '\\';
> +            }
> +        } else
> +            *curr_dst = *curr_src;

Style: if using {} for the first part, have to use {} for the second one
as well.

> +    }
> +
> +    return unescaped;
> +}
> +
> +/*
> + * Try to extract loader and bhyve argv lists from a command line string.
> + */
> +static int
> +bhyveCommandLineToArgv(const char *nativeConfig,
> +                      int *loader_argc,
> +                      char ***loader_argv,
> +                      int *bhyve_argc,
> +                      char ***bhyve_argv)
> +{
> +    const char *curr = NULL;
> +    char *nativeConfig_unescaped = NULL;
> +    const char *start;
> +    const char *next;
> +    char *line;
> +    char **lines = NULL;
> +    size_t line_count = 0;
> +    size_t lines_alloc = 0;
> +    char **_bhyve_argv = NULL;
> +    char **_loader_argv = NULL;
> +
> +    nativeConfig_unescaped = bhyveParseCommandLineUnescape(nativeConfig);
> +    if (nativeConfig_unescaped == NULL) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                       _("Failed to unescape command line string"));

Messages without formatting are not allowed (syntax-checks shows that).

> +        goto error;
> +    }
> +
> +    curr = nativeConfig_unescaped;
> +
> +    /* Iterate over string, splitting on sequences of '\n' */
> +    while (curr && *curr != '\0') {
> +        start = curr;
> +        next = strchr(curr, '\n');
> +
> +        if (VIR_STRNDUP(line, curr, next ? next - curr : -1) < 0)
> +            goto error;
> +
> +        if (VIR_RESIZE_N(lines, lines_alloc, line_count, 2) < 0) {
> +            VIR_FREE(line);
> +            goto error;
> +        }
> +
> +        if (*line)
> +            lines[line_count++] = line;
> +        lines[line_count] = NULL;
> +
> +        while (next && (*next == '\n' || *next == '\r'
> +                        || STRPREFIX(next, "\r\n")))
> +            next++;
> +
> +        curr = next;
> +    }
> +
> +    for (int i = 0; i < line_count; i++) {
size_t + declare outside the loop.

> +        curr = lines[i];
> +        int j;

site_t

> +        char **arglist = NULL;
> +        size_t args_count = 0;
> +        size_t args_alloc = 0;
> +
> +        /* iterate over each line, splitting on sequences of ' '. This code is
> +         * adapted from qemu/qemu_parse_command.c. */
> +        while (curr && *curr != '\0') {
> +            char *arg;
> +            start = curr;
> +
> +            if (*start == '\'') {
> +                if (start == curr)
> +                    curr++;
> +                next = strchr(start + 1, '\'');
> +            } else if (*start == '"') {
> +                if (start == curr)
> +                    curr++;
> +                next = strchr(start + 1, '"');
> +            } else {
> +                next = strchr(start, ' ');
> +            }
> +
> +            if (VIR_STRNDUP(arg, curr, next ? next - curr : -1) < 0)
> +                goto error;
> +
> +            if (next && (*next == '\'' || *next == '"'))
> +                next++;
> +
> +            if (VIR_RESIZE_N(arglist, args_alloc, args_count, 2) < 0) {
> +                VIR_FREE(arg);
> +                goto error;
> +            }
> +
> +            arglist[args_count++] = arg;
> +            arglist[args_count] = NULL;
> +
> +            while (next && c_isspace(*next))
> +                next++;
> +
> +            curr = next;
> +        }
> +
> +        /* To prevent a memory leak here, only set the argument lists when
> +         * the first matching command is found. This shouldn't really be a
> +         * problem, since usually no multiple loaders or bhyverun commands
> +         * are specified (this wouldn't really be valid anyways).
> +         * Otherwise, later argument lists may be assigned to _argv without
> +         * freeing the earlier ones. */
> +        if (!_bhyve_argv && STREQ(arglist[0], "/usr/sbin/bhyve")) {
> +            if ((VIR_REALLOC_N(_bhyve_argv, args_count + 1) < 0)
> +                || (!bhyve_argc))
> +                goto error;
> +            for (j = 0; j < args_count; j++)
> +                _bhyve_argv[j] = arglist[j];
> +            _bhyve_argv[j] = NULL;
> +            *bhyve_argc = args_count-1;
> +        } else if (!_loader_argv) {
> +            if ((VIR_REALLOC_N(_loader_argv, args_count + 1) < 0)
> +                || (!loader_argc))
> +                goto error;
> +            for (j = 0; j < args_count; j++)
> +                _loader_argv[j] = arglist[j];
> +            _loader_argv[j] = NULL;
> +            *loader_argc = args_count-1;
> +        } else
> +            /* To prevent a use-after-free here, only free the argument list
> +             * when it is definitely not going to be used */
> +            virStringFreeList(arglist);

Same style thing with {}.

> +    }
> +
> +    *loader_argv = _loader_argv;
> +    if (!(*bhyve_argv = _bhyve_argv))
> +        goto error;
> +
> +    virStringFreeList(lines);
> +    return 0;
> +
> + error:
> +    VIR_FREE(_loader_argv);
> +    VIR_FREE(_bhyve_argv);
> +    virStringFreeList(lines);
> +    return -1;
> +}
> +
> +virDomainDefPtr
> +bhyveParseCommandLineString(const char* nativeConfig,
> +                            unsigned caps ATTRIBUTE_UNUSED,
> +                            virDomainXMLOptionPtr xmlopt ATTRIBUTE_UNUSED)
> +{
> +    virDomainDefPtr def = NULL;
> +    int bhyve_argc = 0;
> +    char **bhyve_argv = NULL;
> +    int loader_argc = 0;
> +    char **loader_argv = NULL;
> +
> +    if (!(def = virDomainDefNew()))
> +        goto cleanup;
> +
> +    /* Initialize defaults. */
> +    def->virtType = VIR_DOMAIN_VIRT_BHYVE;
> +    if (virUUIDGenerate(def->uuid) < 0) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
> +                       _("failed to generate uuid"));
> +        VIR_FREE(def);
> +        goto cleanup;
> +    }
> +    def->id = -1;
> +    def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
> +
> +    if (bhyveCommandLineToArgv(nativeConfig,
> +                              &loader_argc, &loader_argv,
> +                              &bhyve_argc, &bhyve_argv)) {
> +        virReportError(VIR_ERR_INTERNAL_ERROR,
> +                    _("Failed to convert the command string to argv-lists.."));

Formatting + indent; double dot removed.

> +        goto error;
> +    }
> +
> +cleanup:
> +    virStringFreeList(loader_argv);
> +    virStringFreeList(bhyve_argv);
> +    return def;
> +error:
> +    VIR_FREE(def);
> +    goto cleanup;
> +}
> diff --git a/src/bhyve/bhyve_parse_command.h b/src/bhyve/bhyve_parse_command.h
> new file mode 100644
> index 0000000..7ffe26c
> --- /dev/null
> +++ b/src/bhyve/bhyve_parse_command.h
> @@ -0,0 +1,30 @@
> +/*
> + * bhyve_parse_command.h: Bhyve command parser
> + *
> + * Copyright (C) 2016 Fabian Freyer
> + *
> + * 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/>.
> + *
> + * Author: Fabian Freyer <fabian.freyer at physik.tu-berlin.de>
> + */
> +
> +#ifndef __BHYVE_PARSE_COMMAND_H__
> +#define __BHYVE_PARSE_COMMAND_H__

Not properly indented (should be # define).

> +
> +virDomainDefPtr bhyveParseCommandLineString(const char* nativeConfig,
> +                                            unsigned caps,
> +                                            virDomainXMLOptionPtr xmlopt);
> +
> +#endif /* __BHYVE_PARSE_COMMAND_H__*/
> -- 
> 2.5.5
> 

Roman Bogorodskiy
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20160705/288fcb7f/attachment-0001.sig>


More information about the libvir-list mailing list