summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--generator/actions.ml33
-rw-r--r--generator/c.ml4
-rw-r--r--generator/java.ml34
-rw-r--r--generator/ocaml.ml19
-rw-r--r--generator/perl.ml27
-rw-r--r--generator/python.ml7
-rw-r--r--generator/ruby.ml23
-rw-r--r--ocaml/guestfs-c.c17
-rw-r--r--python/guestfs-py-byhand.c5
-rw-r--r--src/guestfs-internal.h1
-rw-r--r--src/guestfs.c190
-rw-r--r--src/guestfs.pod68
12 files changed, 327 insertions, 101 deletions
diff --git a/generator/actions.ml b/generator/actions.ml
index ac8e354a..dc712349 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -2480,6 +2480,39 @@ call this function to pass the answer back to libvirt.
See L<guestfs(3)/LIBVIRT AUTHENTICATION> for documentation and example code." };
+ { defaults with
+ name = "parse_environment";
+ style = RErr, [], [];
+ tests = [];
+ shortdesc = "parse the environment and set handle flags accordingly";
+ longdesc = "\
+Parse the program's environment and set flags in the handle
+accordingly. For example if C<LIBGUESTFS_DEBUG=1> then the
+'verbose' flag is set in the handle.
+
+I<Most programs do not need to call this>. It is done implicitly
+when you call C<guestfs_create>.
+
+See L<guestfs(3)/ENVIRONMENT VARIABLES> for a list of environment
+variables that can affect libguestfs handles. See also
+L<guestfs(3)/guestfs_create_flags>, and
+C<guestfs_parse_environment_list>." };
+
+ { defaults with
+ name = "parse_environment_list";
+ style = RErr, [StringList "environment"], [];
+ tests = [];
+ shortdesc = "parse the environment and set handle flags accordingly";
+ longdesc = "\
+Parse the list of strings in the argument C<environment>
+and set flags in the handle accordingly.
+For example if C<LIBGUESTFS_DEBUG=1> is a string in the list,
+then the 'verbose' flag is set in the handle.
+
+This is the same as C<guestfs_parse_environment> except that
+it parses an explicit list of strings instead of the program's
+environment." };
+
]
(* daemon_functions are any functions which cause some action
diff --git a/generator/c.ml b/generator/c.ml
index e159d8fa..ac8fd5ee 100644
--- a/generator/c.ml
+++ b/generator/c.ml
@@ -416,6 +416,9 @@ typedef struct guestfs_h guestfs_h;
/* Connection management. */
extern GUESTFS_DLL_PUBLIC guestfs_h *guestfs_create (void);
+extern GUESTFS_DLL_PUBLIC guestfs_h *guestfs_create_flags (unsigned flags, ...);
+#define GUESTFS_CREATE_NO_ENVIRONMENT (1 << 0)
+#define GUESTFS_CREATE_NO_CLOSE_ON_EXIT (1 << 1)
extern GUESTFS_DLL_PUBLIC void guestfs_close (guestfs_h *g);
/* Error handling. */
@@ -1586,6 +1589,7 @@ and generate_linker_script () =
let globals = [
"guestfs_create";
+ "guestfs_create_flags";
"guestfs_close";
"guestfs_delete_event_callback";
"guestfs_first_private";
diff --git a/generator/java.ml b/generator/java.ml
index f3b9f5f3..1e06c62d 100644
--- a/generator/java.ml
+++ b/generator/java.ml
@@ -56,15 +56,39 @@ public class GuestFS {
long g;
/**
+ * Create a libguestfs handle, setting flags.
+ *
+ * @throws LibGuestFSException
+ */
+ public GuestFS (Map<String, Object> optargs) throws LibGuestFSException
+ {
+ int flags = 0;
+
+ /* Unpack optional args. */
+ Object _optobj;
+ _optobj = null;
+ if (optargs != null)
+ _optobj = optargs.get (\"environment\");
+ if (_optobj != null && !((Boolean) _optobj).booleanValue())
+ flags |= 1;
+ if (optargs != null)
+ _optobj = optargs.get (\"close_on_exit\");
+ if (_optobj != null && !((Boolean) _optobj).booleanValue())
+ flags |= 2;
+
+ g = _create (flags);
+ }
+
+ /**
* Create a libguestfs handle.
*
* @throws LibGuestFSException
*/
public GuestFS () throws LibGuestFSException
{
- g = _create ();
+ g = _create (0);
}
- private native long _create () throws LibGuestFSException;
+ private native long _create (int flags) throws LibGuestFSException;
/**
* Close a libguestfs handle.
@@ -409,12 +433,12 @@ throw_exception (JNIEnv *env, const char *msg)
}
JNIEXPORT jlong JNICALL
-Java_com_redhat_et_libguestfs_GuestFS__1create
- (JNIEnv *env, jobject obj)
+Java_com_redhat_et_libguestfs_GuestFS__1create (JNIEnv *env,
+ jobject obj_unused, jint flags)
{
guestfs_h *g;
- g = guestfs_create ();
+ g = guestfs_create_flags ((int) flags);
if (g == NULL) {
throw_exception (env, \"GuestFS.create: failed to allocate handle\");
return 0;
diff --git a/generator/ocaml.ml b/generator/ocaml.ml
index b04eb5fe..84210490 100644
--- a/generator/ocaml.ml
+++ b/generator/ocaml.ml
@@ -62,8 +62,14 @@ exception Handle_closed of string
after calling {!close} on it. The string is the name of
the function. *)
-val create : unit -> t
-(** Create a {!t} handle. *)
+val create : ?environment:bool -> ?close_on_exit:bool -> unit -> t
+(** Create a {!t} handle.
+
+ [?environment] defaults to [true]. If set to false, it sets
+ the [GUESTFS_CREATE_NO_ENVIRONMENT] flag.
+
+ [?close_on_exit] defaults to [true]. If set to false, it sets
+ the [GUESTFS_CREATE_NO_CLOSE_ON_EXIT] flag. *)
val close : t -> unit
(** Close the {!t} handle and free up all resources used
@@ -171,7 +177,7 @@ val user_cancel : t -> unit
For example [g#]{{!guestfs.get_verbose}get_verbose} [()]
calls the method, whereas [g#get_verbose] is a function. *)
-class guestfs : unit -> object
+class guestfs : ?environment:bool -> ?close_on_exit:bool -> unit -> object
method close : unit -> unit
method set_event_callback : event_callback -> event list -> event_handle
method delete_event_callback : event_handle -> unit
@@ -211,7 +217,8 @@ type t
exception Error of string
exception Handle_closed of string
-external create : unit -> t = \"ocaml_guestfs_create\"
+external create : ?environment:bool -> ?close_on_exit:bool -> unit -> t =
+ \"ocaml_guestfs_create\"
external close : t -> unit = \"ocaml_guestfs_close\"
type event =
@@ -265,8 +272,8 @@ let () =
(* OO API. *)
pr "
-class guestfs () =
- let g = create () in
+class guestfs ?environment ?close_on_exit () =
+ let g = create ?environment ?close_on_exit () in
object (self)
method close () = close g
method set_event_callback = set_event_callback g
diff --git a/generator/perl.ml b/generator/perl.ml
index 0bd36a15..7e78ca75 100644
--- a/generator/perl.ml
+++ b/generator/perl.ml
@@ -211,9 +211,10 @@ MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs
PROTOTYPES: ENABLE
guestfs_h *
-_create ()
+_create (flags)
+ unsigned flags;
CODE:
- RETVAL = guestfs_create ();
+ RETVAL = guestfs_create_flags (flags);
if (!RETVAL)
croak (\"could not create guestfs handle\");
guestfs_set_error_handler (RETVAL, NULL, NULL);
@@ -713,18 +714,29 @@ XSLoader::load ('Sys::Guestfs');
(* Methods. *)
pr "\
-=item $g = Sys::Guestfs->new ();
+=item $g = Sys::Guestfs->new ([environment => 0,] [close_on_exit => 0]);
Create a new guestfs handle.
+If the optional argument C<environment> is false, then
+the C<GUESTFS_CREATE_NO_ENVIRONMENT> flag is set.
+
+If the optional argument C<close_on_exit> is false, then
+the C<GUESTFS_CREATE_NO_CLOSE_ON_EXIT> flag is set.
+
=cut
sub new {
my $proto = shift;
my $class = ref ($proto) || $proto;
+ my %%flags = @_;
+
+ my $flags = 0;
+ $flags |= 1 if exists $flags{environment} && !$flags{environment};
+ $flags |= 2 if exists $flags{close_on_exit} && !$flags{close_on_exit};
- my $g = Sys::Guestfs::_create ();
- my $self = { _g => $g };
+ my $g = Sys::Guestfs::_create ($flags);
+ my $self = { _g => $g, _flags => $flags };
bless $self, $class;
return $self;
}
@@ -1013,10 +1025,11 @@ L<guestfs(3)/AVAILABILITY>.
=head1 STORING DATA IN THE HANDLE
The handle returned from L</new> is a hash reference. The hash
-normally contains a single element:
+normally contains some elements:
{
- _g => [private data used by libguestfs]
+ _g => [private data used by libguestfs],
+ _flags => [flags provided when creating the handle]
}
Callers can add other elements to this hash to store data for their own
diff --git a/generator/python.ml b/generator/python.ml
index b4bc3cee..aa1ce8e9 100644
--- a/generator/python.ml
+++ b/generator/python.ml
@@ -645,9 +645,12 @@ class ClosedHandle(ValueError):
class GuestFS:
\"\"\"Instances of this class are libguestfs API handles.\"\"\"
- def __init__ (self):
+ def __init__ (self, environment=True, close_on_exit=True):
\"\"\"Create a new libguestfs handle.\"\"\"
- self._o = libguestfsmod.create ()
+ flags = 0
+ if not environment: flags |= 1
+ if not close_on_exit: flags |= 2
+ self._o = libguestfsmod.create (flags)
def __del__ (self):
if self._o:
diff --git a/generator/ruby.ml b/generator/ruby.ml
index f3b8912d..6cc17fc2 100644
--- a/generator/ruby.ml
+++ b/generator/ruby.ml
@@ -126,7 +126,7 @@ ruby_guestfs_free (void *gvp)
/*
* call-seq:
- * Guestfs::Guestfs.new() -> Guestfs::Guestfs
+ * Guestfs::Guestfs.new([{:environment => false, :close_on_exit => false}]) -> Guestfs::Guestfs
*
* Call
* +guestfs_create+[http://libguestfs.org/guestfs.3.html#guestfs_create]
@@ -134,11 +134,26 @@ ruby_guestfs_free (void *gvp)
* Ruby as an instance of the Guestfs::Guestfs class.
*/
static VALUE
-ruby_guestfs_create (VALUE m)
+ruby_guestfs_create (int argc, VALUE *argv, VALUE m)
{
guestfs_h *g;
- g = guestfs_create ();
+ if (argc > 1)
+ rb_raise (rb_eArgError, \"expecting 0 or 1 arguments\");
+
+ volatile VALUE optargsv = argc == 1 ? argv[0] : rb_hash_new ();
+ Check_Type (optargsv, T_HASH);
+
+ unsigned flags = 0;
+ volatile VALUE v;
+ v = rb_hash_lookup (optargsv, ID2SYM (rb_intern (\"environment\")));
+ if (v != Qnil && !RTEST (v))
+ flags |= GUESTFS_CREATE_NO_ENVIRONMENT;
+ v = rb_hash_lookup (optargsv, ID2SYM (rb_intern (\"close_on_exit\")));
+ if (v != Qnil && !RTEST (v))
+ flags |= GUESTFS_CREATE_NO_CLOSE_ON_EXIT;
+
+ g = guestfs_create_flags (flags);
if (!g)
rb_raise (e_Error, \"failed to create guestfs handle\");
@@ -663,7 +678,7 @@ void Init__guestfs ()
rb_define_alloc_func (c_guestfs, ruby_guestfs_create);
#endif
- rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, 0);
+ rb_define_module_function (m_guestfs, \"create\", ruby_guestfs_create, -1);
rb_define_method (c_guestfs, \"close\", ruby_guestfs_close, 0);
rb_define_method (c_guestfs, \"set_event_callback\",
ruby_set_event_callback, 2);
diff --git a/ocaml/guestfs-c.c b/ocaml/guestfs-c.c
index 469110dc..265698f9 100644
--- a/ocaml/guestfs-c.c
+++ b/ocaml/guestfs-c.c
@@ -48,7 +48,7 @@ static void event_callback_wrapper (guestfs_h *g, void *data, uint64_t event, in
#endif
/* These prototypes are solely to quiet gcc warning. */
-CAMLprim value ocaml_guestfs_create (value unitv);
+CAMLprim value ocaml_guestfs_create (value environmentv, value close_on_exitv, value unitv);
CAMLprim value ocaml_guestfs_close (value gv);
CAMLprim value ocaml_guestfs_set_event_callback (value gv, value closure, value events);
CAMLprim value ocaml_guestfs_delete_event_callback (value gv, value eh);
@@ -141,14 +141,23 @@ ocaml_guestfs_raise_closed (const char *func)
/* Guestfs.create */
CAMLprim value
-ocaml_guestfs_create (value unitv)
+ocaml_guestfs_create (value environmentv, value close_on_exitv, value unitv)
{
- CAMLparam1 (unitv);
+ CAMLparam3 (environmentv, close_on_exitv, unitv);
CAMLlocal1 (gv);
+ unsigned flags = 0;
guestfs_h *g;
value *v;
- g = guestfs_create ();
+ if (environmentv != Val_int (0) &&
+ !Bool_val (Field (environmentv, 0)))
+ flags |= GUESTFS_CREATE_NO_ENVIRONMENT;
+
+ if (close_on_exitv != Val_int (0) &&
+ !Bool_val (Field (close_on_exitv, 0)))
+ flags |= GUESTFS_CREATE_NO_CLOSE_ON_EXIT;
+
+ g = guestfs_create_flags (flags);
if (g == NULL)
caml_failwith ("failed to create guestfs handle");
diff --git a/python/guestfs-py-byhand.c b/python/guestfs-py-byhand.c
index eea10ca0..6cbbf506 100644
--- a/python/guestfs-py-byhand.c
+++ b/python/guestfs-py-byhand.c
@@ -34,8 +34,11 @@ PyObject *
py_guestfs_create (PyObject *self, PyObject *args)
{
guestfs_h *g;
+ unsigned flags;
- g = guestfs_create ();
+ if (!PyArg_ParseTuple (args, (char *) "I:guestfs_create", &flags))
+ return NULL;
+ g = guestfs_create_flags (flags);
if (g == NULL) {
PyErr_SetString (PyExc_RuntimeError,
"guestfs.create: failed to allocate handle");
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_____