#include <sys/stat.h>
#include <sys/select.h>
#include <dirent.h>
-#include <signal.h>
+#include <assert.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "c-ctype.h"
#include "glthread/lock.h"
-#include "ignore-value.h"
+#include "hash.h"
+#include "hash-pjw.h"
#include "guestfs.h"
#include "guestfs-internal.h"
g->error_cb_data = NULL;
g->recovery_proc = 1;
+ g->autosync = 1;
str = getenv ("LIBGUESTFS_DEBUG");
g->verbose = str != NULL && STREQ (str, "1");
if (g->close_cb)
g->close_cb (g, g->close_cb_data);
+ guestfs___free_inspect_info (g);
+
/* Try to sync if autosync flag is set. */
if (g->autosync && g->state == READY) {
guestfs_umount_all (g);
snprintf (filename, sizeof filename, "%s/sock", g->tmpdir);
unlink (filename);
- snprintf (filename, sizeof filename, "%s/initrd", g->tmpdir);
- unlink (filename);
-
- snprintf (filename, sizeof filename, "%s/kernel", g->tmpdir);
- unlink (filename);
-
rmdir (g->tmpdir);
free (g->tmpdir);
}
gl_lock_unlock (handles_lock);
+ if (g->pda)
+ hash_free (g->pda);
free (g->last_error);
free (g->path);
free (g->qemu);
return g->last_error;
}
+int
+guestfs_last_errno (guestfs_h *g)
+{
+ return g->last_errnum;
+}
+
static void
-set_last_error (guestfs_h *g, const char *msg)
+set_last_error (guestfs_h *g, int errnum, const char *msg)
{
free (g->last_error);
g->last_error = strdup (msg);
+ g->last_errnum = errnum;
}
static void
}
void
-guestfs_error (guestfs_h *g, const char *fs, ...)
+guestfs_error_errno (guestfs_h *g, int errnum, const char *fs, ...)
{
va_list args;
char *msg;
if (err < 0) return;
+ /* set_last_error first so that the callback can access the error
+ * message and errno through the handle if it wishes.
+ */
+ set_last_error (g, errnum, msg);
if (g->error_cb) g->error_cb (g, g->error_cb_data, msg);
- set_last_error (g, msg);
free (msg);
}
strcat (msg, ": ");
strcat (msg, buf);
+ /* set_last_error first so that the callback can access the error
+ * message and errno through the handle if it wishes.
+ */
+ set_last_error (g, errnum, msg);
if (g->error_cb) g->error_cb (g, g->error_cb_data, msg);
- set_last_error (g, msg);
free (msg);
}
return s;
}
+char *
+guestfs_safe_strndup (guestfs_h *g, const char *str, size_t n)
+{
+ char *s = strndup (str, n);
+ if (!s) g->abort_cb ();
+ return s;
+}
+
void *
guestfs_safe_memdup (guestfs_h *g, void *ptr, size_t size)
{
return p;
}
+char *
+guestfs_safe_asprintf (guestfs_h *g, const char *fs, ...)
+{
+ va_list args;
+ char *msg;
+
+ va_start (args, fs);
+ int err = vasprintf (&msg, fs, args);
+ va_end (args);
+
+ if (err == -1)
+ g->abort_cb ();
+
+ return msg;
+}
+
void
guestfs_set_out_of_memory_handler (guestfs_h *g, guestfs_abort_cb cb)
{
return g->recovery_proc;
}
+int
+guestfs__set_network (guestfs_h *g, int v)
+{
+ g->enable_network = !!v;
+ return 0;
+}
+
+int
+guestfs__get_network (guestfs_h *g)
+{
+ return g->enable_network;
+}
+
void
guestfs_set_log_message_callback (guestfs_h *g,
guestfs_log_message_cb cb, void *opaque)
g->close_cb = cb;
g->close_cb_data = opaque;
}
+
+void
+guestfs_set_progress_callback (guestfs_h *g,
+ guestfs_progress_cb cb, void *opaque)
+{
+ g->progress_cb = cb;
+ g->progress_cb_data = opaque;
+}
+
+/* Note the private data area is allocated lazily, since the vast
+ * majority of callers will never use it. This means g->pda is
+ * likely to be NULL.
+ */
+struct pda_entry {
+ char *key; /* key */
+ void *data; /* opaque user data pointer */
+};
+
+static size_t
+hasher (void const *x, size_t table_size)
+{
+ struct pda_entry const *p = x;
+ return hash_pjw (p->key, table_size);
+}
+
+static bool
+comparator (void const *x, void const *y)
+{
+ struct pda_entry const *a = x;
+ struct pda_entry const *b = y;
+ return STREQ (a->key, b->key);
+}
+
+static void
+freer (void *x)
+{
+ if (x) {
+ struct pda_entry *p = x;
+ free (p->key);
+ free (p);
+ }
+}
+
+void
+guestfs_set_private (guestfs_h *g, const char *key, void *data)
+{
+ if (g->pda == NULL) {
+ g->pda = hash_initialize (16, NULL, hasher, comparator, freer);
+ if (g->pda == NULL)
+ g->abort_cb ();
+ }
+
+ struct pda_entry *new_entry = safe_malloc (g, sizeof *new_entry);
+ new_entry->key = safe_strdup (g, key);
+ new_entry->data = data;
+
+ struct pda_entry *old_entry = hash_delete (g->pda, new_entry);
+ freer (old_entry);
+
+ struct pda_entry *entry = hash_insert (g->pda, new_entry);
+ if (entry == NULL)
+ g->abort_cb ();
+ assert (entry == new_entry);
+}
+
+static inline char *
+bad_cast (char const *s)
+{
+ return (char *) s;
+}
+
+void *
+guestfs_get_private (guestfs_h *g, const char *key)
+{
+ if (g->pda == NULL)
+ return NULL; /* no keys have been set */
+
+ const struct pda_entry k = { .key = bad_cast (key) };
+ struct pda_entry *entry = hash_lookup (g->pda, &k);
+ if (entry)
+ return entry->data;
+ else
+ return NULL;
+}
+
+/* When tracing, be careful how we print BufferIn parameters which
+ * usually contain large amounts of binary data (RHBZ#646822).
+ */
+void
+guestfs___print_BufferIn (FILE *out, const char *buf, size_t buf_size)
+{
+ size_t i;
+ size_t orig_size = buf_size;
+
+ if (buf_size > 256)
+ buf_size = 256;
+
+ fputc ('"', out);
+
+ for (i = 0; i < buf_size; ++i) {
+ if (c_isprint (buf[i]))
+ fputc (buf[i], out);
+ else
+ fprintf (out, "\\x%02x", (unsigned char) buf[i]);
+ }
+
+ fputc ('"', out);
+
+ if (orig_size > buf_size)
+ fprintf (out,
+ _("<truncated, original size %zu bytes>"), orig_size);
+}
+
+void
+guestfs___print_BufferOut (FILE *out, const char *buf, size_t buf_size)
+{
+ guestfs___print_BufferIn (out, buf, buf_size);
+}
+
+void
+guestfs___free_string_list (char **argv)
+{
+ size_t i;
+ for (i = 0; argv[i] != NULL; ++i)
+ free (argv[i]);
+ free (argv);
+}