xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: Ian Jackson <Ian.Jackson@eu.citrix.com>,
	Ian Jackson <ijackson@chiark.greenend.org.uk>
Subject: [PATCH 08/14] libxl: disks: new xlu_disk_parse function
Date: Thu, 12 May 2011 15:36:38 +0100	[thread overview]
Message-ID: <1305211004-31687-9-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1305211004-31687-8-git-send-email-ian.jackson@eu.citrix.com>

From: Ian Jackson <ijackson@chiark.greenend.org.uk>

Introduce new flex/regexp-based parser for disk configuration strings.
Callers will be updated in following patches.

The existing xm command line syntax for block-attach expects multiple
arguments containing different parameters for different parts of the
disk specification, so we supply a parser function which can take
multiple strings and scan them in sequence.

Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
---
 tools/libxl/Makefile        |    3 +-
 tools/libxl/libxlu_disk.c   |   91 ++++++++++++++++++
 tools/libxl/libxlu_disk_i.h |   21 ++++
 tools/libxl/libxlu_disk_l.l |  217 +++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxlutil.h     |   23 +++++
 5 files changed, 354 insertions(+), 1 deletions(-)
 create mode 100644 tools/libxl/libxlu_disk.c
 create mode 100644 tools/libxl/libxlu_disk_i.h
 create mode 100644 tools/libxl/libxlu_disk_l.l

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 538cd16..3c10051 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -41,7 +41,8 @@ $(LIBXL_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) $(CFLAGS_lib
 
 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
+LIBXLU_OBJS = libxlu_cfg_y.o libxlu_cfg_l.o libxlu_cfg.o \
+	libxlu_disk_l.o libxlu_disk.o
 $(LIBXLU_OBJS): CFLAGS += $(CFLAGS_libxenctrl) # For xentoollog.h
 
 CLIENTS = xl
diff --git a/tools/libxl/libxlu_disk.c b/tools/libxl/libxlu_disk.c
new file mode 100644
index 0000000..52780e6
--- /dev/null
+++ b/tools/libxl/libxlu_disk.c
@@ -0,0 +1,91 @@
+#include "libxlu_internal.h"
+#include "libxlu_disk_l.h"
+#include "libxlu_disk_i.h"
+#include "libxlu_cfg_i.h"
+
+void xlu__disk_err(DiskParseContext *dpc, const char *erroneous,
+                   const char *message) {
+    fprintf(dpc->cfg->report,
+	    "%s: config parsing error in disk specification: %s"
+            "%s%s%s"
+            " in `%s'\n",
+	    dpc->cfg->filename, message,
+            erroneous?": near `":"", erroneous?erroneous:"", erroneous?"'":"",
+            dpc->spec);
+    if (!dpc->err) dpc->err= EINVAL;
+}
+
+static int dpc_prep(DiskParseContext *dpc, const char *spec) {
+    int e;
+
+    dpc->spec = spec;
+    
+    e = xlu__disk_yylex_init_extra(dpc, &dpc->scanner);
+    if (e) goto fail;
+
+    dpc->buf = xlu__disk_yy_scan_bytes(spec, strlen(spec), dpc->scanner);
+    if (!dpc->buf) { e = ENOMEM; goto fail; }
+
+    return 0;
+
+ fail:
+    fprintf(dpc->cfg->report, "cannot init disk scanner: %s\n",
+            strerror(errno));
+    return e;
+}
+
+static void dpc_dispose(DiskParseContext *dpc) {
+    if (dpc->buf) {
+        xlu__disk_yy_delete_buffer(dpc->buf, dpc->scanner);
+        dpc->buf = 0;
+    }
+    if (dpc->scanner) {
+        xlu__disk_yylex_destroy(dpc->scanner);
+        dpc->scanner = 0;
+    }
+}
+
+int xlu_disk_parse(XLU_Config *cfg,
+                   int nspecs, const char *const *specs,
+                   libxl_device_disk *disk) {
+    DiskParseContext dpc;
+    int i, e;
+
+    memset(&dpc,0,sizeof(dpc));
+    dpc.cfg = cfg;
+    dpc.scanner = 0;
+    dpc.disk = disk;
+
+    for (i=0; i<nspecs; i++) {
+        e = dpc_prep(&dpc, specs[i]);
+        if (e) { dpc.err = e; goto x_err; }
+
+        xlu__disk_yylex(dpc.scanner);
+        assert(!e);
+        if (dpc.err) goto x_err;
+
+        dpc_dispose(&dpc);
+    }
+
+    if (disk->format == LIBXL_DISK_FORMAT_UNKNOWN) {
+        disk->format = LIBXL_DISK_FORMAT_RAW;
+    }
+    if (disk->is_cdrom) {
+        disk->removable = 1;
+        disk->readwrite = 0;
+    }
+
+    if (!disk->vdev) {
+        xlu__disk_err(&dpc,0, "no vdev specified");
+        goto x_err;
+    }
+    if (!disk->pdev_path && !disk->removable) {
+        xlu__disk_err(&dpc,0,"no target specified (and device not removable)");
+        goto x_err;
+    }
+
+ x_err:
+    dpc_dispose(&dpc);
+    return dpc.err;
+}
+
diff --git a/tools/libxl/libxlu_disk_i.h b/tools/libxl/libxlu_disk_i.h
new file mode 100644
index 0000000..578920a
--- /dev/null
+++ b/tools/libxl/libxlu_disk_i.h
@@ -0,0 +1,21 @@
+#ifndef LIBXLU_DISK_I_H
+#define LIBXLU_DISK_I_H
+
+#include "libxlu_internal.h"
+
+
+typedef struct {
+    XLU_Config *cfg;
+    int err;
+    void *scanner;
+    YY_BUFFER_STATE buf;
+    libxl_device_disk *disk;
+    int access_set, had_depr_prefix;
+    const char *spec;
+} DiskParseContext;
+
+void xlu__disk_err(DiskParseContext *dpc, const char *erroneous,
+                   const char *message);
+
+
+#endif /*LIBXLU_DISK_I_H*/
diff --git a/tools/libxl/libxlu_disk_l.l b/tools/libxl/libxlu_disk_l.l
new file mode 100644
index 0000000..8e511ea
--- /dev/null
+++ b/tools/libxl/libxlu_disk_l.l
@@ -0,0 +1,217 @@
+/* -*- fundamental -*- */
+/*
+ * libxlu_disk_l.l - parser for disk specification strings
+ *
+ * Copyright (C) 2011      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.
+ */
+
+/*
+ * 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 "libxlu_disk_i.h"
+
+#define YY_NO_INPUT
+
+/* Some versions of flex have a bug (Fedora bugzilla 612465) which causes
+ * it to fail to declare these functions, which it defines.  So declare
+ * them ourselves.  Hopefully we won't have to simultaneously support
+ * a flex version which declares these differently somehow. */
+int xlu__disk_yyget_column(yyscan_t yyscanner);
+void xlu__disk_yyset_column(int  column_no, yyscan_t yyscanner);
+
+
+/*----- useful macros and functions used in actions -----
+ * we use macros in the actual rules to keep the actions short
+ * and particularly to avoid repeating boilerplate values such as
+ * DPC->disk, yytext, etc. */
+
+#define DPC ((DiskParseContext*)yyextra)
+
+/* Sets an enum, checking it hasn't already been set to a different value  */
+#define DSET(dpc,member,enumname,str,valname) do{			\
+	if (dpc->disk->member != LIBXL_DISK_##enumname##_UNKNOWN &&	\
+	    dpc->disk->member != LIBXL_DISK_##enumname##_##valname) {	\
+	    xlu__disk_err(dpc, str, TOSTRING(member) " respecified");	\
+	} else {							\
+	    dpc->disk->member = LIBXL_DISK_##enumname##_##valname;	\
+	}								\
+    }while(0)
+
+/* 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(DiskParseContext *dpc, const char *what_respecified,
+		       char **update, const char *value) {
+    if (*update) {
+        if (**update) { xlu__disk_err(dpc,value,what_respecified); return; }
+        free(*update); /* do not complain about overwriting empty strings */
+    }
+    *update = strdup(value);
+}
+
+/* Sets ->readwrite based on the string value.  This ought to be an enum. */
+static void setaccess(DiskParseContext *dpc, const char *str) {
+    if (!strcmp(str, "r") || !strcmp(str, "ro")) {
+        dpc->disk->readwrite = 0;
+    } else if (!strcmp(str, "rw") || !strcmp(str, "w") || !strcmp(str,"")) {
+	dpc->disk->readwrite = 1;
+    } else {
+	xlu__disk_err(dpc,str,"unknown value for access");
+    }
+}
+
+/* Sets ->format based on the string value.  This ought to be an enum. */
+static void setformat(DiskParseContext *dpc, const char *str) {
+    if (!strcmp(str,"") ||
+             !strcmp(str,"raw"))    DSET(dpc,format,FORMAT,str,RAW);
+    else if (!strcmp(str,"qcow"))   DSET(dpc,format,FORMAT,str,QCOW);
+    else if (!strcmp(str,"qcow2"))  DSET(dpc,format,FORMAT,str,QCOW2);
+    else if (!strcmp(str,"vhd"))    DSET(dpc,format,FORMAT,str,VHD);
+    else xlu__disk_err(dpc,str,"unknown value for format");
+}
+ 
+#define DEPRECATE(usewhatinstead) /* not currently reported */
+
+%}
+
+%option warn
+%option nodefault
+%option batch
+%option 8bit
+%option noyywrap
+%option reentrant
+%option prefix="xlu__disk_yy"
+%option nounput
+
+%x LEXERR
+
+%%
+
+ /*----- the scanner rules which do the parsing -----*/
+
+[ \t\n]+/([^ \t\n].*)? { /* ignore whitespace before parameters */ }
+
+ /* ordinary parameters setting enums or strings */
+
+format=[^,]*,?	{ STRIP(','); setformat(DPC, FROMEQUALS); }
+
+cdrom,?		{ DPC->disk->is_cdrom = 1; }
+devtype=cdrom,?	{ DPC->disk->is_cdrom = 1; }
+devtype=disk,?	{ DPC->disk->is_cdrom = 0; }
+devtype=[^,]*,?	{ xlu__disk_err(DPC,yytext,"unknown value for type"); }
+
+access=[^,]*,?	{ STRIP(','); setaccess(DPC, FROMEQUALS); }
+
+vdev=[^,]*,?	{ STRIP(','); SAVESTRING("vdev", vdev, FROMEQUALS); }
+script=[^,]*,?	{ STRIP(','); SAVESTRING("script", script, FROMEQUALS); }
+
+ /* the target magic parameter, eats the rest of the string */
+
+target=.*	{ STRIP(','); SAVESTRING("target", pdev_path, FROMEQUALS); }
+
+ /* unknown parameters */
+
+[a-z][-a-z0-9]*=[^,],? { xlu__disk_err(DPC,yytext,"unknown parameter"); }
+
+ /* deprecated prefixes */
+
+  /* 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; DEPRECATE("use `[format=]...,'");
+                    setformat(DPC, yytext);
+                 }
+
+iscsi:|e?nbd:drbd:/.* {
+		    STRIP(':');
+                    DPC->had_depr_prefix=1; DEPRECATE("use `script=...'");
+		    SAVESTRING("script", script, yytext);
+		}
+
+tapdisk:/.*	{ DPC->had_depr_prefix=1; DEPRECATE(0); }
+tap2?:/.*	{ DPC->had_depr_prefix=1; DEPRECATE(0); }
+aio:/.*		{ DPC->had_depr_prefix=1; DEPRECATE(0); }
+ioemu:/.*	{ DPC->had_depr_prefix=1; DEPRECATE(0); }
+file:/.*	{ DPC->had_depr_prefix=1; DEPRECATE(0); }
+phy:/.*		{ DPC->had_depr_prefix=1; DEPRECATE(0); }
+
+[a-z][a-z0-9]*:/([^a-z0-9].*)? {
+		  xlu__disk_err(DPC,yytext,"unknown deprecated disk prefix");
+		  return 0;
+		}
+
+ /* positional parameters */
+
+[^=,]*,|[^=,]+,?  {
+    char *colon;
+    STRIP(',');
+
+    if (DPC->err) {
+        /* previous errors may just lead to subsequent ones */
+    } else if (!DPC->disk->pdev_path) {
+        SAVESTRING("target", pdev_path, yytext);
+    } else if (!DPC->had_depr_prefix &&
+               DPC->disk->format == LIBXL_DISK_FORMAT_UNKNOWN) {
+        setformat(DPC,yytext);
+    } else if (!DPC->disk->vdev) {
+        colon = strrchr(yytext, ':');
+        if (colon) {
+            DEPRECATE("use `devtype=...'");
+            *colon++ = 0;
+            if (!strcmp(colon,"cdrom")) {
+                DPC->disk->is_cdrom = 1;
+            } else if (!strcmp(colon,"disk")) {
+                DPC->disk->is_cdrom = 0;
+            } else {
+                xlu__disk_err(DPC,colon,"unknown deprecated type");
+            }
+        }
+        SAVESTRING("vdev", vdev, yytext);
+    } else if (!DPC->access_set) {
+        DPC->access_set = 1;
+        setaccess(DPC,yytext);
+    } else {
+        xlu__disk_err(DPC,yytext,"too many positional parameters");
+        return 0; /* don't print any more errors */
+    }
+}
+
+. {
+    BEGIN(LEXERR);
+    yymore();
+}
+<LEXERR>.* {
+    xlu__disk_err(DPC,yytext,"bad disk syntax"); return 0;
+}
diff --git a/tools/libxl/libxlutil.h b/tools/libxl/libxlutil.h
index 8a6fcbd..80c8753 100644
--- a/tools/libxl/libxlutil.h
+++ b/tools/libxl/libxlutil.h
@@ -58,4 +58,27 @@ 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) */
 
+
+/*
+ * Disk specification parsing.
+ */
+
+int xlu_disk_parse(XLU_Config *cfg, int nspecs, const char *const *specs,
+		   libxl_device_disk *disk);
+  /* disk must have been initialised.
+   *
+   * On error, returns errno value.  Bad strings cause EINVAL and
+   * print a message to cfg's report (that's all cfg is used for).
+   *
+   * Normally one would pass nspecs==1 and only specs[0].  But it is
+   * permitted to pass more strings in which case each is parsed as a
+   * string containing a collection of parameters (but they all refer
+   * to of the configuration for a single disk).
+   *
+   * nspecs==0 is permitted but since it does not specify some mandatory
+   * properties, it produces a run-time configuration error if the
+   * resulting disk struct is used with libxl.
+   */
+
+
 #endif /* LIBXLUTIL_H */
-- 
1.7.2.5

  reply	other threads:[~2011-05-12 14:36 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-05-12 14:36 [PATCH/RFC 00/14] libxl: disk configuration handling Ian Jackson
2011-05-12 14:36 ` [PATCH 01/14] libxl: add missing copyright notices to some files Ian Jackson
2011-05-12 14:36   ` [PATCH 02/14] libxl: add missing copyright notices to autogenerated files Ian Jackson
2011-05-12 14:36     ` [PATCH 03/14] libxl: provide TOSTRING in libxl_internal.h and libxlu_internal.h Ian Jackson
2011-05-12 14:36       ` [PATCH 04/14] libxl: make libxl_ctx_free tolerate NULL ctx argument Ian Jackson
2011-05-12 14:36         ` [PATCH 05/14] libxl: disks: expose new "script" parameter for external block scripts Ian Jackson
2011-05-12 14:36           ` [PATCH 06/14] libxl: disks: rename disk param "unpluggable" to "removable" Ian Jackson
2011-05-12 14:36             ` [PATCH 07/14] libxl: disks: Make LIBXL_DISK_BACKEND_UNKNOWN work Ian Jackson
2011-05-12 14:36               ` Ian Jackson [this message]
2011-05-12 14:36                 ` [PATCH 09/14] libxl: disks: commit libxlu_disk_l.[ch] flex output Ian Jackson
2011-05-12 14:36                   ` [PATCH 10/14] docs: update xl-disk-configuration.txt to describe new syntax Ian Jackson
2011-05-12 14:36                     ` [PATCH 11/14] xl: disks: replace config file disk spec parser with call to xlu_disk_parse Ian Jackson
2011-05-12 14:36                       ` [PATCH 12/14] xl: disks: replace block-attach disk config parser with call to xlu_parse_disk Ian Jackson
2011-05-12 14:36                         ` [PATCH 13/14] libxl: disks: allow specification of "backendtype=phy|tap|qdisk" Ian Jackson
2011-05-12 14:36                           ` [PATCH 14/14] xl: xl block-attach -N (dry run) option Ian Jackson
2011-05-13 12:56                             ` Ian Campbell
2011-05-13 12:53                           ` [PATCH 13/14] libxl: disks: allow specification of "backendtype=phy|tap|qdisk" Ian Campbell
2011-06-02 16:57                             ` Ian Jackson
2011-05-12 14:42                         ` [PATCH 12/14] xl: disks: replace block-attach disk config parser with call to xlu_parse_disk Ian Jackson
2011-05-13 12:50                         ` Ian Campbell
2011-05-13 12:49                       ` [PATCH 11/14] xl: disks: replace config file disk spec parser with call to xlu_disk_parse Ian Campbell
2011-05-13 12:45                     ` [PATCH 10/14] docs: update xl-disk-configuration.txt to describe new syntax Ian Campbell
2011-05-18 10:31                       ` Ian Jackson
2011-05-20  9:27                         ` Ian Campbell
2011-05-20 10:21                           ` Ian Jackson
2011-05-20 10:26                             ` Ian Campbell
2011-05-13 10:49                   ` [PATCH 09/14] libxl: disks: commit libxlu_disk_l.[ch] flex output Ian Campbell
2011-05-13 10:48                 ` [PATCH 08/14] libxl: disks: new xlu_disk_parse function Ian Campbell
2011-06-02 16:50                   ` Ian Jackson
2011-05-13 10:38               ` [PATCH 07/14] libxl: disks: Make LIBXL_DISK_BACKEND_UNKNOWN work Ian Campbell
2011-06-02 16:48                 ` Ian Jackson
2011-05-13 10:36             ` [PATCH 06/14] libxl: disks: rename disk param "unpluggable" to "removable" Ian Campbell
2011-05-13 10:35           ` [PATCH 05/14] libxl: disks: expose new "script" parameter for external block scripts Ian Campbell
2011-06-02 16:48             ` Ian Jackson
2011-05-13 10:33 ` [PATCH/RFC 00/14] libxl: disk configuration handling Ian Campbell
2011-06-02 16:57   ` Ian Jackson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1305211004-31687-9-git-send-email-ian.jackson@eu.citrix.com \
    --to=ian.jackson@eu.citrix.com \
    --cc=ijackson@chiark.greenend.org.uk \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).