From 62df226f26bd6ac3c481a7790eb89d760d2f0386 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Thu, 30 Apr 2009 19:28:54 +0100 Subject: [PATCH] Added 'zero' command to wipe partition tables and superblocks. --- daemon/Makefile.am | 1 + daemon/actions.h | 1 + daemon/stubs.c | 27 +++++ daemon/zero.c | 52 +++++++++ fish/cmds.c | 21 ++++ fish/completion.c | 1 + guestfish-actions.pod | 10 ++ guestfs-actions.pod | 13 +++ java/com/redhat/et/libguestfs/GuestFS.java | 23 ++++ java/com_redhat_et_libguestfs_GuestFS.c | 17 +++ ocaml/guestfs.ml | 1 + ocaml/guestfs.mli | 3 + ocaml/guestfs_c_actions.c | 23 ++++ perl/Guestfs.xs | 11 ++ perl/lib/Sys/Guestfs.pm | 8 ++ python/guestfs-py.c | 26 +++++ python/guestfs.py | 11 ++ ruby/ext/guestfs/_guestfs.c | 23 ++++ src/generator.ml | 24 +++- src/guestfs-actions.c | 86 +++++++++++++++ src/guestfs-actions.h | 1 + src/guestfs_protocol.c | 10 ++ src/guestfs_protocol.h | 10 +- src/guestfs_protocol.x | 5 + tests.c | 170 ++++++++++++++++++++++++++++- 25 files changed, 573 insertions(+), 5 deletions(-) create mode 100644 daemon/zero.c diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 91237e2..c2c4a11 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -41,6 +41,7 @@ guestfsd_SOURCES = \ sync.c \ tar.c \ upload.c \ + zero.c \ ../src/guestfs_protocol.h \ ../src/guestfs_protocol.c diff --git a/daemon/actions.h b/daemon/actions.h index 7455586..501e337 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -105,3 +105,4 @@ extern char *do_get_e2label (const char *device); extern int do_set_e2uuid (const char *device, const char *uuid); extern char *do_get_e2uuid (const char *device); extern int do_fsck (const char *fstype, const char *device); +extern int do_zero (const char *device); diff --git a/daemon/stubs.c b/daemon/stubs.c index 9e0ce55..937913f 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -2103,6 +2103,30 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_fsck_args, (char *) &args); } +static void zero_stub (XDR *xdr_in) +{ + int r; + struct guestfs_zero_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_zero_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "zero"); + return; + } + device = args.device; + + r = do_zero (device); + if (r == -1) + /* do_zero has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_zero_args, (char *) &args); +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -2358,6 +2382,9 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_FSCK: fsck_stub (xdr_in); break; + case GUESTFS_PROC_ZERO: + zero_stub (xdr_in); + break; default: reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr); } diff --git a/daemon/zero.c b/daemon/zero.c new file mode 100644 index 0000000..2c20abc --- /dev/null +++ b/daemon/zero.c @@ -0,0 +1,52 @@ +/* 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 + +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" + +int +do_zero (const char *device) +{ + int fd, i; + char buf[4096]; + + IS_DEVICE (device, -1); + + fd = open (device, O_WRONLY); + if (fd == -1) { + reply_with_perror ("%s", device); + return -1; + } + + memset (buf, 0, sizeof buf); + + for (i = 0; i < 32; ++i) + (void) write (fd, buf, sizeof buf); + + close (fd); + + return 0; +} diff --git a/fish/cmds.c b/fish/cmds.c index e762521..c23da2f 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -133,6 +133,7 @@ void list_commands (void) printf ("%-20s %s\n", "vgs", "list the LVM volume groups (VGs)"); 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 (" Use -h / help to show detailed help for a command.\n"); } @@ -444,6 +445,9 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "fsck") == 0) pod2text ("fsck - run the filesystem checker", " fsck \n\nThis runs the filesystem checker (fsck) on C which\nshould have filesystem type C.\n\nThe returned integer is the status. See L for the\nlist of status codes from C, and note that multiple\nstatus codes can be summed together.\n\nIt is entirely equivalent to running C.\nNote that checking or repairing NTFS volumes is not supported\n(by linux-ntfs)."); else + if (strcasecmp (cmd, "zero") == 0) + pod2text ("zero - write zeroes to the device", " zero \n\nThis command writes zeroes over the first few blocks of C.\n\nHow many blocks are zeroed isn't specified (but it's I enough\nto securely wipe the device). It should be sufficient to remove\nany partition tables, filesystem superblocks and so on."); + else display_builtin_command (cmd); } @@ -2164,6 +2168,20 @@ static int run_fsck (const char *cmd, int argc, char *argv[]) return 0; } +static int run_zero (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_zero (g, device); + return r; +} + int run_action (const char *cmd, int argc, char *argv[]) { if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0) @@ -2472,6 +2490,9 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "fsck") == 0) return run_fsck (cmd, argc, argv); else + if (strcasecmp (cmd, "zero") == 0) + return run_zero (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index cafb84d..cc9991f 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -145,6 +145,7 @@ static const char *const commands[] = { "vgs", "vgs-full", "write-file", + "zero", NULL }; diff --git a/guestfish-actions.pod b/guestfish-actions.pod index c1981c5..d391257 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -1107,3 +1107,13 @@ Because of the message protocol, there is a transfer limit of somewhere between 2MB and 4MB. To transfer large files you should use FTP. +=head2 zero + + zero device + +This command writes zeroes over the first few blocks of C. + +How many blocks are zeroed isn't specified (but it's I enough +to securely wipe the device). It should be sufficient to remove +any partition tables, filesystem superblocks and so on. + diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 07b35af..fb7c3db 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -1507,3 +1507,16 @@ Because of the message protocol, there is a transfer limit of somewhere between 2MB and 4MB. To transfer large files you should use FTP. +=head2 guestfs_zero + + int guestfs_zero (guestfs_h *handle, + const char *device); + +This command writes zeroes over the first few blocks of C. + +How many blocks are zeroed isn't specified (but it's I enough +to securely wipe the device). It should be sufficient to remove +any partition tables, filesystem superblocks and so on. + +This function returns 0 on success or -1 on error. + diff --git a/java/com/redhat/et/libguestfs/GuestFS.java b/java/com/redhat/et/libguestfs/GuestFS.java index 844c3b3..293ee23 100644 --- a/java/com/redhat/et/libguestfs/GuestFS.java +++ b/java/com/redhat/et/libguestfs/GuestFS.java @@ -2382,4 +2382,27 @@ public class GuestFS { private native int _fsck (long g, String fstype, String device) throws LibGuestFSException; + /** + * write zeroes to the device + * + * This command writes zeroes over the first few blocks of + * "device". + * + * How many blocks are zeroed isn't specified (but it's + * *not* enough to securely wipe the device). It should be + * sufficient to remove any partition tables, filesystem + * superblocks and so on. + * + * @throws LibGuestFSException + */ + public void zero (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("zero: handle is closed"); + _zero (g, device); + } + private native void _zero (long g, String device) + throws LibGuestFSException; + } diff --git a/java/com_redhat_et_libguestfs_GuestFS.c b/java/com_redhat_et_libguestfs_GuestFS.c index 1f5579e..466ced8 100644 --- a/java/com_redhat_et_libguestfs_GuestFS.c +++ b/java/com_redhat_et_libguestfs_GuestFS.c @@ -2420,3 +2420,20 @@ Java_com_redhat_et_libguestfs_GuestFS__1fsck return (jint) r; } +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1zero + (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_zero (g, device); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index 32e2264..0d60bcc 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -220,3 +220,4 @@ external get_e2label : t -> string -> string = "ocaml_guestfs_get_e2label" external set_e2uuid : t -> string -> string -> unit = "ocaml_guestfs_set_e2uuid" external get_e2uuid : t -> string -> string = "ocaml_guestfs_get_e2uuid" external fsck : t -> string -> string -> int = "ocaml_guestfs_fsck" +external zero : t -> string -> unit = "ocaml_guestfs_zero" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index 2cbd734..259c8f3 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -439,3 +439,6 @@ val get_e2uuid : t -> string -> string val fsck : t -> string -> string -> int (** run the filesystem checker *) +val zero : t -> string -> unit +(** write zeroes to the device *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index 22dc18f..458d7a7 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -2823,3 +2823,26 @@ ocaml_guestfs_fsck (value gv, value fstypev, value devicev) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_zero (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("zero: used handle after closing it"); + + const char *device = String_val (devicev); + int r; + + caml_enter_blocking_section (); + r = guestfs_zero (g, device); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "zero"); + + rv = Val_unit; + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index 38c60c2..651e7a2 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -1588,3 +1588,14 @@ PREINIT: OUTPUT: RETVAL +void +zero (g, device) + guestfs_h *g; + char *device; +PREINIT: + int r; + PPCODE: + r = guestfs_zero (g, device); + if (r == -1) + croak ("zero: %s", guestfs_last_error (g)); + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index 5b87b27..2d75b69 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -1006,6 +1006,14 @@ Because of the message protocol, there is a transfer limit of somewhere between 2MB and 4MB. To transfer large files you should use FTP. +=item $h->zero ($device); + +This command writes zeroes over the first few blocks of C. + +How many blocks are zeroed isn't specified (but it's I enough +to securely wipe the device). It should be sufficient to remove +any partition tables, filesystem superblocks and so on. + =cut 1; diff --git a/python/guestfs-py.c b/python/guestfs-py.c index 6b93b27..a1cfb09 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -3027,6 +3027,31 @@ py_guestfs_fsck (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_zero (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_zero", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_zero (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 }, @@ -3135,6 +3160,7 @@ static PyMethodDef methods[] = { { (char *) "set_e2uuid", py_guestfs_set_e2uuid, METH_VARARGS, NULL }, { (char *) "get_e2uuid", py_guestfs_get_e2uuid, METH_VARARGS, NULL }, { (char *) "fsck", py_guestfs_fsck, METH_VARARGS, NULL }, + { (char *) "zero", py_guestfs_zero, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index 37dce2b..3cfc86a 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -1163,3 +1163,14 @@ class GuestFS: """ return libguestfsmod.fsck (self._o, fstype, device) + def zero (self, device): + u"""This command writes zeroes over the first few blocks of + "device". + + How many blocks are zeroed isn't specified (but it's + *not* enough to securely wipe the device). It should be + sufficient to remove any partition tables, filesystem + superblocks and so on. + """ + return libguestfsmod.zero (self._o, device) + diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c index 56b3f21..1e87d04 100644 --- a/ruby/ext/guestfs/_guestfs.c +++ b/ruby/ext/guestfs/_guestfs.c @@ -2540,6 +2540,27 @@ static VALUE ruby_guestfs_fsck (VALUE gv, VALUE fstypev, VALUE devicev) return INT2NUM (r); } +static VALUE ruby_guestfs_zero (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", "zero"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "zero"); + + int r; + + r = guestfs_zero (g, device); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + /* Initialize the module. */ void Init__guestfs () { @@ -2760,4 +2781,6 @@ void Init__guestfs () ruby_guestfs_get_e2uuid, 1); rb_define_method (c_guestfs, "fsck", ruby_guestfs_fsck, 2); + rb_define_method (c_guestfs, "zero", + ruby_guestfs_zero, 1); } diff --git a/src/generator.ml b/src/generator.ml index 615d32e..8d5450d 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -1633,8 +1633,13 @@ This returns the ext2/3/4 filesystem UUID of the filesystem on C."); ("fsck", (RInt "status", [String "fstype"; String "device"]), 84, [], - [InitBasicFS, TestRun ( - [["fsck"; "ext2"; "/dev/sda1"]])], + [InitBasicFS, TestOutputInt ( + [["umount"; "/dev/sda1"]; + ["fsck"; "ext2"; "/dev/sda1"]], 0); + InitBasicFS, TestOutputInt ( + [["umount"; "/dev/sda1"]; + ["zero"; "/dev/sda1"]; + ["fsck"; "ext2"; "/dev/sda1"]], 8)], "run the filesystem checker", "\ This runs the filesystem checker (fsck) on C which @@ -1647,6 +1652,21 @@ status codes can be summed together. It is entirely equivalent to running C. Note that checking or repairing NTFS volumes is not supported (by linux-ntfs)."); + + ("zero", (RErr, [String "device"]), 85, [], + [InitBasicFS, TestOutput ( + [["umount"; "/dev/sda1"]; + ["zero"; "/dev/sda1"]; + ["file"; "/dev/sda1"]], "data")], + "write zeroes to the device", + "\ +This command writes zeroes over the first few blocks of C. + +How many blocks are zeroed isn't specified (but it's I enough +to securely wipe the device). It should be sufficient to remove +any partition tables, filesystem superblocks and so on."); + + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index a075b80..e2da1c3 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -7642,3 +7642,89 @@ int guestfs_fsck (guestfs_h *g, return ctx.ret.status; } +struct zero_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 zero_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct zero_ctx *ctx = (struct zero_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_zero"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_zero"); + 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_zero"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_zero (guestfs_h *g, + const char *device) +{ + struct guestfs_zero_args args; + struct zero_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_zero") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_ZERO, + (xdrproc_t) xdr_guestfs_zero_args, (char *) &args); + if (serial == -1) { + guestfs_set_ready (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, zero_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_zero"); + guestfs_set_ready (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_ZERO, serial) == -1) { + guestfs_set_ready (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + guestfs_set_ready (g); + return -1; + } + + guestfs_set_ready (g); + return 0; +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index 6e56099..0fc62a1 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -124,3 +124,4 @@ extern char *guestfs_get_e2label (guestfs_h *handle, const char *device); extern int guestfs_set_e2uuid (guestfs_h *handle, const char *device, const char *uuid); extern char *guestfs_get_e2uuid (guestfs_h *handle, const char *device); extern int guestfs_fsck (guestfs_h *handle, const char *fstype, const char *device); +extern int guestfs_zero (guestfs_h *handle, const char *device); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index 16e80f1..b12133a 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -1450,6 +1450,16 @@ xdr_guestfs_fsck_ret (XDR *xdrs, guestfs_fsck_ret *objp) } bool_t +xdr_guestfs_zero_args (XDR *xdrs, guestfs_zero_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; diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h index 64e4b4d..2e79669 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -750,6 +750,11 @@ struct guestfs_fsck_ret { }; typedef struct guestfs_fsck_ret guestfs_fsck_ret; +struct guestfs_zero_args { + char *device; +}; +typedef struct guestfs_zero_args guestfs_zero_args; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -835,7 +840,8 @@ enum guestfs_procedure { GUESTFS_PROC_SET_E2UUID = 82, GUESTFS_PROC_GET_E2UUID = 83, GUESTFS_PROC_FSCK = 84, - GUESTFS_PROC_NR_PROCS = 84 + 1, + GUESTFS_PROC_ZERO = 85, + GUESTFS_PROC_NR_PROCS = 85 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -1002,6 +1008,7 @@ extern bool_t xdr_guestfs_get_e2uuid_args (XDR *, guestfs_get_e2uuid_args*); extern bool_t xdr_guestfs_get_e2uuid_ret (XDR *, guestfs_get_e2uuid_ret*); extern bool_t xdr_guestfs_fsck_args (XDR *, guestfs_fsck_args*); extern bool_t xdr_guestfs_fsck_ret (XDR *, guestfs_fsck_ret*); +extern bool_t xdr_guestfs_zero_args (XDR *, guestfs_zero_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*); @@ -1127,6 +1134,7 @@ extern bool_t xdr_guestfs_get_e2uuid_args (); extern bool_t xdr_guestfs_get_e2uuid_ret (); extern bool_t xdr_guestfs_fsck_args (); extern bool_t xdr_guestfs_fsck_ret (); +extern bool_t xdr_guestfs_zero_args (); extern bool_t xdr_guestfs_procedure (); extern bool_t xdr_guestfs_message_direction (); extern bool_t xdr_guestfs_message_status (); diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x index 92dc8ea..c940bf4 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -582,6 +582,10 @@ struct guestfs_fsck_ret { int status; }; +struct guestfs_zero_args { + string device<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -667,6 +671,7 @@ enum guestfs_procedure { GUESTFS_PROC_SET_E2UUID = 82, GUESTFS_PROC_GET_E2UUID = 83, GUESTFS_PROC_FSCK = 84, + GUESTFS_PROC_ZERO = 85, GUESTFS_PROC_NR_PROCS }; diff --git a/tests.c b/tests.c index dddb971..5cf8ddc 100644 --- a/tests.c +++ b/tests.c @@ -112,6 +112,78 @@ static void no_test_warnings (void) fprintf (stderr, "warning: \"guestfs_get_e2uuid\" has no tests\n"); } +static int test_zero_0 (void) +{ + /* InitBasicFS for zero (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutput for zero (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_zero (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_file (g, "/dev/sda1"); + if (r == NULL) + return -1; + if (strcmp (r, "data") != 0) { + fprintf (stderr, "test_zero_0: expected \"data\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; +} + static int test_fsck_0 (void) { /* InitBasicFS for fsck (0): create ext2 on /dev/sda1 */ @@ -154,13 +226,95 @@ static int test_fsck_0 (void) if (r == -1) return -1; } - /* TestRun for fsck (0) */ + /* TestOutputInt for fsck (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount (g, "/dev/sda1"); + if (r == -1) + return -1; + } { int r; suppress_error = 0; r = guestfs_fsck (g, "ext2", "/dev/sda1"); if (r == -1) return -1; + if (r != 0) { + fprintf (stderr, "test_fsck_0: expected 0 but got %d\n", (int) r); + return -1; + } + } + return 0; +} + +static int test_fsck_1 (void) +{ + /* InitBasicFS for fsck (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputInt for fsck (1) */ + { + int r; + suppress_error = 0; + r = guestfs_umount (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_zero (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_fsck (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + if (r != 8) { + fprintf (stderr, "test_fsck_1: expected 8 but got %d\n", (int) r); + return -1; + } } return 0; } @@ -6566,15 +6720,27 @@ int main (int argc, char *argv[]) exit (1); } - nr_tests = 92; + nr_tests = 94; test_num++; + printf ("%3d/%3d test_zero_0\n", test_num, nr_tests); + if (test_zero_0 () == -1) { + printf ("test_zero_0 FAILED\n"); + failed++; + } + test_num++; printf ("%3d/%3d test_fsck_0\n", test_num, nr_tests); if (test_fsck_0 () == -1) { printf ("test_fsck_0 FAILED\n"); failed++; } test_num++; + printf ("%3d/%3d test_fsck_1\n", test_num, nr_tests); + if (test_fsck_1 () == -1) { + printf ("test_fsck_1 FAILED\n"); + failed++; + } + test_num++; printf ("%3d/%3d test_set_e2uuid_0\n", test_num, nr_tests); if (test_set_e2uuid_0 () == -1) { printf ("test_set_e2uuid_0 FAILED\n"); -- 1.8.3.1