[libvirt] [PATCH v2 3/5] bhyve: implement virConnectDomainXMLFromNative

Fabian Freyer fabian.freyer at physik.tu-berlin.de
Thu Jun 23 19:16:08 UTC 2016


On 12/06/16 16:03, Roman Bogorodskiy wrote:
>   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 | 263 ++++++++++++++++++++++++++++++++++++++++
>>  src/bhyve/bhyve_parse_command.h |  30 +++++
>>  5 files changed, 338 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 0d92448..b1580b7 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 12b66c2..d53c98f 100644
>> --- a/src/Makefile.am
>> +++ b/src/Makefile.am
>> @@ -901,6 +901,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 c4051a1..c7abea4 100644
>> --- a/src/bhyve/bhyve_driver.c
>> +++ b/src/bhyve/bhyve_driver.c
>> @@ -55,6 +55,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"
>> @@ -1536,6 +1537,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;
>> +
>> +    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;
> 
> Nit: this chunk is over-indented by one space.
> 
>> +
>> +    xml = virDomainDefFormat(def, capabilities, 0);
>> +
>> + cleanup:
>> +    virObjectUnref(capabilities);
>> +    virDomainDefFree(def);
>> +    return xml;
>> +}
>> +
>>  static virHypervisorDriver bhyveHypervisorDriver = {
>>      .name = "bhyve",
>>      .connectOpen = bhyveConnectOpen, /* 1.2.2 */
>> @@ -1589,6 +1630,7 @@ static virHypervisorDriver bhyveHypervisorDriver = {
>>      .connectIsAlive = bhyveConnectIsAlive, /* 1.3.5 */
>>      .connectIsSecure = bhyveConnectIsSecure, /* 1.3.5 */
>>      .connectIsEncrypted = bhyveConnectIsEncrypted, /* 1.3.5 */
>> +    .connectDomainXMLFromNative = bhyveConnectDomainXMLFromNative, /* 1.3.6 */
>>  };
>>  
>>  
>> diff --git a/src/bhyve/bhyve_parse_command.c b/src/bhyve/bhyve_parse_command.c
>> new file mode 100644
>> index 0000000..72367bb
>> --- /dev/null
>> +++ b/src/bhyve/bhyve_parse_command.c
>> @@ -0,0 +1,263 @@
>> +/*
>> + * 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) < 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;
>> +    }
>> +
>> +    return unescaped;
>> +}
>> +
>> +/*
>> + * Try to extract loader and bhyve argv lists from a command line string.
>> + */
>> +static int
>> +bhyveCommandLine2argv(const char *nativeConfig,
>                     ^^^^
> 
> 		    Style: I think it should be 2Argv(...
> 
>> +                      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"));
>> +        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++) {
>> +        curr = lines[i];
>> +        int j;
>> +        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. */
> 
> Is that needed for getopt?

Getopt uses an array of strings, so yes, kindof. However, any other parsing option would most likely also need to do this?

>> +        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;
>> +        }
>> +        /* To prevent a use-after-free here, only free the argument list when
>> +         * it is definitely not going to be used */
>> +        else
>> +            virStringFreeList(arglist);
>> +    }
>> +
>> +    *loader_argv = _loader_argv;
>> +    *bhyve_argv = _bhyve_argv;
>> +
>> +    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.
> 
> Nit: I think C++-style comments are not popular in the tree, so probably
> will be more consistent to use C-style comments instead.
> 
>> +    if (virUUIDGenerate(def->uuid) < 0) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +                       _("failed to generate uuid"));
>> +        goto cleanup;
>> +    }
>> +    def->id = -1;
>> +    def->clock.offset = VIR_DOMAIN_CLOCK_OFFSET_LOCALTIME;
>> +
>> +    if (bhyveCommandLine2argv(nativeConfig,
>> +                              &loader_argc, &loader_argv,
>> +                              &bhyve_argc, &bhyve_argv)) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                    _("Failed to convert the command string to argv-lists.."));
>> +        goto cleanup;
>> +    }
>> +
>> +cleanup:
>> +    virStringFreeList(loader_argv);
>> +    virStringFreeList(bhyve_argv);
>> +    return def;
>> +}
>> 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__
>> +
>> +virDomainDefPtr bhyveParseCommandLineString(const char* nativeConfig,
>> +                                            unsigned caps,
>> +                                            virDomainXMLOptionPtr xmlopt);
>> +
>> +#endif /* __BHYVE_PARSE_COMMAND_H__*/
>> -- 
>> 2.7.0
>>
>> --
>> libvir-list mailing list
>> libvir-list at redhat.com
>> https://www.redhat.com/mailman/listinfo/libvir-list
> 
> Roman Bogorodskiy
> 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 842 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20160623/36f86cf1/attachment-0001.sig>


More information about the libvir-list mailing list