diff --git a/fish/guestfish.pod b/fish/guestfish.pod index 93e0d26c4..04d9aa969 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -1413,6 +1413,11 @@ This is the old way to set C. Choose the default way to create the appliance. See L. +=item LIBGUESTFS_BACKEND_SETTINGS + +A colon-separated list of backend-specific settings. +See L, L. + =item LIBGUESTFS_CACHEDIR The location where libguestfs will cache its appliance, when diff --git a/generator/actions.ml b/generator/actions.ml index b4b746f1e..508417b6f 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -3060,6 +3060,39 @@ If you set the data threshold to unlimited (C<0>) then this call 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 was set when the handle +was created. This environment variable contains a colon-separated +list of settings. + +See L, L." }; + + { 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, L." }; + ] (* daemon_functions are any functions which cause some action diff --git a/src/guestfs-internal-all.h b/src/guestfs-internal-all.h index 0e46b8457..23c3490fe 100644 --- a/src/guestfs-internal-all.h +++ b/src/guestfs-internal-all.h @@ -46,6 +46,7 @@ #define STRNEQLEN(a,b,n) (strncmp((a),(b),(n)) != 0) #define STRCASENEQLEN(a,b,n) (strncasecmp((a),(b),(n)) != 0) #define STRPREFIX(a,b) (strncmp((a),(b),strlen((b))) == 0) +#define STRCASEPREFIX(a,b) (strncasecmp((a),(b),strlen((b))) == 0) #define STRSUFFIX(a,b) (strlen((a)) >= strlen((b)) && STREQ((a)+strlen((a))-strlen((b)),(b))) #ifndef SOCK_CLOEXEC diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 61f41a1fb..3752f7982 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -407,6 +407,7 @@ struct guestfs_h char *backend_arg; /* Pointer to the argument part. */ const struct backend_ops *backend_ops; void *backend_data; /* Per-handle data. */ + char **backend_settings; /* Backend settings (can be NULL). */ /**** Runtime information. ****/ char *last_error; /* Last error on handle. */ @@ -724,6 +725,8 @@ 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/guestfs.pod b/src/guestfs.pod index cf3f80b03..2011faa5a 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -1483,6 +1483,13 @@ backend, do: unset LIBGUESTFS_BACKEND guestfish get-backend +=head2 BACKEND SETTINGS + +Each backend can be configured by passing a list of strings. You can +either call L with a list of strings, +or set the C environment variable to a +colon-separated list of strings (before creating the handle). + =head2 ATTACHING TO RUNNING DAEMONS I This is B and has a tendency to eat @@ -4613,6 +4620,11 @@ This is the old way to set C. Choose the default way to create the appliance. See L and L. +=item LIBGUESTFS_BACKEND_SETTINGS + +A colon-separated list of backend-specific settings. +See L, L. + =item LIBGUESTFS_CACHEDIR The location where libguestfs will cache its appliance, when diff --git a/src/handle.c b/src/handle.c index d1367bea7..687f0592c 100644 --- a/src/handle.c +++ b/src/handle.c @@ -245,6 +245,19 @@ parse_environment (guestfs_h *g, } } + str = do_getenv (data, "LIBGUESTFS_BACKEND_SETTINGS"); + if (str && STRNEQ (str, "")) { + CLEANUP_FREE_STRING_LIST char **settings = guestfs___split_string (':', str); + + if (settings == NULL) { + perrorf (g, "split_string: malloc"); + return -1; + } + + if (guestfs_set_backend_settings (g, settings) == -1) + return -1; + } + return 0; } @@ -673,6 +686,42 @@ guestfs__get_attach_method (guestfs_h *g) return guestfs_get_backend (g); } +int +guestfs__set_backend_settings (guestfs_h *g, char *const *settings) +{ + char **copy; + + copy = guestfs___copy_string_list (settings); + if (copy == NULL) { + perrorf (g, "copy: malloc"); + return -1; + } + + guestfs___free_string_list (g->backend_settings); + g->backend_settings = copy; + + return 0; +} + +char ** +guestfs__get_backend_settings (guestfs_h *g) +{ + char *empty_list[1] = { NULL }; + char **ret; + + if (g->backend_settings == NULL) + ret = guestfs___copy_string_list (empty_list); + else + ret = guestfs___copy_string_list (g->backend_settings); + + if (ret == NULL) { + perrorf (g, "copy: malloc"); + return NULL; + } + + return ret; /* caller frees */ +} + int guestfs__set_pgroup (guestfs_h *g, int v) { diff --git a/src/launch.c b/src/launch.c index cdc4a421c..72ff88249 100644 --- a/src/launch.c +++ b/src/launch.c @@ -481,3 +481,51 @@ 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/test-tool/test-tool.c b/test-tool/test-tool.c index 3a35226c4..45c0980e6 100644 --- a/test-tool/test-tool.c +++ b/test-tool/test-tool.c @@ -90,6 +90,7 @@ main (int argc, char *argv[]) size_t i; struct guestfs_version *vers; char *p; + char **pp; guestfs_h *g; char *qemu = NULL; int qemu_use_wrapper; @@ -230,6 +231,16 @@ main (int argc, char *argv[]) p = guestfs_get_backend (g); printf ("guestfs_get_backend: %s\n", p ? : "(null)"); free (p); + pp = guestfs_get_backend_settings (g); + printf ("guestfs_get_backend_settings: ["); + for (i = 0; pp[i] != NULL; ++i) { + if (i > 0) + printf (", "); + printf ("%s", pp[i]); + free (pp[i]); + } + printf ("]\n"); + free (pp); printf ("guestfs_get_autosync: %d\n", guestfs_get_autosync (g)); p = guestfs_get_cachedir (g); printf ("guestfs_get_cachedir: %s\n", p ? : "(null)");