An experimental series that adds support for rsync. Rich.
Richard W.M. Jones
2012-Aug-04 13:38 UTC
[Libguestfs] [PATCH 1/2] fish: Add --network option.
From: "Richard W.M. Jones" <rjones at redhat.com> This enables the network. --- fish/fish.c | 6 +++++- fish/guestfish.pod | 14 +++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/fish/fish.c b/fish/fish.c index 9bb8c90..d0e2d8a 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -125,8 +125,9 @@ usage (int status) " --listen Listen for remote commands\n" " --live Connect to a live virtual machine\n" " -m|--mount dev[:mnt[:opts]] Mount dev on mnt (if omitted, /)\n" - " -n|--no-sync Don't autosync\n" + " --network Enable network\n" " -N|--new type Create prepared disk (test1.img, ...)\n" + " -n|--no-sync Don't autosync\n" " --pipe-error Pipe commands can detect write errors\n" " --progress-bars Enable progress bars even when not interactive\n" " --no-progress-bars Disable progress bars\n" @@ -190,6 +191,7 @@ main (int argc, char *argv[]) { "listen", 0, 0, 0 }, { "live", 0, 0, 0 }, { "mount", 1, 0, 'm' }, + { "network", 0, 0, 0 }, { "new", 1, 0, 'N' }, { "no-dest-paths", 0, 0, 'D' }, { "no-sync", 0, 0, 'n' }, @@ -286,6 +288,8 @@ main (int argc, char *argv[]) live = 1; } else if (STREQ (long_options[option_index].name, "pipe-error")) { pipe_error = 1; + } else if (STREQ (long_options[option_index].name, "network")) { + guestfs_set_network (g, 1); } else { fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), program_name, long_options[option_index].name, option_index); diff --git a/fish/guestfish.pod b/fish/guestfish.pod index 83b358b..01571ea 100644 --- a/fish/guestfish.pod +++ b/fish/guestfish.pod @@ -332,12 +332,9 @@ filesystem can support them: Using this flag is equivalent to using the C<mount-options> command. -=item B<-n> - -=item B<--no-sync> +=item B<--network> -Disable autosync. This is enabled by default. See the discussion -of autosync in the L<guestfs(3)> manpage. +Enable QEMU user networking in the guest. =item B<-N type> @@ -350,6 +347,13 @@ alternative to the I<-a> option: whereas I<-a> adds an existing disk, I<-N> creates a preformatted disk with a filesystem and adds it. See L</PREPARED DISK IMAGES> below. +=item B<-n> + +=item B<--no-sync> + +Disable autosync. This is enabled by default. See the discussion +of autosync in the L<guestfs(3)> manpage. + =item B<--pipe-error> If writes fail to pipe commands (see L</PIPES> below), then the -- 1.7.10.4
Richard W.M. Jones
2012-Aug-04 13:38 UTC
[Libguestfs] [PATCH 2/2] New APIs: rsync, rsync-in, rsync-out
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