On 12/15/2014 11:30 PM, Jim Fehlig wrote: > From: Kiarie Kahurani <davidkiarie4@xxxxxxxxx> > > 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@xxxxxxxxx> > Signed-off-by: Jim Fehlig <jfehlig@xxxxxxxx> > --- > .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@xxxxxxxxx> > + */ > + > +#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@xxxxxxxxx> > + */ > + > +#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@xxxxxxxxxxxxx> > + * > + * 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@xxxxxxxxxxxxx> > + * > + * 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__ */ > -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list