qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [RFC][PATCH 0/3] Make qemu-img create options generic
@ 2009-05-14 14:12 Kevin Wolf
  2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 1/3] Create qemu-option.h Kevin Wolf
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Kevin Wolf @ 2009-05-14 14:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf

Currently, qemu-img and the bdrv_create() interface need to carry parameters
for every single option that is used by at least one file format. We already
have a few of such format specific options (encryption for qcow2, version 6
header for VMDK, backing file for some formats) and there are more to come
(like qcow cluster size).

This patch series changes this into a more generic approach: All block drivers
contain a data structure which describes all options this driver recognizes.
qemu-img can use this structure then instead of hard-coding every single
option. An -o option is introduced for these parameteres, the format is the
usual comma separated name=value style as in -drive.

This series is not yet meant to be applied. qemu-img convert still needs to be
converted to the new interface and it's not exactly tested extensively (let
alone the state after patch 1 or 2 applied without the rest). Maybe it also
could use some better identifiers, I'm open for suggestions.

Kevin Wolf (3):
  Create qemu-option.h
  Convert all block drivers
  Convert qemu-img create

 Makefile          |    2 +-
 block-cow.c       |   24 ++++-
 block-qcow.c      |   28 +++++-
 block-qcow2.c     |   36 ++++++-
 block-raw-posix.c |   37 +++++--
 block-raw-win32.c |   20 +++-
 block-vmdk.c      |   28 +++++-
 block-vpc.c       |   21 +++-
 block-vvfat.c     |    4 +-
 block.c           |   44 ++++++--
 block.h           |    6 +-
 block_int.h       |   17 ++-
 qemu-img.c        |  133 +++++++++++++++++---------
 qemu-option.c     |  280 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-option.h     |   61 ++++++++++++
 sysemu.h          |    2 -
 vl.c              |   38 +-------
 17 files changed, 642 insertions(+), 139 deletions(-)
 create mode 100644 qemu-option.c
 create mode 100644 qemu-option.h

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

* [Qemu-devel] [RFC][PATCH 1/3] Create qemu-option.h
  2009-05-14 14:12 [Qemu-devel] [RFC][PATCH 0/3] Make qemu-img create options generic Kevin Wolf
@ 2009-05-14 14:12 ` Kevin Wolf
  2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 2/3] Convert all block drivers Kevin Wolf
  2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 3/3] Convert qemu-img create Kevin Wolf
  2 siblings, 0 replies; 4+ messages in thread
From: Kevin Wolf @ 2009-05-14 14:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf

This patch creates a new header file and the corresponding implementation file
for parsing of parameter strings for options (like used in -drive). Part of
this is code moved from vl.c (so qemu-img can use it later).

The idea is to have a data structure describing all accepted parameters. When
parsing a parameter string, the structure is copied and filled with the
parameter values.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 Makefile      |    2 +-
 qemu-option.c |  280 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qemu-option.h |   61 +++++++++++++
 sysemu.h      |    2 -
 vl.c          |   38 +--------
 5 files changed, 343 insertions(+), 40 deletions(-)
 create mode 100644 qemu-option.c
 create mode 100644 qemu-option.h

diff --git a/Makefile b/Makefile
index 8649938..7277de7 100644
--- a/Makefile
+++ b/Makefile
@@ -63,7 +63,7 @@ recurse-all: $(SUBDIR_RULES)
 #######################################################################
 # BLOCK_OBJS is code used by both qemu system emulation and qemu-img
 
-BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o
+BLOCK_OBJS=cutils.o cache-utils.o qemu-malloc.o qemu-option.o
 BLOCK_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o
 BLOCK_OBJS+=block-dmg.o block-bochs.o block-vpc.o block-vvfat.o
 BLOCK_OBJS+=block-qcow2.o block-parallels.o block-nbd.o
diff --git a/qemu-option.c b/qemu-option.c
new file mode 100644
index 0000000..bfc7545
--- /dev/null
+++ b/qemu-option.c
@@ -0,0 +1,280 @@
+/*
+ * Commandline option parsing functions
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "qemu-common.h"
+#include "qemu-option.h"
+
+const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
+{
+    char *q;
+
+    q = buf;
+    while (*p != '\0' && *p != delim) {
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
+const char *get_opt_value(char *buf, int buf_size, const char *p)
+{
+    char *q;
+
+    q = buf;
+    while (*p != '\0') {
+        if (*p == ',') {
+            if (*(p + 1) != ',')
+                break;
+            p++;
+        }
+        if (q && (q - buf) < buf_size - 1)
+            *q++ = *p;
+        p++;
+    }
+    if (q)
+        *q = '\0';
+
+    return p;
+}
+
+QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
+    const char *name)
+{
+    while (list && list->name) {
+        if (!strcmp(list->name, name)) {
+            return list;
+        }
+        list++;
+    }
+
+    return NULL;
+}
+
+int set_option_parameter(QEMUOptionParameter *list, const char *name,
+    const char *value)
+{
+    // Find a matching parameter
+    list = get_option_parameter(list, name);
+    if (list == NULL) {
+        fprintf(stderr, "Unknown option '%s'\n", name);
+        return -1;
+    }
+
+    // Process parameter
+    switch (list->type) {
+    case OPT_FLAG:
+        if (value != NULL) {
+            if (!strcmp(value, "on")) {
+                list->value.n = 1;
+            } else if (!strcmp(value, "off")) {
+                list->value.n = 0;
+            } else {
+                fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name);
+                return -1;
+            }
+        } else {
+            list->value.n = 1;
+        }
+        break;
+
+    case OPT_STRING:
+        if (value != NULL) {
+            list->value.s = strdup(value);
+        } else {
+            fprintf(stderr, "Option '%s' needs a parameter\n", name);
+            return -1;
+        }
+        break;
+
+    case OPT_SIZE:
+        if (value != NULL) {
+            double sizef = strtod(value, (char**) &value);
+
+            switch (*value) {
+            case 'T':
+                sizef *= 1024;
+            case 'G':
+                sizef *= 1024;
+            case 'M':
+                sizef *= 1024;
+            case 'K':
+            case 'k':
+                sizef *= 1024;
+            case 'b':
+            case '\0':
+                list->value.n = (uint64_t) sizef;
+                break;
+            default:
+                fprintf(stderr, "Option '%s' needs size as parameter\n", name);
+                fprintf(stderr, "You may use k, M, G or T suffixes for "
+                    "kilobytes, megabytes, gigabytes and terabytes.\n");
+                return -1;
+            }
+        } else {
+            fprintf(stderr, "Option '%s' needs a parameter\n", name);
+            return -1;
+        }
+        break;
+    default:
+        fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
+        return -1;
+    }
+
+    return 0;
+}
+
+int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
+    uint64_t value)
+{
+    // Find a matching parameter
+    list = get_option_parameter(list, name);
+    if (list == NULL) {
+        fprintf(stderr, "Unknown option '%s'\n", name);
+        return -1;
+    }
+
+    // Process parameter
+    switch (list->type) {
+    case OPT_FLAG:
+    case OPT_NUMBER:
+    case OPT_SIZE:
+        list->value.n = value;
+        break;
+
+    default:
+        return -1;
+    }
+
+    return 0;
+}
+
+void free_option_parameters(QEMUOptionParameter *list)
+{
+    QEMUOptionParameter *cur = list;
+
+    while (cur && cur->name) {
+        if (cur->type == OPT_STRING) {
+            free(cur->value.s);
+        }
+        cur++;
+    }
+
+    free(list);
+}
+
+QEMUOptionParameter *parse_option_parameters(const char *param,
+    QEMUOptionParameter *list, QEMUOptionParameter *dest)
+{
+    QEMUOptionParameter *cur;
+    QEMUOptionParameter *allocated = NULL;
+    char name[256];
+    char value[256];
+    char *param_delim, *value_delim;
+    char next_delim;
+    size_t num_options;
+
+    if (list == NULL) {
+        return NULL;
+    }
+
+    if (dest == NULL) {
+        // Count valid options
+        num_options = 0;
+        cur = list;
+        while (cur->name) {
+            num_options++;
+            cur++;
+        }
+
+        // Create a copy of the option list to fill in values
+        dest = qemu_mallocz((num_options + 1) * sizeof(QEMUOptionParameter));
+        allocated = dest;
+        memcpy(dest, list, (num_options + 1) * sizeof(QEMUOptionParameter));
+    }
+
+    while (*param) {
+
+        // Find parameter name and value in the string
+        param_delim = strchr(param, ',');
+        value_delim = strchr(param, '=');
+
+        if (value_delim && (value_delim < param_delim || !param_delim)) {
+            next_delim = '=';
+        } else {
+            next_delim = ',';
+            value_delim = NULL;
+        }
+
+        param = get_opt_name(name, sizeof(name), param, next_delim);
+        if (value_delim) {
+            param = get_opt_value(value, sizeof(value), param + 1);
+        }
+        if (*param != '\0') {
+            param++;
+        }
+
+        // Set the parameter
+        if (set_option_parameter(dest, name, value_delim ? value : NULL)) {
+            goto fail;
+        }
+    }
+
+    return dest;
+
+fail:
+    free_option_parameters(allocated);
+    return NULL;
+}
+
+void print_option_parameters(QEMUOptionParameter *list)
+{
+    while (list && list->name) {
+        switch (list->type) {
+            case OPT_STRING:
+                 if (list->value.s != NULL) {
+                     printf("%s='%s' ", list->name, list->value.s);
+                 }
+                break;
+            case OPT_FLAG:
+                printf("%s=%s ", list->name, list->value.n ? "on" : "off");
+                break;
+            case OPT_SIZE:
+            case OPT_NUMBER:
+                printf("%s=%" PRId64 " ", list->name, list->value.n);
+                break;
+            default:
+                printf("%s=(unkown type) ", list->name);
+                break;
+        }
+        list++;
+    }
+}
diff --git a/qemu-option.h b/qemu-option.h
new file mode 100644
index 0000000..15d8cb8
--- /dev/null
+++ b/qemu-option.h
@@ -0,0 +1,61 @@
+/*
+ * Commandline option parsing functions
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_OPTIONS_H
+#define QEMU_OPTIONS_H
+
+enum QEMUOptionParType {
+    OPT_FLAG,
+    OPT_NUMBER,
+    OPT_SIZE,
+    OPT_STRING,
+};
+
+typedef struct QEMUOptionParameter {
+    const char *name;
+    enum QEMUOptionParType type;
+    union {
+        uint64_t n;
+        char* s;
+    } value;
+} QEMUOptionParameter;
+
+
+const char *get_opt_name(char *buf, int buf_size, const char *p, char delim);
+const char *get_opt_value(char *buf, int buf_size, const char *p);
+
+
+QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
+    const char *name);
+int set_option_parameter(QEMUOptionParameter *list, const char *name,
+    const char *value);
+int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
+    uint64_t value);
+QEMUOptionParameter *parse_option_parameters(const char *param,
+    QEMUOptionParameter *list, QEMUOptionParameter *dest);
+void free_option_parameters(QEMUOptionParameter *list);
+void print_option_parameters(QEMUOptionParameter *list);
+
+#endif
diff --git a/sysemu.h b/sysemu.h
index 25a7c32..b054015 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -253,8 +253,6 @@ void do_usb_add(Monitor *mon, const char *devname);
 void do_usb_del(Monitor *mon, const char *devname);
 void usb_info(Monitor *mon);
 
-const char *get_opt_name(char *buf, int buf_size, const char *p, char delim);
-const char *get_opt_value(char *buf, int buf_size, const char *p);
 int get_param_value(char *buf, int buf_size,
                     const char *tag, const char *str);
 int check_params(const char * const *params, const char *str);
diff --git a/vl.c b/vl.c
index 8e4fba6..1a042a8 100644
--- a/vl.c
+++ b/vl.c
@@ -156,6 +156,7 @@ int main(int argc, char **argv)
 #include "migration.h"
 #include "kvm.h"
 #include "balloon.h"
+#include "qemu-option.h"
 
 #include "disas.h"
 
@@ -1807,43 +1808,6 @@ static int socket_init(void)
 }
 #endif
 
-const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
-{
-    char *q;
-
-    q = buf;
-    while (*p != '\0' && *p != delim) {
-        if (q && (q - buf) < buf_size - 1)
-            *q++ = *p;
-        p++;
-    }
-    if (q)
-        *q = '\0';
-
-    return p;
-}
-
-const char *get_opt_value(char *buf, int buf_size, const char *p)
-{
-    char *q;
-
-    q = buf;
-    while (*p != '\0') {
-        if (*p == ',') {
-            if (*(p + 1) != ',')
-                break;
-            p++;
-        }
-        if (q && (q - buf) < buf_size - 1)
-            *q++ = *p;
-        p++;
-    }
-    if (q)
-        *q = '\0';
-
-    return p;
-}
-
 int get_param_value(char *buf, int buf_size,
                     const char *tag, const char *str)
 {
-- 
1.6.0.6

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

* [Qemu-devel] [RFC][PATCH 2/3] Convert all block drivers
  2009-05-14 14:12 [Qemu-devel] [RFC][PATCH 0/3] Make qemu-img create options generic Kevin Wolf
  2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 1/3] Create qemu-option.h Kevin Wolf
@ 2009-05-14 14:12 ` Kevin Wolf
  2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 3/3] Convert qemu-img create Kevin Wolf
  2 siblings, 0 replies; 4+ messages in thread
From: Kevin Wolf @ 2009-05-14 14:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf

Now we can make use of the newly introduced option structures. Instead of
having bdrv_create carry more and more parameters (which are format specific in
most cases), just pass a option structure as defined by the driver itself.

bdrv_create2() contains an emulation of the old interface to simplify the
transition.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block-cow.c       |   24 ++++++++++++++++++++----
 block-qcow.c      |   28 ++++++++++++++++++++++++++--
 block-qcow2.c     |   36 +++++++++++++++++++++++++++++++-----
 block-raw-posix.c |   37 +++++++++++++++++++++++++++----------
 block-raw-win32.c |   20 ++++++++++++++++----
 block-vmdk.c      |   28 ++++++++++++++++++++++++++--
 block-vpc.c       |   21 +++++++++++++++++----
 block-vvfat.c     |    4 ++--
 block.c           |   44 +++++++++++++++++++++++++++++++++-----------
 block.h           |    6 +++---
 block_int.h       |   17 +++++++++++------
 qemu-img.c        |    2 +-
 12 files changed, 213 insertions(+), 54 deletions(-)

diff --git a/block-cow.c b/block-cow.c
index 17e3292..2bfd17b 100644
--- a/block-cow.c
+++ b/block-cow.c
@@ -201,15 +201,23 @@ static void cow_close(BlockDriverState *bs)
     close(s->fd);
 }
 
-static int cow_create(const char *filename, int64_t image_sectors,
-                      const char *image_filename, int flags)
+static int cow_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd, cow_fd;
     struct cow_header_v2 cow_header;
     struct stat st;
+    int64_t image_sectors = 0;
+    const char *image_filename = NULL;
 
-    if (flags)
-        return -ENOTSUP;
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            image_sectors = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            image_filename = options->value.s;
+        }
+        options++;
+    }
 
     cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
@@ -252,6 +260,12 @@ static void cow_flush(BlockDriverState *bs)
     fsync(s->fd);
 }
 
+static QEMUOptionParameter cow_create_options[] = {
+    { BLOCK_OPT_SIZE,           OPT_SIZE },
+    { BLOCK_OPT_BACKING_FILE,   OPT_STRING },
+    { NULL }
+};
+
 BlockDriver bdrv_cow = {
     .format_name	= "cow",
     .instance_size	= sizeof(BDRVCowState),
@@ -263,5 +277,7 @@ BlockDriver bdrv_cow = {
     .bdrv_create	= cow_create,
     .bdrv_flush		= cow_flush,
     .bdrv_is_allocated	= cow_is_allocated,
+
+    .create_options = cow_create_options,
 };
 #endif
diff --git a/block-qcow.c b/block-qcow.c
index fc6b809..5bfb2ee 100644
--- a/block-qcow.c
+++ b/block-qcow.c
@@ -766,12 +766,26 @@ static void qcow_close(BlockDriverState *bs)
     bdrv_delete(s->hd);
 }
 
-static int qcow_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
+static int qcow_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd, header_size, backing_filename_len, l1_size, i, shift;
     QCowHeader header;
     uint64_t tmp;
+    int64_t total_size = 0;
+    const char *backing_file = NULL;
+    int flags = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
+            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
+        }
+        options++;
+    }
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
     if (fd < 0)
@@ -917,6 +931,14 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
     return 0;
 }
 
+
+static QEMUOptionParameter qcow_create_options[] = {
+    { BLOCK_OPT_SIZE,           OPT_SIZE },
+    { BLOCK_OPT_BACKING_FILE,   OPT_STRING },
+    { BLOCK_OPT_ENCRYPT,        OPT_FLAG },
+    { NULL }
+};
+
 BlockDriver bdrv_qcow = {
     .format_name	= "qcow",
     .instance_size	= sizeof(BDRVQcowState),
@@ -934,4 +956,6 @@ BlockDriver bdrv_qcow = {
     .aiocb_size		= sizeof(QCowAIOCB),
     .bdrv_write_compressed = qcow_write_compressed,
     .bdrv_get_info	= qcow_get_info,
+
+    .create_options = qcow_create_options,
 };
diff --git a/block-qcow2.c b/block-qcow2.c
index 9a49777..2c87701 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -1696,10 +1696,28 @@ static int qcow_create2(const char *filename, int64_t total_size,
     return 0;
 }
 
-static int qcow_create(const char *filename, int64_t total_size,
-                       const char *backing_file, int flags)
-{
-    return qcow_create2(filename, total_size, backing_file, NULL, flags);
+static int qcow_create(const char *filename, QEMUOptionParameter *options)
+{
+    const char *backing_file = NULL;
+    const char *backing_fmt = NULL;
+    uint64_t sectors = 0;
+    int flags = 0;
+
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            sectors = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
+            backing_fmt = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
+            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
+        }
+        options++;
+    }
+
+    return qcow_create2(filename, sectors, backing_file, backing_fmt, flags);
 }
 
 static int qcow_make_empty(BlockDriverState *bs)
@@ -2892,6 +2910,14 @@ static int qcow_get_buffer(BlockDriverState *bs, uint8_t *buf,
     return ret;
 }
 
+static QEMUOptionParameter qcow_create_options[] = {
+    { BLOCK_OPT_SIZE,           OPT_SIZE },
+    { BLOCK_OPT_BACKING_FILE,   OPT_STRING },
+    { BLOCK_OPT_BACKING_FMT,    OPT_STRING },
+    { BLOCK_OPT_ENCRYPT,        OPT_FLAG },
+    { NULL }
+};
+
 BlockDriver bdrv_qcow2 = {
     .format_name	= "qcow2",
     .instance_size	= sizeof(BDRVQcowState),
@@ -2919,6 +2945,6 @@ BlockDriver bdrv_qcow2 = {
     .bdrv_put_buffer    = qcow_put_buffer,
     .bdrv_get_buffer    = qcow_get_buffer,
 
-    .bdrv_create2 = qcow_create2,
+    .create_options = qcow_create_options,
     .bdrv_check = qcow_check,
 };
diff --git a/block-raw-posix.c b/block-raw-posix.c
index 0663c06..a32ce37 100644
--- a/block-raw-posix.c
+++ b/block-raw-posix.c
@@ -823,13 +823,18 @@ again:
 }
 #endif
 
-static int raw_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
+static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
+    int64_t total_size = 0;
 
-    if (flags || backing_file)
-        return -ENOTSUP;
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        }
+        options++;
+    }
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
@@ -846,6 +851,12 @@ static void raw_flush(BlockDriverState *bs)
     fsync(s->fd);
 }
 
+
+static QEMUOptionParameter raw_create_options[] = {
+    { BLOCK_OPT_SIZE,           OPT_SIZE },
+    { NULL }
+};
+
 BlockDriver bdrv_raw = {
     .format_name = "raw",
     .instance_size = sizeof(BDRVRawState),
@@ -866,6 +877,8 @@ BlockDriver bdrv_raw = {
 
     .bdrv_truncate = raw_truncate,
     .bdrv_getlength = raw_getlength,
+
+    .create_options = raw_create_options,
 };
 
 /***********************************************/
@@ -1364,15 +1377,20 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
 #endif /* !linux && !FreeBSD */
 
 #if defined(__linux__) || defined(__FreeBSD__)
-static int hdev_create(const char *filename, int64_t total_size,
-                       const char *backing_file, int flags)
+static int hdev_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
     int ret = 0;
     struct stat stat_buf;
+    int64_t total_size = 0;
 
-    if (flags || backing_file)
-        return -ENOTSUP;
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, "size")) {
+            total_size = options->value.n / 512;
+        }
+        options++;
+    }
 
     fd = open(filename, O_WRONLY | O_BINARY);
     if (fd < 0)
@@ -1391,8 +1409,7 @@ static int hdev_create(const char *filename, int64_t total_size,
 
 #else  /* !(linux || freebsd) */
 
-static int hdev_create(const char *filename, int64_t total_size,
-                       const char *backing_file, int flags)
+static int hdev_create(const char *filename, QEMUOptionParameter *options)
 {
     return -ENOTSUP;
 }
diff --git a/block-raw-win32.c b/block-raw-win32.c
index b5287d2..a05c687 100644
--- a/block-raw-win32.c
+++ b/block-raw-win32.c
@@ -210,13 +210,18 @@ static int64_t raw_getlength(BlockDriverState *bs)
     return l.QuadPart;
 }
 
-static int raw_create(const char *filename, int64_t total_size,
-                      const char *backing_file, int flags)
+static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
+    int64_t total_size = 0;
 
-    if (flags || backing_file)
-        return -ENOTSUP;
+    /* Read out options */
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        }
+        options++;
+    }
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
@@ -228,6 +233,11 @@ static int raw_create(const char *filename, int64_t total_size,
     return 0;
 }
 
+static QEMUOptionParameter raw_create_options[] = {
+    { BLOCK_OPT_SIZE,           OPT_SIZE },
+    { NULL }
+};
+
 BlockDriver bdrv_raw = {
     .format_name	= "raw",
     .instance_size	= sizeof(BDRVRawState),
@@ -239,6 +249,8 @@ BlockDriver bdrv_raw = {
     .bdrv_write		= raw_write,
     .bdrv_truncate	= raw_truncate,
     .bdrv_getlength	= raw_getlength,
+
+    .create_options = raw_create_options,
 };
 
 /***********************************************/
diff --git a/block-vmdk.c b/block-vmdk.c
index d47d483..bba6b9c 100644
--- a/block-vmdk.c
+++ b/block-vmdk.c
@@ -686,8 +686,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
     return 0;
 }
 
-static int vmdk_create(const char *filename, int64_t total_size,
-                       const char *backing_file, int flags)
+static int vmdk_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd, i;
     VMDK4Header header;
@@ -712,6 +711,21 @@ static int vmdk_create(const char *filename, int64_t total_size,
         "ddb.adapterType = \"ide\"\n";
     char desc[1024];
     const char *real_filename, *temp_str;
+    int64_t total_size = 0;
+    const char *backing_file = NULL;
+    int flags = 0;
+
+    // Read out options
+    while (options && options->name) {
+        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
+            total_size = options->value.n / 512;
+        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
+            backing_file = options->value.s;
+        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
+            flags |= options->value.n ? BLOCK_FLAG_COMPAT6: 0;
+        }
+        options++;
+    }
 
     /* XXX: add support for backing file */
     if (backing_file) {
@@ -811,6 +825,14 @@ static void vmdk_flush(BlockDriverState *bs)
     bdrv_flush(s->hd);
 }
 
+
+static QEMUOptionParameter vmdk_create_options[] = {
+    { BLOCK_OPT_SIZE,           OPT_SIZE },
+    { BLOCK_OPT_BACKING_FILE,   OPT_STRING },
+    { BLOCK_OPT_COMPAT6,        OPT_FLAG },
+    { NULL }
+};
+
 BlockDriver bdrv_vmdk = {
     .format_name	= "vmdk",
     .instance_size	= sizeof(BDRVVmdkState),
@@ -822,4 +844,6 @@ BlockDriver bdrv_vmdk = {
     .bdrv_create	= vmdk_create,
     .bdrv_flush		= vmdk_flush,
     .bdrv_is_allocated	= vmdk_is_allocated,
+
+    .create_options = vmdk_create_options,
 };
diff --git a/block-vpc.c b/block-vpc.c
index 71a171d..45b99f8 100644
--- a/block-vpc.c
+++ b/block-vpc.c
@@ -476,8 +476,7 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
     return 0;
 }
 
-static int vpc_create(const char *filename, int64_t total_sectors,
-    const char *backing_file, int flags)
+static int vpc_create(const char *filename, QEMUOptionParameter *options)
 {
     uint8_t buf[1024];
     struct vhd_footer* footer = (struct vhd_footer*) buf;
@@ -488,10 +487,17 @@ static int vpc_create(const char *filename, int64_t total_sectors,
     uint8_t heads;
     uint8_t secs_per_cyl;
     size_t block_size, num_bat_entries;
+    int64_t total_sectors = 0;
 
-    if (backing_file != NULL)
-        return -ENOTSUP;
+    // Read out options
+    while (options && options->name) {
+        if (!strcmp(options->name, "size")) {
+            total_sectors = options->value.n / 512;
+        }
+        options++;
+    }
 
+    // Create the file
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
     if (fd < 0)
         return -EIO;
@@ -586,6 +592,11 @@ static void vpc_close(BlockDriverState *bs)
     bdrv_delete(s->hd);
 }
 
+static QEMUOptionParameter vpc_create_options[] = {
+    { "size", OPT_SIZE },
+    { NULL }
+};
+
 BlockDriver bdrv_vpc = {
     .format_name	= "vpc",
     .instance_size	= sizeof(BDRVVPCState),
@@ -595,4 +606,6 @@ BlockDriver bdrv_vpc = {
     .bdrv_write		= vpc_write,
     .bdrv_close		= vpc_close,
     .bdrv_create	= vpc_create,
+
+    .create_options = vpc_create_options,
 };
diff --git a/block-vvfat.c b/block-vvfat.c
index 7905931..5323e9a 100644
--- a/block-vvfat.c
+++ b/block-vvfat.c
@@ -2777,8 +2777,8 @@ static int enable_write_target(BDRVVVFATState *s)
 
     s->qcow_filename = qemu_malloc(1024);
     get_tmp_filename(s->qcow_filename, 1024);
-    if (bdrv_create(&bdrv_qcow,
-		s->qcow_filename, s->sector_count, "fat:", 0) < 0)
+    if (bdrv_create2(&bdrv_qcow,
+		s->qcow_filename, s->sector_count, "fat:", NULL, 0) < 0)
 	return -1;
     s->qcow = bdrv_new("");
     if (s->qcow == NULL || bdrv_open(s->qcow, s->qcow_filename, 0) < 0)
diff --git a/block.c b/block.c
index acb8976..fe9c3ef 100644
--- a/block.c
+++ b/block.c
@@ -188,22 +188,44 @@ int bdrv_create2(BlockDriver *drv,
                 const char *backing_file, const char *backing_format,
                 int flags)
 {
-    if (drv->bdrv_create2)
-        return drv->bdrv_create2(filename, size_in_sectors, backing_file,
-                                 backing_format, flags);
-    if (drv->bdrv_create)
-        return drv->bdrv_create(filename, size_in_sectors, backing_file,
-                                flags);
-    return -ENOTSUP;
+    QEMUOptionParameter *options;
+
+    options = parse_option_parameters("", drv->create_options, NULL);
+
+    // Process flags
+    if (flags & ~(BLOCK_FLAG_ENCRYPT | BLOCK_FLAG_COMPAT6)) {
+        return -ENOTSUP;
+    }
+
+    if (flags & BLOCK_FLAG_ENCRYPT) {
+        set_option_parameter_int(options, BLOCK_OPT_ENCRYPT, 1);
+    }
+    if (flags & BLOCK_FLAG_COMPAT6) {
+        set_option_parameter_int(options, BLOCK_OPT_COMPAT6, 1);
+    }
+
+    // Add size to options
+    set_option_parameter_int(options, BLOCK_OPT_SIZE, size_in_sectors * 512);
+
+    // Backing files
+    if ((backing_file != NULL && set_option_parameter(options,
+            BLOCK_OPT_BACKING_FILE, backing_file))
+        || (backing_format != NULL && set_option_parameter(options,
+            BLOCK_OPT_BACKING_FMT, backing_format)))
+    {
+        return -ENOTSUP;
+    }
+
+    return bdrv_create(drv, filename, options);
 }
 
-int bdrv_create(BlockDriver *drv,
-                const char *filename, int64_t size_in_sectors,
-                const char *backing_file, int flags)
+int bdrv_create(BlockDriver *drv, const char* filename,
+    QEMUOptionParameter *options)
 {
     if (!drv->bdrv_create)
         return -ENOTSUP;
-    return drv->bdrv_create(filename, size_in_sectors, backing_file, flags);
+
+    return drv->bdrv_create(filename, options);
 }
 
 #ifdef _WIN32
diff --git a/block.h b/block.h
index 5aef076..dcb2941 100644
--- a/block.h
+++ b/block.h
@@ -3,6 +3,7 @@
 
 #include "qemu-aio.h"
 #include "qemu-common.h"
+#include "qemu-option.h"
 
 /* block.c */
 typedef struct BlockDriver BlockDriver;
@@ -59,9 +60,8 @@ void bdrv_info_stats(Monitor *mon);
 
 void bdrv_init(void);
 BlockDriver *bdrv_find_format(const char *format_name);
-int bdrv_create(BlockDriver *drv,
-                const char *filename, int64_t size_in_sectors,
-                const char *backing_file, int flags);
+int bdrv_create(BlockDriver *drv, const char* filename,
+    QEMUOptionParameter *options);
 int bdrv_create2(BlockDriver *drv,
                  const char *filename, int64_t size_in_sectors,
                  const char *backing_file, const char *backing_format,
diff --git a/block_int.h b/block_int.h
index 9d11940..694daa9 100644
--- a/block_int.h
+++ b/block_int.h
@@ -25,11 +25,18 @@
 #define BLOCK_INT_H
 
 #include "block.h"
+#include "qemu-option.h"
 
 #define BLOCK_FLAG_ENCRYPT	1
 #define BLOCK_FLAG_COMPRESS	2
 #define BLOCK_FLAG_COMPAT6	4
 
+#define BLOCK_OPT_SIZE          "size"
+#define BLOCK_OPT_ENCRYPT       "encrpytion"
+#define BLOCK_OPT_COMPAT6       "compat6"
+#define BLOCK_OPT_BACKING_FILE  "backing_file"
+#define BLOCK_OPT_BACKING_FMT   "backing_fmt"
+
 typedef struct AIOPool {
     void (*cancel)(BlockDriverAIOCB *acb);
     int aiocb_size;
@@ -46,8 +53,7 @@ struct BlockDriver {
     int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
-    int (*bdrv_create)(const char *filename, int64_t total_sectors,
-                       const char *backing_file, int flags);
+    int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
     void (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum);
@@ -97,10 +103,9 @@ struct BlockDriver {
 
     AIOPool aio_pool;
 
-    /* new create with backing file format */
-    int (*bdrv_create2)(const char *filename, int64_t total_sectors,
-                        const char *backing_file, const char *backing_format,
-                        int flags);
+    /* List of options for creating images, terminated by name == NULL */
+    QEMUOptionParameter *create_options;
+
 
     /* Returns number of errors in image, -errno for internal errors */
     int (*bdrv_check)(BlockDriverState* bs);
diff --git a/qemu-img.c b/qemu-img.c
index 29149a2..15f9cfd 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -552,7 +552,7 @@ static int img_convert(int argc, char **argv)
     if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
         error("Compression and encryption not supported at the same time");
 
-    ret = bdrv_create(drv, out_filename, total_sectors, out_baseimg, flags);
+    ret = bdrv_create2(drv, out_filename, total_sectors, out_baseimg, NULL, flags);
     if (ret < 0) {
         if (ret == -ENOTSUP) {
             error("Formatting not supported for file format '%s'", out_fmt);
-- 
1.6.0.6

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

* [Qemu-devel] [RFC][PATCH 3/3] Convert qemu-img create
  2009-05-14 14:12 [Qemu-devel] [RFC][PATCH 0/3] Make qemu-img create options generic Kevin Wolf
  2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 1/3] Create qemu-option.h Kevin Wolf
  2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 2/3] Convert all block drivers Kevin Wolf
@ 2009-05-14 14:12 ` Kevin Wolf
  2 siblings, 0 replies; 4+ messages in thread
From: Kevin Wolf @ 2009-05-14 14:12 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf

This patch changes qemu-img to actually use the new bdrv_create interface. It
translates the old-style qemu-img options which have been bdrv_create2
parameters or flags so far to option structures. As the generic approach, it
introduces an -o option which accepts any parameter the driver knows.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 qemu-img.c |  131 +++++++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 86 insertions(+), 45 deletions(-)

diff --git a/qemu-img.c b/qemu-img.c
index 15f9cfd..4d8aa43 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 #include "qemu-common.h"
+#include "qemu-option.h"
 #include "osdep.h"
 #include "block_int.h"
 #include <assert.h>
@@ -185,6 +186,7 @@ static int read_password(char *buf, int buf_size)
 }
 #endif
 
+
 static BlockDriverState *bdrv_new_open(const char *filename,
                                        const char *fmt)
 {
@@ -222,14 +224,13 @@ static int img_create(int argc, char **argv)
     const char *base_fmt = NULL;
     const char *filename;
     const char *base_filename = NULL;
-    uint64_t size;
-    double sizef;
-    const char *p;
     BlockDriver *drv;
+    QEMUOptionParameter *param = NULL;
+    char *options = NULL;
 
     flags = 0;
     for(;;) {
-        c = getopt(argc, argv, "F:b:f:he6");
+        c = getopt(argc, argv, "F:b:f:he6o:");
         if (c == -1)
             break;
         switch(c) {
@@ -251,59 +252,99 @@ static int img_create(int argc, char **argv)
         case '6':
             flags |= BLOCK_FLAG_COMPAT6;
             break;
+        case 'o':
+            options = optarg;
+            break;
         }
     }
     if (optind >= argc)
         help();
     filename = argv[optind++];
-    size = 0;
-    if (base_filename) {
-        BlockDriverState *bs;
-        BlockDriver *base_drv = NULL;
 
-        if (base_fmt) {
-            base_drv = bdrv_find_format(base_fmt);
-            if (base_drv == NULL)
-                error("Unknown basefile format '%s'", base_fmt);
-        }
+    /* Find driver and parse its options */
+    drv = bdrv_find_format(fmt);
+    if (!drv)
+        error("Unknown file format '%s'", fmt);
 
-        bs = bdrv_new_open(base_filename, base_fmt);
-        bdrv_get_geometry(bs, &size);
-        size *= 512;
-        bdrv_delete(bs);
+    if (options) {
+        param = parse_option_parameters(options, drv->create_options, param);
+        if (param == NULL) {
+            error("Invalid options for file format '%s'.", fmt);
+        }
     } else {
-        if (optind >= argc)
-            help();
-        p = argv[optind];
-        sizef = strtod(p, (char **)&p);
-        if (*p == 'M') {
-            size = (uint64_t)(sizef * 1024 * 1024);
-        } else if (*p == 'G') {
-            size = (uint64_t)(sizef * 1024 * 1024 * 1024);
-        } else if (*p == 'k' || *p == 'K' || *p == '\0') {
-            size = (uint64_t)(sizef * 1024);
-        } else {
-            help();
+        param = parse_option_parameters("", drv->create_options, param);
+    }
+
+    /* Add size to parameters */
+    if (optind < argc) {
+        set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
+    }
+
+    /* Add old-style options to parameters */
+    if (flags & BLOCK_FLAG_ENCRYPT) {
+        if (set_option_parameter(param, BLOCK_OPT_ENCRYPT, "on")) {
+            error("Encryption not supported for file format '%s'", fmt);
         }
     }
-    drv = bdrv_find_format(fmt);
-    if (!drv)
-        error("Unknown file format '%s'", fmt);
-    printf("Formatting '%s', fmt=%s",
-           filename, fmt);
-    if (flags & BLOCK_FLAG_ENCRYPT)
-        printf(", encrypted");
-    if (flags & BLOCK_FLAG_COMPAT6)
-        printf(", compatibility level=6");
+    if (flags & BLOCK_FLAG_COMPAT6) {
+        if (set_option_parameter(param, BLOCK_OPT_COMPAT6, "on")) {
+            error("VMDK version 6 not supported for file format '%s'", fmt);
+        }
+    }
+
     if (base_filename) {
-        printf(", backing_file=%s",
-               base_filename);
-         if (base_fmt)
-             printf(", backing_fmt=%s",
-                    base_fmt);
-    }
-    printf(", size=%" PRIu64 " kB\n", size / 1024);
-    ret = bdrv_create2(drv, filename, size / 512, base_filename, base_fmt, flags);
+        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE, base_filename)) {
+            error("Backing file not supported for file format '%s'", fmt);
+        }
+    }
+    if (base_fmt) {
+        if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
+            error("Backing file format not supported for file format '%s'", fmt);
+        }
+    }
+
+    // The size for the image must always be specified, with one exception:
+    // If we are using a backing file, we can obtain the size from there
+    if (get_option_parameter(param, BLOCK_OPT_SIZE)->value.n == 0) {
+
+        QEMUOptionParameter *backing_file =
+            get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
+        QEMUOptionParameter *backing_fmt =
+            get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
+
+        if (backing_file && backing_file->value.s) {
+            BlockDriverState *bs;
+            uint64_t size;
+            const char *fmt = NULL;
+            char buf[32];
+
+            if (backing_fmt && backing_fmt->value.s) {
+                 if (bdrv_find_format(backing_fmt->value.s)) {
+                     fmt = backing_fmt->value.s;
+                } else {
+                     error("Unknown basefile format '%s'", base_fmt);
+                }
+            }
+
+            bs = bdrv_new_open(base_filename, base_fmt);
+            bdrv_get_geometry(bs, &size);
+            size *= 512;
+            bdrv_delete(bs);
+
+            snprintf(buf, sizeof(buf), "%" PRId64, size);
+            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
+        } else {
+            error("Image creation needs a size parameter");
+        }
+    }
+
+    printf("Formatting '%s', fmt=%s ", filename, fmt);
+    print_option_parameters(param);
+    puts("");
+
+    ret = bdrv_create(drv, filename, param);
+    free_option_parameters(param);
+
     if (ret < 0) {
         if (ret == -ENOTSUP) {
             error("Formatting or formatting option not supported for file format '%s'", fmt);
-- 
1.6.0.6

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

end of thread, other threads:[~2009-05-14 14:13 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-05-14 14:12 [Qemu-devel] [RFC][PATCH 0/3] Make qemu-img create options generic Kevin Wolf
2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 1/3] Create qemu-option.h Kevin Wolf
2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 2/3] Convert all block drivers Kevin Wolf
2009-05-14 14:12 ` [Qemu-devel] [RFC][PATCH 3/3] Convert qemu-img create Kevin Wolf

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).