summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/appliance.c35
-rw-r--r--src/filearch.c4
-rw-r--r--src/guestfs-internal.h27
-rw-r--r--src/guestfs.c19
-rw-r--r--src/guestfs.pod32
-rw-r--r--src/launch-libvirt.c13
-rw-r--r--src/launch.c75
-rw-r--r--src/tmpdirs.c119
9 files changed, 208 insertions, 117 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index d3755beb..7b7f6065 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -165,6 +165,7 @@ libguestfs_la_SOURCES = \
listfs.c \
match.c \
proto.c \
+ tmpdirs.c \
libguestfs.syms
libguestfs_la_LIBADD = \
diff --git a/src/appliance.c b/src/appliance.c
index 2241e181..8a22064b 100644
--- a/src/appliance.c
+++ b/src/appliance.c
@@ -354,7 +354,7 @@ check_for_cached_appliance (guestfs_h *g,
uid_t uid,
char **kernel, char **initrd, char **appliance)
{
- const char *tmpdir = guestfs___persistent_tmpdir ();
+ char *tmpdir = guestfs_get_cachedir (g);
/* len must be longer than the length of any pathname we can
* generate in this function.
@@ -365,6 +365,8 @@ check_for_cached_appliance (guestfs_h *g,
char filename[len];
snprintf (filename, len, "%s/checksum", cachedir);
+ free (tmpdir);
+
(void) mkdir (cachedir, 0755);
/* See if the cache directory exists and passes some simple checks
@@ -472,15 +474,18 @@ build_supermin_appliance (guestfs_h *g,
uid_t uid,
char **kernel, char **initrd, char **appliance)
{
+ char *tmpdir;
+ size_t len;
+
if (g->verbose)
guestfs___print_timestamped_message (g, "begin building supermin appliance");
- const char *tmpdir = guestfs___persistent_tmpdir ();
+ tmpdir = guestfs_get_cachedir (g);
/* len must be longer than the length of any pathname we can
* generate in this function.
*/
- size_t len = strlen (tmpdir) + 128;
+ len = strlen (tmpdir) + 128;
/* Build the appliance into a temporary directory. */
char tmpcd[len];
@@ -488,6 +493,7 @@ build_supermin_appliance (guestfs_h *g,
if (mkdtemp (tmpcd) == NULL) {
perrorf (g, "mkdtemp");
+ free (tmpdir);
return -1;
}
@@ -496,7 +502,8 @@ build_supermin_appliance (guestfs_h *g,
int r = run_supermin_helper (g, supermin_path, tmpcd);
if (r == -1) {
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
+ free (tmpdir);
return -1;
}
@@ -509,13 +516,15 @@ build_supermin_appliance (guestfs_h *g,
char filename2[len];
snprintf (filename, len, "%s/checksum", cachedir);
+ free (tmpdir);
+
/* Open and acquire write lock on checksum file. The file might
* not exist, in which case we want to create it.
*/
int fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_CLOEXEC, 0755);
if (fd == -1) {
perrorf (g, "open: %s", filename);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
struct flock fl;
@@ -529,7 +538,7 @@ build_supermin_appliance (guestfs_h *g,
goto again;
perrorf (g, "fcntl: F_SETLKW: %s", filename);
close (fd);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
@@ -541,7 +550,7 @@ build_supermin_appliance (guestfs_h *g,
if (ftruncate (fd, clen) == -1) {
perrorf (g, "ftruncate: %s", filename);
close (fd);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
@@ -549,13 +558,13 @@ build_supermin_appliance (guestfs_h *g,
if (rr == -1) {
perrorf (g, "write: %s", filename);
close (fd);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
if ((size_t) rr != clen) {
error (g, "partial write: %s", filename);
close (fd);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
@@ -565,7 +574,7 @@ build_supermin_appliance (guestfs_h *g,
if (rename (filename, filename2) == -1) {
perrorf (g, "rename: %s %s", filename, filename2);
close (fd);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
@@ -575,7 +584,7 @@ build_supermin_appliance (guestfs_h *g,
if (rename (filename, filename2) == -1) {
perrorf (g, "rename: %s %s", filename, filename2);
close (fd);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
@@ -585,11 +594,11 @@ build_supermin_appliance (guestfs_h *g,
if (rename (filename, filename2) == -1) {
perrorf (g, "rename: %s %s", filename, filename2);
close (fd);
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
return -1;
}
- guestfs___remove_tmpdir (g, tmpcd);
+ guestfs___recursive_remove_dir (g, tmpcd);
/* Now finish off by linking to the cached appliance and returning it. */
if (hard_link_to_cached_appliance (g, cachedir,
diff --git a/src/filearch.c b/src/filearch.c
index 93a697f5..1ad6af68 100644
--- a/src/filearch.c
+++ b/src/filearch.c
@@ -127,7 +127,7 @@ is_regular_file (const char *filename)
static char *
cpio_arch (guestfs_h *g, const char *file, const char *path)
{
- TMP_TEMPLATE_ON_STACK (dir);
+ TMP_TEMPLATE_ON_STACK (g, dir);
#define dir_len (strlen (dir))
#define initrd_len (dir_len + 16)
char initrd[initrd_len];
@@ -221,7 +221,7 @@ cpio_arch (guestfs_h *g, const char *file, const char *path)
if (cmd)
guestfs___cmd_close (cmd);
- guestfs___remove_tmpdir (g, dir);
+ guestfs___recursive_remove_dir (g, dir);
return ret;
#undef dir_len
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index aed4182c..17903d30 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -71,10 +71,11 @@
#define TRACE4(name, arg1, arg2, arg3, arg4)
#endif
-#define TMP_TEMPLATE_ON_STACK(var) \
- const char *ttos_tmpdir = guestfs_tmpdir (); \
+#define TMP_TEMPLATE_ON_STACK(g,var) \
+ char *ttos_tmpdir = guestfs_get_tmpdir (g); \
char var[strlen (ttos_tmpdir) + 32]; \
- sprintf (var, "%s/libguestfsXXXXXX", ttos_tmpdir) \
+ sprintf (var, "%s/libguestfsXXXXXX", ttos_tmpdir); \
+ free (ttos_tmpdir)
#ifdef __APPLE__
#define UNIX_PATH_MAX 104
@@ -234,11 +235,19 @@ struct guestfs_h
const struct attach_ops *attach_ops;
/**** Runtime information. ****/
- char *tmpdir; /* Temporary directory containing socket. */
-
char *last_error; /* Last error on handle. */
int last_errnum; /* errno, or 0 if there was no errno */
+ /* Temporary and cache directories. */
+ /* The actual temporary directory - this is not created with the
+ * handle, you have to call guestfs___lazy_make_tmpdir.
+ */
+ char *tmpdir;
+ /* Environment variables that affect tmpdir/cachedir locations. */
+ char *env_tmpdir; /* $TMPDIR (NULL if not set) */
+ char *int_tmpdir; /* $LIBGUESTFS_TMPDIR or guestfs_set_tmpdir or NULL */
+ char *int_cachedir; /* $LIBGUESTFS_CACHEDIR or guestfs_set_cachedir or NULL */
+
/* Callbacks. */
guestfs_abort_cb abort_cb;
guestfs_error_handler_cb error_cb;
@@ -526,13 +535,15 @@ extern void guestfs___call_callbacks_void (guestfs_h *g, uint64_t event);
extern void guestfs___call_callbacks_message (guestfs_h *g, uint64_t event, const char *buf, size_t buf_len);
extern void guestfs___call_callbacks_array (guestfs_h *g, uint64_t event, const uint64_t *array, size_t array_len);
+/* tmpdirs.c */
+extern int guestfs___lazy_make_tmpdir (guestfs_h *g);
+extern void guestfs___remove_tmpdir (guestfs_h *g);
+extern void guestfs___recursive_remove_dir (guestfs_h *g, const char *dir);
+
/* appliance.c */
extern int guestfs___build_appliance (guestfs_h *g, char **kernel, char **initrd, char **appliance);
/* launch.c */
-extern const char *guestfs___persistent_tmpdir (void);
-extern int guestfs___lazy_make_tmpdir (guestfs_h *g);
-extern void guestfs___remove_tmpdir (guestfs_h *g, const char *dir);
extern int64_t guestfs___timeval_diff (const struct timeval *x, const struct timeval *y);
extern void guestfs___print_timestamped_message (guestfs_h *g, const char *fs, ...);
extern void guestfs___launch_send_progress (guestfs_h *g, int perdozen);
diff --git a/src/guestfs.c b/src/guestfs.c
index 5428b28a..4a1ee930 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -195,6 +195,18 @@ parse_environment (guestfs_h *g,
if (str != NULL && STREQ (str, "1"))
guestfs_set_verbose (g, 1);
+ str = do_getenv (data, "LIBGUESTFS_TMPDIR");
+ if (str)
+ guestfs_set_tmpdir (g, str);
+
+ str = do_getenv (data, "LIBGUESTFS_CACHEDIR");
+ if (str)
+ guestfs_set_cachedir (g, str);
+
+ free (g->env_tmpdir);
+ str = do_getenv (data, "TMPDIR");
+ g->env_tmpdir = str ? safe_strdup (g, str) : NULL;
+
str = do_getenv (data, "LIBGUESTFS_PATH");
if (str)
guestfs_set_path (g, str);
@@ -300,14 +312,13 @@ guestfs_close (guestfs_h *g)
/* Run user close callbacks. */
guestfs___call_callbacks_void (g, GUESTFS_EVENT_CLOSE);
- /* Remove whole temporary directory. */
- if (g->tmpdir)
- guestfs___remove_tmpdir (g, g->tmpdir);
-
/* Test output file used by bindtests. */
if (g->test_fp != NULL)
fclose (g->test_fp);
+ /* Remove temporary directory. */
+ guestfs___remove_tmpdir (g);
+
/* Mark the handle as dead and then free up all memory. */
g->state = NO_HANDLE;
diff --git a/src/guestfs.pod b/src/guestfs.pod
index f243c2c4..bac81d86 100644
--- a/src/guestfs.pod
+++ b/src/guestfs.pod
@@ -2934,7 +2934,7 @@ C<febootstrap-supermin-helper> is invoked to create the kernel, a
small initrd and the appliance.
The appliance is cached in C</var/tmp/.guestfs-E<lt>UIDE<gt>> (or in
-another directory if C<TMPDIR> is set).
+another directory if C<LIBGUESTFS_CACHEDIR> or C<TMPDIR> are set).
For a complete description of how the appliance is created and cached,
read the L<febootstrap(8)> and L<febootstrap-supermin-helper(8)> man
@@ -3890,6 +3890,17 @@ Pass additional options to the guest kernel.
Choose the default way to create the appliance. See
L</guestfs_set_attach_method>.
+=item LIBGUESTFS_CACHEDIR
+
+The location where libguestfs will cache its appliance, when
+using a supermin appliance. The appliance is cached and shared
+between all handles which have the same effective user ID.
+
+If C<LIBGUESTFS_CACHEDIR> is not set, then C<TMPDIR> is used. If
+C<TMPDIR> is not set, then C</var/tmp> is used.
+
+See also L</LIBGUESTFS_TMPDIR>, L</guestfs_set_cachedir>.
+
=item LIBGUESTFS_DEBUG
Set C<LIBGUESTFS_DEBUG=1> to enable verbose messages. This
@@ -3915,6 +3926,16 @@ used.
See also L</QEMU WRAPPERS> above.
+=item LIBGUESTFS_TMPDIR
+
+The location where libguestfs will store temporary files used
+by each handle.
+
+If C<LIBGUESTFS_TMPDIR> is not set, then C<TMPDIR> is used. If
+C<TMPDIR> is not set, then C</tmp> is used.
+
+See also L</LIBGUESTFS_CACHEDIR>, L</guestfs_set_tmpdir>.
+
=item LIBGUESTFS_TRACE
Set C<LIBGUESTFS_TRACE=1> to enable command traces. This
@@ -3922,14 +3943,7 @@ has the same effect as calling C<guestfs_set_trace (g, 1)>.
=item TMPDIR
-Location of temporary directory, defaults to C</tmp> except for the
-cached supermin appliance which defaults to C</var/tmp>.
-
-If libguestfs was compiled to use the supermin appliance then the
-real appliance is cached in this directory, shared between all
-handles belonging to the same EUID. You can use C<$TMPDIR> to
-configure another directory to use in case C</var/tmp> is not large
-enough.
+See L</LIBGUESTFS_CACHEDIR>, L</LIBGUESTFS_TMPDIR>.
=back
diff --git a/src/launch-libvirt.c b/src/launch-libvirt.c
index c243fcbb..e4df2a6b 100644
--- a/src/launch-libvirt.c
+++ b/src/launch-libvirt.c
@@ -1043,16 +1043,15 @@ static int
construct_libvirt_xml_qemu_cmdline (guestfs_h *g, xmlTextWriterPtr xo)
{
struct qemu_param *qp;
- const char *tmpdir;
+ char *tmpdir;
XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "qemu:commandline"));
- /* We need to ensure the snapshots are created in $TMPDIR (RHBZ#856619).
- * If TMPDIR is not set, we must choose one, because otherwise libvirt
- * will use a random TMPDIR (RHBZ#865464). Luckily the
- * guestfs___persistent_tmpdir function does both of these tasks.
+ /* We need to ensure the snapshots are created in the persistent
+ * temporary directory (RHBZ#856619). We must set one, because
+ * otherwise libvirt will use a random TMPDIR (RHBZ#865464).
*/
- tmpdir = guestfs___persistent_tmpdir ();
+ tmpdir = guestfs_get_cachedir (g);
XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "qemu:env"));
XMLERROR (-1,
@@ -1063,6 +1062,8 @@ construct_libvirt_xml_qemu_cmdline (guestfs_h *g, xmlTextWriterPtr xo)
BAD_CAST tmpdir));
XMLERROR (-1, xmlTextWriterEndElement (xo));
+ free (tmpdir);
+
/* Workaround because libvirt user networking cannot specify "net="
* parameter.
*/
diff --git a/src/launch.c b/src/launch.c
index 46817073..d2c1a42a 100644
--- a/src/launch.c
+++ b/src/launch.c
@@ -701,81 +701,6 @@ guestfs___launch_failed_error (guestfs_h *g)
"and/or run 'libguestfs-test-tool'."));
}
-/* Return the location of the tmpdir (eg. "/tmp") and allow users
- * to override it at runtime using $TMPDIR.
- * http://www.pathname.com/fhs/pub/fhs-2.3.html#TMPTEMPORARYFILES
- */
-const char *
-guestfs_tmpdir (void)
-{
- const char *tmpdir;
-
-#ifdef P_tmpdir
- tmpdir = P_tmpdir;
-#else
- tmpdir = "/tmp";
-#endif
-
- const char *t = getenv ("TMPDIR");
- if (t) tmpdir = t;
-
- return tmpdir;
-}
-
-/* Return the location of the persistent tmpdir (eg. "/var/tmp") and
- * allow users to override it at runtime using $TMPDIR.
- * http://www.pathname.com/fhs/pub/fhs-2.3.html#VARTMPTEMPORARYFILESPRESERVEDBETWEE
- */
-const char *
-guestfs___persistent_tmpdir (void)
-{
- const char *tmpdir;
-
- tmpdir = "/var/tmp";
-
- const char *t = getenv ("TMPDIR");
- if (t) tmpdir = t;
-
- return tmpdir;
-}
-
-/* The g->tmpdir (per-handle temporary directory) is not created when
- * the handle is created. Instead we create it lazily before the
- * first time it is used, or during launch.
- */
-int
-guestfs___lazy_make_tmpdir (guestfs_h *g)
-{
- if (!g->tmpdir) {
- TMP_TEMPLATE_ON_STACK (dir_template);
- g->tmpdir = safe_strdup (g, dir_template);
- if (mkdtemp (g->tmpdir) == NULL) {
- perrorf (g, _("%s: cannot create temporary directory"), dir_template);
- return -1;
- }
- }
- return 0;
-}
-
-/* Recursively remove a temporary directory. If removal fails, just
- * return (it's a temporary directory so it'll eventually be cleaned
- * up by a temp cleaner). This is done using "rm -rf" because that's
- * simpler and safer.
- */
-void
-guestfs___remove_tmpdir (guestfs_h *g, const char *dir)
-{
- struct command *cmd;
-
- cmd = guestfs___new_command (g);
- guestfs___cmd_add_arg (cmd, "rm");
- guestfs___cmd_add_arg (cmd, "-rf");
- guestfs___cmd_add_arg (cmd, dir);
- /* Ignore failures. */
- guestfs___cmd_run (cmd);
- guestfs___cmd_close (cmd);
-}
-
int
guestfs__get_pid (guestfs_h *g)
{
diff --git a/src/tmpdirs.c b/src/tmpdirs.c
new file mode 100644
index 00000000..b7167a9d
--- /dev/null
+++ b/src/tmpdirs.c
@@ -0,0 +1,119 @@
+/* libguestfs
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "guestfs.h"
+#include "guestfs-internal.h"
+#include "guestfs-internal-actions.h"
+
+int
+guestfs__set_tmpdir (guestfs_h *g, const char *tmpdir)
+{
+ free (g->int_tmpdir);
+ g->int_tmpdir = tmpdir ? safe_strdup (g, tmpdir) : NULL;
+ return 0;
+}
+
+/* Note this actually calculates the tmpdir, so it never returns NULL. */
+char *
+guestfs__get_tmpdir (guestfs_h *g)
+{
+ const char *str;
+
+ if (g->int_tmpdir)
+ str = g->int_tmpdir;
+ else if (g->env_tmpdir)
+ str = g->env_tmpdir;
+ else
+ str = "/tmp";
+
+ return safe_strdup (g, str);
+}
+
+int
+guestfs__set_cachedir (guestfs_h *g, const char *cachedir)
+{
+ free (g->int_cachedir);
+ g->int_cachedir = cachedir ? safe_strdup (g, cachedir) : NULL;
+ return 0;
+}
+
+/* Note this actually calculates the cachedir, so it never returns NULL. */
+char *
+guestfs__get_cachedir (guestfs_h *g)
+{
+ const char *str;
+
+ if (g->int_cachedir)
+ str = g->int_cachedir;
+ else if (g->env_tmpdir)
+ str = g->env_tmpdir;
+ else
+ str = "/var/tmp";
+
+ return safe_strdup (g, str);
+}
+
+/* The g->tmpdir (per-handle temporary directory) is not created when
+ * the handle is created. Instead we create it lazily before the
+ * first time it is used, or during launch.
+ */
+int
+guestfs___lazy_make_tmpdir (guestfs_h *g)
+{
+ if (!g->tmpdir) {
+ TMP_TEMPLATE_ON_STACK (g, dir_template);
+ g->tmpdir = safe_strdup (g, dir_template);
+ if (mkdtemp (g->tmpdir) == NULL) {
+ perrorf (g, _("%s: cannot create temporary directory"), dir_template);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Recursively remove a temporary directory. If removal fails, just
+ * return (it's a temporary directory so it'll eventually be cleaned
+ * up by a temp cleaner). This is done using "rm -rf" because that's
+ * simpler and safer.
+ */
+void
+guestfs___recursive_remove_dir (guestfs_h *g, const char *dir)
+{
+ struct command *cmd;
+
+ cmd = guestfs___new_command (g);
+ guestfs___cmd_add_arg (cmd, "rm");
+ guestfs___cmd_add_arg (cmd, "-rf");
+ guestfs___cmd_add_arg (cmd, dir);
+ /* Ignore failures. */
+ guestfs___cmd_run (cmd);
+ guestfs___cmd_close (cmd);
+}
+
+void
+guestfs___remove_tmpdir (guestfs_h *g)
+{
+ if (g->tmpdir)
+ guestfs___recursive_remove_dir (g, g->tmpdir);
+}