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

John Ferlan jferlan at redhat.com
Fri Jan 9 15:36:12 UTC 2015



On 12/15/2014 11:30 PM, Jim Fehlig wrote:
> From: Kiarie Kahurani <davidkiarie4 at gmail.com>
> 
> 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. These 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, the above diskspec would be written as
> 
> phy:/dev/vg/guest-volume,hda,w
> 
> The disk parser is based on the same parser used successfully by
> the Xen project for several years now.  Ian Jackson authored the
> scanner, which is used by this commit with mimimal changes.  Only
> the PREFIX option is changed, to produce function and file names
> more consistent with libvirt's convention.
> 
> Signed-off-by: Kiarie Kahurani <davidkiarie4 at gmail.com>
> Signed-off-by: Jim Fehlig <jfehlig at suse.com>
> ---
>  .gitignore                    |   1 +
>  cfg.mk                        |   3 +-
>  configure.ac                  |   1 +
>  po/POTFILES.in                |   1 +
>  src/Makefile.am               |  25 ++-
>  src/libvirt_xenconfig.syms    |   4 +
>  src/xenconfig/xen_common.c    |   3 +-
>  src/xenconfig/xen_xl.c        | 499 ++++++++++++++++++++++++++++++++++++++++++
>  src/xenconfig/xen_xl.h        |  33 +++
>  src/xenconfig/xen_xl_disk.l   | 256 ++++++++++++++++++++++
>  src/xenconfig/xen_xl_disk_i.h |  39 ++++
>  11 files changed, 861 insertions(+), 4 deletions(-)
> 

In addition to the build issues - it seems the generated "xen_xl_disk.c"
has numerous issues found by Coverity. Since it's not clear to me how
this is all put together - I'll cut-n-paste from my Coverity output and
provide some basic analysis - hope it all makes sense... 


Coverity Error: FORWARD_NULL  (4 times - same root cause)
   Routines: xl_disk_restart, xl_disk__switch_to_buffer, xl_disk_push_buffer_state
             xl_disk_lex

  NOTE: While the generated .c file indicates YY_CURRENT_BUFFER_LVALUE is the same
        as YY_CURRENT_BUFFER, but useful when we know the buffer stack is not NULL
        or when we need an lvalue.

        As it turns out the yy_set_interactive and yy_set_bol macros will check 
        if ( ! YY_CURRENT_BUFFER ), but then follow that up with a YY_CURRENT_BUFFER_LVALUE
        access both within the if statement and after the if statement.

        So it seems the YY_CURRENT_BUFFER_LVALUE needs a similar yyg->yy_buffer_stack
        check to prevent a possible bad access.

The following output is just from xl_disk_restart, but is similar to others...

1782 	 */
1783 	    void xl_disk_restart  (FILE * input_file , yyscan_t yyscanner)
1784 	{
1785 	    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
1786 	

(1) Event cond_false: 	Condition "yyg->yy_buffer_stack", taking false branch
(2) Event var_compare_op: 	Comparing "yyg->yy_buffer_stack" to null implies that "yyg->yy_buffer_stack" might be null.
(3) Event cond_true: 	Condition "!(yyg->yy_buffer_stack ? yyg->yy_buffer_stack[yyg->yy_buffer_stack_top] : NULL)", taking true branch
Also see events: 	[var_deref_op]

1787 		if ( ! YY_CURRENT_BUFFER ){
1788 	        xl_disk_ensure_buffer_stack (yyscanner);

(4) Event var_deref_op: 	Dereferencing null pointer "yyg->yy_buffer_stack".
Also see events: 	[var_compare_op]

1789 			YY_CURRENT_BUFFER_LVALUE =
1790 	            xl_disk__create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
1791 		}


Coverity Error: NESTING_INDENT_MISMATCH
   Routine: xl_disk_lex
   NOTE: Based on what I see, it seems the if statement at line 1118 needs an 
         open parenthesis "{" followed by a close parenthesis at line 1140

1105 	 /*----- the scanner rules which do the parsing -----*/
1106 	
1107 	#line 1108 "xenconfig/xen_xl_disk.c"
1108 	
1109 		if ( !yyg->yy_init )
1110 			{
1111 			yyg->yy_init = 1;
1112 	
1113 	#ifdef YY_USER_INIT
1114 			YY_USER_INIT;
1115 	#endif
1116 	
1117 	        /* Create the reject buffer large enough to save one state per allowed character. */

(1) Event parent: 	This 'if' statement is the parent, indented to column 9.
Also see events: 	[nephew][uncle]

1118 	        if ( ! yyg->yy_state_buf )

(2) Event nephew: 	This statement is nested within its parent, indented to column 13.
Also see events: 	[parent][uncle]

1119 	            yyg->yy_state_buf = (yy_state_type *)xl_disk_alloc(YY_STATE_BUF_SIZE  ,yyscanner);

(3) Event uncle: 	This 'if' statement is indented to column 13, as if it were nested within the preceding parent statement, but it is not.
Also see events: 	[parent][nephew]

1120 	            if ( ! yyg->yy_state_buf )
1121 	                YY_FATAL_ERROR( "out of dynamic memory in xl_disk_lex()" );
1122 	
1123 			if ( ! yyg->yy_start )
1124 				yyg->yy_start = 1;	/* first start state */
...
1137 	
1138 			xl_disk__load_buffer_state(yyscanner );
1139 			}
1140 	
1141 		while ( 1 )		/* loops until end-of-file is reached */



Coverity Error: REVERSE_INULL
    Routine: xl_disk_pop_buffer_state
    NOTE: Similar to the first issue, except that in this case we have the 
          check/return at lines 1989 and 1990, but then later on we check
          it again at line 1997, which causes the (2) event below.

1986 	void xl_disk_pop_buffer_state (yyscan_t yyscanner)
1987 	{
1988 	    struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
1989 		if (!YY_CURRENT_BUFFER)
1990 			return;
1991 	
1992 		xl_disk__delete_buffer(YY_CURRENT_BUFFER ,yyscanner);

(1) Event deref_ptr: 	Directly dereferencing pointer "yyg->yy_buffer_stack".
Also see events: 	[check_after_deref]

1993 		YY_CURRENT_BUFFER_LVALUE = NULL;
1994 		if (yyg->yy_buffer_stack_top > 0)
1995 			--yyg->yy_buffer_stack_top;
1996 	

(2) Event check_after_deref: 	Null-checking "yyg->yy_buffer_stack" suggests that it may be null, but it has already been dereferenced on all paths leading to the check.
Also see events: 	[deref_ptr]

1997 		if (YY_CURRENT_BUFFER) {
1998 			xl_disk__load_buffer_state(yyscanner );


Coverity Error: UNUSED_VALUE
    Routine: xl_disk_lex
    NOTE: This one I'm not sure about - usually it's the unconditional setting
          at (1) that ends up being the issue because a setting at (2) does it
          for something specific.  But in this case, I'm not sure what the exact
          complaint is.

1179 	
1180 	yy_find_action:

(1) Event value_overwrite: 	Value from "yy_get_previous_state(yyscanner)" is overwritten with value from "*--yyg->yy_state_ptr".
Also see events: 	[returned_value]

1181 			yy_current_state = *--yyg->yy_state_ptr;
1182 			yyg->yy_lp = yy_accept[yy_current_state];
1183 	find_rule: /* we branch to this label when backing up */
...
1517 				case EOB_ACT_LAST_MATCH:
1518 					yyg->yy_c_buf_p =
1519 					&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[yyg->yy_n_chars];
1520 	

(2) Event returned_value: 	Value from "yy_get_previous_state(yyscanner)" is assigned to "yy_current_state" here, but that stored value is not used before it is overwritten.
Also see events: 	[value_overwrite]

1521 					yy_current_state = yy_get_previous_state( yyscanner );
1522 	
1523 					yy_cp = yyg->yy_c_buf_p;
1524 					yy_bp = yyg->yytext_ptr + YY_MORE_ADJ;


> diff --git a/.gitignore b/.gitignore
> index 9d09709..eac2203 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -140,6 +140,7 @@
>  /src/remote/*_protocol.[ch]
>  /src/rpc/virkeepaliveprotocol.[ch]
>  /src/rpc/virnetprotocol.[ch]
> +/src/xenconfig/xen_xl_disk.[ch]
>  /src/test_libvirt*.aug
>  /src/test_virtlockd.aug
>  /src/util/virkeymaps.h
> diff --git a/cfg.mk b/cfg.mk
> index 21f83c3..3df3dcb 100644
> --- a/cfg.mk
> +++ b/cfg.mk
> @@ -89,8 +89,9 @@ distdir: sc_vulnerable_makefile_CVE-2012-3386.z
>  endif
>  
>  # Files that should never cause syntax check failures.
> +#  (^(HACKING|docs/(news\.html\.in|.*\.patch))|\.(po|fig|gif|ico|png))$$
>  VC_LIST_ALWAYS_EXCLUDE_REGEX = \
> -  (^(HACKING|docs/(news\.html\.in|.*\.patch))|\.(po|fig|gif|ico|png))$$
> +  (^(HACKING|docs/(news\.html\.in|.*\.patch)|src/xenconfig/xen_xl_disk.[chl])|\.(po|fig|gif|ico|png))$$
>  
>  # Functions like free() that are no-ops on NULL arguments.
>  useless_free_options =				\
> diff --git a/configure.ac b/configure.ac
> index 9fd44b2..777367e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -146,6 +146,7 @@ m4_ifndef([LT_INIT], [
>  ])
>  AM_PROG_CC_C_O
>  AM_PROG_LD
> +AM_PROG_LEX
>  
>  AC_MSG_CHECKING([for how to mark DSO non-deletable at runtime])
>  LIBVIRT_NODELETE=
> diff --git a/po/POTFILES.in b/po/POTFILES.in
> index e7cb2cc..094c8e3 100644
> --- a/po/POTFILES.in
> +++ b/po/POTFILES.in
> @@ -247,6 +247,7 @@ src/xenapi/xenapi_driver.c
>  src/xenapi/xenapi_utils.c
>  src/xenconfig/xen_common.c
>  src/xenconfig/xen_sxpr.c
> +src/xenconfig/xen_xl.c
>  src/xenconfig/xen_xm.c
>  tests/virpolkittest.c
>  tools/libvirt-guests.sh.in
> diff --git a/src/Makefile.am b/src/Makefile.am
> index b6c1701..23c433d 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -999,11 +999,22 @@ CPU_SOURCES =							\
>  VMX_SOURCES =							\
>  		vmx/vmx.c vmx/vmx.h
>  
> +AM_LFLAGS = -Pxl_disk_ --header-file=../$*.h
> +LEX_OUTPUT_ROOT = lex.xl_disk_
> +BUILT_SOURCES += xenconfig/xen_xl_disk.c xenconfig/xen_xl_disk.h
> +# Generated header file is not implicitly added to dist
> +EXTRA_DIST += xenconfig/xen_xl_disk.h
> +CLEANFILES += xenconfig/xen_xl_disk.h xenconfig/xen_xl_disk.c
> +
> +XENXLDISKPARSER_SOURCES = xenconfig/xen_xl_disk.l
> +
>  XENCONFIG_SOURCES =						\
>  		xenconfig/xenxs_private.h			\
> -		xenconfig/xen_common.c xenconfig/xen_common.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_xm.c xenconfig/xen_xm.h		\
> +		xenconfig/xen_xl.c xenconfig/xen_xl.h		\
> +		xenconfig/xen_xl_disk_i.h
>  
>  pkgdata_DATA =	cpu/cpu_map.xml
>  
> @@ -1058,10 +1069,19 @@ libvirt_vmx_la_SOURCES = $(VMX_SOURCES)
>  endif WITH_VMX
>  
>  if WITH_XENCONFIG
> +# Flex generated XL disk parser needs to be compiled without WARN_FLAGS
> +# Add the generated object to its own library to control CFLAGS
> +noinst_LTLIBRARIES += libvirt_xenxldiskparser.la
> +libvirt_xenxldiskparser_la_CFLAGS = \
> +		-I$(top_srcdir)/src/conf
> +libvirt_xenxldiskparser_la_SOURCES = \
> +	$(XENXLDISKPARSER_SOURCES)
> +
>  noinst_LTLIBRARIES += libvirt_xenconfig.la
>  libvirt_la_BUILT_LIBADD += libvirt_xenconfig.la
>  libvirt_xenconfig_la_CFLAGS = \
>  		-I$(top_srcdir)/src/conf $(AM_CFLAGS)
> +libvirt_xenconfig_la_LIBADD = libvirt_xenxldiskparser.la
>  libvirt_xenconfig_la_SOURCES = $(XENCONFIG_SOURCES)
>  endif WITH_XENCONFIG
>  
> @@ -1823,6 +1843,7 @@ EXTRA_DIST +=							\
>  		$(VBOX_DRIVER_EXTRA_DIST)			\
>  		$(VMWARE_DRIVER_SOURCES)			\
>  		$(XENCONFIG_SOURCES)				\
> +		$(XENXLDISKPARSER_SOURCES)			\
>  		$(ACCESS_DRIVER_POLKIT_POLICY)
>  
>  check-local: check-augeas
> 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/xen_common.c b/src/xenconfig/xen_common.c
> index 8ff10a0..b94b5db 100644
> --- a/src/xenconfig/xen_common.c
> +++ b/src/xenconfig/xen_common.c
> @@ -1801,7 +1801,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..8d1d2a7
> --- /dev/null
> +++ b/src/xenconfig/xen_xl.c
> @@ -0,0 +1,499 @@
> +/*
> + * 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 "virconf.h"
> +#include "virerror.h"
> +#include "domain_conf.h"
> +#include "viralloc.h"
> +#include "virstring.h"
> +#include "xen_xl.h"
> +#include "xen_xl_disk.h"
> +#include "xen_xl_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
> +xenXLDiskParserError(xenXLDiskParserContext *dpc,
> +                     const char *erroneous,
> +                     const char *message)
> +{
> +    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
> +                   _("disk config %s not supported: %s"),
> +                   erroneous, message);
> +
> +    if (!dpc->err)
> +        dpc->err = EINVAL;
> +}
> +
> +
> +static int
> +xenXLDiskParserPrep(xenXLDiskParserContext *dpc,
> +                    const char *spec,
> +                    virDomainDiskDefPtr disk)
> +{
> +    int err;
> +
> +    dpc->spec = spec;
> +    dpc->disk = disk;
> +    dpc->access_set = 0;
> +
> +    err = xl_disk_lex_init_extra(dpc, &dpc->scanner);
> +    if (err)
> +        goto fail;
> +
> +    dpc->buf = xl_disk__scan_bytes(spec, strlen(spec), dpc->scanner);
> +    if (!dpc->buf) {
> +        err = ENOMEM;
> +        goto fail;
> +    }
> +
> +    return 0;
> +
> + fail:
> +    virReportSystemError(errno, "%s",
> +                         _("failed to initialize disk configuration parser"));
> +    return err;
> +}
> +
> +
> +static void
> +xenXLDiskParserCleanup(xenXLDiskParserContext *dpc)
> +{
> +    if (dpc->buf) {
> +        xl_disk__delete_buffer(dpc->buf, dpc->scanner);
> +        dpc->buf = NULL;
> +    }
> +
> +    if (dpc->scanner) {
> +        xl_disk_lex_destroy(dpc->scanner);
> +        dpc->scanner = NULL;
> +    }
> +}
> +
> +
> +/*
> + * 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)
> +{
> +    virConfValuePtr list = virConfGetValue(conf, "disk");
> +    xenXLDiskParserContext dpc;
> +    virDomainDiskDefPtr disk;
> +
> +    memset(&dpc, 0, sizeof(dpc));
> +
> +    if (list && list->type == VIR_CONF_LIST) {
> +        list = list->list;
> +        while (list) {
> +            char *disk_spec = list->str;
> +            const char *driver;
> +
> +            if ((list->type != VIR_CONF_STRING) || (list->str == NULL))
> +                goto skipdisk;
> +
> +            if (!(disk = virDomainDiskDefNew()))
> +                    return -1;
> +
> +            disk->src->readonly = 0;
> +            disk->src->format = VIR_STORAGE_FILE_LAST;
> +
> +            if (xenXLDiskParserPrep(&dpc, disk_spec, disk))
> +                goto fail;
> +
> +            xl_disk_lex(dpc.scanner);
> +
> +            if (dpc.err)
> +                goto fail;
> +
> +            if (disk->src->format == VIR_STORAGE_FILE_LAST)
> +                disk->src->format = VIR_STORAGE_FILE_RAW;
> +
> +            if (disk->device == VIR_DOMAIN_DISK_DEVICE_CDROM) {
> +                disk->removable = true;
> +                disk->src->readonly = true;
> +                if (virDomainDiskSetDriver(disk, "qemu") < 0)
> +                    goto fail;
> +
> +                virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
> +                if (!disk->src->path || STREQ(disk->src->path, ""))
> +                    disk->src->format = VIR_STORAGE_FILE_NONE;
> +            }
> +
> +            if (STRPREFIX(disk->dst, "xvd") || !STREQ(def->os.type, "hvm"))
> +                disk->bus = VIR_DOMAIN_DISK_BUS_XEN;
> +            else if (STRPREFIX(disk->dst, "sd"))
> +                disk->bus = VIR_DOMAIN_DISK_BUS_SCSI;
> +            else
> +                disk->bus = VIR_DOMAIN_DISK_BUS_IDE;
> +
> +            driver = virDomainDiskGetDriver(disk);
> +            if (!driver) {
> +                switch (disk->src->format) {
> +                case VIR_STORAGE_FILE_QCOW:
> +                case VIR_STORAGE_FILE_QCOW2:
> +                case VIR_STORAGE_FILE_VHD:
> +                    driver = "qemu";
> +                    if (virDomainDiskSetDriver(disk, "qemu") < 0)
> +                        goto fail;
> +                    break;
> +                default:
> +                    driver = "phy";
> +                    if (virDomainDiskSetDriver(disk, "phy") < 0)
> +                        goto fail;
> +                }
> +            }
> +
> +            if (STREQ(driver, "phy"))
> +                virDomainDiskSetType(disk, VIR_STORAGE_TYPE_BLOCK);
> +            else
> +                virDomainDiskSetType(disk, VIR_STORAGE_TYPE_FILE);
> +
> +            if (VIR_APPEND_ELEMENT(def->disks, def->ndisks, disk) < 0)
> +                goto fail;
> +
> +        skipdisk:
> +            list = list->next;
> +            xenXLDiskParserCleanup(&dpc);
> +        }
> +    }
> +    return 0;
> +
> + fail:
> +    xenXLDiskParserCleanup(&dpc);
> +    virDomainDiskDefFree(disk);
> +    return -1;
> +}
> +
> +
> +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, "devtype=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")) {
> +        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, "spicemouse_mouse",
> +                                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..536e9b7
> --- /dev/null
> +++ b/src/xenconfig/xen_xl.h
> @@ -0,0 +1,33 @@
> +/*
> + * 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 __VIR_XEN_XL_H__
> +# define __VIR_XEN_XL_H__
> +
> +# include "virconf.h"
> +# include "domain_conf.h"
> +# include "xen_common.h"
> +
> +virDomainDefPtr xenParseXL(virConfPtr conn, virCapsPtr caps,
> +                           int xendConfigVersion);
> +virConfPtr xenFormatXL(virDomainDefPtr def,
> +                       virConnectPtr, int xendConfigVersion);
> +
> +#endif /* __VIR_XEN_XL_H__ */
> diff --git a/src/xenconfig/xen_xl_disk.l b/src/xenconfig/xen_xl_disk.l
> new file mode 100644
> index 0000000..164aa32
> --- /dev/null
> +++ b/src/xenconfig/xen_xl_disk.l
> @@ -0,0 +1,256 @@
> +/*
> + * xen_xl_disk.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 "viralloc.h"
> +# include "virstoragefile.h"
> +# include "virstring.h"
> +# include "domain_conf.h"
> +# include "xen_xl.h"
> +# include "xen_xl_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 xl_disk_lexget_column(yyscan_t yyscanner);
> +void xl_disk_lexset_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)
> +
> +
> +static void
> +savestring(xenXLDiskParserContext *dpc,
> +           const char *what_respecified,
> +           char **update,
> +           const char *value)
> +{
> +    if (*update) {
> +        if (**update) {
> +            xenXLDiskParserError(dpc, value, what_respecified);
> +            return;
> +        }
> +
> +        VIR_FREE(*update); /* do not complain about overwriting empty strings */
> +    }
> +
> +    ignore_value(VIR_STRDUP(*update, value));
> +}
> +
> +#define DPC dpc /* our convention in lexer helper functions */
> +
> +/* Sets ->readwrite from the string. */
> +static void
> +setaccess(xenXLDiskParserContext *dpc, const char *str)
> +{
> +    if (STREQ(str, "rw") || STREQ(str, "w")) {
> +        dpc->disk->src->readonly = 0;
> +    } else if (STREQ(str, "r") || STREQ(str, "ro")) {
> +        dpc->disk->src->readonly = 1;
> +    } else if (STREQ(str, "w!") || STREQ(str, "!")) {
> +        dpc->disk->src->readonly = 0;
> +	dpc->disk->src->shared = 1;
> +    } else {
> +        xenXLDiskParserError(dpc, str, "unknown value for access");
> +    }
> +    dpc->access_set = 1;
> +}
> +
> +/* Sets ->format from the string.  IDL should provide something for this. */
> +static void
> +setformat(xenXLDiskParserContext *dpc, const char *str)
> +{
> +    if (STREQ(str, "") || 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
> +        xenXLDiskParserError(dpc, str, "unknown value for format");
> +}
> +
> +
> +/* Sets ->backend from the string.  IDL should provide something for this. */
> +static void
> +setdrivertype(xenXLDiskParserContext *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, "file") || STREQ(str, ""))
> +        ignore_value(virDomainDiskSetDriver(dpc->disk, "qemu"));
> +    else
> +        xenXLDiskParserError(dpc, str, "unknown value for backendtype");
> +}
> +
> +
> +/* Handles a vdev positional parameter which includes a devtype. */
> +static int
> +vdev_and_devtype(xenXLDiskParserContext *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 {
> +        xenXLDiskParserError(DPC, colon, "unknown deprecated type");
> +    }
> +    return 1;
> +}
> +
> +#undef DPC /* needs to be defined differently the actual lexer */
> +#define DPC ((xenXLDiskParserContext*)yyextra)
> +
> +%}
> +
> +%option warn
> +%option nodefault
> +%option batch
> +%option 8bit
> +%option noyywrap
> +%option reentrant
> +%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=[^,]*,?	{ xenXLDiskParserError(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]*=[^,],? { xenXLDiskParserError(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].*)? {
> +		  xenXLDiskParserError(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 {
> +        xenXLDiskParserError(DPC, yytext, "too many positional parameters");
> +        return 0; /* don't print any more errors */
> +    }
> +}
> +
> +. {
> +    BEGIN(LEXERR);
> +    yymore();
> +}
> +<LEXERR>.* {
> +    xenXLDiskParserError(DPC, yytext, "bad disk syntax");
> +    return 0;
> +}
> diff --git a/src/xenconfig/xen_xl_disk_i.h b/src/xenconfig/xen_xl_disk_i.h
> new file mode 100644
> index 0000000..063dedf
> --- /dev/null
> +++ b/src/xenconfig/xen_xl_disk_i.h
> @@ -0,0 +1,39 @@
> +/*
> + * xen_xl_disk_i.h - common header for disk spec parser
> + *
> + * 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.
> + */
> +
> +#ifndef __VIR_XEN_XL_DISK_I_H__
> +# define __VIR_XEN_XL_DISK_I_H__
> +
> +# include "virconf.h"
> +# include "domain_conf.h"
> +
> +
> +typedef struct {
> +    int err;
> +    void *scanner;
> +    YY_BUFFER_STATE buf;
> +    virDomainDiskDefPtr disk;
> +    int access_set;
> +    int had_depr_prefix;
> +    const char *spec;
> +} xenXLDiskParserContext;
> +
> +void xenXLDiskParserError(xenXLDiskParserContext *dpc,
> +                          const char *erroneous,
> +                          const char *message);
> +
> +#endif /* __VIR_XEN_XL_DISK_I_H__ */
> 




More information about the libvir-list mailing list