resize: Fix canonical device function (RHBZ#655554).
[libguestfs.git] / tools / virt-tar
1 #!/usr/bin/perl -w
2 # virt-tar
3 # Copyright (C) 2009-2010 Red Hat Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 use warnings;
20 use strict;
21
22 use Sys::Guestfs;
23 use Sys::Guestfs::Lib qw(open_guest);
24 use Pod::Usage;
25 use Getopt::Long;
26 use File::Basename;
27 use Locale::TextDomain 'libguestfs';
28
29 =encoding utf8
30
31 =head1 NAME
32
33 virt-tar - Extract or upload files to a virtual machine
34
35 =head1 SYNOPSIS
36
37  virt-tar [--options] -x domname directory tarball
38
39  virt-tar [--options] -u domname tarball directory
40
41  virt-tar [--options] disk.img [disk.img ...] -x directory tarball
42
43  virt-tar [--options] disk.img [disk.img ...] -u tarball directory
44
45 =head1 EXAMPLES
46
47 Download C</home> from the VM into a local tarball:
48
49  virt-tar -x domname /home home.tar
50
51  virt-tar -zx domname /home home.tar.gz
52
53 Upload a local tarball and unpack it inside C</tmp> in the VM:
54
55  virt-tar -u domname uploadstuff.tar /tmp
56
57  virt-tar -zu domname uploadstuff.tar.gz /tmp
58
59 =head1 WARNING
60
61 You must I<not> use C<virt-tar> with the C<-u> option (upload) on live
62 virtual machines.  If you do this, you risk disk corruption in the VM.
63 C<virt-tar> tries to stop you from doing this, but doesn't catch all
64 cases.
65
66 You can use C<-x> (extract) on live virtual machines, but you might
67 get inconsistent results or errors if there is filesystem activity
68 inside the VM.  If the live VM is synched and quiescent, then
69 C<virt-tar> will usually work, but the only way to guarantee
70 consistent results is if the virtual machine is shut down.
71
72 =head1 DESCRIPTION
73
74 C<virt-tar> is a general purpose archive tool for downloading and
75 uploading parts of a guest filesystem.  There are many possibilities:
76 making backups, uploading data files, snooping on guest activity,
77 fixing or customizing guests, etc.
78
79 If you want to just view a single file, use L<virt-cat(1)>.  If you
80 just want to edit a single file, use L<virt-edit(1)>.  For more
81 complex cases you should look at the L<guestfish(1)> tool.
82
83 There are two modes of operation: C<-x> (eXtract) downloads a
84 directory and its contents (recursively) from the virtual machine into
85 a local tarball.  C<-u> uploads from a local tarball, unpacking it
86 into a directory inside the virtual machine.  You cannot use these two
87 options together.
88
89 In addition, you may need to use the C<-z> (gZip) option to enable
90 compression.  When uploading, you have to specify C<-z> if the upload
91 file is compressed because virt-tar won't detect this on its own.
92
93 C<virt-tar> can only handle tar (optionally gzipped) format tarballs.
94 For example it cannot do PKZip files or bzip2 compression.  If you
95 want that then you'll have to rebuild the tarballs yourself.  (This is
96 a limitation of the L<libguestfs(3)> API).
97
98 =head1 OPTIONS
99
100 =over 4
101
102 =cut
103
104 my $help;
105
106 =item B<--help>
107
108 Display brief help.
109
110 =cut
111
112 my $version;
113
114 =item B<--version>
115
116 Display version number and exit.
117
118 =cut
119
120 my $uri;
121
122 =item B<--connect URI> | B<-c URI>
123
124 If using libvirt, connect to the given I<URI>.  If omitted, then we
125 connect to the default libvirt hypervisor.
126
127 If you specify guest block devices directly, then libvirt is not used
128 at all.
129
130 =cut
131
132 my $format;
133
134 =item B<--format> raw
135
136 Specify the format of disk images given on the command line.  If this
137 is omitted then the format is autodetected from the content of the
138 disk image.
139
140 If disk images are requested from libvirt, then this program asks
141 libvirt for this information.  In this case, the value of the format
142 parameter is ignored.
143
144 If working with untrusted raw-format guest disk images, you should
145 ensure the format is always specified.
146
147 =cut
148
149 my $mode;
150
151 =item B<-x> | B<--extract> | B<--download>
152
153 =item B<-u> | B<--upload>
154
155 Use C<-x> to extract (download) a directory from a virtual machine
156 to a local tarball.
157
158 Use C<-u> to upload and unpack from a local tarball into a virtual
159 machine.  Please read the L</WARNING> section above before using this
160 option.
161
162 You must specify exactly one of these options.
163
164 =cut
165
166 my $gzip;
167
168 =item B<-z> | B<--gzip>
169
170 Specify that the input or output tarball is gzip-compressed.
171
172 =back
173
174 =cut
175
176 sub set_mode_x
177 {
178     die __"virt-tar: extract/upload mode specified twice on the command line\n"
179         if $mode;
180     $mode = "x";
181 }
182
183 sub set_mode_u
184 {
185     die __"virt-tar: extract/upload mode specified twice on the command line\n"
186         if $mode;
187     $mode = "u";
188 }
189
190 Getopt::Long::Configure ("bundling");
191 GetOptions ("help|?" => \$help,
192             "version" => \$version,
193             "connect|c=s" => \$uri,
194             "format=s" => \$format,
195             "extract|download|x" => \&set_mode_x,
196             "upload|u" => \&set_mode_u,
197             "gzip|z" => \$gzip,
198     ) or pod2usage (2);
199 pod2usage (1) if $help;
200 if ($version) {
201     my $g = Sys::Guestfs->new ();
202     my %h = $g->version ();
203     print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
204     exit
205 }
206
207 pod2usage (__"virt-tar: no image, VM names, directory or filename given")
208     if @ARGV <= 2;
209
210 die __"virt-tar: either -x or -u must be specified on the command line\n"
211     unless $mode;
212
213 # Note: 'pop' reads arguments right to left.
214 my ($tarball, $directory);
215 if ($mode eq "x") {
216     $tarball = pop @ARGV;
217     $directory = pop @ARGV;
218 } else { # $mode eq "u"
219     $directory = pop @ARGV;
220     $tarball = pop @ARGV;
221     die __x("virt-tar: {tarball}: file not found\n",
222             tarball => $tarball) unless -f $tarball;
223 }
224 die __x("virt-tar: {dir}: directory name must start with '/' character\n",
225         dir => $directory)
226     unless substr ($directory, 0, 1) eq "/";
227
228 my @args = (\@ARGV);
229 push @args, address => $uri if $uri;
230 push @args, rw => 1 if $mode eq "u";
231 push @args, format => $format if defined $format;
232
233 my $g = open_guest (@args);
234 $g->launch ();
235
236 my @roots = $g->inspect_os ();
237 if (@roots == 0) {
238     die __x("{prog}: No operating system could be detected inside this disk image.\n\nThis may be because the file is not a disk image, or is not a virtual machine\nimage, or because the OS type is not understood by libguestfs.\n\nIf you feel this is an error, please file a bug report including as much\ninformation about the disk image as possible.\n",
239             prog => basename ($0));
240 }
241 if (@roots > 1) {
242     die __x("{prog}: multiboot operating systems are not supported.\n",
243             prog => basename ($0))
244 }
245 my %fses = $g->inspect_get_mountpoints ($roots[0]);
246 my @fses = sort { length $a <=> length $b } keys %fses;
247 my $mountopts = $mode eq "u" ? "" : "ro";
248 foreach (@fses) {
249     $g->mount_options ($mountopts, $fses{$_}, $_);
250 }
251
252 # Do the tar command.
253 if ($mode eq "x") {
254     if ($gzip) {
255         $g->tgz_out ($directory, $tarball);
256     } else {
257         $g->tar_out ($directory, $tarball);
258     }
259 } else { # mode eq "u"
260     if ($gzip) {
261         $g->tgz_in ($tarball, $directory);
262     } else {
263         $g->tar_in ($tarball, $directory);
264     }
265 }
266
267 $g->sync ();
268 $g->umount_all ();
269
270 undef $g;
271
272 exit 0;
273
274 =head1 SHELL QUOTING
275
276 Libvirt guest names can contain arbitrary characters, some of which
277 have meaning to the shell such as C<#> and space.  You may need to
278 quote or escape these characters on the command line.  See the shell
279 manual page L<sh(1)> for details.
280
281 =head1 SEE ALSO
282
283 L<guestfs(3)>,
284 L<guestfish(1)>,
285 L<virt-cat(1)>,
286 L<virt-edit(1)>,
287 L<Sys::Guestfs(3)>,
288 L<Sys::Guestfs::Lib(3)>,
289 L<Sys::Virt(3)>,
290 L<http://libguestfs.org/>.
291
292 =head1 AUTHOR
293
294 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
295
296 =head1 COPYRIGHT
297
298 Copyright (C) 2009 Red Hat Inc.
299
300 This program is free software; you can redistribute it and/or modify
301 it under the terms of the GNU General Public License as published by
302 the Free Software Foundation; either version 2 of the License, or
303 (at your option) any later version.
304
305 This program is distributed in the hope that it will be useful,
306 but WITHOUT ANY WARRANTY; without even the implied warranty of
307 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
308 GNU General Public License for more details.
309
310 You should have received a copy of the GNU General Public License
311 along with this program; if not, write to the Free Software
312 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.