Fix 'file(1)' command to work on /dev devices.
[libguestfs.git] / src / guestfs.c
index 3492c62..e104633 100644 (file)
 
 static void error (guestfs_h *g, const char *fs, ...);
 static void perrorf (guestfs_h *g, const char *fs, ...);
-static void *safe_malloc (guestfs_h *g, int nbytes);
+static void *safe_malloc (guestfs_h *g, size_t nbytes);
 static void *safe_realloc (guestfs_h *g, void *ptr, int nbytes);
 static char *safe_strdup (guestfs_h *g, const char *str);
+static void *safe_memdup (guestfs_h *g, void *ptr, size_t size);
 
 static void default_error_cb (guestfs_h *g, void *data, const char *msg);
 static void stdout_event (void *data, int watch, int fd, int events);
@@ -120,6 +121,8 @@ struct guestfs_h
 
   const char *path;
 
+  char *last_error;
+
   /* Callbacks. */
   guestfs_abort_cb           abort_cb;
   guestfs_error_handler_cb   error_cb;
@@ -263,6 +266,7 @@ guestfs_close (guestfs_h *g)
   }
   /* release mutex (XXX) */
 
+  free (g->last_error);
   free (g);
 }
 
@@ -273,6 +277,19 @@ close_handles (void)
   while (handles) guestfs_close (handles);
 }
 
+const char *
+guestfs_last_error (guestfs_h *g)
+{
+  return g->last_error;
+}
+
+static void
+set_last_error (guestfs_h *g, const char *msg)
+{
+  free (g->last_error);
+  g->last_error = strdup (msg);
+}
+
 static void
 default_error_cb (guestfs_h *g, void *data, const char *msg)
 {
@@ -285,13 +302,12 @@ error (guestfs_h *g, const char *fs, ...)
   va_list args;
   char *msg;
 
-  if (!g->error_cb) return;
-
   va_start (args, fs);
   vasprintf (&msg, fs, args);
   va_end (args);
 
-  g->error_cb (g, g->error_cb_data, msg);
+  if (g->error_cb) g->error_cb (g, g->error_cb_data, msg);
+  set_last_error (g, msg);
 
   free (msg);
 }
@@ -303,8 +319,6 @@ perrorf (guestfs_h *g, const char *fs, ...)
   char *msg;
   int err = errno;
 
-  if (!g->error_cb) return;
-
   va_start (args, fs);
   vasprintf (&msg, fs, args);
   va_end (args);
@@ -322,13 +336,14 @@ perrorf (guestfs_h *g, const char *fs, ...)
   strcat (msg, ": ");
   strcat (msg, buf);
 
-  g->error_cb (g, g->error_cb_data, msg);
+  if (g->error_cb) g->error_cb (g, g->error_cb_data, msg);
+  set_last_error (g, msg);
 
   free (msg);
 }
 
 static void *
-safe_malloc (guestfs_h *g, int nbytes)
+safe_malloc (guestfs_h *g, size_t nbytes)
 {
   void *ptr = malloc (nbytes);
   if (!ptr) g->abort_cb ();
@@ -351,6 +366,15 @@ safe_strdup (guestfs_h *g, const char *str)
   return s;
 }
 
+static void *
+safe_memdup (guestfs_h *g, void *ptr, size_t size)
+{
+  void *p = malloc (size);
+  if (!p) g->abort_cb ();
+  memcpy (p, ptr, size);
+  return p;
+}
+
 void
 guestfs_set_out_of_memory_handler (guestfs_h *g, guestfs_abort_cb cb)
 {
@@ -377,10 +401,11 @@ guestfs_get_error_handler (guestfs_h *g, void **data_rtn)
   return g->error_cb;
 }
 
-void
+int
 guestfs_set_verbose (guestfs_h *g, int v)
 {
-  g->verbose = v;
+  g->verbose = !!v;
+  return 0;
 }
 
 int
@@ -389,10 +414,11 @@ guestfs_get_verbose (guestfs_h *g)
   return g->verbose;
 }
 
-void
+int
 guestfs_set_autosync (guestfs_h *g, int a)
 {
-  g->autosync = a;
+  g->autosync = !!a;
+  return 0;
 }
 
 int
@@ -401,13 +427,14 @@ guestfs_get_autosync (guestfs_h *g)
   return g->autosync;
 }
 
-void
+int
 guestfs_set_path (guestfs_h *g, const char *path)
 {
   if (path == NULL)
     g->path = GUESTFS_DEFAULT_PATH;
   else
     g->path = path;
+  return 0;
 }
 
 const char *
@@ -1019,6 +1046,28 @@ sock_read_event (void *data, int watch, int fd, int events)
     goto cleanup;
   }
 
+  /* Got the full message, begin processing it. */
+  if (g->verbose) {
+    int i, j;
+
+    for (i = 0; i < g->msg_in_size; i += 16) {
+      printf ("%04x: ", i);
+      for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
+       printf ("%02x ", (unsigned char) g->msg_in[j]);
+      for (; j < i+16; ++j)
+       printf ("   ");
+      printf ("|");
+      for (j = i; j < MIN (i+16, g->msg_in_size); ++j)
+       if (isprint (g->msg_in[j]))
+         printf ("%c", g->msg_in[j]);
+       else
+         printf (".");
+      for (; j < i+16; ++j)
+       printf (" ");
+      printf ("|\n");
+    }
+  }
+
   /* Not in the expected state. */
   if (g->state != BUSY)
     error (g, "state %d != BUSY", g->state);
@@ -1231,6 +1280,37 @@ check_reply_header (guestfs_h *g,
  */
 #include "guestfs-actions.c"
 
+/* Structure-freeing functions.  These rely on the fact that the
+ * structure format is identical to the XDR format.  See note in
+ * generator.ml.
+ */
+void
+guestfs_free_int_bool (struct guestfs_int_bool *x)
+{
+  free (x);
+}
+
+void
+guestfs_free_lvm_pv_list (struct guestfs_lvm_pv_list *x)
+{
+  xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_pv_list, (char *) x);
+  free (x);
+}
+
+void
+guestfs_free_lvm_vg_list (struct guestfs_lvm_vg_list *x)
+{
+  xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_vg_list, (char *) x);
+  free (x);
+}
+
+void
+guestfs_free_lvm_lv_list (struct guestfs_lvm_lv_list *x)
+{
+  xdr_free ((xdrproc_t) xdr_guestfs_lvm_int_lv_list, (char *) x);
+  free (x);
+}
+
 /* This is the default main loop implementation, using select(2). */
 
 struct handle_cb_data {