summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-10-15 11:14:59 +0100
committerRichard W.M. Jones <rjones@redhat.com>2012-10-15 15:04:43 +0100
commit9466060201600db47016133d80af22eb38091a49 (patch)
treed3784e6936c9c6a5e62190eaeb67e91d3a78506b /src
parent389cb608df19b80323214eefad464a7ebfb7f235 (diff)
downloadlibguestfs-9466060201600db47016133d80af22eb38091a49.tar.gz
libguestfs-9466060201600db47016133d80af22eb38091a49.tar.xz
libguestfs-9466060201600db47016133d80af22eb38091a49.zip
New APIs: guestfs_create_flags, guestfs_parse_environment,
guestfs_parse_environment_list. Add a new function for creating a handle: guestfs_h *guestfs_create_flags (unsigned flags [, ...]); This variant lets you supply flags and extra arguments, although extra arguments are not used at the moment. Of particular interest is the ability to separate the creation of the handle from the parsing of environment variables like LIBGUESTFS_DEBUG. guestfs_create does both together, which prevents us from propagating errors from parsing environment variables back to the caller (guestfs_create has always printed any errors on stderr and then just ignored them). If you are interested in these errors, you can now write: g = guestfs_create_flags (GUESTFS_CREATE_NO_ENVIRONMENT); if (!g) exit (EXIT_FAILURE); r = guestfs_parse_environment (g); if (!r) exit (EXIT_FAILURE); Also you can *omit* the call to guestfs_parse_environment, which creates a handle unaffected by the environment (which was not possible before). This commit also includes new (backwards compatible) changes to the OCaml, Perl, Python, Ruby and Java constructors that let you use the flags.
Diffstat (limited to 'src')
-rw-r--r--src/guestfs-internal.h1
-rw-r--r--src/guestfs.c190
-rw-r--r--src/guestfs.pod68
3 files changed, 187 insertions, 72 deletions
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index 80906133..90954f18 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -193,6 +193,7 @@ struct guestfs_h
bool enable_network; /* Enable the network. */
bool selinux; /* selinux enabled? */
bool pgroup; /* Create process group for children? */
+ bool close_on_exit; /* Is this handle on the atexit list? */
int smp; /* If > 1, -smp flag passed to qemu. */
int memsize; /* Size of RAM (megabytes). */
diff --git a/src/guestfs.c b/src/guestfs.c
index b026524c..cc645fd3 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -100,14 +100,17 @@ init_libguestfs (void)
guestfs_h *
guestfs_create (void)
{
+ return guestfs_create_flags (0);
+}
+
+guestfs_h *
+guestfs_create_flags (unsigned flags, ...)
+{
guestfs_h *g;
- const char *str;
- g = malloc (sizeof (*g));
+ g = calloc (1, sizeof (*g));
if (!g) return NULL;
- memset (g, 0, sizeof (*g));
-
g->state = CONFIG;
g->fd[0] = -1;
@@ -121,74 +124,45 @@ guestfs_create (void)
g->recovery_proc = 1;
g->autosync = 1;
- str = getenv ("LIBGUESTFS_DEBUG");
- g->verbose = str != NULL && STREQ (str, "1");
+ g->memsize = 500;
+
+ /* Start with large serial numbers so they are easy to spot
+ * inside the protocol.
+ */
+ g->msg_next_serial = 0x00123400;
- str = getenv ("LIBGUESTFS_TRACE");
- g->trace = str != NULL && STREQ (str, "1");
+ /* Default is uniprocessor appliance. */
+ g->smp = 1;
- str = getenv ("LIBGUESTFS_PATH");
- g->path = str != NULL ? strdup (str) : strdup (GUESTFS_DEFAULT_PATH);
+ g->path = strdup (GUESTFS_DEFAULT_PATH);
if (!g->path) goto error;
- str = getenv ("LIBGUESTFS_QEMU");
- g->qemu = str != NULL ? strdup (str) : strdup (QEMU);
+ g->qemu = strdup (QEMU);
if (!g->qemu) goto error;
- str = getenv ("LIBGUESTFS_APPEND");
- if (str) {
- g->append = strdup (str);
- if (!g->append) goto error;
- }
-
- /* Choose a suitable memory size. Previously we tried to choose
- * a minimal memory size, but this isn't really necessary since
- * recent QEMU and KVM don't do anything nasty like locking
- * memory into core any more. Thus we can safely choose a
- * large, generous amount of memory, and it'll just get swapped
- * on smaller systems.
- */
- str = getenv ("LIBGUESTFS_MEMSIZE");
- if (str) {
- if (sscanf (str, "%d", &g->memsize) != 1 || g->memsize < 128) {
- warning (g, "non-numeric or too small value for LIBGUESTFS_MEMSIZE");
- goto error;
- }
- } else
- g->memsize = 500;
-
- str = getenv ("LIBGUESTFS_ATTACH_METHOD");
- if (str) {
- if (parse_attach_method (g, str) == -1) {
- warning (g, _("invalid or unknown value for LIBGUESTFS_ATTACH_METHOD environment variable"));
- goto error;
- }
- } else {
- if (parse_attach_method (g, DEFAULT_ATTACH_METHOD) == -1) {
- warning (g, _("libguestfs was built with an invalid default attach-method, using 'appliance' instead"));
- g->attach_method = ATTACH_METHOD_APPLIANCE;
- }
+ if (parse_attach_method (g, DEFAULT_ATTACH_METHOD) == -1) {
+ warning (g, _("libguestfs was built with an invalid default attach-method, using 'appliance' instead"));
+ g->attach_method = ATTACH_METHOD_APPLIANCE;
}
- /* Start with large serial numbers so they are easy to spot
- * inside the protocol.
- */
- g->msg_next_serial = 0x00123400;
+ if (!(flags & GUESTFS_CREATE_NO_ENVIRONMENT))
+ guestfs_parse_environment (g);
- /* Default is uniprocessor appliance. */
- g->smp = 1;
+ if (!(flags & GUESTFS_CREATE_NO_CLOSE_ON_EXIT)) {
+ g->close_on_exit = true;
- /* Link the handles onto a global list. */
- gl_lock_lock (handles_lock);
- g->next = handles;
- handles = g;
- if (!atexit_handler_set) {
- atexit (close_handles);
- atexit_handler_set = 1;
+ /* Link the handles onto a global list. */
+ gl_lock_lock (handles_lock);
+ g->next = handles;
+ handles = g;
+ if (!atexit_handler_set) {
+ atexit (close_handles);
+ atexit_handler_set = 1;
+ }
+ gl_lock_unlock (handles_lock);
}
- gl_lock_unlock (handles_lock);
- debug (g, "new guestfs handle %p", g);
+ debug (g, "create: flags = %u, handle = %p", flags, g);
return g;
@@ -201,10 +175,92 @@ guestfs_create (void)
return NULL;
}
+static int
+parse_environment (guestfs_h *g,
+ char *(*do_getenv) (const void *data, const char *),
+ const void *data)
+{
+ int memsize;
+ char *str;
+
+ /* Don't bother checking the return values of functions
+ * that cannot return errors.
+ */
+
+ str = do_getenv (data, "LIBGUESTFS_DEBUG");
+ if (str != NULL && STREQ (str, "1"))
+ guestfs_set_verbose (g, 1);
+
+ str = do_getenv (data, "LIBGUESTFS_TRACE");
+ if (str != NULL && STREQ (str, "1"))
+ guestfs_set_trace (g, 1);
+
+ str = do_getenv (data, "LIBGUESTFS_PATH");
+ if (str)
+ guestfs_set_path (g, str);
+
+ str = do_getenv (data, "LIBGUESTFS_QEMU");
+ if (str)
+ guestfs_set_qemu (g, str);
+
+ str = do_getenv (data, "LIBGUESTFS_APPEND");
+ if (str)
+ guestfs_set_append (g, str);
+
+ str = do_getenv (data, "LIBGUESTFS_MEMSIZE");
+ if (str) {
+ if (sscanf (str, "%d", &memsize) != 1 || memsize < 128) {
+ error (g, "non-numeric or too small value for LIBGUESTFS_MEMSIZE");
+ return -1;
+ }
+ guestfs_set_memsize (g, memsize);
+ }
+
+ str = do_getenv (data, "LIBGUESTFS_ATTACH_METHOD");
+ if (str) {
+ if (guestfs_set_attach_method (g, str) == -1)
+ return -1;
+ }
+
+ return 0;
+}
+
+static char *
+call_getenv (const void *data, const char *name)
+{
+ return getenv (name);
+}
+
+int
+guestfs__parse_environment (guestfs_h *g)
+{
+ return parse_environment (g, call_getenv, NULL);
+}
+
+static char *
+getenv_from_strings (const void *stringsv, const char *name)
+{
+ char **strings = (char **) stringsv;
+ size_t len = strlen (name);
+ size_t i;
+
+ for (i = 0; strings[i] != NULL; ++i)
+ if (STRPREFIX (strings[i], name) && strings[i][len] == '=')
+ return (char *) &strings[i][len+1];
+ return NULL;
+}
+
+int
+guestfs__parse_environment_list (guestfs_h *g, char * const *strings)
+{
+ return parse_environment (g, getenv_from_strings, strings);
+}
+
void
guestfs_close (guestfs_h *g)
{
struct qemu_param *qp, *qp_next;
+ guestfs_h **gg;
if (g->state == NO_HANDLE) {
/* Not safe to call ANY callbacks here, so ... */
@@ -213,17 +269,13 @@ guestfs_close (guestfs_h *g)
}
/* Remove the handle from the handles list. */
- gl_lock_lock (handles_lock);
- if (handles == g)
- handles = g->next;
- else {
- guestfs_h *gg;
-
- for (gg = handles; gg->next != g; gg = gg->next)
+ if (g->close_on_exit) {
+ gl_lock_lock (handles_lock);
+ for (gg = &handles; *gg != g; gg = &(*gg)->next)
;
- gg->next = g->next;
+ *gg = g->next;
+ gl_lock_unlock (handles_lock);
}
- gl_lock_unlock (handles_lock);
if (g->trace) {
const char trace_msg[] = "close";
diff --git a/src/guestfs.pod b/src/guestfs.pod
index 7002f46e..74b1a81d 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -1628,8 +1628,9 @@ appropriate.
=head2 guestfs_h *
C<guestfs_h> is the opaque type representing a connection handle.
-Create a handle by calling L</guestfs_create>. Call L</guestfs_close>
-to free the handle and release all resources used.
+Create a handle by calling L</guestfs_create> or
+L</guestfs_create_flags>. Call L</guestfs_close> to free the handle
+and release all resources used.
For information on using multiple handles and threads, see the section
L</MULTIPLE HANDLES AND MULTIPLE THREADS> above.
@@ -1652,6 +1653,67 @@ After configuring the handle, you have to call L</guestfs_launch>.
You may also want to configure error handling for the handle. See the
L</ERROR HANDLING> section below.
+=head2 guestfs_create_flags
+
+ guestfs_h *guestfs_create_flags (unsigned flags [, ...]);
+
+Create a connection handle, supplying extra flags and
+extra arguments to control how the handle is created.
+
+On success this returns a non-NULL pointer to a handle. On error it
+returns NULL.
+
+L</guestfs_create> is equivalent to calling C<guestfs_create_flags(0)>.
+
+The following flags may be logically ORed together. (Currently
+no extra arguments are used).
+
+=over 4
+
+=item C<GUESTFS_CREATE_NO_ENVIRONMENT>
+
+Don't parse any environment variables (such as C<LIBGUESTFS_DEBUG> etc).
+
+You can call L</guestfs_parse_environment> or
+L</guestfs_parse_environment_list> afterwards to parse environment
+variables. Alternately, I<don't> call these functions if you want the
+handle to be unaffected by environment variables. See the example below.
+
+The default (if this flag is not given) is to implicitly call
+L</guestfs_parse_environment>.
+
+=item C<GUESTFS_CREATE_NO_CLOSE_ON_EXIT>
+
+Don't try to close the handle in an L<atexit(3)> handler if the
+program exits without explicitly closing the handle.
+
+The default (if this flag is not given) is to install such an atexit
+handler.
+
+=back
+
+=head3 USING C<GUESTFS_CREATE_NO_ENVIRONMENT>
+
+You might use C<GUESTFS_CREATE_NO_ENVIRONMENT> and
+an explicit call to L</guestfs_parse_environment> like this:
+
+ guestfs_h *g;
+ int r;
+
+ g = guestfs_create_flags (GUESTFS_CREATE_NO_ENVIRONMENT);
+ if (!g)
+ exit (EXIT_FAILURE);
+ r = guestfs_parse_environment (g);
+ if (!r)
+ exit (EXIT_FAILURE);
+
+Or to create a handle which is unaffected by environment variables,
+omit the call to C<guestfs_parse_environment> from the above code.
+
+The above code has another advantage which is that any errors from
+parsing the environment are passed through the error handler, whereas
+C<guestfs_create> prints errors on stderr and ignores them.
+
=head2 guestfs_close
void guestfs_close (guestfs_h *g);
@@ -2785,7 +2847,7 @@ since these usually results in massive disk corruption).
libguestfs uses a state machine to model the child process:
|
- guestfs_create
+ guestfs_create / guestfs_create_flags
|
|
____V_____