3 # Copyright (C) 2009 Red Hat Inc.
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.
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.
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.
23 use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path
24 inspect_all_partitions inspect_partition
25 inspect_operating_systems mount_operating_system inspect_in_detail);
30 use Locale::TextDomain 'libguestfs';
36 virt-df - Display free space on virtual filesystems
42 virt-df [--options] domname
44 virt-df [--options] disk.img [disk.img ...]
48 C<virt-df> is a command line tool to display free space on virtual
49 machine filesystems. Unlike other tools, it doesn't just display the
50 amount of space allocated to a virtual machine, but can look inside
51 the virtual machine to see how much space is really being used.
53 It is like the L<df(1)> command, but for virtual machines, except that
54 it also works for Windows virtual machines.
56 If used without any arguments, C<virt-df> checks with libvirt to get a
57 list of all active and inactive guests, and performs a C<df>-type
58 operation on each one in turn, printing out the results.
60 If used with any argument(s), C<virt-df> performs a C<df>-type
61 operation on either the single named libvirt domain, or on the disk
62 image(s) listed on the command line (which must all belong to a single
63 VM). In this mode (with arguments), C<virt-df> will I<only work for a
64 single guest>. If you want to run on multiple guests, then you have
65 to invoke C<virt-df> multiple times.
67 Use the C<--csv> option to get a format which can be easily parsed by
68 other programs. Other options are mostly similar to standard C<df>
69 options. See below for the complete list.
89 Display version number and exit.
95 =item B<--connect URI> | B<-c URI>
97 If using libvirt, connect to the given I<URI>. If omitted, then we
98 connect to the default libvirt hypervisor.
100 If you specify guest block devices directly, then libvirt is not used
109 Write out the results in CSV format (comma-separated values). This
110 format can be imported easily into databases and spreadsheets, but
111 read L</NOTE ABOUT CSV FORMAT> below.
117 =item B<--human-readable> | B<-h>
119 Print sizes in human-readable format.
125 =item B<--inodes> | B<-i>
127 Print inodes instead of blocks.
133 GetOptions ("help|?" => \$help,
134 "version" => \$version,
135 "connect|c=s" => \$uri,
137 "human-readable|human|h" => \$human,
138 "inodes|i" => \$inodes,
140 pod2usage (1) if $help;
142 my $g = Sys::Guestfs->new ();
143 my %h = $g->version ();
144 print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
148 # Open the guest handle.
154 $conn = Sys::Virt->new (readonly => 1, address => $uri);
156 $conn = Sys::Virt->new (readonly => 1);
159 my @doms = $conn->list_defined_domains ();
160 push @doms, $conn->list_domains ();
162 # https://bugzilla.redhat.com/show_bug.cgi?id=538041
163 @doms = grep { $_->get_id () != 0 } @doms;
165 my @domnames = map { $_->get_name () } @doms;
169 foreach (@domnames) {
170 eval { do_df ($_); };
184 $g = open_guest (\@_, address => $uri);
186 $g = open_guest (\@_);
191 my @partitions = get_partitions ($g);
193 # Think of a printable name for this domain. Just choose the
194 # first parameter passed to this function, which will work for
195 # most cases (it'll either be the domain name or the first disk
199 # Mount each partition in turn, and if mountable, do a statvfs on it.
200 foreach my $partition (@partitions) {
203 $g->mount_ro ($partition, "/");
204 %stat = $g->statvfs ("/");
207 print_stat ($domname, $partition, \%stat);
216 my $partition = shift;
219 my @cols = ($domname, $partition);
222 my $bsize = $stat->{bsize}; # block size
223 my $blocks = $stat->{blocks}; # total number of blocks
224 my $bfree = $stat->{bfree}; # blocks free (total)
225 my $bavail = $stat->{bavail}; # blocks free (for non-root users)
227 my $factor = $bsize / 1024;
229 push @cols, $blocks*$factor; # total 1K blocks
230 push @cols, ($blocks-$bfree)*$factor; # total 1K blocks used
231 push @cols, $bavail*$factor; # total 1K blocks available
233 # XXX %used column comes out different from the native 'df'
234 # program. Need to check how 'df' calculates this.
235 push @cols, 100.0 - 100.0 * $bavail / $blocks;
238 $cols[2] = human_size ($cols[2]);
239 $cols[3] = human_size ($cols[3]);
240 $cols[4] = human_size ($cols[4]);
243 my $files = $stat->{files}; # total number of inodes
244 my $ffree = $stat->{ffree}; # inodes free (total)
245 my $favail = $stat->{favail}; # inodes free (for non-root users)
248 push @cols, $files-$ffree;
251 # XXX %used column comes out different from the native 'df'
252 # program. Need to check how 'df' calculates this.
253 push @cols, 100.0 - 100.0 * $favail / $files;
261 my @cols = (__"Virtual Machine", __"Filesystem");
264 push @cols, __"1K-blocks";
266 push @cols, __"Size";
268 push @cols, __"Used";
269 push @cols, __"Available";
270 push @cols, __"Use%";
272 push @cols, __"Inodes";
273 push @cols, __"IUsed";
274 push @cols, __"IFree";
275 push @cols, __"IUse%";
279 # ignore $cols[0] in this mode
280 printf "%-36s%10s %10s %10s %5s\n",
281 $cols[1], $cols[2], $cols[3], $cols[4], $cols[5];
283 print (join (",", @cols), "\n");
290 my $label = sprintf "%s:%s", $_[0], $_[1];
292 printf ("%-36s", $label);
293 print "\n"," "x36 if length ($label) > 36;
295 my $percent = sprintf "%3.1f%%", $_[5];
296 printf ("%10s %10s %10s %5s\n", $_[2], $_[3], $_[4], $percent);
298 printf ("\"%s\",\"%s\",%d,%d,%d,%.1f%%\n", @_);
302 # Convert a number of 1K blocks to a human-readable number.
309 } elsif ($_ < 1024 * 1024) {
310 sprintf "%.1fM", ($_ / 1024);
312 sprintf "%.1fG", ($_ / 1024 / 1024);
316 =head1 NOTE ABOUT CSV FORMAT
318 Comma-separated values (CSV) is a deceptive format. It I<seems> like
319 it should be easy to parse, but it is definitely not easy to parse.
321 Myth: Just split fields at commas. Reality: This does I<not> work
322 reliably. This example has two columns:
326 Myth: Read the file one line at a time. Reality: This does I<not>
327 work reliably. This example has one row:
332 For shell scripts, use C<csvtool> (L<http://merjis.com/developers/csv>
333 also packaged in major Linux distributions).
335 For other languages, use a CSV processing library (eg. C<Text::CSV>
336 for Perl or Python's built-in csv library).
338 Most spreadsheets and databases can import CSV directly.
345 L<Sys::Guestfs::Lib(3)>,
347 L<http://libguestfs.org/>.
351 Richard W.M. Jones L<http://et.redhat.com/~rjones/>
355 Copyright (C) 2009 Red Hat Inc.
357 This program is free software; you can redistribute it and/or modify
358 it under the terms of the GNU General Public License as published by
359 the Free Software Foundation; either version 2 of the License, or
360 (at your option) any later version.
362 This program is distributed in the hope that it will be useful,
363 but WITHOUT ANY WARRANTY; without even the implied warranty of
364 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
365 GNU General Public License for more details.
367 You should have received a copy of the GNU General Public License
368 along with this program; if not, write to the Free Software
369 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.