[Pkg-libvirt-commits] [libguestfs] 16/78: New APIs: set-backend-setting, get-backend-setting, clear-backend-setting.

Hilko Bengen bengen at moszumanska.debian.org
Fri May 9 12:55:36 UTC 2014


This is an automated email from the git hooks/post-receive script.

bengen pushed a commit to branch experimental
in repository libguestfs.

commit d137ad52c52f8b448d3413660a18c636b6f9ae65
Author: Richard W.M. Jones <rjones at redhat.com>
Date:   Mon Mar 31 12:53:25 2014 +0100

    New APIs: set-backend-setting, get-backend-setting, clear-backend-setting.
    
    Currently the backend settings are treated as a list of strings.  You
    can set the whole list (clearing any strings there previously), but
    you cannot search for an individual string or replace an individual
    string.
    
    This adds further APIs allowing you to do that.  We treat the backend
    settings as a list of environment-like strings (ie.  name=value), and
    add the following functions:
    
     - set-backend-setting (name, value)
    
       Set name=value.  Any previous settings of name are cleared.
    
     - get-backend-setting (name)
    
       Search for name or name=value and return the value.
    
     - clear-backend-setting (name)
    
       Remove any name or name=value settings.
    
    This also adds a regression test.
---
 .gitignore                          |   1 +
 generator/actions.ml                | 120 +++++++++++++++++++++--------
 src/guestfs-internal.h              |   5 +-
 src/handle.c                        | 102 ++++++++++++++++++++++++
 src/launch-direct.c                 |   4 +-
 src/launch-libvirt.c                |   4 +-
 src/launch.c                        |  48 ------------
 tests/c-api/Makefile.am             |  12 +++
 tests/c-api/test-backend-settings.c | 149 ++++++++++++++++++++++++++++++++++++
 9 files changed, 360 insertions(+), 85 deletions(-)

diff --git a/.gitignore b/.gitignore
index 4351e09..1d3311a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -461,6 +461,7 @@ Makefile.in
 /test.out
 /tests/c-api/test-add-drive-opts
 /tests/c-api/test-add-libvirt-dom
+/tests/c-api/test-backend-settings
 /tests/c-api/test-command
 /tests/c-api/test-config
 /tests/c-api/test-create-handle
diff --git a/generator/actions.ml b/generator/actions.ml
index afca296..f9cf28d 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -3091,39 +3091,6 @@ can read a journal entry of any size, ie. it is not limited by
 the libguestfs protocol." };
 
   { defaults with
-    name = "set_backend_settings";
-    style = RErr, [StringList "settings"], [];
-    config_only = true;
-    blocking = false;
-    shortdesc = "set per-backend settings";
-    longdesc = "\
-Set a list of zero or more settings which are passed through to
-the current backend.  Each setting is a string which is interpreted
-in a backend-specific way, or ignored if not understood by the
-backend.
-
-The default value is an empty list, unless the environment
-variable C<LIBGUESTFS_BACKEND_SETTINGS> was set when the handle
-was created.  This environment variable contains a colon-separated
-list of settings.
-
-See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." };
-
-  { defaults with
-    name = "get_backend_settings";
-    style = RStringList "settings", [], [];
-    blocking = false;
-    tests = [
-      InitNone, Always, TestRun (
-        [["get_backend_settings"]]), []
-    ];
-    shortdesc = "get per-backend settings";
-    longdesc = "\
-Return the current backend settings.
-
-See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." };
-
-  { defaults with
     name = "disk_create";
     style = RErr, [String "filename"; String "format"; Int64 "size"], [OString "backingfile"; OString "backingformat"; OString "preallocation"; OString "compat"; OInt "clustersize"];
     test_excuse = "tests in tests/create subdirectory";
@@ -3171,6 +3138,93 @@ this setting may be any power of two between 512 and 2097152.
 Note that this call does not add the new disk to the handle.  You
 may need to call C<guestfs_add_drive_opts> separately." };
 
+  { defaults with
+    name = "get_backend_settings";
+    style = RStringList "settings", [], [];
+    blocking = false;
+    tests = [
+      InitNone, Always, TestRun (
+        [["get_backend_settings"]]), []
+    ];
+    shortdesc = "get per-backend settings";
+    longdesc = "\
+Return the current backend settings.
+
+This call returns all backend settings strings.  If you want to
+find a single backend setting, see C<guestfs_get_backend_setting>.
+
+See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." };
+
+  { defaults with
+    name = "set_backend_settings";
+    style = RErr, [StringList "settings"], [];
+    config_only = true;
+    blocking = false;
+    shortdesc = "replace per-backend settings strings";
+    longdesc = "\
+Set a list of zero or more settings which are passed through to
+the current backend.  Each setting is a string which is interpreted
+in a backend-specific way, or ignored if not understood by the
+backend.
+
+The default value is an empty list, unless the environment
+variable C<LIBGUESTFS_BACKEND_SETTINGS> was set when the handle
+was created.  This environment variable contains a colon-separated
+list of settings.
+
+This call replaces all backend settings.  If you want to replace
+a single backend setting, see C<guestfs_set_backend_setting>.
+If you want to clear a single backend setting, see
+C<guestfs_clear_backend_setting>.
+
+See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." };
+
+  { defaults with
+    name = "get_backend_setting";
+    style = RString "val", [String "name"], [];
+    blocking = false;
+    shortdesc = "get a single per-backend settings string";
+    longdesc = "\
+Find a backend setting string which is either C<\"name\"> or
+begins with C<\"name=\">.  If C<\"name\">, this returns the
+string C<\"1\">.  If C<\"name=\">, this returns the part
+after the equals sign (which may be an empty string).
+
+If no such setting is found, this function throws an error.
+The errno (see C<guestfs_last_errno>) will be C<ESRCH> in this
+case.
+
+See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." };
+
+  { defaults with
+    name = "set_backend_setting";
+    style = RErr, [String "name"; String "val"], [];
+    config_only = true;
+    blocking = false;
+    shortdesc = "set a single per-backend settings string";
+    longdesc = "\
+Append C<\"name=value\"> to the backend settings string list.
+However if a string already exists matching C<\"name\">
+or beginning with C<\"name=\">, then that setting is replaced.
+
+See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." };
+
+  { defaults with
+    name = "clear_backend_setting";
+    style = RInt "count", [String "name"], [];
+    config_only = true;
+    blocking = false;
+    shortdesc = "remove a single per-backend settings string";
+    longdesc = "\
+If there is a backend setting string matching C<\"name\"> or
+beginning with C<\"name=\">, then that string is removed
+from the backend settings.
+
+This call returns the number of strings which were removed
+(which may be 0, 1 or greater than 1).
+
+See L<guestfs(3)/BACKEND>, L<guestfs(3)/BACKEND SETTINGS>." };
+
 ]
 
 (* daemon_functions are any functions which cause some action
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index 648f005..a89731b 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -605,6 +605,9 @@ struct guestfs_message_header;
 struct guestfs_message_error;
 struct guestfs_progress;
 
+/* handle.c */
+extern int guestfs___get_backend_setting_bool (guestfs_h *g, const char *name);
+
 /* errors.c */
 extern void guestfs___init_error_handler (guestfs_h *g);
 
@@ -736,8 +739,6 @@ extern char *guestfs___appliance_command_line (guestfs_h *g, const char *applian
 #define APPLIANCE_COMMAND_LINE_IS_TCG 1
 extern void guestfs___register_backend (const char *name, const struct backend_ops *);
 extern int guestfs___set_backend (guestfs_h *g, const char *method);
-extern const char *guestfs___get_backend_setting (guestfs_h *g, const char *name);
-extern int guestfs___get_backend_setting_bool (guestfs_h *g, const char *name);
 
 /* inspect.c */
 extern void guestfs___free_inspect_info (guestfs_h *g);
diff --git a/src/handle.c b/src/handle.c
index 393ac1e..719bbcd 100644
--- a/src/handle.c
+++ b/src/handle.c
@@ -724,6 +724,108 @@ guestfs__get_backend_settings (guestfs_h *g)
   return ret;                   /* caller frees */
 }
 
+char *
+guestfs__get_backend_setting (guestfs_h *g, const char *name)
+{
+  char **settings = g->backend_settings;
+  size_t namelen = strlen (name);
+  size_t i;
+
+  if (settings == NULL)
+    goto not_found;
+
+  for (i = 0; settings[i] != NULL; ++i) {
+    /* "name" is the same as "name=1" */
+    if (STREQ (settings[i], name))
+      return safe_strdup (g, "1");
+    /* "name=...", return value */
+    if (STRPREFIX (settings[i], name) && settings[i][namelen] == '=')
+      return safe_strdup (g, &settings[i][namelen+1]);
+  }
+
+ not_found:
+  guestfs___error_errno (g, ESRCH, _("setting not found"));
+  return NULL;
+}
+
+int
+guestfs__clear_backend_setting (guestfs_h *g, const char *name)
+{
+  char **settings = g->backend_settings;
+  size_t namelen = strlen (name);
+  size_t i, j;
+  int count = 0;
+
+  if (settings == NULL)
+    return 0;
+
+  for (i = 0; settings[i] != NULL; ++i) {
+    if (STREQ (settings[i], name) ||
+        (STRPREFIX (settings[i], name) && settings[i][namelen] == '=')) {
+      count++;
+      free (settings[i]);
+
+      /* We move all the following strings down one place, including the NULL. */
+      for (j = i; settings[j] != NULL; ++j)
+        settings[j] = settings[j+1];
+
+      i--;
+    }
+  }
+
+  return count;
+}
+
+int
+guestfs__set_backend_setting (guestfs_h *g, const char *name, const char *value)
+{
+  char *new_setting;
+  size_t len;
+
+  new_setting = safe_asprintf (g, "%s=%s", name, value);
+
+  if (g->backend_settings == NULL) {
+    g->backend_settings = safe_malloc (g, sizeof (char *));
+    g->backend_settings[0] = NULL;
+    len = 0;
+  }
+  else {
+    ignore_value (guestfs_clear_backend_setting (g, name));
+    len = guestfs___count_strings (g->backend_settings);
+  }
+
+  g->backend_settings =
+    safe_realloc (g, g->backend_settings, (len+2) * sizeof (char *));
+  g->backend_settings[len++] = new_setting;
+  g->backend_settings[len++] = NULL;
+
+  return 0;
+}
+
+/* This is a convenience function, but we might consider exporting
+ * it as an API in future.
+ */
+int
+guestfs___get_backend_setting_bool (guestfs_h *g, const char *name)
+{
+  CLEANUP_FREE char *value = NULL;
+
+  guestfs_push_error_handler (g, NULL, NULL);
+  value = guestfs_get_backend_setting (g, name);
+  guestfs_pop_error_handler (g);
+
+  if (value == NULL && guestfs_last_errno (g) == ESRCH)
+    return 0;
+
+  if (value == NULL)
+    return -1;
+
+  if (STREQ (value, "1"))
+    return 1;
+
+  return 0;
+}
+
 int
 guestfs__set_pgroup (guestfs_h *g, int v)
 {
diff --git a/src/launch-direct.c b/src/launch-direct.c
index 5c756b7..37bf144 100644
--- a/src/launch-direct.c
+++ b/src/launch-direct.c
@@ -278,7 +278,7 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
   int virtio_scsi;
   struct hv_param *hp;
   bool has_kvm;
-  bool force_tcg;
+  int force_tcg;
 
   /* At present you must add drives before starting the appliance.  In
    * future when we enable hotplugging you won't need to do this.
@@ -289,6 +289,8 @@ launch_direct (guestfs_h *g, void *datav, const char *arg)
   }
 
   force_tcg = guestfs___get_backend_setting_bool (g, "force_tcg");
+  if (force_tcg == -1)
+    return -1;
 
   if (!force_tcg)
     debian_kvm_warning (g);
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index e4563f8..085a521 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -599,7 +599,7 @@ parse_capabilities (guestfs_h *g, const char *capabilities_xml,
   xmlNodeSetPtr nodes;
   xmlAttrPtr attr;
   size_t seen_qemu, seen_kvm;
-  bool force_tcg;
+  int force_tcg;
 
   doc = xmlParseMemory (capabilities_xml, strlen (capabilities_xml));
   if (doc == NULL) {
@@ -667,6 +667,8 @@ parse_capabilities (guestfs_h *g, const char *capabilities_xml,
   }
 
   force_tcg = guestfs___get_backend_setting_bool (g, "force_tcg");
+  if (force_tcg == -1)
+    return -1;
 
   if (!force_tcg)
     data->is_kvm = seen_kvm;
diff --git a/src/launch.c b/src/launch.c
index 3851b6a..e207cc7 100644
--- a/src/launch.c
+++ b/src/launch.c
@@ -485,51 +485,3 @@ guestfs___set_backend (guestfs_h *g, const char *method)
 
   return 0;
 }
-
-/* Convenience functions for backends to read settings. */
-
-/* Return the string value of a setting, or NULL if not set. */
-const char *
-guestfs___get_backend_setting (guestfs_h *g, const char *name)
-{
-  char **settings = g->backend_settings;
-  size_t namelen = strlen (name);
-  size_t i;
-
-  if (settings == NULL)
-    return NULL;
-
-  for (i = 0; settings[i] != NULL; ++i) {
-    if (STRCASEEQ (settings[i], name))
-      return ""; /* setting exists, no value */
-    if (STRCASEPREFIX (settings[i], name) && settings[i][namelen] == '=')
-      return &settings[i][namelen+1]; /* "name=...", return value */
-  }
-
-  return NULL;
-}
-
-/* If there a setting "name", "name=1", etc?  This is similar to
- * fish/fish.c:is_true.
- */
-int
-guestfs___get_backend_setting_bool (guestfs_h *g, const char *name)
-{
-  const char *value = guestfs___get_backend_setting (g, name);
-
-  if (value == NULL)
-    return 0;
-
-  if (STREQ (value, ""))
-    return 1;
-
-  if (STREQ (value, "1") ||
-      STRCASEEQ (value, "true") ||
-      STRCASEEQ (value, "t") ||
-      STRCASEEQ (value, "yes") ||
-      STRCASEEQ (value, "y") ||
-      STRCASEEQ (value, "on"))
-    return 1;
-
-  return 0;
-}
diff --git a/tests/c-api/Makefile.am b/tests/c-api/Makefile.am
index bb146c9..3df00b1 100644
--- a/tests/c-api/Makefile.am
+++ b/tests/c-api/Makefile.am
@@ -31,6 +31,7 @@ check_PROGRAMS = \
 	test-config \
 	test-add-drive-opts \
 	test-last-errno \
+	test-backend-settings \
 	test-private-data \
 	test-user-cancel \
 	test-debug-to-file \
@@ -45,6 +46,7 @@ TESTS = \
 	test-config \
 	test-add-drive-opts \
 	test-last-errno \
+	test-backend-settings \
 	test-private-data \
 	test-user-cancel \
 	test-debug-to-file \
@@ -160,6 +162,16 @@ test_last_errno_LDADD = \
 	$(top_builddir)/src/libguestfs.la \
 	$(top_builddir)/gnulib/lib/libgnu.la
 
+test_backend_settings_SOURCES = test-backend-settings.c
+test_backend_settings_CPPFLAGS = \
+	-I$(top_srcdir)/src -I$(top_builddir)/src
+test_backend_settings_CFLAGS = \
+	$(WARN_CFLAGS) $(WERROR_CFLAGS) \
+	$(GPROF_CFLAGS) $(GCOV_CFLAGS)
+test_backend_settings_LDADD = \
+	$(top_builddir)/src/libutils_la-utils.lo \
+	$(top_builddir)/src/libguestfs.la
+
 test_private_data_SOURCES = test-private-data.c
 test_private_data_CPPFLAGS = \
 	-I$(top_srcdir)/src -I$(top_builddir)/src
diff --git a/tests/c-api/test-backend-settings.c b/tests/c-api/test-backend-settings.c
new file mode 100644
index 0000000..4b24e21
--- /dev/null
+++ b/tests/c-api/test-backend-settings.c
@@ -0,0 +1,149 @@
+/* libguestfs
+ * Copyright (C) 2014 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Test backend settings API. */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "guestfs.h"
+#include "guestfs-internal-frontend.h"
+
+int
+main (int argc, char *argv[])
+{
+  guestfs_h *g;
+  char **strs;
+  char *str;
+  int r, pass;
+
+  /* Make sure that LIBGUESTFS_BACKEND_SETTINGS in the test
+   * environment doesn't affect the handle.
+   */
+  unsetenv ("LIBGUESTFS_BACKEND_SETTINGS");
+
+  g = guestfs_create ();
+  if (g == NULL) {
+    fprintf (stderr, "failed to create handle\n");
+    exit (EXIT_FAILURE);
+  }
+
+  /* There should be no backend settings initially. */
+  strs = guestfs_get_backend_settings (g);
+  assert (strs != NULL);
+  assert (strs[0] == NULL);
+  guestfs___free_string_list (strs);
+
+  guestfs_push_error_handler (g, NULL, NULL);
+  str = guestfs_get_backend_setting (g, "foo");
+  guestfs_pop_error_handler (g);
+  assert (str == NULL);
+  assert (guestfs_last_errno (g) == ESRCH);
+
+  r = guestfs_clear_backend_setting (g, "bar");
+  assert (r == 0);
+
+  /* Create some settings in the handle, either using
+   * guestfs_set_backend_settings or using the environment variable.
+   */
+  for (pass = 0; pass <= 1; ++pass) {
+    if (pass == 0) {
+      const char *initial_settings[] = {
+        "foo", "foo=1", "foo=bar", "bar", "baz=value", NULL
+      };
+      r = guestfs_set_backend_settings (g, (char **) initial_settings);
+      assert (r == 0);
+    }
+    else /* pass == 1 */ {
+      const char *initial_settings = "foo:foo=1:foo=bar:bar:baz=value";
+
+      guestfs_close (g);
+
+      setenv ("LIBGUESTFS_BACKEND_SETTINGS", initial_settings, 1);
+      g = guestfs_create ();
+      if (g == NULL) {
+        fprintf (stderr, "failed to create handle\n");
+        exit (EXIT_FAILURE);
+      }
+    }
+
+    /* Check the settings are correct. */
+    strs = guestfs_get_backend_settings (g);
+    assert (strs != NULL);
+    assert (STREQ (strs[0], "foo"));
+    assert (STREQ (strs[1], "foo=1"));
+    assert (STREQ (strs[2], "foo=bar"));
+    assert (STREQ (strs[3], "bar"));
+    assert (STREQ (strs[4], "baz=value"));
+    assert (strs[5] == NULL);
+    guestfs___free_string_list (strs);
+
+    str = guestfs_get_backend_setting (g, "bar");
+    assert (str != NULL);
+    assert (STREQ (str, "1"));
+    free (str);
+
+    str = guestfs_get_backend_setting (g, "baz");
+    assert (str != NULL);
+    assert (STREQ (str, "value"));
+    free (str);
+
+    str = guestfs_get_backend_setting (g, "foo");
+    assert (str != NULL);
+    /* An implementation could return any of the values. */
+    free (str);
+
+    guestfs_push_error_handler (g, NULL, NULL);
+    str = guestfs_get_backend_setting (g, "nothere");
+    guestfs_pop_error_handler (g);
+    assert (str == NULL);
+    assert (guestfs_last_errno (g) == ESRCH);
+
+    r = guestfs_set_backend_setting (g, "foo", "");
+    assert (r == 0);
+    r = guestfs_set_backend_setting (g, "foo", "1");
+    assert (r == 0);
+    r = guestfs_set_backend_setting (g, "foo", "2");
+    assert (r == 0);
+    r = guestfs_set_backend_setting (g, "foo", "3");
+    assert (r == 0);
+    r = guestfs_clear_backend_setting (g, "foo");
+    assert (r == 1);
+
+    r = guestfs_clear_backend_setting (g, "bar");
+    assert (r == 1);
+
+    r = guestfs_clear_backend_setting (g, "baz");
+    assert (r == 1);
+
+    strs = guestfs_get_backend_settings (g);
+    assert (strs != NULL);
+    assert (strs[0] == NULL);
+    guestfs___free_string_list (strs);
+  }
+
+  guestfs_close (g);
+
+  exit (EXIT_SUCCESS);
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-libvirt/libguestfs.git



More information about the Pkg-libvirt-commits mailing list