[Libguestfs] [PATCH 2/2] New APIs: rsync, rsync-in, rsync-out

Richard W.M. Jones rjones at redhat.com
Sat Aug 4 13:38:56 UTC 2012


From: "Richard W.M. Jones" <rjones at redhat.com>

Implement rsync.
---
 .gitignore                     |    1 +
 Makefile.am                    |    1 +
 configure.ac                   |    1 +
 daemon/Makefile.am             |    1 +
 daemon/rsync.c                 |  151 ++++++++++++++++++++++++++++++++++++++++
 generator/generator_actions.ml |   83 ++++++++++++++++++++++
 gobject/Makefile.inc           |   10 ++-
 po/POTFILES                    |    4 ++
 src/MAX_PROC_NR                |    2 +-
 tests/rsync/Makefile.am        |   26 +++++++
 tests/rsync/test-rsync.sh      |  100 ++++++++++++++++++++++++++
 11 files changed, 377 insertions(+), 3 deletions(-)
 create mode 100644 daemon/rsync.c
 create mode 100644 tests/rsync/Makefile.am
 create mode 100755 tests/rsync/test-rsync.sh

diff --git a/.gitignore b/.gitignore
index de5a688..9ac2037 100644
--- a/.gitignore
+++ b/.gitignore
@@ -408,6 +408,7 @@ Makefile.in
 /tests/mount-local/test-parallel-mount-local
 /tests/regressions/rhbz501893
 /tests/regressions/rhbz790721
+/tests/rsync/rsyncd.pid
 /test-tool/libguestfs-test-tool
 /test-tool/libguestfs-test-tool.1
 /test-tool/libguestfs-test-tool-helper
diff --git a/Makefile.am b/Makefile.am
index 7b1f219..803aec8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -49,6 +49,7 @@ SUBDIRS += tests/charsets
 SUBDIRS += tests/xml
 SUBDIRS += tests/mount-local
 SUBDIRS += tests/9p
+SUBDIRS += tests/rsync
 SUBDIRS += tests/regressions
 endif
 
diff --git a/configure.ac b/configure.ac
index 61b6e35..1bae297 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1385,6 +1385,7 @@ AC_CONFIG_FILES([Makefile
                  tests/protocol/Makefile
                  tests/qemu/Makefile
                  tests/regressions/Makefile
+                 tests/rsync/Makefile
                  tests/selinux/Makefile
                  tests/xml/Makefile
                  tools/Makefile])
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index 590901f..9ea6ce3 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -148,6 +148,7 @@ guestfsd_SOURCES = \
 	proto.c \
 	readdir.c \
 	realpath.c \
+	rsync.c \
 	scrub.c \
 	selinux.c \
 	sfdisk.c \
diff --git a/daemon/rsync.c b/daemon/rsync.c
new file mode 100644
index 0000000..a49b4ef
--- /dev/null
+++ b/daemon/rsync.c
@@ -0,0 +1,151 @@
+/* libguestfs - the guestfsd daemon
+ * Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "daemon.h"
+#include "actions.h"
+#include "optgroups.h"
+
+#define MAX_ARGS 64
+
+int
+optgroup_rsync_available (void)
+{
+  return prog_exists ("rsync");
+}
+
+static int
+rsync (const char *src, const char *src_orig,
+       const char *dest, const char *dest_orig,
+       int archive, int delete)
+{
+  const char *argv[MAX_ARGS];
+  size_t i = 0;
+  int r;
+  char *err;
+
+  ADD_ARG (argv, i, "rsync");
+
+  if (archive)
+    ADD_ARG (argv, i, "--archive");
+
+  if (delete)
+    ADD_ARG (argv, i, "--delete");
+
+  ADD_ARG (argv, i, src);
+  ADD_ARG (argv, i, dest);
+  ADD_ARG (argv, i, NULL);
+
+  r = commandv (NULL, &err, argv);
+  if (r == -1) {
+    reply_with_error ("'%s' to '%s': %s", src_orig, dest_orig, err);
+    free (err);
+    return -1;
+  }
+
+  free (err);
+
+  return 0;
+}
+
+/* Takes optional arguments, consult optargs_bitmask. */
+int
+do_rsync (const char *src_orig, const char *dest_orig,
+          int archive, int delete)
+{
+  char *src = NULL, *dest = NULL;
+  int r = -1;
+
+  src = sysroot_path (src_orig);
+  dest = sysroot_path (dest_orig);
+  if (!src || !dest) {
+    reply_with_perror ("malloc");
+    goto out;
+  }
+
+  if (!(optargs_bitmask & GUESTFS_RSYNC_ARCHIVE_BITMASK))
+    archive = 0;
+  if (!(optargs_bitmask & GUESTFS_RSYNC_DELETE_BITMASK))
+    delete = 0;
+
+  r = rsync (src, src_orig, dest, dest_orig, archive, delete);
+
+ out:
+  free (src);
+  free (dest);
+  return r;
+}
+
+/* Takes optional arguments, consult optargs_bitmask. */
+int
+do_rsync_in (const char *remote, const char *dest_orig,
+             int archive, int delete)
+{
+  char *dest = NULL;
+  int r = -1;
+
+  dest = sysroot_path (dest_orig);
+  if (!dest) {
+    reply_with_perror ("malloc");
+    goto out;
+  }
+
+  if (!(optargs_bitmask & GUESTFS_RSYNC_IN_ARCHIVE_BITMASK))
+    archive = 0;
+  if (!(optargs_bitmask & GUESTFS_RSYNC_IN_DELETE_BITMASK))
+    delete = 0;
+
+  r = rsync (remote, remote, dest, dest_orig, archive, delete);
+
+ out:
+  free (dest);
+  return r;
+}
+
+/* Takes optional arguments, consult optargs_bitmask. */
+int
+do_rsync_out (const char *src_orig, const char *remote,
+              int archive, int delete)
+{
+  char *src = NULL;
+  int r = -1;
+
+  src = sysroot_path (src_orig);
+  if (!src) {
+    reply_with_perror ("malloc");
+    goto out;
+  }
+
+  if (!(optargs_bitmask & GUESTFS_RSYNC_OUT_ARCHIVE_BITMASK))
+    archive = 0;
+  if (!(optargs_bitmask & GUESTFS_RSYNC_OUT_DELETE_BITMASK))
+    delete = 0;
+
+  r = rsync (src, src_orig, remote, remote, archive, delete);
+
+ out:
+  free (src);
+  return r;
+}
diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml
index b7283d7..3b1fbc5 100644
--- a/generator/generator_actions.ml
+++ b/generator/generator_actions.ml
@@ -9148,6 +9148,89 @@ The returned struct contains geometry information.  Missing
 fields are returned as C<-1> (for numeric fields) or empty
 string." };
 
+  { defaults with
+    name = "rsync";
+    style = RErr, [Pathname "src"; Pathname "dest"], [OBool "archive"; OBool "delete"];
+    proc_nr = Some 344;
+    optional = Some "rsync";
+    tests = []; (* tests are in tests/rsync *)
+    shortdesc = "synchronize the contents of two directories";
+    longdesc = "\
+This call may be used to copy or synchronize two directories
+under the same libguestfs handle.  This uses the L<rsync(1)>
+program which uses a fast algorithm that avoids copying files
+unnecessarily.
+
+C<src> and C<dest> are the source and destination directories.
+Files are copied from C<src> to C<dest>.
+
+The optional arguments are:
+
+=over 4
+
+=item C<archive>
+
+Turns on archive mode.  This is the same as passing the
+I<--archive> flag to C<rsync>.
+
+=item C<delete>
+
+Delete files at the destination that do not exist at the source.
+
+=back" };
+
+  { defaults with
+    name = "rsync_in";
+    style = RErr, [String "remote"; Pathname "dest"], [OBool "archive"; OBool "delete"];
+    proc_nr = Some 345;
+    optional = Some "rsync";
+    tests = []; (* tests are in tests/rsync *)
+    shortdesc = "synchronize host or remote filesystem with filesystem";
+    longdesc = "\
+This call may be used to copy or synchronize the filesystem
+on the host or on a remote computer with the filesystem
+within libguestfs.  This uses the L<rsync(1)> program
+which uses a fast algorithm that avoids copying files unnecessarily.
+
+This call only works if the network is enabled.  See
+C<guestfs_set_network> or the I<--network> option to
+various tools like L<guestfish(1)>.
+
+Files are copied from the remote server and directory
+specified by C<remote> to the destination directory C<dest>.
+
+The format of the remote server string is defined by L<rsync(1)>.
+Note that there is no way to supply a password or passphrase
+so the target must be set up not to require one.
+
+The optional arguments are the same as those of C<guestfs_rsync>." };
+
+  { defaults with
+    name = "rsync_out";
+    style = RErr, [Pathname "path"; String "remote"], [OBool "archive"; OBool "delete"];
+    proc_nr = Some 346;
+    optional = Some "rsync";
+    tests = []; (* tests are in tests/rsync *)
+    shortdesc = "synchronize filesystem with host or remote filesystem";
+    longdesc = "\
+This call may be used to copy or synchronize the filesystem within
+libguestfs with a filesystem on the host or on a remote computer.
+This uses the L<rsync(1)> program which uses a fast algorithm that
+avoids copying files unnecessarily.
+
+This call only works if the network is enabled.  See
+C<guestfs_set_network> or the I<--network> option to
+various tools like L<guestfish(1)>.
+
+Files are copied from the source directory C<src> to the
+remote server and directory specified by C<remote>.
+
+The format of the remote server string is defined by L<rsync(1)>.
+Note that there is no way to supply a password or passphrase
+so the target must be set up not to require one.
+
+The optional arguments are the same as those of C<guestfs_rsync>." };
+
 ]
 
 (* Non-API meta-commands available only in guestfish.
diff --git a/gobject/Makefile.inc b/gobject/Makefile.inc
index ba148b0..8c4b2d1 100644
--- a/gobject/Makefile.inc
+++ b/gobject/Makefile.inc
@@ -67,7 +67,10 @@ guestfs_gobject_headers= \
   include/guestfs-gobject/optargs-set_e2attrs.h \
   include/guestfs-gobject/optargs-btrfs_fsck.h \
   include/guestfs-gobject/optargs-fstrim.h \
-  include/guestfs-gobject/optargs-xfs_growfs.h
+  include/guestfs-gobject/optargs-xfs_growfs.h \
+  include/guestfs-gobject/optargs-rsync.h \
+  include/guestfs-gobject/optargs-rsync_in.h \
+  include/guestfs-gobject/optargs-rsync_out.h
 
 guestfs_gobject_sources= \
   src/session.c \
@@ -116,4 +119,7 @@ guestfs_gobject_sources= \
   src/optargs-set_e2attrs.c \
   src/optargs-btrfs_fsck.c \
   src/optargs-fstrim.c \
-  src/optargs-xfs_growfs.c
+  src/optargs-xfs_growfs.c \
+  src/optargs-rsync.c \
+  src/optargs-rsync_in.c \
+  src/optargs-rsync_out.c
diff --git a/po/POTFILES b/po/POTFILES
index dffa899..d1fcc4d 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -67,6 +67,7 @@ daemon/pingdaemon.c
 daemon/proto.c
 daemon/readdir.c
 daemon/realpath.c
+daemon/rsync.c
 daemon/scrub.c
 daemon/selinux.c
 daemon/sfdisk.c
@@ -157,6 +158,9 @@ gobject/src/optargs-mount_local.c
 gobject/src/optargs-ntfsclone_out.c
 gobject/src/optargs-ntfsfix.c
 gobject/src/optargs-ntfsresize.c
+gobject/src/optargs-rsync.c
+gobject/src/optargs-rsync_in.c
+gobject/src/optargs-rsync_out.c
 gobject/src/optargs-set_e2attrs.c
 gobject/src/optargs-tune2fs.c
 gobject/src/optargs-umount.c
diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR
index fe2cd8b..99ca0d5 100644
--- a/src/MAX_PROC_NR
+++ b/src/MAX_PROC_NR
@@ -1 +1 @@
-343
+346
diff --git a/tests/rsync/Makefile.am b/tests/rsync/Makefile.am
new file mode 100644
index 0000000..41bbf4d
--- /dev/null
+++ b/tests/rsync/Makefile.am
@@ -0,0 +1,26 @@
+# libguestfs
+# Copyright (C) 2009-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+include $(top_srcdir)/subdir-rules.mk
+
+TESTS = \
+	test-rsync.sh
+
+TESTS_ENVIRONMENT = $(top_builddir)/run --test
+
+EXTRA_DIST = \
+	$(TESTS)
diff --git a/tests/rsync/test-rsync.sh b/tests/rsync/test-rsync.sh
new file mode 100755
index 0000000..e7f62f9
--- /dev/null
+++ b/tests/rsync/test-rsync.sh
@@ -0,0 +1,100 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test rsync by copying a local directory using an involved and
+# unrealistic method.
+
+unset CDPATH
+set -e
+
+guestfish=../../fish/guestfish
+
+# Check we have the rsync command.
+if ! rsync --help >/dev/null 2>&1; then
+    echo "$0: skipping test because local rsync command is not available"
+    exit 77
+fi
+
+# If rsync is not available, bail.
+if ! $guestfish -a /dev/null run : available rsync; then
+    echo "$0: skipping test because rsync is not available in the appliance"
+    exit 77
+fi
+
+pwd="$(pwd)"
+datadir="$(cd ../../tests/data && pwd)"
+
+rm -rf tmp
+mkdir tmp
+
+# rsync must listen on a port, but we want tests to be able to
+# run in parallel.  Try to choose a random-ish port number (XXX).
+port="$(awk 'BEGIN{srand(); print 65000+int(500*rand())}' </dev/null)"
+
+# Write an rsync daemon config file.
+cat > rsyncd.conf <<EOF
+address = localhost
+port = $port
+pid file = $pwd/rsyncd.pid
+[src]
+  path = $datadir
+  comment = source
+  use chroot = false
+  read only = true
+[dest]
+  path = $pwd/tmp
+  comment = destination
+  use chroot = false
+  read only = false
+EOF
+
+# Start a local rsync daemon.
+rsync --daemon --config=rsyncd.conf
+
+function cleanup ()
+{
+    kill `cat rsyncd.pid`
+}
+trap cleanup INT TERM QUIT EXIT
+
+# XXX
+ip=169.254.2.2
+user="$(id -un)"
+
+$guestfish --network -N fs -m /dev/sda1 <<EOF
+mkdir /dir1
+rsync-in "rsync://$user@$ip:$port/src/" /dir1/ archive:true
+mkdir /dir2
+rsync /dir1/ /dir2/ archive:true
+rsync-out /dir2/ "rsync://$user@$ip:$port/dest/" archive:true
+EOF
+
+# Compare test data to copied data.
+# XXX Because we used the archive flag, dates must be preserved.
+
+if [ ! -f tmp/100kallnewlines ] || \
+   [ ! -f tmp/bin-x86_64-dynamic ] || \
+   [ ! -f tmp/initrd-x86_64.img.gz ] || \
+   [ ! -f tmp/mbr-ext2-empty.img.gz ]; then
+    echo "$0: some files failed to copy"
+    exit 1
+fi
+
+rm -r tmp
+rm test1.img
+rm rsyncd.conf
-- 
1.7.10.4




More information about the Libguestfs mailing list