xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Replace config file parser for "xl"
@ 2010-03-02 19:24 Ian Jackson
  2010-03-02 21:29 ` Vincent Hanquez
  2010-03-04 18:47 ` [PATCH] Fix config file interpretation when pci= not specified Ian Jackson
  0 siblings, 2 replies; 3+ messages in thread
From: Ian Jackson @ 2010-03-02 19:24 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: message body text --]
[-- Type: text/plain, Size: 981 bytes --]

This provides a replacement config file parser for "xl" based on bison
and flex.

Benefits:
  * proper error reporting with line numbers
  * parser can understand nearly all "xm" configuration files directly
     (doesn't understand Python code but should do everything else)
  * parser also understands the ;-infested "xl" style files
  * removes the dependency on libconfig
  * better checking for certain kinds of mistakes
  * eliminates the strange "massage file and try again" code

This is intended to support all config files currently supported by
"xl" and almost all files supported by "xm".  (NB that whether a
feature works depends on the implementation of that feature in
xl/libxl of course.)

This patch also introduces a new library "libxlutil" which is mainly
for the benefit of "xl".  Users of libxl do not need to use libxlutil,
but they can do so if they want to parse "xl" files without being
"xl".

Ian.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>


[-- Attachment #2: New config parser for xl --]
[-- Type: text/plain, Size: 34167 bytes --]

diff -r 9c0793e75f54 .hgignore
--- a/.hgignore	Wed Feb 24 11:03:56 2010 +0000
+++ b/.hgignore	Tue Mar 02 19:19:48 2010 +0000
@@ -180,7 +180,8 @@
 ^tools/libxen/libxenapi-
 ^tools/libxen/test/test_bindings$
 ^tools/libxen/test/test_event_handling$
-^tools/libxl/libconfig.*$
+^tools/libxl/libxlu_cfg_[yl]\.[ch]$
+^tools/libxl/libxlu_cfg_y\.output
 ^tools/libxl/xl$
 ^tools/libaio/src/.*\.ol$
 ^tools/libaio/src/.*\.os$
diff -r 9c0793e75f54 Config.mk
--- a/Config.mk	Wed Feb 24 11:03:56 2010 +0000
+++ b/Config.mk	Tue Mar 02 19:19:48 2010 +0000
@@ -34,6 +34,9 @@
 EXTRA_INCLUDES += $(EXTRA_PREFIX)/include
 EXTRA_LIB += $(EXTRA_PREFIX)/$(LIBLEAFDIR)
 endif
+
+BISON	?= bison
+FLEX	?= flex
 
 PYTHON      ?= python
 PYTHON_PREFIX_ARG ?= --prefix="$(PREFIX)"
diff -r 9c0793e75f54 README
--- a/README	Wed Feb 24 11:03:56 2010 +0000
+++ b/README	Tue Mar 02 19:19:48 2010 +0000
@@ -49,6 +49,7 @@
     * bridge-utils package (/sbin/brctl)
     * iproute package (/sbin/ip)
     * hotplug or udev
+    * GNU bison and GNU flex
 
 [NB. Unless noted otherwise, all the following steps should be
 performed with root privileges.]
diff -r 9c0793e75f54 tools/libxl/Makefile
--- a/tools/libxl/Makefile	Wed Feb 24 11:03:56 2010 +0000
+++ b/tools/libxl/Makefile	Tue Mar 02 19:19:48 2010 +0000
@@ -8,24 +8,40 @@
 MAJOR = 1.0
 MINOR = 0
 
+XLUMAJOR = 1.0
+XLUMINOR = 0
+
 #CFLAGS += -Werror
 CFLAGS += -I. -fPIC
 CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_libxenstore)
 
 LIBS = $(LDFLAGS_libxenctrl) $(LDFLAGS_libxenguest) $(LDFLAGS_libxenstore)
 
-#LIBCONFIG_URL ?= http://www.hyperrealm.com/libconfig
-LIBCONFIG_URL = $(XEN_EXTFILES_URL)
-LIBCONFIG_SOURCE = libconfig-1.3.2
-LIBCONFIG_OUTPUT = $(LIBCONFIG_SOURCE)/.libs
-
 LIBXL_OBJS-y = osdeps.o
 LIBXL_OBJS = flexarray.o libxl.o libxl_dom.o libxl_exec.o libxl_xshelp.o libxl_device.o libxl_internal.o xenguest.o libxl_utils.o $(LIBXL_OBJS-y)
+
+AUTOINCS= libxlu_cfg_y.h libxlu_cfg_l.h
+AUTOSRCS= libxlu_cfg_y.c libxlu_cfg_l.c
+LIBXLU_OBJS = libxlu_cfg_y.o libxlu_cfg_l.o libxlu_cfg.o
 
 CLIENTS = xl
 
 .PHONY: all
-all: $(CLIENTS) libxenlight.so libxenlight.a
+all: $(CLIENTS) libxenlight.so libxenlight.a libxlutil.so libxlutil.a \
+	$(AUTOSRCS) $(AUTOINCS)
+
+$(AUTOINCS): $(AUTOSRCS)
+
+#%_y.h: %_y.c
+#%_l.h: %_l.c
+
+$(LIBXLU_OBJS): $(AUTOINCS)
+
+%.c: %.y
+	$(BISON) --output=$@ $<
+
+%.c: %.l
+	$(FLEX) --header-file=$*.h --outfile=$@ $<
 
 libxenlight.so: libxenlight.so.$(MAJOR)
 	ln -sf $< $@
@@ -39,18 +55,23 @@
 libxenlight.a: $(LIBXL_OBJS)
 	$(AR) rcs libxenlight.a $^
 
-$(LIBCONFIG_SOURCE).tar.gz:
-	$(WGET) $(LIBCONFIG_URL)/$@
+libxlutil.so: libxlutil.so.$(XLUMAJOR)
+	ln -sf $< $@
 
-$(LIBCONFIG_OUTPUT)/libconfig.so: $(LIBCONFIG_SOURCE).tar.gz
-	[ ! -d "$(LIBCONFIG_SOURCE)" ] && tar xzf $<
-	cd $(LIBCONFIG_SOURCE) && ./configure --prefix=$(PREFIX) --libdir=$(LIBDIR) --disable-cxx && $(MAKE)
+libxlutil.so.$(XLUMAJOR): libxlutil.so.$(XLUMAJOR).$(XLUMINOR)
+	ln -sf $< $@
 
-xl.o: $(LIBCONFIG_OUTPUT)/libconfig.so xl.c
-	$(CC) $(CFLAGS) -I$(LIBCONFIG_SOURCE) -c xl.c
+libxlutil.so.$(XLUMAJOR).$(XLUMINOR): $(LIBXLU_OBJS)
+	$(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxlutil.so.$(XLUMAJOR) $(SHLIB_CFLAGS) -o $@ $^
 
-$(CLIENTS): xl.o libxenlight.so $(LIBCONFIG_OUTPUT)/libconfig.so
-	$(CC) $(LDFLAGS) -o $@ $< $(LIBS) -L . -lxenlight -L$(LIBCONFIG_OUTPUT) -lconfig
+libxlutil.a: $(LIBXLU_OBJS)
+	$(AR) rcs libxlutil.a $^
+
+xl.o: xl.c
+	$(CC) $(CFLAGS) -c xl.c
+
+$(CLIENTS): xl.o libxlutil.so libxenlight.so
+	$(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
 
 .PHONY: install
 install: all
@@ -59,15 +80,17 @@
 	ln -sf libxenlight.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)/libxenlight.so.$(MAJOR)
 	ln -sf libxenlight.so.$(MAJOR) $(DESTDIR)$(LIBDIR)/libxenlight.so
 	$(INSTALL_DATA) libxenlight.a $(DESTDIR)$(LIBDIR)
+	$(INSTALL_PROG) libxlutil.so.$(XLUMAJOR).$(XLUMINOR) $(DESTDIR)$(LIBDIR)
+	ln -sf libxlutil.so.$(XLUMAJOR).$(XLUMINOR) $(DESTDIR)$(LIBDIR)/libxlutil.so.$(XLUMAJOR)
+	ln -sf libxlutil.so.$(XLUMAJOR) $(DESTDIR)$(LIBDIR)/libxlutil.so
+	$(INSTALL_DATA) libxlutil.a $(DESTDIR)$(LIBDIR)
 	$(INSTALL_DATA) libxl.h $(DESTDIR)$(INCLUDEDIR)
-	cd $(LIBCONFIG_SOURCE) && DESTDIR=$(DESTDIR) $(MAKE) install
 
 .PHONY: clean
 clean:
 	$(RM) -f *.o *.so* *.a $(CLIENTS) $(DEPS)
-	$(RM) -rf $(LIBCONFIG_SOURCE)
+	$(RM) -f $(AUTOSRCS) $(AUTOINCS)
 
 distclean: clean
-	$(RM) -f $(LIBCONFIG_SOURCE).tar.gz
 
 -include $(DEPS)
diff -r 9c0793e75f54 tools/libxl/libxlu_cfg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxlu_cfg.c	Tue Mar 02 19:19:48 2010 +0000
@@ -0,0 +1,341 @@
+
+#include "libxlu_internal.h"
+#include "libxlu_cfg_y.h"
+#include "libxlu_cfg_l.h"
+#include "libxlu_cfg_i.h"
+
+XLU_Config *xlu_cfg_init(FILE *report, const char *report_filename) {
+    XLU_Config *cfg;
+
+    cfg= malloc(sizeof(*cfg));
+    if (!cfg) return 0;
+
+    cfg->report= report;
+    cfg->filename= strdup(report_filename);
+    if (!cfg->filename) { free(cfg); return 0; }
+
+    cfg->settings= 0;
+    return cfg;
+}
+
+int xlu_cfg_readfile(XLU_Config *cfg, const char *real_filename) {
+    CfgParseContext ctx;
+    FILE *f;
+    int e, r;
+
+    ctx.cfg= cfg;
+    ctx.err= 0;
+    ctx.lexerrlineno= -1;
+    
+    f= fopen(real_filename, "r");
+    if (!f) {
+        e= errno;
+        fprintf(cfg->report,"%s: unable to open configuration file: %s\n",
+                real_filename, strerror(e));
+        return e;
+    }
+
+    e= xlu__cfg_yylex_init_extra(&ctx, &ctx.scanner);
+    if (e) {
+        fprintf(cfg->report,"%s: unable to create scanner: %s\n",
+                cfg->filename, strerror(e));
+        return e;
+    }
+
+    xlu__cfg_yyrestart(f, ctx.scanner);
+
+    r= xlu__cfg_yyparse(&ctx);
+    if (r) assert(ctx.err);
+
+    xlu__cfg_yylex_destroy(ctx.scanner);
+    fclose(f);
+
+    return ctx.err;
+}
+
+void xlu__cfg_set_free(XLU_ConfigSetting *set) {
+    free(set->name);
+    free(set->values);
+    free(set);
+}
+
+void xlu_cfg_destroy(XLU_Config *cfg) {
+    XLU_ConfigSetting *set, *set_next;
+
+    for (set= cfg->settings;
+         set;
+         set= set_next) {
+        set_next= set->next;
+        xlu__cfg_set_free(set);
+    }
+    free(cfg->filename);
+    free(cfg);
+}
+
+static XLU_ConfigSetting *find(const XLU_Config *cfg, const char *n) {
+    XLU_ConfigSetting *set;
+
+    for (set= cfg->settings;
+         set;
+         set= set->next)
+        if (!strcmp(set->name, n))
+            return set;
+    return 0;
+}
+
+static int find_atom(const XLU_Config *cfg, const char *n,
+                     XLU_ConfigSetting **set_r) {
+    XLU_ConfigSetting *set;
+
+    set= find(cfg,n);
+    if (!set) return ESRCH;
+
+    if (set->avalues!=1) {
+        fprintf(cfg->report,
+                "%s:%d: warning: parameter `%s' is"
+                " a list but should be a single value\n",
+                cfg->filename, set->lineno, n);
+        return EINVAL;
+    }
+    *set_r= set;
+    return 0;
+}
+
+int xlu_cfg_get_string(const XLU_Config *cfg, const char *n,
+                       const char **value_r) {
+    XLU_ConfigSetting *set;
+    int e;
+
+    e= find_atom(cfg,n,&set);  if (e) return e;
+    *value_r= set->values[0];
+    return 0;
+}
+        
+int xlu_cfg_get_long(const XLU_Config *cfg, const char *n,
+                     long *value_r) {
+    long l;
+    XLU_ConfigSetting *set;
+    int e;
+    char *ep;
+
+    e= find_atom(cfg,n,&set);  if (e) return e;
+    errno= 0; l= strtol(set->values[0], &ep, 0);
+    e= errno;
+    if (errno) {
+        e= errno;
+        assert(e==EINVAL || e==ERANGE);
+        fprintf(cfg->report,
+                "%s:%d: warning: parameter `%s' could not be parsed"
+                " as a number: %s\n",
+                cfg->filename, set->lineno, n, strerror(e));
+        return e;
+    }
+    if (*ep || ep==set->values[0]) {
+        fprintf(cfg->report,
+                "%s:%d: warning: parameter `%s' is not a valid number\n",
+                cfg->filename, set->lineno, n);
+        return EINVAL;
+    }
+    *value_r= l;
+    return 0;
+}
+        
+
+int xlu_cfg_get_list(const XLU_Config *cfg, const char *n,
+                     XLU_ConfigList **list_r, int *entries_r) {
+    XLU_ConfigSetting *set;
+    set= find(cfg,n);  if (!set) return ESRCH;
+    if (set->avalues==1) {
+        fprintf(cfg->report,
+                "%s:%d: warning: parameter `%s' is a single value"
+                " but should be a list\n",
+                cfg->filename, set->lineno, n);
+        return EINVAL;
+    }
+    if (list_r) *list_r= set;
+    if (entries_r) *entries_r= set->nvalues;
+    return 0;
+}
+
+const char *xlu_cfg_get_listitem(const XLU_ConfigList *set, int entry) {
+    if (entry < 0 || entry >= set->nvalues) return 0;
+    return set->values[entry];
+}
+
+
+XLU_ConfigSetting *xlu__cfg_set_mk(CfgParseContext *ctx,
+                                   int alloc, char *atom) {
+    XLU_ConfigSetting *set= 0;
+
+    if (ctx->err) goto x;
+    assert(!!alloc == !!atom);
+
+    set= malloc(sizeof(*set));
+    if (!set) goto xe;
+
+    set->name= 0; /* tbd */
+    set->avalues= alloc;
+    
+    if (!alloc) {
+        set->nvalues= 0;
+        set->values= 0;
+    } else {
+        set->values= malloc(sizeof(*set->values) * alloc);
+        if (!set->values) goto xe;
+
+        set->nvalues= 1;
+        set->values[0]= atom;
+    }
+    return set;
+
+ xe:
+    ctx->err= errno;
+ x:
+    free(set);
+    free(atom);
+    return 0;
+}
+
+void xlu__cfg_set_add(CfgParseContext *ctx, XLU_ConfigSetting *set,
+                      char *atom) {
+    if (ctx->err) return;
+
+    assert(atom);
+    
+    if (set->nvalues >= set->avalues) {
+        int new_avalues;
+        char **new_values;
+        
+        if (set->avalues > INT_MAX / 100) { ctx->err= ERANGE; return; }
+        new_avalues= set->avalues * 4;
+        new_values= realloc(set->values,
+                            sizeof(*new_values) * new_avalues);
+        if (!new_values) { ctx->err= errno; free(atom); return; }
+        set->values= new_values;
+        set->avalues= new_avalues;
+    }
+    set->values[set->nvalues++]= atom;
+}
+
+void xlu__cfg_set_store(CfgParseContext *ctx, char *name,
+                        XLU_ConfigSetting *set, int lineno) {
+    if (ctx->err) return;
+
+    assert(name);
+    set->name= name;
+    set->lineno= lineno;
+    set->next= ctx->cfg->settings;
+    ctx->cfg->settings= set;
+}
+
+char *xlu__cfgl_strdup(CfgParseContext *ctx, const char *src) {
+    char *result;
+    
+    if (ctx->err) return 0;
+    result= strdup(src);
+    if (!result) ctx->err= errno;
+    return result;
+}
+
+char *xlu__cfgl_dequote(CfgParseContext *ctx, const char *src) {
+    char *result;
+    const char *p;
+    char *q;
+    int len, c, nc;
+
+    if (ctx->err) return 0;
+
+    len= strlen(src);
+    assert(len>=2 && src[0]==src[len-1]);
+
+    result= malloc(len-1);
+    if (!result) { ctx->err= errno; return 0; }
+
+    q= result;
+
+    for (p= src+1;
+         p < src+len-1;
+         ) {
+        c= *p++;
+        if (c=='\\') {
+            assert(p < src+len-1);
+            nc= *p++;
+            if (nc=='"' || nc=='\'' || nc=='\\') {
+                *q++= nc;
+            } else if (nc=='a') { *q++= '\007';
+            } else if (nc=='b') { *q++= '\010';
+            } else if (nc=='f') { *q++= '\014';
+            } else if (nc=='n') { *q++= '\n';
+            } else if (nc=='r') { *q++= '\r';
+            } else if (nc=='t') { *q++= '\t';
+            } else if (nc=='v') { *q++= '\013';
+            } else if (nc=='x') {
+
+#define NUMERIC_CHAR(minlen,maxlen,base,basetext) do{                        \
+                char numbuf[(maxlen)+1], *ep;                                \
+                unsigned long val;                                           \
+                                                                             \
+                strncpy(numbuf,p,(maxlen));                                  \
+                numbuf[(maxlen)]= 0;                                         \
+                val= strtoul(numbuf, &ep, (base));                           \
+                if (ep <= numbuf+(minlen)) {                                 \
+                    xlu__cfgl_lexicalerror(ctx,"invalid digit after"         \
+                         " backslash " basetext "numerical character escape" \
+                         " in quoted string");                               \
+                    ctx->err= EINVAL;                                        \
+                    goto x;                                                  \
+                }                                                            \
+                p += (ep - numbuf);                                          \
+ }while(0) 
+
+                p++;
+                NUMERIC_CHAR(2,2,16,"hex");
+            } else if (nc>='0' && nc<='7') {
+                NUMERIC_CHAR(1,3,10,"octal");
+            }
+            assert(p <= src+len-1);
+        } else {
+            *q++= c;
+        }
+    }
+
+ x:
+    *q++= 0;
+    return result;
+}
+
+void xlu__cfgl_lexicalerror(CfgParseContext *ctx, char const *msg) {
+    YYLTYPE loc;
+    loc.first_line= xlu__cfg_yyget_lineno(ctx->scanner);
+    xlu__cfg_yyerror(&loc, ctx, msg);
+    ctx->lexerrlineno= loc.first_line;
+}
+
+void xlu__cfg_yyerror(YYLTYPE *loc, CfgParseContext *ctx, char const *msg) {
+    const char *text, *newline;
+    int len, lineno;
+
+    lineno= loc->first_line;
+    if (lineno <= ctx->lexerrlineno) return;
+
+    text= xlu__cfg_yyget_text(ctx->scanner);
+    len= xlu__cfg_yyget_leng(ctx->scanner);
+    newline= "";
+    if (len>0 && text[len-1]=='\n') {
+        len--;
+        lineno--;
+        if (!len) {
+            newline= "<newline>";
+        }
+    }
+    while (len>0 && (text[len-1]=='\t' || text[len-1]==' ')) {
+        len--;
+    }
+
+    fprintf(ctx->cfg->report,
+            "%s:%d: config parsing error near %s%.*s%s%s: %s\n",
+            ctx->cfg->filename, lineno,
+            len?"`":"", len, text, len?"'":"", newline,
+            msg);
+    if (!ctx->err) ctx->err= EINVAL;
+}
diff -r 9c0793e75f54 tools/libxl/libxlu_cfg_i.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxlu_cfg_i.h	Tue Mar 02 19:19:48 2010 +0000
@@ -0,0 +1,25 @@
+#ifndef LIBXLU_CFG_I_H
+#define LIBXLU_CFG_I_H
+
+#include "libxlu_internal.h"
+#include "libxlu_cfg_y.h"
+
+void xlu__cfg_set_free(XLU_ConfigSetting *set);
+XLU_ConfigSetting *xlu__cfg_set_mk(CfgParseContext*, int alloc, char *atom);
+void xlu__cfg_set_add(CfgParseContext*, XLU_ConfigSetting *set, char *atom);
+void xlu__cfg_set_store(CfgParseContext*, char *name,
+                        XLU_ConfigSetting *set, int lineno);
+
+char *xlu__cfgl_strdup(CfgParseContext*, const char *src);
+char *xlu__cfgl_dequote(CfgParseContext*, const char *src);
+
+void xlu__cfg_yyerror(YYLTYPE *locp, CfgParseContext*, char const *msg);
+void xlu__cfgl_lexicalerror(CfgParseContext*, char const *msg);
+
+
+
+/* Why oh why does bison not declare this in its autogenerated .h ? */
+int xlu__cfg_yyparse(CfgParseContext *ctx);
+
+
+#endif /*LIBXLU_CFG_I_H*/
diff -r 9c0793e75f54 tools/libxl/libxlu_cfg_l.l
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxlu_cfg_l.l	Tue Mar 02 19:19:48 2010 +0000
@@ -0,0 +1,74 @@
+/* -*- fundamental -*- */
+
+%{
+#include "libxlu_cfg_i.h"
+
+#define ctx ((CfgParseContext*)yyextra)
+#define YY_NO_INPUT
+
+#define GOT(x) do{                \
+    yylloc->first_line= yylineno; \
+    return (x);                   \
+  }while(0)
+
+%}
+
+%option warn
+%option nodefault
+%option batch
+%option 8bit
+%option yylineno
+%option noyywrap
+%option bison-bridge
+%option bison-locations
+%option reentrant
+%option prefix="xlu__cfg_yy"
+%option nounput
+
+%x lexerr
+
+%%
+
+[a-z][_0-9a-z]*         {
+                          yylval->string= xlu__cfgl_strdup(ctx,yytext);
+                          GOT(IDENT);
+                        }
+[0-9][0-9a-fx]*         {
+                          yylval->string= xlu__cfgl_strdup(ctx,yytext);
+                          GOT(NUMBER);
+                        }
+
+[ \t]
+
+,                       { GOT(','); }
+\[                      { GOT('['); }
+\]                      { GOT(']'); }
+\=                      { GOT('='); }
+\;                      { GOT(';'); }
+
+\n|\#.*\n               { yylloc->first_line= yylineno-1; return NEWLINE; }
+
+\'([^\'\\\n]|\\.)*\'    {
+                          yylval->string= xlu__cfgl_dequote(ctx,yytext);
+                          GOT(STRING);
+                        }
+\"([^\"\\\n]|\\.)*\"    {
+                          yylval->string= xlu__cfgl_dequote(ctx,yytext);
+                          GOT(STRING);
+                        }
+
+.                       {
+                          BEGIN(lexerr);
+                          yymore();
+                        }
+
+<lexerr>[^ \t\n]*|[ \t] {
+                          xlu__cfgl_lexicalerror(ctx,"lexical error");
+                          BEGIN(0);
+                        }
+
+<lexerr>\n              {
+                          xlu__cfgl_lexicalerror(ctx,"lexical error");
+                          BEGIN(0);
+                          GOT(NEWLINE);
+                        }
diff -r 9c0793e75f54 tools/libxl/libxlu_cfg_y.y
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxlu_cfg_y.y	Tue Mar 02 19:19:48 2010 +0000
@@ -0,0 +1,57 @@
+/* -*- fundamental -*- */
+
+%{
+#define YYLEX_PARAM ctx->scanner
+#include "libxlu_cfg_i.h"
+#include "libxlu_cfg_l.h"
+%}
+
+%union {
+  char *string;
+  XLU_ConfigSetting *setting;
+}
+
+%locations
+%pure-parser
+%defines
+%error-verbose
+%name-prefix="xlu__cfg_yy"
+%parse-param { CfgParseContext *ctx }
+%lex-param { void *scanner }
+
+%token <string>                IDENT STRING NUMBER NEWLINE
+%type <string>            atom
+%destructor { free($$); } atom IDENT STRING NUMBER
+
+%type <setting>                         value valuelist values
+%destructor { xlu__cfg_set_free($$); }  value valuelist values
+
+%%
+
+file: /* empty */
+ |     file setting           
+
+setting: IDENT '=' value      { xlu__cfg_set_store(ctx,$1,$3,@3.first_line); }
+                     endstmt
+ |      endstmt
+ |      error NEWLINE
+
+endstmt: NEWLINE
+ |      ';'
+
+value:  atom                         { $$= xlu__cfg_set_mk(ctx,1,$1); }
+ |      '[' nlok valuelist ']'       { $$= $3; }
+
+atom:   STRING                   { $$= $1; }
+ |      NUMBER                   { $$= $1; }
+
+valuelist: /* empty */           { $$= xlu__cfg_set_mk(ctx,0,0); }
+ |      values                  { $$= $1; }
+ |      values ',' nlok         { $$= $1; }
+
+values: atom nlok                  { $$= xlu__cfg_set_mk(ctx,2,$1); }
+ |      values ',' nlok atom nlok  { xlu__cfg_set_add(ctx,$1,$4); $$= $1; }
+
+nlok:
+        /* nothing */
+ |      nlok NEWLINE
diff -r 9c0793e75f54 tools/libxl/libxlu_internal.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxlu_internal.h	Tue Mar 02 19:19:48 2010 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010      Citrix Ltd.
+ * Author Ian Jackson <ian.jackson@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 LIBXLU_INTERNAL_H
+#define LIBXLU_INTERNAL_H
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <assert.h>
+
+#define XLU_ConfigList XLU_ConfigSetting
+
+#include "libxlutil.h"
+
+struct XLU_ConfigSetting { /* transparent */
+    struct XLU_ConfigSetting *next;
+    char *name;
+    int nvalues, avalues; /* lists have avalues>1 */
+    char **values;
+    int lineno;
+};
+
+struct XLU_Config {
+    XLU_ConfigSetting *settings;
+    FILE *report;
+    char *filename;
+};
+
+typedef struct {
+    XLU_Config *cfg;
+    int err, lexerrlineno;
+    void *scanner;
+} CfgParseContext;
+
+#endif /*LIBXLU_INTERNAL_H*/
diff -r 9c0793e75f54 tools/libxl/libxlutil.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxl/libxlutil.h	Tue Mar 02 19:19:48 2010 +0000
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010      Citrix Ltd.
+ * Author Ian Jackson <ian.jackson@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 LIBXLUTIL_H
+#define LIBXLUTIL_H
+
+#include <stdio.h>
+
+#include "libxl.h"
+
+/* Unless otherwise stated, all functions return an errno value. */
+typedef struct XLU_Config XLU_Config;
+typedef struct XLU_ConfigList XLU_ConfigList;
+
+XLU_Config *xlu_cfg_init(FILE *report, const char *report_filename);
+  /* 0 means we got ENOMEM. */
+  /* report_filename is copied; report is saved and must remain valid
+   *  until the Config is destroyed. */
+
+int xlu_cfg_readfile(XLU_Config*, const char *real_filename);
+  /* If this fails, then it is undefined behaviour to call xlu_cfg_get_...
+   * functions.  You have to just xlu_cfg_destroy. */
+ 
+void xlu_cfg_destroy(XLU_Config*);
+
+
+/* All of the following print warnings to "report" if there is a problem.
+ * Return values are:
+ *   0        OK
+ *   ESRCH    not defined
+ *   EINVAL   value found but wrong format for request (prints warning)
+ *   ERANGE   value out of range (from strtol)
+ */
+
+int xlu_cfg_get_string(const XLU_Config*, const char *n, const char **value_r);
+int xlu_cfg_get_long(const XLU_Config*, const char *n, long *value_r);
+
+int xlu_cfg_get_list(const XLU_Config*, const char *n,
+                     XLU_ConfigList **list_r /* may be 0 */,
+                     int *entries_r /* may be 0 */);
+  /* there is no need to free *list_r; lifetime is that of the XLU_Config */
+const char *xlu_cfg_get_listitem(const XLU_ConfigList*, int entry);
+  /* xlu_cfg_get_listitem cannot fail, except that if entry is
+   * out of range it returns 0 (not setting errno) */
+
+#endif /* LIBXLUTIL_H */
diff -r 9c0793e75f54 tools/libxl/xl.c
--- a/tools/libxl/xl.c	Wed Feb 24 11:03:56 2010 +0000
+++ b/tools/libxl/xl.c	Tue Mar 02 19:19:48 2010 +0000
@@ -19,7 +19,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <libconfig.h>
 #include <unistd.h>
 #include <sys/time.h> /* for time */
 #include <getopt.h>
@@ -34,6 +33,7 @@
 
 #include "libxl.h"
 #include "libxl_utils.h"
+#include "libxlutil.h"
 
 #define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
 
@@ -320,63 +320,6 @@
     }
 }
 
-static char* compat_config_file(const char *filename)
-{
-    char t;
-    char *newfile = (char*) malloc(strlen(filename) + 4);
-    char *buf = (char *) malloc(2048);
-    int size = 2048, i;
-    FILE *s;
-    FILE *d;
-
-    sprintf(newfile, "%s.xl", filename);
-
-    s = fopen(filename, "r");
-    if (!s) {
-        perror("cannot open file for reading");
-        return NULL;
-    }
-    d = fopen(newfile, "w");
-    if (!d) {
-        fclose(s);
-        perror("cannot open file for writting");
-        return NULL;
-    }
-
-    while (!feof(s)) {
-        buf[0] = 0;
-        fgets(buf, size, s);
-        while (buf[strlen(buf) - 1] != '\n' && !feof(s)) {
-            size += 1024;
-            buf = realloc(buf, size + 1024);
-            fgets(buf + (size - 1025), 1025, s);
-        }
-        for (i = 0; i < strlen(buf); i++)
-            if (buf[i] == '\'')
-                buf[i] = '\"';
-        if (strchr(buf, '=') != NULL) {
-            if ((buf[strlen(buf) - 1] == '\n' && buf[strlen(buf) - 2] == ';') ||
-                    buf[strlen(buf) - 1] == ';') {
-                fputs(buf, d);
-            } else {
-                t = buf[strlen(buf) - 1];
-                buf[strlen(buf) - 1] = ';';
-                fputs(buf, d);
-                fputc(t, d);
-            }
-        } else if (buf[0] == '#' || buf[0] == ' ' || buf[0] == '\n') {
-            fputs(buf, d);
-        }
-    }
-
-    fclose(s);
-    fclose(d);
-
-    free(buf);
-
-    return newfile;
-}
-
 static void parse_config_file(const char *filename,
                               libxl_domain_create_info *c_info,
                               libxl_domain_build_info *b_info,
@@ -394,35 +337,33 @@
 {
     const char *buf;
     long l;
-    struct config_t config;
-    struct config_setting_t *vbds, *nics, *pcis, *cvfbs;
+    XLU_Config *config;
+    XLU_ConfigList *vbds, *nics, *pcis, *cvfbs;
     int pci_power_mgmt = 0;
     int pci_msitranslate = 1;
-    int i;
+    int i, e;
 
-    config_init (&config);
+    config= xlu_cfg_init(stderr, filename);
+    if (!config) {
+        fprintf(stderr, "Failed to allocate for configuration\n");
+        exit(1);
+    }
 
-    if (!config_read_file(&config, filename)) {
-        char *newfilename;
-        config_destroy(&config);
-        newfilename = compat_config_file(filename);
-        config_init (&config);
-        if (!config_read_file(&config, newfilename)) {
-            fprintf(stderr, "Failed to parse config file %s on line %d, try removing any embedded python code\n", config_error_text(&config), config_error_line(&config));
-            exit(1);
-        }
-        free(newfilename);
+    e= xlu_cfg_readfile (config, filename);
+    if (e) {
+        fprintf(stderr, "Failed to parse config file: %s\n", strerror(e));
+        exit(1);
     }
 
     init_create_info(c_info);
 
     c_info->hvm = 0;
-    if ((config_lookup_string (&config, "builder", &buf) == CONFIG_TRUE) &&
+    if (!xlu_cfg_get_string (config, "builder", &buf) &&
         !strncmp(buf, "hvm", strlen(buf)))
         c_info->hvm = 1;
 
     /* hap is missing */
-    if (config_lookup_string (&config, "name", &buf) == CONFIG_TRUE)
+    if (!xlu_cfg_get_string (config, "name", &buf))
         c_info->name = strdup(buf);
     else
         c_info->name = "test";
@@ -433,48 +374,48 @@
     init_build_info(b_info, c_info);
 
     /* the following is the actual config parsing with overriding values in the structures */
-    if (config_lookup_int (&config, "vcpus", &l) == CONFIG_TRUE)
+    if (!xlu_cfg_get_long (config, "vcpus", &l))
         b_info->max_vcpus = l;
 
-    if (config_lookup_int (&config, "memory", &l) == CONFIG_TRUE) {
+    if (!xlu_cfg_get_long (config, "memory", &l)) {
         b_info->max_memkb = l * 1024;
         b_info->target_memkb = b_info->max_memkb;
     }
 
-    if (config_lookup_int (&config, "shadow_memory", &l) == CONFIG_TRUE)
+    if (!xlu_cfg_get_long (config, "shadow_memory", &l))
         b_info->shadow_memkb = l * 1024;
 
-    if (config_lookup_int (&config, "videoram", &l) == CONFIG_TRUE)
+    if (!xlu_cfg_get_long (config, "videoram", &l))
         b_info->video_memkb = l * 1024;
 
-    if (config_lookup_string (&config, "kernel", &buf) == CONFIG_TRUE)
+    if (!xlu_cfg_get_string (config, "kernel", &buf))
         b_info->kernel = strdup(buf);
 
     if (c_info->hvm == 1) {
-        if (config_lookup_int (&config, "pae", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "pae", &l))
             b_info->u.hvm.pae = l;
-        if (config_lookup_int (&config, "apic", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "apic", &l))
             b_info->u.hvm.apic = l;
-        if (config_lookup_int (&config, "acpi", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "acpi", &l))
             b_info->u.hvm.acpi = l;
-        if (config_lookup_int (&config, "nx", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "nx", &l))
             b_info->u.hvm.nx = l;
-        if (config_lookup_int (&config, "viridian", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "viridian", &l))
             b_info->u.hvm.viridian = l;
     } else {
         char *cmdline;
-        if (config_lookup_string (&config, "root", &buf) == CONFIG_TRUE) {
+        if (!xlu_cfg_get_string (config, "root", &buf)) {
             asprintf(&cmdline, "root=%s", buf);
             b_info->u.pv.cmdline = cmdline;
         }
-        if (config_lookup_string (&config, "ramdisk", &buf) == CONFIG_TRUE)
+        if (!xlu_cfg_get_string (config, "ramdisk", &buf))
             b_info->u.pv.ramdisk = strdup(buf);
     }
 
-    if ((vbds = config_lookup (&config, "disk")) != NULL) {
+    if (!xlu_cfg_get_list (config, "disk", &vbds, 0)) {
         *num_disks = 0;
         *disks = NULL;
-        while ((buf = config_setting_get_string_elem (vbds, *num_disks)) != NULL) {
+        while ((buf = xlu_cfg_get_listitem (vbds, *num_disks)) != NULL) {
             char *buf2 = strdup(buf);
             char *p, *p2;
             *disks = (libxl_device_disk *) realloc(*disks, sizeof (libxl_device_disk) * ((*num_disks) + 1));
@@ -530,10 +471,10 @@
         }
     }
 
-    if ((nics = config_lookup (&config, "vif")) != NULL) {
+    if (!xlu_cfg_get_list (config, "vif", &nics, 0)) {
         *num_vifs = 0;
         *vifs = NULL;
-        while ((buf = config_setting_get_string_elem (nics, *num_vifs)) != NULL) {
+        while ((buf = xlu_cfg_get_listitem (nics, *num_vifs)) != NULL) {
             char *buf2 = strdup(buf);
             char *p, *p2;
             *vifs = (libxl_device_nic *) realloc(*vifs, sizeof (libxl_device_nic) * ((*num_vifs) + 1));
@@ -593,12 +534,12 @@
         }
     }
 
-    if ((cvfbs = config_lookup (&config, "vfb")) != NULL) {
+    if (!xlu_cfg_get_list (config, "vfb", &cvfbs, 0)) {
         *num_vfbs = 0;
         *num_vkbs = 0;
         *vfbs = NULL;
         *vkbs = NULL;
-        while ((buf = config_setting_get_string_elem (cvfbs, *num_vfbs)) != NULL) {
+        while ((buf = xlu_cfg_get_listitem (cvfbs, *num_vfbs)) != NULL) {
             char *buf2 = strdup(buf);
             char *p, *p2;
             *vfbs = (libxl_device_vfb *) realloc(*vfbs, sizeof(libxl_device_vfb) * ((*num_vfbs) + 1));
@@ -643,16 +584,16 @@
         }
     }
 
-    if (config_lookup_int (&config, "pci_msitranslate", &l) == CONFIG_TRUE)
+    if (!xlu_cfg_get_long (config, "pci_msitranslate", &l))
         pci_msitranslate = l;
 
-    if (config_lookup_int (&config, "pci_power_mgmt", &l) == CONFIG_TRUE)
+    if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l))
         pci_power_mgmt = l;
 
-    if ((pcis = config_lookup (&config, "pci")) != NULL) {
+    if (xlu_cfg_get_list (config, "pci", &pcis, 0)) {
         *num_pcidevs = 0;
         *pcidevs = NULL;
-        while ((buf = config_setting_get_string_elem (pcis, *num_pcidevs)) != NULL) {
+        while ((buf = xlu_cfg_get_listitem (pcis, *num_pcidevs)) != NULL) {
             unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
             char *buf2 = strdup(buf);
             char *p;
@@ -690,37 +631,37 @@
         init_dm_info(dm_info, c_info, b_info);
 
         /* then process config related to dm */
-        if (config_lookup_string (&config, "device_model", &buf) == CONFIG_TRUE)
+        if (!xlu_cfg_get_string (config, "device_model", &buf))
             dm_info->device_model = strdup(buf);
-        if (config_lookup_int (&config, "stdvga", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "stdvga", &l))
             dm_info->stdvga = l;
-        if (config_lookup_int (&config, "vnc", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "vnc", &l))
             dm_info->vnc = l;
-        if (config_lookup_string (&config, "vnclisten", &buf) == CONFIG_TRUE)
+        if (!xlu_cfg_get_string (config, "vnclisten", &buf))
             dm_info->vnclisten = strdup(buf);
-        if (config_lookup_int (&config, "vncdisplay", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "vncdisplay", &l))
             dm_info->vncdisplay = l;
-        if (config_lookup_int (&config, "vncunused", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "vncunused", &l))
             dm_info->vncunused = l;
-        if (config_lookup_string (&config, "keymap", &buf) == CONFIG_TRUE)
+        if (!xlu_cfg_get_string (config, "keymap", &buf))
             dm_info->keymap = strdup(buf);
-        if (config_lookup_int (&config, "sdl", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "sdl", &l))
             dm_info->sdl = l;
-        if (config_lookup_int (&config, "opengl", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "opengl", &l))
             dm_info->opengl = l;
-        if (config_lookup_int (&config, "nographic", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "nographic", &l))
             dm_info->nographic = l;
-        if (config_lookup_string (&config, "serial", &buf) == CONFIG_TRUE)
+        if (!xlu_cfg_get_string (config, "serial", &buf))
             dm_info->serial = strdup(buf);
-        if (config_lookup_string (&config, "boot", &buf) == CONFIG_TRUE)
+        if (!xlu_cfg_get_string (config, "boot", &buf))
             dm_info->boot = strdup(buf);
-        if (config_lookup_int (&config, "usb", &l) == CONFIG_TRUE)
+        if (!xlu_cfg_get_long (config, "usb", &l))
             dm_info->usb = l;
-        if (config_lookup_string (&config, "usbdevice", &buf) == CONFIG_TRUE)
+        if (!xlu_cfg_get_string (config, "usbdevice", &buf))
             dm_info->usbdevice = strdup(buf);
     }
 
-    config_destroy(&config);
+    xlu_cfg_destroy(config);
 }
 
 #define MUST( call ) ({                                                 \

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Replace config file parser for "xl"
  2010-03-02 19:24 [PATCH] Replace config file parser for "xl" Ian Jackson
@ 2010-03-02 21:29 ` Vincent Hanquez
  2010-03-04 18:47 ` [PATCH] Fix config file interpretation when pci= not specified Ian Jackson
  1 sibling, 0 replies; 3+ messages in thread
From: Vincent Hanquez @ 2010-03-02 21:29 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel@lists.xensource.com

On 02/03/10 19:24, Ian Jackson wrote:
> This provides a replacement config file parser for "xl" based on bison
> and flex.
>
> Benefits:
>    * proper error reporting with line numbers
>    * parser can understand nearly all "xm" configuration files directly
>       (doesn't understand Python code but should do everything else)
>    * parser also understands the ;-infested "xl" style files
>    * removes the dependency on libconfig
>    * better checking for certain kinds of mistakes
>    * eliminates the strange "massage file and try again" code
>
> This is intended to support all config files currently supported by
> "xl" and almost all files supported by "xm".  (NB that whether a
> feature works depends on the implementation of that feature in
> xl/libxl of course.)
>
> This patch also introduces a new library "libxlutil" which is mainly
> for the benefit of "xl".  Users of libxl do not need to use libxlutil,
> but they can do so if they want to parse "xl" files without being
> "xl".

this is merely replacing a library dependency by a compilation 
dependency, plus the burden on maintaining a ad-hoc grammar. At least it 
would probably be useful to take the same approch as the linux kernel, 
i.e. checking bison/flex output in the repository to account for bison 
annoying volatility.

however since it's well separated from libxl,

Acked-by: Vincent Hanquez <vincent.hanquez@eu.citrix.com>

-- 
Vincent

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH] Fix config file interpretation when pci= not specified
  2010-03-02 19:24 [PATCH] Replace config file parser for "xl" Ian Jackson
  2010-03-02 21:29 ` Vincent Hanquez
@ 2010-03-04 18:47 ` Ian Jackson
  1 sibling, 0 replies; 3+ messages in thread
From: Ian Jackson @ 2010-03-04 18:47 UTC (permalink / raw)
  To: xen-devel

My code for interpreting the results of the new config parser has
undefined behaviour in the case when pci=... is not specified.  Bad
luck meant it worked for me in my tests.  This patch fixes it.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>

# HG changeset patch
# User Ian Jackson <Ian.Jackson@eu.citrix.com>
# Date 1267728147 0
# Node ID 2c7d21b063a59bfcc5c327820ffe1b15cf6915ac
# Parent  32c721712bcef07b8e24834abbf1f23ef49640ed
xl: Fix undefined behaviour when pci not specified in input file

diff -r 32c721712bce -r 2c7d21b063a5 tools/libxl/xl.c
--- a/tools/libxl/xl.c	Thu Mar 04 11:23:57 2010 +0000
+++ b/tools/libxl/xl.c	Thu Mar 04 18:42:27 2010 +0000
@@ -590,7 +590,7 @@
     if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l))
         pci_power_mgmt = l;
 
-    if (xlu_cfg_get_list (config, "pci", &pcis, 0)) {
+    if (!xlu_cfg_get_list (config, "pci", &pcis, 0)) {
         *num_pcidevs = 0;
         *pcidevs = NULL;
         while ((buf = xlu_cfg_get_listitem (pcis, *num_pcidevs)) != NULL) {

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-03-04 18:47 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-02 19:24 [PATCH] Replace config file parser for "xl" Ian Jackson
2010-03-02 21:29 ` Vincent Hanquez
2010-03-04 18:47 ` [PATCH] Fix config file interpretation when pci= not specified Ian Jackson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).