Add support for zerofree command.
authorRichard W.M. Jones <rjones@redhat.com>
Thu, 14 May 2009 22:47:17 +0000 (23:47 +0100)
committerRichard W.M. Jones <rjones@redhat.com>
Thu, 14 May 2009 22:47:17 +0000 (23:47 +0100)
28 files changed:
contrib/fedora-libguestfs.spec
daemon/Makefile.am
daemon/actions.h
daemon/stubs.c
daemon/zerofree.c [new file with mode: 0644]
fish/cmds.c
fish/completion.c
guestfish-actions.pod
guestfs-actions.pod
haskell/Guestfs.hs
java/com/redhat/et/libguestfs/GuestFS.java
java/com_redhat_et_libguestfs_GuestFS.c
make-initramfs.sh.in
ocaml/guestfs.ml
ocaml/guestfs.mli
ocaml/guestfs_c_actions.c
perl/Guestfs.xs
perl/lib/Sys/Guestfs.pm
python/guestfs-py.c
python/guestfs.py
ruby/ext/guestfs/_guestfs.c
src/generator.ml
src/guestfs-actions.c
src/guestfs-actions.h
src/guestfs_protocol.c
src/guestfs_protocol.h
src/guestfs_protocol.x
tests.c

index b7d66ba..9c3e3ed 100644 (file)
@@ -36,6 +36,7 @@ BuildRequires: kernel, bash, coreutils, lvm2, ntfs-3g, util-linux-ng
 BuildRequires: MAKEDEV, net-tools, augeas-libs, file
 BuildRequires: module-init-tools, procps, strace, iputils
 BuildRequires: grub, dosfstools, ntfsprogs
 BuildRequires: MAKEDEV, net-tools, augeas-libs, file
 BuildRequires: module-init-tools, procps, strace, iputils
 BuildRequires: grub, dosfstools, ntfsprogs
+BuildRequires: zerofree
 
 # These are only required if you want to build the bindings for
 # different languages:
 
 # These are only required if you want to build the bindings for
 # different languages:
index 8460d44..d6ae6c3 100644 (file)
@@ -50,6 +50,7 @@ guestfsd_SOURCES = \
        tar.c \
        upload.c \
        zero.c \
        tar.c \
        upload.c \
        zero.c \
+       zerofree.c \
        ../src/guestfs_protocol.h \
        ../src/guestfs_protocol.c
 
        ../src/guestfs_protocol.h \
        ../src/guestfs_protocol.c
 
index f4678f8..37ec125 100644 (file)
@@ -117,3 +117,4 @@ extern int do_equal (const char *file1, const char *file2);
 extern char **do_strings (const char *path);
 extern char **do_strings_e (const char *encoding, const char *path);
 extern char *do_hexdump (const char *path);
 extern char **do_strings (const char *path);
 extern char **do_strings_e (const char *encoding, const char *path);
 extern char *do_hexdump (const char *path);
+extern int do_zerofree (const char *device);
index 0e5b351..212634f 100644 (file)
@@ -2397,6 +2397,30 @@ done:
   xdr_free ((xdrproc_t) xdr_guestfs_hexdump_args, (char *) &args);
 }
 
   xdr_free ((xdrproc_t) xdr_guestfs_hexdump_args, (char *) &args);
 }
 
+static void zerofree_stub (XDR *xdr_in)
+{
+  int r;
+  struct guestfs_zerofree_args args;
+  const char *device;
+
+  memset (&args, 0, sizeof args);
+
+  if (!xdr_guestfs_zerofree_args (xdr_in, &args)) {
+    reply_with_error ("%s: daemon failed to decode procedure arguments", "zerofree");
+    return;
+  }
+  device = args.device;
+
+  r = do_zerofree (device);
+  if (r == -1)
+    /* do_zerofree has already called reply_with_error */
+    goto done;
+
+  reply (NULL, NULL);
+done:
+  xdr_free ((xdrproc_t) xdr_guestfs_zerofree_args, (char *) &args);
+}
+
 void dispatch_incoming_message (XDR *xdr_in)
 {
   switch (proc_nr) {
 void dispatch_incoming_message (XDR *xdr_in)
 {
   switch (proc_nr) {
@@ -2688,6 +2712,9 @@ void dispatch_incoming_message (XDR *xdr_in)
     case GUESTFS_PROC_HEXDUMP:
       hexdump_stub (xdr_in);
       break;
     case GUESTFS_PROC_HEXDUMP:
       hexdump_stub (xdr_in);
       break;
+    case GUESTFS_PROC_ZEROFREE:
+      zerofree_stub (xdr_in);
+      break;
     default:
       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
   }
     default:
       reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr);
   }
diff --git a/daemon/zerofree.c b/daemon/zerofree.c
new file mode 100644 (file)
index 0000000..b44965a
--- /dev/null
@@ -0,0 +1,48 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2009 Red Hat Inc. 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "daemon.h"
+#include "actions.h"
+
+int
+do_zerofree (const char *device)
+{
+  char *err;
+  int r;
+
+  IS_DEVICE (device, -1);
+
+  r = command (NULL, &err, "/usr/sbin/zerofree", device, NULL);
+  if (r == -1) {
+    reply_with_error ("zerofree: %s: %s", device, err);
+    free (err);
+    return -1;
+  }
+
+  free (err);
+
+  return 0;
+}
index 1e442d8..1f3d9ce 100644 (file)
@@ -147,6 +147,7 @@ void list_commands (void)
   printf ("%-20s %s\n", "vgs-full", "list the LVM volume groups (VGs)");
   printf ("%-20s %s\n", "write-file", "create a file");
   printf ("%-20s %s\n", "zero", "write zeroes to the device");
   printf ("%-20s %s\n", "vgs-full", "list the LVM volume groups (VGs)");
   printf ("%-20s %s\n", "write-file", "create a file");
   printf ("%-20s %s\n", "zero", "write zeroes to the device");
+  printf ("%-20s %s\n", "zerofree", "zero unused inodes and disk blocks on ext2/3 filesystem");
   printf ("    Use -h <cmd> / help <cmd> to show detailed help for a command.\n");
 }
 
   printf ("    Use -h <cmd> / help <cmd> to show detailed help for a command.\n");
 }
 
@@ -500,6 +501,9 @@ void display_command (const char *cmd)
   if (strcasecmp (cmd, "hexdump") == 0)
     pod2text ("hexdump - dump a file in hexadecimal", " hexdump <path>\n\nThis runs C<hexdump -C> on the given C<path>.  The result is\nthe human-readable, canonical hex dump of the file.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB.  To transfer large files you should use\nFTP.");
   else
   if (strcasecmp (cmd, "hexdump") == 0)
     pod2text ("hexdump - dump a file in hexadecimal", " hexdump <path>\n\nThis runs C<hexdump -C> on the given C<path>.  The result is\nthe human-readable, canonical hex dump of the file.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB.  To transfer large files you should use\nFTP.");
   else
+  if (strcasecmp (cmd, "zerofree") == 0)
+    pod2text ("zerofree - zero unused inodes and disk blocks on ext2/3 filesystem", " zerofree <device>\n\nThis runs the I<zerofree> program on C<device>.  This program\nclaims to zero unused inodes and disk blocks on an ext2/3\nfilesystem, thus making it possible to compress the filesystem\nmore effectively.\n\nYou should B<not> run this program if the filesystem is\nmounted.\n\nIt is possible that using this program can damage the filesystem\nor data on the filesystem.");
+  else
     display_builtin_command (cmd);
 }
 
     display_builtin_command (cmd);
 }
 
@@ -2438,6 +2442,20 @@ static int run_hexdump (const char *cmd, int argc, char *argv[])
   return 0;
 }
 
   return 0;
 }
 
+static int run_zerofree (const char *cmd, int argc, char *argv[])
+{
+  int r;
+  const char *device;
+  if (argc != 1) {
+    fprintf (stderr, "%s should have 1 parameter(s)\n", cmd);
+    fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd);
+    return -1;
+  }
+  device = argv[0];
+  r = guestfs_zerofree (g, device);
+  return r;
+}
+
 int run_action (const char *cmd, int argc, char *argv[])
 {
   if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
 int run_action (const char *cmd, int argc, char *argv[])
 {
   if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0)
@@ -2788,6 +2806,9 @@ int run_action (const char *cmd, int argc, char *argv[])
   if (strcasecmp (cmd, "hexdump") == 0)
     return run_hexdump (cmd, argc, argv);
   else
   if (strcasecmp (cmd, "hexdump") == 0)
     return run_hexdump (cmd, argc, argv);
   else
+  if (strcasecmp (cmd, "zerofree") == 0)
+    return run_zerofree (cmd, argc, argv);
+  else
     {
       fprintf (stderr, "%s: unknown command\n", cmd);
       return -1;
     {
       fprintf (stderr, "%s: unknown command\n", cmd);
       return -1;
index 4db2d5e..5c7f5e0 100644 (file)
@@ -160,6 +160,7 @@ static const char *const commands[] = {
   "vgs-full",
   "write-file",
   "zero",
   "vgs-full",
   "write-file",
   "zero",
+  "zerofree",
   NULL
 };
 
   NULL
 };
 
index 9146c41..7b5a4be 100644 (file)
@@ -1283,3 +1283,18 @@ How many blocks are zeroed isn't specified (but it's I<not> enough
 to securely wipe the device).  It should be sufficient to remove
 any partition tables, filesystem superblocks and so on.
 
 to securely wipe the device).  It should be sufficient to remove
 any partition tables, filesystem superblocks and so on.
 
+=head2 zerofree
+
+ zerofree device
+
+This runs the I<zerofree> program on C<device>.  This program
+claims to zero unused inodes and disk blocks on an ext2/3
+filesystem, thus making it possible to compress the filesystem
+more effectively.
+
+You should B<not> run this program if the filesystem is
+mounted.
+
+It is possible that using this program can damage the filesystem
+or data on the filesystem.
+
index 53bfa54..109c73e 100644 (file)
@@ -1747,3 +1747,21 @@ any partition tables, filesystem superblocks and so on.
 
 This function returns 0 on success or -1 on error.
 
 
 This function returns 0 on success or -1 on error.
 
+=head2 guestfs_zerofree
+
+ int guestfs_zerofree (guestfs_h *handle,
+               const char *device);
+
+This runs the I<zerofree> program on C<device>.  This program
+claims to zero unused inodes and disk blocks on an ext2/3
+filesystem, thus making it possible to compress the filesystem
+more effectively.
+
+You should B<not> run this program if the filesystem is
+mounted.
+
+It is possible that using this program can damage the filesystem
+or data on the filesystem.
+
+This function returns 0 on success or -1 on error.
+
index 4721376..c061a7a 100644 (file)
@@ -78,7 +78,8 @@ module Guestfs (
   cp,
   cp_a,
   mv,
   cp,
   cp_a,
   mv,
-  ping_daemon
+  ping_daemon,
+  zerofree
   ) where
 import Foreign
 import Foreign.C
   ) where
 import Foreign
 import Foreign.C
@@ -788,3 +789,15 @@ ping_daemon h = do
       fail err
     else return ()
 
       fail err
     else return ()
 
+foreign import ccall unsafe "guestfs_zerofree" c_zerofree
+  :: GuestfsP -> CString -> IO (CInt)
+
+zerofree :: GuestfsH -> String -> IO ()
+zerofree h device = do
+  r <- withCString device $ \device -> withForeignPtr h (\p -> c_zerofree p device)
+  if (r == -1)
+    then do
+      err <- last_error h
+      fail err
+    else return ()
+
index c816baa..76ada90 100644 (file)
@@ -2729,4 +2729,30 @@ public class GuestFS {
   private native String _hexdump (long g, String path)
     throws LibGuestFSException;
 
   private native String _hexdump (long g, String path)
     throws LibGuestFSException;
 
+  /**
+   * zero unused inodes and disk blocks on ext2/3 filesystem
+   *
+   * This runs the *zerofree* program on "device". This
+   * program claims to zero unused inodes and disk blocks on
+   * an ext2/3 filesystem, thus making it possible to
+   * compress the filesystem more effectively.
+   * 
+   * You should not run this program if the filesystem is
+   * mounted.
+   * 
+   * It is possible that using this program can damage the
+   * filesystem or data on the filesystem.
+   * 
+   * @throws LibGuestFSException
+   */
+  public void zerofree (String device)
+    throws LibGuestFSException
+  {
+    if (g == 0)
+      throw new LibGuestFSException ("zerofree: handle is closed");
+    _zerofree (g, device);
+  }
+  private native void _zerofree (long g, String device)
+    throws LibGuestFSException;
+
 }
 }
index ce1f2db..a823d84 100644 (file)
@@ -2722,3 +2722,20 @@ Java_com_redhat_et_libguestfs_GuestFS__1hexdump
   return jr;
 }
 
   return jr;
 }
 
+JNIEXPORT void JNICALL
+Java_com_redhat_et_libguestfs_GuestFS__1zerofree
+  (JNIEnv *env, jobject obj, jlong jg, jstring jdevice)
+{
+  guestfs_h *g = (guestfs_h *) (long) jg;
+  int r;
+  const char *device;
+
+  device = (*env)->GetStringUTFChars (env, jdevice, NULL);
+  r = guestfs_zerofree (g, device);
+  (*env)->ReleaseStringUTFChars (env, jdevice, device);
+  if (r == -1) {
+    throw_exception (env, guestfs_last_error (g));
+    return ;
+  }
+}
+
index b8faa3b..b6e7820 100755 (executable)
@@ -41,6 +41,7 @@ modules="
 -i procps
 -i strace
 -i util-linux-ng
 -i procps
 -i strace
 -i util-linux-ng
+-i zerofree
 "
 
 # Decide on names for the final output.  These have to match Makefile.am.
 "
 
 # Decide on names for the final output.  These have to match Makefile.am.
index 2544b16..3886022 100644 (file)
@@ -235,3 +235,4 @@ external equal : t -> string -> string -> bool = "ocaml_guestfs_equal"
 external strings : t -> string -> string array = "ocaml_guestfs_strings"
 external strings_e : t -> string -> string -> string array = "ocaml_guestfs_strings_e"
 external hexdump : t -> string -> string = "ocaml_guestfs_hexdump"
 external strings : t -> string -> string array = "ocaml_guestfs_strings"
 external strings_e : t -> string -> string -> string array = "ocaml_guestfs_strings_e"
 external hexdump : t -> string -> string = "ocaml_guestfs_hexdump"
+external zerofree : t -> string -> unit = "ocaml_guestfs_zerofree"
index 870ffb6..3776abe 100644 (file)
@@ -484,3 +484,6 @@ val strings_e : t -> string -> string -> string array
 val hexdump : t -> string -> string
 (** dump a file in hexadecimal *)
 
 val hexdump : t -> string -> string
 (** dump a file in hexadecimal *)
 
+val zerofree : t -> string -> unit
+(** zero unused inodes and disk blocks on ext2/3 filesystem *)
+
index 22e6500..79a5c16 100644 (file)
@@ -3178,3 +3178,26 @@ ocaml_guestfs_hexdump (value gv, value pathv)
   CAMLreturn (rv);
 }
 
   CAMLreturn (rv);
 }
 
+CAMLprim value
+ocaml_guestfs_zerofree (value gv, value devicev)
+{
+  CAMLparam2 (gv, devicev);
+  CAMLlocal1 (rv);
+
+  guestfs_h *g = Guestfs_val (gv);
+  if (g == NULL)
+    caml_failwith ("zerofree: used handle after closing it");
+
+  const char *device = String_val (devicev);
+  int r;
+
+  caml_enter_blocking_section ();
+  r = guestfs_zerofree (g, device);
+  caml_leave_blocking_section ();
+  if (r == -1)
+    ocaml_guestfs_raise_error (g, "zerofree");
+
+  rv = Val_unit;
+  CAMLreturn (rv);
+}
+
index 973f56e..e87131b 100644 (file)
@@ -1787,3 +1787,14 @@ PREINIT:
  OUTPUT:
       RETVAL
 
  OUTPUT:
       RETVAL
 
+void
+zerofree (g, device)
+      guestfs_h *g;
+      char *device;
+PREINIT:
+      int r;
+ PPCODE:
+      r = guestfs_zerofree (g, device);
+      if (r == -1)
+        croak ("zerofree: %s", guestfs_last_error (g));
+
index 13c084f..b11594f 100644 (file)
@@ -1162,6 +1162,19 @@ How many blocks are zeroed isn't specified (but it's I<not> enough
 to securely wipe the device).  It should be sufficient to remove
 any partition tables, filesystem superblocks and so on.
 
 to securely wipe the device).  It should be sufficient to remove
 any partition tables, filesystem superblocks and so on.
 
+=item $h->zerofree ($device);
+
+This runs the I<zerofree> program on C<device>.  This program
+claims to zero unused inodes and disk blocks on an ext2/3
+filesystem, thus making it possible to compress the filesystem
+more effectively.
+
+You should B<not> run this program if the filesystem is
+mounted.
+
+It is possible that using this program can damage the filesystem
+or data on the filesystem.
+
 =cut
 
 1;
 =cut
 
 1;
index 3a09afb..8301c70 100644 (file)
@@ -3402,6 +3402,31 @@ py_guestfs_hexdump (PyObject *self, PyObject *args)
   return py_r;
 }
 
   return py_r;
 }
 
+static PyObject *
+py_guestfs_zerofree (PyObject *self, PyObject *args)
+{
+  PyObject *py_g;
+  guestfs_h *g;
+  PyObject *py_r;
+  int r;
+  const char *device;
+
+  if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_zerofree",
+                         &py_g, &device))
+    return NULL;
+  g = get_handle (py_g);
+
+  r = guestfs_zerofree (g, device);
+  if (r == -1) {
+    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
+    return NULL;
+  }
+
+  Py_INCREF (Py_None);
+  py_r = Py_None;
+  return py_r;
+}
+
 static PyMethodDef methods[] = {
   { (char *) "create", py_guestfs_create, METH_VARARGS, NULL },
   { (char *) "close", py_guestfs_close, METH_VARARGS, NULL },
 static PyMethodDef methods[] = {
   { (char *) "create", py_guestfs_create, METH_VARARGS, NULL },
   { (char *) "close", py_guestfs_close, METH_VARARGS, NULL },
@@ -3525,6 +3550,7 @@ static PyMethodDef methods[] = {
   { (char *) "strings", py_guestfs_strings, METH_VARARGS, NULL },
   { (char *) "strings_e", py_guestfs_strings_e, METH_VARARGS, NULL },
   { (char *) "hexdump", py_guestfs_hexdump, METH_VARARGS, NULL },
   { (char *) "strings", py_guestfs_strings, METH_VARARGS, NULL },
   { (char *) "strings_e", py_guestfs_strings_e, METH_VARARGS, NULL },
   { (char *) "hexdump", py_guestfs_hexdump, METH_VARARGS, NULL },
+  { (char *) "zerofree", py_guestfs_zerofree, METH_VARARGS, NULL },
   { NULL, NULL, 0, NULL }
 };
 
   { NULL, NULL, 0, NULL }
 };
 
index e61ba65..044e1fa 100644 (file)
@@ -1334,3 +1334,17 @@ class GuestFS:
         """
         return libguestfsmod.hexdump (self._o, path)
 
         """
         return libguestfsmod.hexdump (self._o, path)
 
+    def zerofree (self, device):
+        u"""This runs the *zerofree* program on "device". This
+        program claims to zero unused inodes and disk blocks on
+        an ext2/3 filesystem, thus making it possible to
+        compress the filesystem more effectively.
+        
+        You should not run this program if the filesystem is
+        mounted.
+        
+        It is possible that using this program can damage the
+        filesystem or data on the filesystem.
+        """
+        return libguestfsmod.zerofree (self._o, device)
+
index 0c20703..4fb6ce7 100644 (file)
@@ -2885,6 +2885,27 @@ static VALUE ruby_guestfs_hexdump (VALUE gv, VALUE pathv)
   return rv;
 }
 
   return rv;
 }
 
+static VALUE ruby_guestfs_zerofree (VALUE gv, VALUE devicev)
+{
+  guestfs_h *g;
+  Data_Get_Struct (gv, guestfs_h, g);
+  if (!g)
+    rb_raise (rb_eArgError, "%s: used handle after closing it", "zerofree");
+
+  const char *device = StringValueCStr (devicev);
+  if (!device)
+    rb_raise (rb_eTypeError, "expected string for parameter %s of %s",
+              "device", "zerofree");
+
+  int r;
+
+  r = guestfs_zerofree (g, device);
+  if (r == -1)
+    rb_raise (e_Error, "%s", guestfs_last_error (g));
+
+  return Qnil;
+}
+
 /* Initialize the module. */
 void Init__guestfs ()
 {
 /* Initialize the module. */
 void Init__guestfs ()
 {
@@ -3135,4 +3156,6 @@ void Init__guestfs ()
         ruby_guestfs_strings_e, 2);
   rb_define_method (c_guestfs, "hexdump",
         ruby_guestfs_hexdump, 1);
         ruby_guestfs_strings_e, 2);
   rb_define_method (c_guestfs, "hexdump",
         ruby_guestfs_hexdump, 1);
+  rb_define_method (c_guestfs, "zerofree",
+        ruby_guestfs_zerofree, 1);
 }
 }
index 82bfb88..652564d 100755 (executable)
@@ -1996,6 +1996,29 @@ The returned strings are transcoded to UTF-8.");
 This runs C<hexdump -C> on the given C<path>.  The result is
 the human-readable, canonical hex dump of the file.");
 
 This runs C<hexdump -C> on the given C<path>.  The result is
 the human-readable, canonical hex dump of the file.");
 
+  ("zerofree", (RErr, [String "device"]), 97, [],
+   [InitNone, Always, TestOutput (
+      [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","];
+       ["mkfs"; "ext3"; "/dev/sda1"];
+       ["mount"; "/dev/sda1"; "/"];
+       ["write_file"; "/new"; "test file"; "0"];
+       ["umount"; "/dev/sda1"];
+       ["zerofree"; "/dev/sda1"];
+       ["mount"; "/dev/sda1"; "/"];
+       ["cat"; "/new"]], "test file")],
+   "zero unused inodes and disk blocks on ext2/3 filesystem",
+   "\
+This runs the I<zerofree> program on C<device>.  This program
+claims to zero unused inodes and disk blocks on an ext2/3
+filesystem, thus making it possible to compress the filesystem
+more effectively.
+
+You should B<not> run this program if the filesystem is
+mounted.
+
+It is possible that using this program can damage the filesystem
+or data on the filesystem.");
+
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
 ]
 
 let all_functions = non_daemon_functions @ daemon_functions
index 1296051..d27ef01 100644 (file)
@@ -8809,3 +8809,90 @@ char *guestfs_hexdump (guestfs_h *g,
   return ctx.ret.dump; /* caller will free */
 }
 
   return ctx.ret.dump; /* caller will free */
 }
 
+struct zerofree_ctx {
+  /* This flag is set by the callbacks, so we know we've done
+   * the callbacks as expected, and in the right sequence.
+   * 0 = not called, 1 = reply_cb called.
+   */
+  int cb_sequence;
+  struct guestfs_message_header hdr;
+  struct guestfs_message_error err;
+};
+
+static void zerofree_reply_cb (guestfs_h *g, void *data, XDR *xdr)
+{
+  guestfs_main_loop *ml = guestfs_get_main_loop (g);
+  struct zerofree_ctx *ctx = (struct zerofree_ctx *) data;
+
+  /* This should definitely not happen. */
+  if (ctx->cb_sequence != 0) {
+    ctx->cb_sequence = 9999;
+    error (g, "%s: internal error: reply callback called twice", "guestfs_zerofree");
+    return;
+  }
+
+  ml->main_loop_quit (ml, g);
+
+  if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) {
+    error (g, "%s: failed to parse reply header", "guestfs_zerofree");
+    return;
+  }
+  if (ctx->hdr.status == GUESTFS_STATUS_ERROR) {
+    if (!xdr_guestfs_message_error (xdr, &ctx->err)) {
+      error (g, "%s: failed to parse reply error", "guestfs_zerofree");
+      return;
+    }
+    goto done;
+  }
+ done:
+  ctx->cb_sequence = 1;
+}
+
+int guestfs_zerofree (guestfs_h *g,
+               const char *device)
+{
+  struct guestfs_zerofree_args args;
+  struct zerofree_ctx ctx;
+  guestfs_main_loop *ml = guestfs_get_main_loop (g);
+  int serial;
+
+  if (check_state (g, "guestfs_zerofree") == -1) return -1;
+  guestfs_set_busy (g);
+
+  memset (&ctx, 0, sizeof ctx);
+
+  args.device = (char *) device;
+  serial = guestfs__send_sync (g, GUESTFS_PROC_ZEROFREE,
+        (xdrproc_t) xdr_guestfs_zerofree_args, (char *) &args);
+  if (serial == -1) {
+    guestfs_end_busy (g);
+    return -1;
+  }
+
+  guestfs__switch_to_receiving (g);
+  ctx.cb_sequence = 0;
+  guestfs_set_reply_callback (g, zerofree_reply_cb, &ctx);
+  (void) ml->main_loop_run (ml, g);
+  guestfs_set_reply_callback (g, NULL, NULL);
+  if (ctx.cb_sequence != 1) {
+    error (g, "%s reply failed, see earlier error messages", "guestfs_zerofree");
+    guestfs_end_busy (g);
+    return -1;
+  }
+
+  if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_ZEROFREE, serial) == -1) {
+    guestfs_end_busy (g);
+    return -1;
+  }
+
+  if (ctx.hdr.status == GUESTFS_STATUS_ERROR) {
+    error (g, "%s", ctx.err.error_message);
+    free (ctx.err.error_message);
+    guestfs_end_busy (g);
+    return -1;
+  }
+
+  guestfs_end_busy (g);
+  return 0;
+}
+
index 92c1a93..9a4e923 100644 (file)
@@ -139,3 +139,4 @@ extern int guestfs_equal (guestfs_h *handle, const char *file1, const char *file
 extern char **guestfs_strings (guestfs_h *handle, const char *path);
 extern char **guestfs_strings_e (guestfs_h *handle, const char *encoding, const char *path);
 extern char *guestfs_hexdump (guestfs_h *handle, const char *path);
 extern char **guestfs_strings (guestfs_h *handle, const char *path);
 extern char **guestfs_strings_e (guestfs_h *handle, const char *encoding, const char *path);
 extern char *guestfs_hexdump (guestfs_h *handle, const char *path);
+extern int guestfs_zerofree (guestfs_h *handle, const char *device);
index d53bcff..c505b25 100644 (file)
@@ -1614,6 +1614,16 @@ xdr_guestfs_hexdump_ret (XDR *xdrs, guestfs_hexdump_ret *objp)
 }
 
 bool_t
 }
 
 bool_t
+xdr_guestfs_zerofree_args (XDR *xdrs, guestfs_zerofree_args *objp)
+{
+       register int32_t *buf;
+
+        if (!xdr_string (xdrs, &objp->device, ~0))
+                return FALSE;
+       return TRUE;
+}
+
+bool_t
 xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
 {
        register int32_t *buf;
 xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp)
 {
        register int32_t *buf;
index 87db39b..a855307 100644 (file)
@@ -837,6 +837,11 @@ struct guestfs_hexdump_ret {
 };
 typedef struct guestfs_hexdump_ret guestfs_hexdump_ret;
 
 };
 typedef struct guestfs_hexdump_ret guestfs_hexdump_ret;
 
+struct guestfs_zerofree_args {
+       char *device;
+};
+typedef struct guestfs_zerofree_args guestfs_zerofree_args;
+
 enum guestfs_procedure {
        GUESTFS_PROC_MOUNT = 1,
        GUESTFS_PROC_SYNC = 2,
 enum guestfs_procedure {
        GUESTFS_PROC_MOUNT = 1,
        GUESTFS_PROC_SYNC = 2,
@@ -934,7 +939,8 @@ enum guestfs_procedure {
        GUESTFS_PROC_STRINGS = 94,
        GUESTFS_PROC_STRINGS_E = 95,
        GUESTFS_PROC_HEXDUMP = 96,
        GUESTFS_PROC_STRINGS = 94,
        GUESTFS_PROC_STRINGS_E = 95,
        GUESTFS_PROC_HEXDUMP = 96,
-       GUESTFS_PROC_NR_PROCS = 96 + 1,
+       GUESTFS_PROC_ZEROFREE = 97,
+       GUESTFS_PROC_NR_PROCS = 97 + 1,
 };
 typedef enum guestfs_procedure guestfs_procedure;
 #define GUESTFS_MESSAGE_MAX 4194304
 };
 typedef enum guestfs_procedure guestfs_procedure;
 #define GUESTFS_MESSAGE_MAX 4194304
@@ -1116,6 +1122,7 @@ extern  bool_t xdr_guestfs_strings_e_args (XDR *, guestfs_strings_e_args*);
 extern  bool_t xdr_guestfs_strings_e_ret (XDR *, guestfs_strings_e_ret*);
 extern  bool_t xdr_guestfs_hexdump_args (XDR *, guestfs_hexdump_args*);
 extern  bool_t xdr_guestfs_hexdump_ret (XDR *, guestfs_hexdump_ret*);
 extern  bool_t xdr_guestfs_strings_e_ret (XDR *, guestfs_strings_e_ret*);
 extern  bool_t xdr_guestfs_hexdump_args (XDR *, guestfs_hexdump_args*);
 extern  bool_t xdr_guestfs_hexdump_ret (XDR *, guestfs_hexdump_ret*);
+extern  bool_t xdr_guestfs_zerofree_args (XDR *, guestfs_zerofree_args*);
 extern  bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*);
 extern  bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
 extern  bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
 extern  bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*);
 extern  bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*);
 extern  bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*);
@@ -1256,6 +1263,7 @@ extern bool_t xdr_guestfs_strings_e_args ();
 extern bool_t xdr_guestfs_strings_e_ret ();
 extern bool_t xdr_guestfs_hexdump_args ();
 extern bool_t xdr_guestfs_hexdump_ret ();
 extern bool_t xdr_guestfs_strings_e_ret ();
 extern bool_t xdr_guestfs_hexdump_args ();
 extern bool_t xdr_guestfs_hexdump_ret ();
+extern bool_t xdr_guestfs_zerofree_args ();
 extern bool_t xdr_guestfs_procedure ();
 extern bool_t xdr_guestfs_message_direction ();
 extern bool_t xdr_guestfs_message_status ();
 extern bool_t xdr_guestfs_procedure ();
 extern bool_t xdr_guestfs_message_direction ();
 extern bool_t xdr_guestfs_message_status ();
index 4226424..f09e5b5 100644 (file)
@@ -648,6 +648,10 @@ struct guestfs_hexdump_ret {
   string dump<>;
 };
 
   string dump<>;
 };
 
+struct guestfs_zerofree_args {
+  string device<>;
+};
+
 enum guestfs_procedure {
   GUESTFS_PROC_MOUNT = 1,
   GUESTFS_PROC_SYNC = 2,
 enum guestfs_procedure {
   GUESTFS_PROC_MOUNT = 1,
   GUESTFS_PROC_SYNC = 2,
@@ -745,6 +749,7 @@ enum guestfs_procedure {
   GUESTFS_PROC_STRINGS = 94,
   GUESTFS_PROC_STRINGS_E = 95,
   GUESTFS_PROC_HEXDUMP = 96,
   GUESTFS_PROC_STRINGS = 94,
   GUESTFS_PROC_STRINGS_E = 95,
   GUESTFS_PROC_HEXDUMP = 96,
+  GUESTFS_PROC_ZEROFREE = 97,
   GUESTFS_PROC_NR_PROCS
 };
 
   GUESTFS_PROC_NR_PROCS
 };
 
diff --git a/tests.c b/tests.c
index b1382c0..11a1568 100644 (file)
--- a/tests.c
+++ b/tests.c
@@ -118,6 +118,97 @@ static void no_test_warnings (void)
   fprintf (stderr, "warning: \"guestfs_get_e2uuid\" has no tests\n");
 }
 
   fprintf (stderr, "warning: \"guestfs_get_e2uuid\" has no tests\n");
 }
 
+static int test_zerofree_0 (void)
+{
+  /* TestOutput for zerofree (0) */
+  char expected[] = "test file";
+  {
+    char device[] = "/dev/sda";
+    device[5] = devchar;
+    char lines_0[] = ",";
+    char *lines[] = {
+      lines_0,
+      NULL
+    };
+    int r;
+    suppress_error = 0;
+    r = guestfs_sfdisk (g, device, 0, 0, 0, lines);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char fstype[] = "ext3";
+    char device[] = "/dev/sda1";
+    device[5] = devchar;
+    int r;
+    suppress_error = 0;
+    r = guestfs_mkfs (g, fstype, device);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char device[] = "/dev/sda1";
+    device[5] = devchar;
+    char mountpoint[] = "/";
+    int r;
+    suppress_error = 0;
+    r = guestfs_mount (g, device, mountpoint);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char path[] = "/new";
+    char content[] = "test file";
+    int r;
+    suppress_error = 0;
+    r = guestfs_write_file (g, path, content, 0);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char pathordevice[] = "/dev/sda1";
+    pathordevice[5] = devchar;
+    int r;
+    suppress_error = 0;
+    r = guestfs_umount (g, pathordevice);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char device[] = "/dev/sda1";
+    device[5] = devchar;
+    int r;
+    suppress_error = 0;
+    r = guestfs_zerofree (g, device);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char device[] = "/dev/sda1";
+    device[5] = devchar;
+    char mountpoint[] = "/";
+    int r;
+    suppress_error = 0;
+    r = guestfs_mount (g, device, mountpoint);
+    if (r == -1)
+      return -1;
+  }
+  {
+    char path[] = "/new";
+    char *r;
+    suppress_error = 0;
+    r = guestfs_cat (g, path);
+    if (r == NULL)
+      return -1;
+    if (strcmp (r, expected) != 0) {
+      fprintf (stderr, "test_zerofree_0: expected \"%s\" but got \"%s\"\n", expected, r);
+      return -1;
+    }
+    free (r);
+  }
+  return 0;
+}
+
 static int test_hexdump_0 (void)
 {
   /* InitBasicFS for hexdump (0): create ext2 on /dev/sda1 */
 static int test_hexdump_0 (void)
 {
   /* InitBasicFS for hexdump (0): create ext2 on /dev/sda1 */
@@ -5101,7 +5192,7 @@ static int test_command_lines_0 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_0");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_0");
   return 0;
 }
 
   return 0;
 }
 
@@ -5225,7 +5316,7 @@ static int test_command_lines_1 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_1");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_1");
   return 0;
 }
 
   return 0;
 }
 
@@ -5361,7 +5452,7 @@ static int test_command_lines_2 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_2");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_2");
   return 0;
 }
 
   return 0;
 }
 
@@ -5497,7 +5588,7 @@ static int test_command_lines_3 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_3");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_3");
   return 0;
 }
 
   return 0;
 }
 
@@ -5645,7 +5736,7 @@ static int test_command_lines_4 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_4");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_4");
   return 0;
 }
 
   return 0;
 }
 
@@ -5805,7 +5896,7 @@ static int test_command_lines_5 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_5");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_5");
   return 0;
 }
 
   return 0;
 }
 
@@ -5917,7 +6008,7 @@ static int test_command_lines_6 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_6");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_6");
   return 0;
 }
 
   return 0;
 }
 
@@ -6041,7 +6132,7 @@ static int test_command_lines_7 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_7");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_7");
   return 0;
 }
 
   return 0;
 }
 
@@ -6177,7 +6268,7 @@ static int test_command_lines_8 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_8");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_8");
   return 0;
 }
 
   return 0;
 }
 
@@ -6313,7 +6404,7 @@ static int test_command_lines_9 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_9");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_9");
   return 0;
 }
 
   return 0;
 }
 
@@ -6449,7 +6540,7 @@ static int test_command_lines_10 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_lines_10");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_lines_10");
   return 0;
 }
 
   return 0;
 }
 
@@ -6558,7 +6649,7 @@ static int test_command_0 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_0");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_0");
   return 0;
 }
 
   return 0;
 }
 
@@ -6667,7 +6758,7 @@ static int test_command_1 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_1");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_1");
   return 0;
 }
 
   return 0;
 }
 
@@ -6776,7 +6867,7 @@ static int test_command_2 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_2");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_2");
   return 0;
 }
 
   return 0;
 }
 
@@ -6885,7 +6976,7 @@ static int test_command_3 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_3");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_3");
   return 0;
 }
 
   return 0;
 }
 
@@ -6994,7 +7085,7 @@ static int test_command_4 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_4");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_4");
   return 0;
 }
 
   return 0;
 }
 
@@ -7103,7 +7194,7 @@ static int test_command_5 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_5");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_5");
   return 0;
 }
 
   return 0;
 }
 
@@ -7212,7 +7303,7 @@ static int test_command_6 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_6");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_6");
   return 0;
 }
 
   return 0;
 }
 
@@ -7321,7 +7412,7 @@ static int test_command_7 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_7");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_7");
   return 0;
 }
 
   return 0;
 }
 
@@ -7430,7 +7521,7 @@ static int test_command_8 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_8");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_8");
   return 0;
 }
 
   return 0;
 }
 
@@ -7539,7 +7630,7 @@ static int test_command_9 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_9");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_9");
   return 0;
 }
 
   return 0;
 }
 
@@ -7648,7 +7739,7 @@ static int test_command_10 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_10");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_10");
   return 0;
 }
 
   return 0;
 }
 
@@ -7750,7 +7841,7 @@ static int test_command_11 (void)
     free (r);
   }
   } else
     free (r);
   }
   } else
-    printf ("%s skippedd (reason: test prerequisite)\n", "test_command_11");
+    printf ("%s skipped (reason: test prerequisite)\n", "test_command_11");
   return 0;
 }
 
   return 0;
 }
 
@@ -13025,9 +13116,15 @@ int main (int argc, char *argv[])
     free (devs[i]);
   free (devs);
 
     free (devs[i]);
   free (devs);
 
-  nr_tests = 135;
+  nr_tests = 136;
 
   test_num++;
 
   test_num++;
+  printf ("%3d/%3d test_zerofree_0\n", test_num, nr_tests);
+  if (test_zerofree_0 () == -1) {
+    printf ("test_zerofree_0 FAILED\n");
+    failed++;
+  }
+  test_num++;
   printf ("%3d/%3d test_hexdump_0\n", test_num, nr_tests);
   if (test_hexdump_0 () == -1) {
     printf ("test_hexdump_0 FAILED\n");
   printf ("%3d/%3d test_hexdump_0\n", test_num, nr_tests);
   if (test_hexdump_0 () == -1) {
     printf ("test_hexdump_0 FAILED\n");