From 74e8cfade30e514deecbeb3963b34a30ace84b58 Mon Sep 17 00:00:00 2001
From: Jes Sorensen <Jes.Sorensen@redhat.com>
Date: Mon, 31 Jan 2011 12:23:05 -0200
Subject: [PATCH 11/37] add support for protocol driver create_options

RH-Author: Jes Sorensen <Jes.Sorensen@redhat.com>
Message-id: <1296476610-28514-2-git-send-email-Jes.Sorensen@redhat.com>
Patchwork-id: 17296
O-Subject: [PATCH 01/26] add support for protocol driver create_options
Bugzilla: 637701
RH-Acked-by: Alex Williamson <alex.williamson@redhat.com>
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>

From: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>

This patch enables protocol drivers to use their create options which
are not supported by the format.  For example, protcol drivers can use
a backing_file option with raw format.

Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
(cherry picked from commit b50cbabc1bc12e6b0082089c70015c1b97db86a1)
---
 block.c       |    7 +++----
 block.h       |    1 +
 qemu-img.c    |   49 ++++++++++++++++++++++++++++++++++---------------
 qemu-option.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++-------
 qemu-option.h |    2 ++
 5 files changed, 86 insertions(+), 26 deletions(-)

Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
---
 block.c       |    7 +++----
 block.h       |    1 +
 qemu-img.c    |   49 ++++++++++++++++++++++++++++++++++---------------
 qemu-option.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++-------
 qemu-option.h |    2 ++
 5 files changed, 86 insertions(+), 26 deletions(-)

diff --git a/block.c b/block.c
index b8f73f1..fe13c2e 100644
--- a/block.c
+++ b/block.c
@@ -57,7 +57,6 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
                         uint8_t *buf, int nb_sectors);
 static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
                          const uint8_t *buf, int nb_sectors);
-static BlockDriver *find_protocol(const char *filename);
 
 static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
     QTAILQ_HEAD_INITIALIZER(bdrv_states);
@@ -211,7 +210,7 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
 {
     BlockDriver *drv;
 
-    drv = find_protocol(filename);
+    drv = bdrv_find_protocol(filename);
     if (drv == NULL) {
         drv = bdrv_find_format("file");
     }
@@ -284,7 +283,7 @@ static BlockDriver *find_hdev_driver(const char *filename)
     return drv;
 }
 
-static BlockDriver *find_protocol(const char *filename)
+BlockDriver *bdrv_find_protocol(const char *filename)
 {
     BlockDriver *drv1;
     char protocol[128];
@@ -482,7 +481,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
     BlockDriver *drv;
     int ret;
 
-    drv = find_protocol(filename);
+    drv = bdrv_find_protocol(filename);
     if (!drv) {
         return -ENOENT;
     }
diff --git a/block.h b/block.h
index efa6ff5..705e78c 100644
--- a/block.h
+++ b/block.h
@@ -53,6 +53,7 @@ void bdrv_info_stats(Monitor *mon, QObject **ret_data);
 
 void bdrv_init(void);
 void bdrv_init_with_whitelist(void);
+BlockDriver *bdrv_find_protocol(const char *filename);
 BlockDriver *bdrv_find_format(const char *format_name);
 BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
 int bdrv_create(BlockDriver *drv, const char* filename,
diff --git a/qemu-img.c b/qemu-img.c
index 771016e..0744945 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -251,8 +251,8 @@ static int img_create(int argc, char **argv)
     const char *base_fmt = NULL;
     const char *filename;
     const char *base_filename = NULL;
-    BlockDriver *drv;
-    QEMUOptionParameter *param = NULL;
+    BlockDriver *drv, *proto_drv;
+    QEMUOptionParameter *param = NULL, *create_options = NULL;
     char *options = NULL;
 
     flags = 0;
@@ -285,33 +285,42 @@ static int img_create(int argc, char **argv)
         }
     }
 
+    /* Get the filename */
+    if (optind >= argc)
+        help();
+    filename = argv[optind++];
+
     /* Find driver and parse its options */
     drv = bdrv_find_format(fmt);
     if (!drv)
         error("Unknown file format '%s'", fmt);
 
+    proto_drv = bdrv_find_protocol(filename);
+    if (!proto_drv)
+        error("Unknown protocol '%s'", filename);
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    create_options = append_option_parameters(create_options,
+                                              proto_drv->create_options);
+
     if (options && !strcmp(options, "?")) {
-        print_option_help(drv->create_options);
+        print_option_help(create_options);
         return 0;
     }
 
     /* Create parameter list with default values */
-    param = parse_option_parameters("", drv->create_options, param);
+    param = parse_option_parameters("", create_options, param);
     set_option_parameter_int(param, BLOCK_OPT_SIZE, -1);
 
     /* Parse -o options */
     if (options) {
-        param = parse_option_parameters(options, drv->create_options, param);
+        param = parse_option_parameters(options, create_options, param);
         if (param == NULL) {
             error("Invalid options for file format '%s'.", fmt);
         }
     }
 
-    /* Get the filename */
-    if (optind >= argc)
-        help();
-    filename = argv[optind++];
-
     /* Add size to parameters */
     if (optind < argc) {
         set_option_parameter(param, BLOCK_OPT_SIZE, argv[optind++]);
@@ -361,6 +370,7 @@ static int img_create(int argc, char **argv)
     puts("");
 
     ret = bdrv_create(drv, filename, param);
+    free_option_parameters(create_options);
     free_option_parameters(param);
 
     if (ret < 0) {
@@ -577,14 +587,14 @@ static int img_convert(int argc, char **argv)
 {
     int c, ret, n, n1, bs_n, bs_i, flags, cluster_size, cluster_sectors;
     const char *fmt, *out_fmt, *out_baseimg, *out_filename;
-    BlockDriver *drv;
+    BlockDriver *drv, *proto_drv;
     BlockDriverState **bs, *out_bs;
     int64_t total_sectors, nb_sectors, sector_num, bs_offset;
     uint64_t bs_sectors;
     uint8_t * buf;
     const uint8_t *buf1;
     BlockDriverInfo bdi;
-    QEMUOptionParameter *param = NULL;
+    QEMUOptionParameter *param = NULL, *create_options = NULL;
     char *options = NULL;
 
     fmt = NULL;
@@ -649,19 +659,27 @@ static int img_convert(int argc, char **argv)
     if (!drv)
         error("Unknown file format '%s'", out_fmt);
 
+    proto_drv = bdrv_find_protocol(out_filename);
+    if (!proto_drv)
+        error("Unknown protocol '%s'", out_filename);
+
+    create_options = append_option_parameters(create_options,
+                                              drv->create_options);
+    create_options = append_option_parameters(create_options,
+                                              proto_drv->create_options);
     if (options && !strcmp(options, "?")) {
-        print_option_help(drv->create_options);
+        print_option_help(create_options);
         free(bs);
         return 0;
     }
 
     if (options) {
-        param = parse_option_parameters(options, drv->create_options, param);
+        param = parse_option_parameters(options, create_options, param);
         if (param == NULL) {
             error("Invalid options for file format '%s'.", out_fmt);
         }
     } else {
-        param = parse_option_parameters("", drv->create_options, param);
+        param = parse_option_parameters("", create_options, param);
     }
 
     set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
@@ -683,6 +701,7 @@ static int img_convert(int argc, char **argv)
 
     /* Create the new image */
     ret = bdrv_create(drv, out_filename, param);
+    free_option_parameters(create_options);
     free_option_parameters(param);
 
     if (ret < 0) {
diff --git a/qemu-option.c b/qemu-option.c
index c4e61b3..9512370 100644
--- a/qemu-option.c
+++ b/qemu-option.c
@@ -346,6 +346,51 @@ void free_option_parameters(QEMUOptionParameter *list)
 }
 
 /*
+ * Count valid options in list
+ */
+static size_t count_option_parameters(QEMUOptionParameter *list)
+{
+    size_t num_options = 0;
+
+    while (list && list->name) {
+        num_options++;
+        list++;
+    }
+
+    return num_options;
+}
+
+/*
+ * Append an option list (list) to an option list (dest).
+ *
+ * If dest is NULL, a new copy of list is created.
+ *
+ * Returns a pointer to the first element of dest (or the newly allocated copy)
+ */
+QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
+    QEMUOptionParameter *list)
+{
+    size_t num_options, num_dest_options;
+
+    num_options = count_option_parameters(dest);
+    num_dest_options = num_options;
+
+    num_options += count_option_parameters(list);
+
+    dest = qemu_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter));
+
+    while (list && list->name) {
+        if (get_option_parameter(dest, list->name) == NULL) {
+            dest[num_dest_options++] = *list;
+            dest[num_dest_options].name = NULL;
+        }
+        list++;
+    }
+
+    return dest;
+}
+
+/*
  * Parses a parameter string (param) into an option list (dest).
  *
  * list is the templace is. If dest is NULL, a new copy of list is created for
@@ -365,7 +410,6 @@ void free_option_parameters(QEMUOptionParameter *list)
 QEMUOptionParameter *parse_option_parameters(const char *param,
     QEMUOptionParameter *list, QEMUOptionParameter *dest)
 {
-    QEMUOptionParameter *cur;
     QEMUOptionParameter *allocated = NULL;
     char name[256];
     char value[256];
@@ -379,12 +423,7 @@ QEMUOptionParameter *parse_option_parameters(const char *param,
 
     if (dest == NULL) {
         // Count valid options
-        num_options = 0;
-        cur = list;
-        while (cur->name) {
-            num_options++;
-            cur++;
-        }
+        num_options = count_option_parameters(list);
 
         // Create a copy of the option list to fill in values
         dest = qemu_mallocz((num_options + 1) * sizeof(QEMUOptionParameter));
diff --git a/qemu-option.h b/qemu-option.h
index a3bc061..02a1a86 100644
--- a/qemu-option.h
+++ b/qemu-option.h
@@ -70,6 +70,8 @@ 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 *append_option_parameters(QEMUOptionParameter *dest,
+    QEMUOptionParameter *list);
 QEMUOptionParameter *parse_option_parameters(const char *param,
     QEMUOptionParameter *list, QEMUOptionParameter *dest);
 void free_option_parameters(QEMUOptionParameter *list);
-- 
1.7.4.rc1.16.gd2f15e

