From: "Richard W.M. Jones" <rjones(a)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