[libvirt] [PATCH V1 2/4] src/xenconfig: Xen-xl parser

Jim Fehlig jfehlig at suse.com
Tue Sep 9 22:17:42 UTC 2014


Kiarie Kahurani wrote:
> Introduce a xen xl parser
>
> This parser allows for users to convert the new xl disk format and
> spice graphics config to libvirt xml format and vice versa.Regarding
> the spice graphics config, the code is pretty much straight forward
> For the disk {formating, parsing} this parser takes care of the new
> xl format which include positional parameters and key/value parameters
> In xl format disk config a <diskspec> consists of parameters separated by
> commas.If the parameters do not contain an '=' they are automatically
> assigned to certain options following the order below
>
>    target, format, vdev, access
>
> The above are the only mandatory parameters in the <diskspec> but there
> are many more disk config options.This options can be specified as
> key=value pairs This takes care of the rest of the options such as
>
>   devtype, backend, backendtype, script, direct-io-safe,
>
> The positional paramters can also be specified in key/value form
> for example
>
>     /dev/vg/guest-volume,,hda
>     /dev/vg/guest-volume,raw,hda,rw
>     format=raw, vdev=hda, access=rw, target=/dev/vg/guest-volume
>
> are interpleted to one config
>
> In xm format a config equivalent to the one about would have been
>
> raw:/dev/vg/guest-volume,hda,w
>
> As of this commit, libvirt can not convert xl disk config such as
>
> /dev/vg/guest-volume,,hda
>
> to libvirt xml
>
>   <disk type='block' device='disk'>
>     <driver name='qemu' type='raw'/>
>     <source file=/dev/vg/guest-volume/>
>     <target dev='hdc' bus='ide'/>
>  </disk>
>
> Signed-off-by: Kiarie Kahurani <davidkiarie4 at gmail.com>
> ---
>  configure.ac                  |   5 +-
>  src/Makefile.am               |  21 +-
>  src/libvirt_xenconfig.syms    |   4 +
>  src/xenconfig/libxlu_disk_i.h |  28 +++
>  src/xenconfig/libxlu_disk_l.l | 292 ++++++++++++++++++++++++++
>  src/xenconfig/xen_common.c    |   3 +-
>  src/xenconfig/xen_xl.c        | 476 ++++++++++++++++++++++++++++++++++++++++++
>  src/xenconfig/xen_xl.h        |  29 +++
>  8 files changed, 852 insertions(+), 6 deletions(-)
>  create mode 100644 src/xenconfig/libxlu_disk_i.h
>  create mode 100644 src/xenconfig/libxlu_disk_l.l
>  create mode 100644 src/xenconfig/xen_xl.c
>  create mode 100644 src/xenconfig/xen_xl.h
>
> diff --git a/configure.ac b/configure.ac
> index f93c6c2..a60d0ad 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -2176,7 +2176,10 @@ AC_PATH_PROG([PERL], [perl])
>  if test -z "$PERL"; then
>           AC_MSG_ERROR([Failed to find perl.])
>  fi
> -
> +AC_PATH_PROG([FLEX], [flex])
> +if test -z "$FLEX"; then
> +         AC_MSG_ERROR([failed to find flex.])
> +fi
>   

According to the automake manual [1], AM_PROG_FLEX is recommended in
configure.ac

"If a |lex| source file is seen, then your configure.ac must define the
variable |LEX|. You can use |AC_PROG_LEX| to do this (see Particular
Program Checks in The Autoconf Manual), but using |AM_PROG_LEX| macro
(see Macros) is recommended."

>  AC_ARG_WITH([test-suite],
>              [AS_HELP_STRING([--with-test-suite],
>                 [build test suite by default @<:@default=check@:>@])],
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 46e411e..38560ce 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -35,7 +35,6 @@ INCLUDES =	-I../gnulib/lib					\
>  		$(GETTEXT_CPPFLAGS)
>  
>  AM_CFLAGS =	$(LIBXML_CFLAGS)				\
> -		$(WARN_CFLAGS)					\
>   

Hmm, that won't fly. I assume you made this change to squelch warnings
when compiling the generated file?

>  		$(LOCK_CHECKING_CFLAGS)				\
>  		$(WIN32_EXTRA_CFLAGS)				\
>  		$(COVERAGE_CFLAGS)
> @@ -964,11 +963,25 @@ CPU_SOURCES =							\
>  VMX_SOURCES =							\
>  		vmx/vmx.c vmx/vmx.h
>  
> +XENCONFIG_GENERATED =                                           \
> +		xenconfig/libxlu_disk_l.c                       \
> +                xenconfig/libxlu_disk_l.h
> +
> +$(XENCONFIG_GENERATED): $(srcdir)/xenconfig/libxlu_disk_l.l     \
> +	    $(srcdir)/xenconfig/libxlu_disk_i.h Makefile.am
> +	$(AM_V_GEN)$(FLEX) --outfile=$(srcdir)/xenconfig/libxlu_disk_l.c            \
> +		--header-file=$(srcdir)/xenconfig/libxlu_disk_l.h \
> +		$(srcdir)/xenconfig/libxlu_disk_l.l
> +
> +CLEANFILES += $(XENCONFIG_GENERATED)
>   

I suppose this is one way to generate the files with flex, but according
to the manual it should be something like

BUILT_SOURCES += xenconfig/libxlu_disk_l.h xenconfig/libxlu_disk_l.c

XENCONFIG_SOURCES = \
xenconfig/xenxs_private.h \
xenconfig/xen_common.c xenconfig/xen_common.h \
xenconfig/xen_sxpr.c xenconfig/xen_sxpr.h \
xenconfig/xen_xm.c xenconfig/xen_xm.h \
xenconfig/xen_xl.c xenconfig/xen_xl.h \
xenconfig/libxlu_disk_l.l

However, I can't nudge flex to generate the header file with this
approach. I tried adding 'AM_LFLAGS = --header-file' after
BUILT_SOURCES, but still no header is generated. I haven't had much luck
searching for an example doing this in the automake framework. Eric has
a lot of expertise in this area and might have suggestions.

Regards,
Jim

[1] http://www.gnu.org/software/automake/manual/html_node/Yacc-and-Lex.html

> +
>  XENCONFIG_SOURCES =						\
>  		xenconfig/xenxs_private.h			\
> -		xenconfig/xen_common.c xenconfig/xen_common.h   \
> -		xenconfig/xen_sxpr.c xenconfig/xen_sxpr.h	\
> -		xenconfig/xen_xm.c xenconfig/xen_xm.h
> +		xenconfig/xen_common.c xenconfig/xen_common.h  \
> +		xenconfig/xen_sxpr.c xenconfig/xen_sxpr.h	 \
> +		xenconfig/xen_xm.c xenconfig/xen_xm.h           \
> +		xenconfig/xen_xl.c xenconfig/xen_xl.h           \
> +		$(XENCONFIG_GENERATED)
>  
>  pkgdata_DATA =	cpu/cpu_map.xml
>  
> diff --git a/src/libvirt_xenconfig.syms b/src/libvirt_xenconfig.syms
> index 6541685..3e2e5d6 100644
> --- a/src/libvirt_xenconfig.syms
> +++ b/src/libvirt_xenconfig.syms
> @@ -16,6 +16,10 @@ xenParseSxprChar;
>  xenParseSxprSound;
>  xenParseSxprString;
>  
> +#xenconfig/xen_xl.h
> +xenFormatXL;
> +xenParseXL;
> +
>  # xenconfig/xen_xm.h
>  xenFormatXM;
>  xenParseXM;
> diff --git a/src/xenconfig/libxlu_disk_i.h b/src/xenconfig/libxlu_disk_i.h
> new file mode 100644
> index 0000000..911ea42
> --- /dev/null
> +++ b/src/xenconfig/libxlu_disk_i.h
> @@ -0,0 +1,28 @@
> +#ifndef LIBXLU_DISK_I_H
> +#define LIBXLU_DISK_I_H
> +
> +#include "../util/virconf.h"
> +
> +typedef struct {
> +    virConfPtr conf;
> +    int err;
> +    void *scanner;
> +    YY_BUFFER_STATE buf;
> +    virDomainDiskDefPtr disk;
> +    int access_set, had_depr_prefix;
> +    const char *spec;
> +} DiskParseContext;
> +
> +void xlu__disk_err(DiskParseContext *dpc, const char *erroneous,
> +                   const char *message);
> +
> +
> +#endif /*LIBXLU_DISK_I_H*/
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/src/xenconfig/libxlu_disk_l.l b/src/xenconfig/libxlu_disk_l.l
> new file mode 100644
> index 0000000..7b6893b
> --- /dev/null
> +++ b/src/xenconfig/libxlu_disk_l.l
> @@ -0,0 +1,292 @@
> +/* -*- fundamental -*- */
> +/*
> + * libxlu_disk_l.l - parser for disk specification strings
> + *
> + * Copyright (C) 2011      Citrix Ltd.
> + * Author Ian Jackson <ian.jackson at eu.citrix.com>
> + *
> + * This program 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; version 2.1 only. with the special
> + * exception on linking described in file LICENSE.
> + *
> + * This program 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.
> + */
> +
> +/*
> + * Parsing the old xm/xend/xl-4.1 disk specs is a tricky problem,
> + * because the target string might in theory contain "," which is the
> + * delimiter we use for stripping off things on the RHS, and ":",
> + * which is the delimiter we use for stripping off things on the LHS.
> + *
> + * In this parser we do not support such target strings in the old
> + * syntax; if the target string has to contain "," or ":" the new
> + * syntax's "target=" should be used.
> + */
> +%{
> +# include <config.h>
> +# include <stdio.h>
> +# include <stdarg.h>
> +# include "virstring.h"
> +# include "virstoragefile.h"
> +# include "viralloc.h"
> +# include "virconf.h"
> +# include "domain_conf.h"
> +# include "viralloc.h"
> +# include "virstring.h"
> +# include "xen_xl.h"
> +# include "libxlu_disk_i.h"
> +# include "libxlu_disk_i.h"
> +
> +#define YY_NO_INPUT
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +/* Some versions of flex have a bug (Fedora bugzilla 612465) which causes
> + * it to fail to declare these functions, which it defines.  So declare
> + * them ourselves.  Hopefully we won't have to simultaneously support
> + * a flex version which declares these differently somehow. */
> +int xlu__disk_yyget_column(yyscan_t yyscanner);
> +void xlu__disk_yyset_column(int  column_no, yyscan_t yyscanner);
> +
> +
> +/*----- useful macros and functions used in actions -----
> + * we use macros in the actual rules to keep the actions short
> + * and particularly to avoid repeating boilerplate values such as
> + * DPC->disk, yytext, etc. */
> +
> +/* For actions whose patterns contain '=', finds the start of the value */
> +#define FROMEQUALS (strchr(yytext,'=')+1)
> +
> +/* Chops the delimiter off, modifying yytext and yyleng. */
> +#define STRIP(delim) do{                                                \
> +	if (yyleng>0 && yytext[yyleng-1]==(delim))                      \
> +	    yytext[--yyleng] = 0;                                       \
> +    }while(0)
> +
> +/* Sets a string value, checking it hasn't been set already. */
> +#define SAVESTRING(what,loc,val) do{					\
> +	savestring(DPC, what " respecified", &DPC->disk->loc, (val));	\
> +    }while(0)
> +
> +int
> +asprintf(char **ret, const char *format, ...)
> +{
> +    va_list ap;
> +
> +    *ret = NULL;  /* Ensure value can be passed to free() */
> +
> +    va_start(ap, format);
> +    int count = vsnprintf(NULL, 0, format, ap);
> +    va_end(ap);
> +
> +    if (count >= 0)
> +    {
> +        char* buffer = malloc(count + 1);
> +        if (buffer == NULL)
> +            return -1;
> +
> +        va_start(ap, format);
> +        count = vsnprintf(buffer, count + 1, format, ap);
> +        va_end(ap);
> +
> +        if (count < 0)
> +        {
> +            free(buffer);
> +            return count;
> +        }
> +        *ret = buffer;
> +    }
> +
> +    return count;
> +}
> +
> +
> +static void
> +savestring(DiskParseContext *dpc,
> +           const char *what_respecified,
> +           char **update,
> +           const char *value)
> +{
> +    if (*update) {
> +        if (**update) {
> +            xlu__disk_err(dpc, value, what_respecified);
> +            return;
> +        }
> +
> +        free(*update); /* do not complain about overwriting empty strings */
> +    }
> +
> +    *update = strdup(value);
> +}
> +
> +#define DPC dpc /* our convention in lexer helper functions */
> +
> +/* Sets ->readwrite from the string.  This ought to be an enum, perhaps. */
> +static void
> +setaccess(DiskParseContext *dpc, const char *str)
> +{
> +    if (STREQ(str, "r") || STREQ(str, "ro")) {
> +        dpc->disk->src->readonly = 1;
> +    } else if (STREQ(str, "w!") || STREQ(str, "!")) {
> +	dpc->disk->src->shared = 1;
> +    } else {
> +	xlu__disk_err(dpc,str,"unknown value for access");
> +    }
> +}
> +
> +/* Sets ->format from the string.  IDL should provide something for this. */
> +static void
> +setformat(DiskParseContext *dpc, const char *str)
> +{
> +    if (STREQ(str, ""))
> +        virDomainDiskSetFormat(dpc->disk, VIR_STORAGE_FILE_RAW);
> +    else if (STREQ(str, "raw"))
> +        virDomainDiskSetFormat(dpc->disk, VIR_STORAGE_FILE_RAW);
> +    else if (STREQ(str, "qcow"))
> +        virDomainDiskSetFormat(dpc->disk, VIR_STORAGE_FILE_QCOW);
> +    else if (STREQ(str, "qcow2"))
> +        virDomainDiskSetFormat(dpc->disk, VIR_STORAGE_FILE_QCOW2);
> +    else if (STREQ(str, "vhd"))
> +        virDomainDiskSetFormat(dpc->disk, VIR_STORAGE_FILE_VHD);
> +    else xlu__disk_err(dpc, str, "unknown value for format");
> +}
> +
> +
> +/* Sets ->backend from the string.  IDL should provide something for this. */
> +static void
> +setdrivertype(DiskParseContext *dpc, const char *str)
> +{
> +    if (STREQ(str, "phy"))
> +        ignore_value(virDomainDiskSetDriver(dpc->disk, "phy"));
> +    else if (STREQ(str, "tap"))
> +        ignore_value(virDomainDiskSetDriver(dpc->disk, "tap"));
> +    else if (STREQ(str, "qdisk"))
> +        ignore_value(virDomainDiskSetDriver(dpc->disk, "qemu"));
> +    else if (STREQ(str, ""))
> +        ignore_value(virDomainDiskSetDriver(dpc->disk, "phy"));
> +    else
> +        xlu__disk_err(dpc, str, "unknown value for backendtype");
> +}
> +
> +
> +/* Handles a vdev positional parameter which includes a devtype. */
> +static int
> +vdev_and_devtype(DiskParseContext *dpc, char *str)
> +{
> +    /* returns 1 if it was <vdev>:<devtype>, 0 (doing nothing) otherwise */
> +    char *colon = strrchr(str, ':');
> +    if (!colon)
> +        return 0;
> +
> +    *colon++ = 0;
> +    SAVESTRING("vdev", dst, str);
> +
> +    if (STREQ(colon,"cdrom")) {
> +        DPC->disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM;
> +    } else if (STREQ(colon, "disk")) {
> +        DPC->disk->device = VIR_DOMAIN_DISK_DEVICE_DISK;
> +    } else {
> +        xlu__disk_err(DPC, colon, "unknown deprecated type");
> +    }
> +    return 1;
> +}
> +
> +#undef DPC /* needs to be defined differently the actual lexer */
> +#define DPC ((DiskParseContext*)yyextra)
> +
> +%}
> +
> +%option warn
> +%option nodefault
> +%option batch
> +%option 8bit
> +%option noyywrap
> +%option reentrant
> +%option prefix="xlu__disk_yy"
> +%option nounput
> +
> +%x LEXERR
> +
> +%%
> +
> + /*----- the scanner rules which do the parsing -----*/
> +
> +[ \t\n]+/([^ \t\n].*)? { /* ignore whitespace before parameters */ }
> +
> + /* ordinary parameters setting enums or strings */
> +
> +format=[^,]*,?	{ STRIP(','); setformat(DPC, FROMEQUALS); }
> +
> +cdrom,?		{ DPC->disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; }
> +devtype=cdrom,?	{ DPC->disk->device = VIR_DOMAIN_DISK_DEVICE_CDROM; }
> +devtype=disk,?	{ DPC->disk->device = VIR_DOMAIN_DISK_DEVICE_DISK; }
> +devtype=[^,]*,?	{ xlu__disk_err(DPC, yytext,"unknown value for type"); }
> +
> +access=[^,]*,?	{ STRIP(','); setaccess(DPC, FROMEQUALS); }
> +backendtype=[^,]*,? { STRIP(','); setdrivertype(DPC, FROMEQUALS); }
> +
> +vdev=[^,]*,?	{ STRIP(','); SAVESTRING("vdev", dst, FROMEQUALS); }
> +
> + /* the target magic parameter, eats the rest of the string */
> +
> +target=.*	{ STRIP(','); SAVESTRING("target", src->path, FROMEQUALS); }
> +
> + /* unknown parameters */
> +
> +[a-z][-a-z0-9]*=[^,],? { xlu__disk_err(DPC, yytext, "unknown parameter"); }
> +
> +  /* the "/.*" in these patterns ensures that they count as if they
> +   * matched the whole string, so these patterns take precedence */
> +
> +(raw|qcow2?|vhd):/.* {
> +                    STRIP(':');
> +                    DPC->had_depr_prefix=1;
> +                    setformat(DPC, yytext);
> +                 }
> +
> +tapdisk:/.*	{ DPC->had_depr_prefix=1; }
> +tap2?:/.*	{ DPC->had_depr_prefix=1; }
> +aio:/.*		{ DPC->had_depr_prefix=1; }
> +ioemu:/.*	{ DPC->had_depr_prefix=1; }
> +file:/.*	{ DPC->had_depr_prefix=1; }
> +phy:/.*		{ DPC->had_depr_prefix=1; }
> +[a-z][a-z0-9]*:/([^a-z0-9].*)? {
> +		  xlu__disk_err(DPC, yytext, "unknown deprecated disk prefix");
> +		  return 0;
> +		}
> +
> + /* positional parameters */
> +
> +[^=,]*,|[^=,]+,?  {
> +    STRIP(',');
> +
> +    if (DPC->err) {
> +        /* previous errors may just lead to subsequent ones */
> +    } else if (!DPC->disk->src->path) {
> +        SAVESTRING("target", src->path, yytext);
> +    } else if (DPC->disk->src->format == VIR_STORAGE_FILE_LAST){
> +        setformat(DPC, yytext);
> +    }
> +     else if (!DPC->disk->dst) {
> +        if (!vdev_and_devtype(DPC, yytext))
> +            SAVESTRING("vdev", dst, yytext);
> +    } else if (!DPC->access_set) {
> +        DPC->access_set = 1;
> +        setaccess(DPC, yytext);
> +    } else {
> +        xlu__disk_err(DPC, yytext, "too many positional parameters");
> +        return 0; /* don't print any more errors */
> +    }
> +}
> +
> +. {
> +    BEGIN(LEXERR);
> +    yymore();
> +}
> +<LEXERR>.* {
> +    xlu__disk_err(DPC, yytext, "bad disk syntax");
> +    return 0;
> +}
> diff --git a/src/xenconfig/xen_common.c b/src/xenconfig/xen_common.c
> index d71dd07..3949b37 100644
> --- a/src/xenconfig/xen_common.c
> +++ b/src/xenconfig/xen_common.c
> @@ -1804,7 +1804,8 @@ xenFormatVfb(virConfPtr conf, virDomainDefPtr def, int xendConfigVersion)
>  {
>      int hvm = STREQ(def->os.type, "hvm") ? 1 : 0;
>  
> -    if (def->ngraphics == 1) {
> +    if (def->ngraphics == 1 &&
> +        def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
>          if (hvm || (xendConfigVersion < XEND_CONFIG_MIN_VERS_PVFB_NEWCONF)) {
>              if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SDL) {
>                  if (xenConfigSetInt(conf, "sdl", 1) < 0)
> diff --git a/src/xenconfig/xen_xl.c b/src/xenconfig/xen_xl.c
> new file mode 100644
> index 0000000..f491958
> --- /dev/null
> +++ b/src/xenconfig/xen_xl.c
> @@ -0,0 +1,476 @@
> +/*
> + * xen_xl.c: Xen XL parsing functions
> + *
> + * 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: Kiarie Kahurani <davidkiarie4 at gmail.com>
> + */
> +#include <config.h>
> +#include <assert.h>
> +#include "virconf.h"
> +#include "virerror.h"
> +#include "domain_conf.h"
> +#include "viralloc.h"
> +#include "virstring.h"
> +#include "xen_xl.h"
> +#include "libxlu_disk_l.h"
> +#include "libxlu_disk_i.h"
> +
> +#define VIR_FROM_THIS VIR_FROM_NONE
> +
> +static int
> +xenParseXLSpice(virConfPtr conf, virDomainDefPtr def)
> +{
> +    virDomainGraphicsDefPtr graphics = NULL;
> +    unsigned long port;
> +    char *listenAddr = NULL;
> +    int val;
> +
> +    if (STREQ(def->os.type, "hvm")) {
> +        if (xenConfigGetBool(conf, "spice", &val, 0) < 0)
> +            return -1;
> +
> +        if (val) {
> +            if (VIR_ALLOC(graphics) < 0)
> +                return -1;
> +
> +            graphics->type = VIR_DOMAIN_GRAPHICS_TYPE_SPICE;
> +            if (xenConfigCopyStringOpt(conf, "spicehost", &listenAddr) < 0)
> +                goto cleanup;
> +            if (listenAddr &&
> +                virDomainGraphicsListenSetAddress(graphics, 0, listenAddr,
> +                                                  -1, true) < 0) {
> +                goto cleanup;
> +            }
> +            VIR_FREE(listenAddr);
> +
> +            if (xenConfigGetULong(conf, "spicetls_port", &port, 0) < 0)
> +                goto cleanup;
> +            graphics->data.spice.tlsPort = (int)port;
> +
> +            if (xenConfigGetULong(conf, "spiceport", &port, 0) < 0)
> +                goto cleanup;
> +
> +            graphics->data.spice.port = (int)port;
> +
> +            if (!graphics->data.spice.tlsPort &&
> +                !graphics->data.spice.port)
> +            graphics->data.spice.autoport = 1;
> +
> +            if (xenConfigGetBool(conf, "spicedisable_ticketing", &val, 0) < 0)
> +                goto cleanup;
> +            if (val) {
> +                if (xenConfigCopyStringOpt(conf, "spicepasswd",
> +                                           &graphics->data.spice.auth.passwd) < 0)
> +                    goto cleanup;
> +            }
> +
> +            if (xenConfigGetBool(conf, "spiceagent_mouse",
> +                                 &graphics->data.spice.mousemode, 0) < 0)
> +                goto cleanup;
> +            if (xenConfigGetBool(conf, "spicedvagent", &val, 0) < 0)
> +                goto cleanup;
> +            if (val) {
> +                if (xenConfigGetBool(conf, "spice_clipboard_sharing",
> +                                     &graphics->data.spice.copypaste,
> +                                     0) < 0)
> +                    goto cleanup;
> +            }
> +
> +            if (VIR_ALLOC_N(def->graphics, 1) < 0)
> +                goto cleanup;
> +            def->graphics[0] = graphics;
> +            def->ngraphics = 1;
> +        }
> +    }
> +
> +    return 0;
> +
> + cleanup:
> +    virDomainGraphicsDefFree(graphics);
> +    return -1;
> +}
> +
> +
> +
> +void
> +xlu__disk_err(DiskParseContext *dpc,
> +                   const char *erroneous,
> +                   const char *message)
> +{
> +    /*virReportError(VIR_ERR_INTERNAL_ERROR,
> +            "%s: config parsing error in disk specification: %s"
> +            "%s%s"
> +            " in `%s'\n",
> +            message,
> +            erroneous?": near `":"", erroneous?erroneous:"", erroneous?"'":"",
> +            dpc->spec);
> +    if (!dpc->err)
> +        dpc->err= EINVAL;
> +        */
> +}
> +
> +
> +static int
> +dpc_prep(DiskParseContext *dpc, const char *spec)
> +{
> +    int e;
> +    dpc->spec = spec;
> +
> +    e = xlu__disk_yylex_init_extra(dpc, &dpc->scanner);
> +    if (e)
> +        goto fail;
> +
> +    dpc->buf = xlu__disk_yy_scan_bytes(spec, strlen(spec), dpc->scanner);
> +    if (!dpc->buf) {
> +        e = ENOMEM;
> +        goto fail;
> +    }
> +
> +    return 0;
> +
> + fail:
> +    virReportError(VIR_ERR_INTERNAL_ERROR, "cannot init disk scanner: %s\n",
> +                   strerror(errno));
> +    return e;
> +}
> +
> +
> +static void
> +dpc_dispose(DiskParseContext *dpc)
> +{
> +    virDomainDiskDefFree(dpc->disk);
> +
> +    if (dpc->buf) {
> +        xlu__disk_yy_delete_buffer(dpc->buf, dpc->scanner);
> +        dpc->buf = 0;
> +    }
> +    if (dpc->scanner) {
> +        xlu__disk_yylex_destroy(dpc->scanner);
> +        dpc->scanner = 0;
> +    }
> +}
> +
> +/*
> + * positional parameters
> + *     (If the <diskspec> strings are not separated by "="
> + *     the  string is split following ',' and assigned to
> + *     the following options in the following order)
> + *     target,format,vdev,access
> + * ================================================================
> + *
> + * The parameters below cannot be specified as positional parameters:
> + *
> + * other parameters
> + *    devtype = <devtype>
> + *    backendtype = <backend-type>
> + * parameters not taken care of
> + *    backend = <domain-name>
> + *    script = <script>
> + *    direct-io-safe
> + *
> + * ================================================================
> + * The parser does not take any deprecated parameters
> + *
> + * For more information refer to /xen/docs/misc/xl-disk-configuration.txt
> + */
> +static int
> +xenParseXLDisk(virConfPtr conf, virDomainDefPtr def)
> +{
> +    int e;
> +    DiskParseContext dpc;
> +
> +    virConfValuePtr list = virConfGetValue(conf, "disk");
> +    dpc.conf = conf;
> +    dpc.scanner = 0;
> +    memset(&dpc, 0, sizeof(dpc));
> +
> +    if (list && list->type == VIR_CONF_LIST) {
> +        list = list->list;
> +        while (list) {
> +            char *specs = list->str;
> +            dpc.spec = specs;
> +
> +            if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
> +                goto skipdisk;
> +
> +            if (!(dpc.disk = virDomainDiskDefNew()))
> +                    return -1;
> +            dpc.disk->src->readonly = 0;
> +            dpc.disk->src->format = VIR_STORAGE_FILE_LAST;
> +
> +            e = dpc_prep(&dpc, specs);
> +            if (e) {
> +                dpc.err = e;
> +            }
> +            xlu__disk_yylex(dpc.scanner);
> +
> +            if (dpc.err) {
> +                dpc_dispose(&dpc);
> +            }
> +            if (dpc.disk->src->format == VIR_STORAGE_FILE_LAST) {
> +                dpc.disk->src->format = VIR_STORAGE_FILE_RAW;
> +            }
> +
> +            if (dpc.disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
> +                dpc.disk->removable = true;
> +                dpc.disk->src->readonly = true;
> +                if (!dpc.disk->src->path || STREQ(dpc.disk->src->path, ""))
> +                    dpc.disk->src->format = VIR_STORAGE_FILE_NONE;
> +            }
> +
> +            if (STRPREFIX(dpc.disk->dst, "xvd") || !STREQ(def->os.type, "hvm")) {
> +                dpc.disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
> +            } else if (STRPREFIX(dpc.disk->dst, "sd")) {
> +                dpc.disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
> +            } else {
> +                dpc.disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
> +            }
> +
> +            virDomainDiskSetType(dpc.disk, STREQ(virDomainDiskGetDriver(dpc.disk), "phy") ?
> +                                             VIR_STORAGE_TYPE_BLOCK :
> +                                             VIR_STORAGE_TYPE_FILE);
> +            if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, dpc.disk) < 0)
> +                return -1;
> +skipdisk:
> +        list = list->next;
> +        virDomainDiskDefFree(dpc.disk);
> +        dpc.disk = NULL;
> +        }
> +
> +    }
> +    return 0;
> +}
> +
> +
> +virDomainDefPtr
> +xenParseXL(virConfPtr conf, virCapsPtr caps,
> +           int xendConfigVersion)
> +{
> +    virDomainDefPtr def = NULL;
> +
> +    if (VIR_ALLOC(def) < 0)
> +        return NULL;
> +
> +    def->virtType = VIR_DOMAIN_VIRT_XEN;
> +    def->id = -1;
> +
> +    if (xenParseConfigCommon(conf, def, caps, xendConfigVersion) < 0)
> +        goto cleanup;
> +
> +    if (xenParseXLDisk(conf, def) < 0)
> +        goto cleanup;
> +
> +    if (xenParseXLSpice(conf, def) < 0)
> +        goto cleanup;
> +
> +    return def;
> +
> + cleanup:
> +    virDomainDefFree(def);
> +    return NULL;
> +}
> +
> +
> +static int
> +xenFormatXLDisk(virConfValuePtr list, virDomainDiskDefPtr disk)
> +{
> +    virBuffer buf = VIR_BUFFER_INITIALIZER;
> +    virConfValuePtr val, tmp;
> +    const char *src = virDomainDiskGetSource(disk);
> +    int format = virDomainDiskGetFormat(disk);
> +
> +    /* target */
> +    virBufferAsprintf(&buf, "%s,", src);
> +    /* format */
> +    switch (format) {
> +        case VIR_STORAGE_FILE_RAW:
> +            virBufferAddLit(&buf, "raw,");
> +            break;
> +        case VIR_STORAGE_FILE_VHD:
> +            virBufferAddLit(&buf, "xvhd,");
> +            break;
> +        case VIR_STORAGE_FILE_QCOW:
> +            virBufferAddLit(&buf, "qcow,");
> +            break;
> +        case VIR_STORAGE_FILE_QCOW2:
> +            virBufferAddLit(&buf, "qcow2,");
> +            break;
> +      /* set default */
> +        default:
> +            virBufferAddLit(&buf, "raw,");
> +    }
> +
> +    /* device */
> +    virBufferAdd(&buf, disk->dst, -1);
> +
> +    virBufferAddLit(&buf, ",");
> +
> +    if (disk->src->readonly)
> +        virBufferAddLit(&buf, "r,");
> +    else if (disk->src->shared)
> +        virBufferAddLit(&buf, "!,");
> +    else
> +        virBufferAddLit(&buf, "w,");
> +    if (disk->transient) {
> +        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
> +                       _("transient disks not supported yet"));
> +        goto cleanup;
> +    }
> +
> +    if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM)
> +        virBufferAddLit(&buf, "cdrom");
> +
> +    if (virBufferCheckError(&buf) < 0)
> +        goto cleanup;
> +
> +    if (VIR_ALLOC(val) < 0)
> +        goto cleanup;
> +
> +    val->type = VIR_CONF_STRING;
> +    val->str = virBufferContentAndReset(&buf);
> +    tmp = list->list;
> +    while (tmp && tmp->next)
> +        tmp = tmp->next;
> +    if (tmp)
> +        tmp->next = val;
> +    else
> +        list->list = val;
> +    return 0;
> +
> + cleanup:
> +    virBufferFreeAndReset(&buf);
> +    return -1;
> +}
> +
> +
> +static int
> +xenFormatXLDomainDisks(virConfPtr conf, virDomainDefPtr def)
> +{
> +    virConfValuePtr diskVal = NULL;
> +    size_t i = 0;
> +
> +    if (VIR_ALLOC(diskVal) < 0)
> +        return -1;
> +
> +    diskVal->type = VIR_CONF_LIST;
> +    diskVal->list = NULL;
> +
> +    for (i = 0; i < def->ndisks; i++) {
> +        if (def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)
> +            continue;
> +        if (xenFormatXLDisk(diskVal, def->disks[i]) < 0)
> +
> +                goto cleanup;
> +    }
> +
> +    if (diskVal->list != NULL) {
> +        int ret = virConfSetValue(conf, "disk", diskVal);
> +        diskVal = NULL;
> +        if (ret < 0)
> +            goto cleanup;
> +    }
> +
> +    return 0;
> +
> + cleanup:
> +    virConfFreeValue(diskVal);
> +    return 0;
> +}
> +
> +
> +static int
> +xenFormatXLSpice(virConfPtr conf, virDomainDefPtr def)
> +{
> +    const char *listenAddr = NULL;
> +
> +    if (STREQ(def->os.type, "hvm")) { /*save's CPU :-) */
> +        if (def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
> +            /* set others to false but may not be necessary */
> +            if (xenConfigSetInt(conf, "sdl", 0) < 0)
> +                return -1;
> +
> +            if (xenConfigSetInt(conf, "vnc", 0) < 0)
> +                return -1;
> +
> +            if (xenConfigSetInt(conf, "spice", 1) < 0)
> +                return -1;
> +
> +            if (xenConfigSetInt(conf, "spiceport",
> +                                def->graphics[0]->data.spice.port) < 0)
> +                return -1;
> +
> +            if (xenConfigSetInt(conf, "spicetls_port",
> +                                def->graphics[0]->data.spice.tlsPort) < 0)
> +                return -1;
> +
> +            if (def->graphics[0]->data.spice.auth.passwd) {
> +                if (xenConfigSetInt(conf, "spicedisable_ticketing", 1) < 0)
> +                    return -1;
> +
> +                if (def->graphics[0]->data.spice.auth.passwd &&
> +                    xenConfigSetString(conf, "spicepasswd",
> +                                def->graphics[0]->data.spice.auth.passwd) < 0)
> +                    return -1;
> +            }
> +
> +            listenAddr = virDomainGraphicsListenGetAddress(def->graphics[0], 0);
> +            if (listenAddr &&
> +                xenConfigSetString(conf, "spicehost", listenAddr) < 0) {
> +                return -1;
> +            }
> +
> +            if (xenConfigSetInt(conf, "spice_mouse_agent",
> +                                def->graphics[0]->data.spice.mousemode) < 0)
> +                return -1;
> +            if (def->graphics[0]->data.spice.copypaste) {
> +                if (xenConfigSetInt(conf, "spicedvagent", 1) < 0)
> +                    return -1;
> +                if (xenConfigSetInt(conf, "spice_clipboard_sharing",
> +                                def->graphics[0]->data.spice.copypaste) < 0)
> +                return -1;
> +            }
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +
> +virConfPtr
> +xenFormatXL(virDomainDefPtr def, virConnectPtr conn,
> +            int xendConfigVersion)
> +{
> +    virConfPtr conf = NULL;
> +
> +    if (!(conf = virConfNew()))
> +        goto cleanup;
> +
> +    if (xenFormatConfigCommon(conf, def, conn, xendConfigVersion) < 0)
> +        goto cleanup;
> +
> +    if (xenFormatXLDomainDisks(conf, def) < 0)
> +        goto cleanup;
> +
> +    if (xenFormatXLSpice(conf, def) < 0)
> +        goto cleanup;
> +
> +    return conf;
> +
> + cleanup:
> +    if (conf)
> +        virConfFree(conf);
> +    return NULL;
> +}
> diff --git a/src/xenconfig/xen_xl.h b/src/xenconfig/xen_xl.h
> new file mode 100644
> index 0000000..d60fe5e
> --- /dev/null
> +++ b/src/xenconfig/xen_xl.h
> @@ -0,0 +1,29 @@
> +/*
> + * xen_xl.h: Xen XL parsing functions
> + *
> + * 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: Kiarie Kahurani<davidkiarie4 at gmail.com>
> + */
> +#ifndef _XEN_XL_H_
> +# define _XEN_XL_H_
> +
> +# include "xen_common.h"
> +
> +virDomainDefPtr xenParseXL(virConfPtr conn, virCapsPtr caps,
> +                           int xendConfigVersion);
> +virConfPtr xenFormatXL(virDomainDefPtr def,
> +                       virConnectPtr, int xendConfigVersion);
> +#endif /* _XEN_XL_H_ */
>   




More information about the libvir-list mailing list