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);
33 use Locale::TextDomain 'libguestfs';
39 virt-df - Display free space on virtual filesystems
45 virt-df [--options] domname
47 virt-df [--options] disk.img [disk.img ...]
51 C<virt-df> is a command line tool to display free space on virtual
52 machine filesystems. Unlike other tools, it doesn't just display the
53 amount of space allocated to a virtual machine, but can look inside
54 the virtual machine to see how much space is really being used.
56 It is like the L<df(1)> command, but for virtual machines, except that
57 it also works for Windows virtual machines.
59 If used without any arguments, C<virt-df> checks with libvirt to get a
60 list of all active and inactive guests, and performs a C<df>-type
61 operation on each one in turn, printing out the results.
63 If used with any argument(s), C<virt-df> performs a C<df>-type
64 operation on either the single named libvirt domain, or on the disk
65 image(s) listed on the command line (which must all belong to a single
66 VM). In this mode (with arguments), C<virt-df> will I<only work for a
67 single guest>. If you want to run on multiple guests, then you have
68 to invoke C<virt-df> multiple times.
70 Use the C<--csv> option to get a format which can be easily parsed by
71 other programs. Other options are mostly similar to standard C<df>
72 options. See below for the complete list.
92 Display version number and exit.
98 =item B<--connect URI> | B<-c URI>
100 If using libvirt, connect to the given I<URI>. If omitted, then we
101 connect to the default libvirt hypervisor.
103 If you specify guest block devices directly, then libvirt is not used
112 Write out the results in CSV format (comma-separated values). This format
113 can be imported easily into databases and spreadsheets, but
114 read L</NOTE ABOUT CSV FORMAT> below.
120 =item B<--human-readable> | B<-h>
122 Print sizes in human-readable format.
128 =item B<--inodes> | B<-i>
130 Print inodes instead of blocks.
136 GetOptions ("help|?" => \$help,
137 "version" => \$version,
138 "connect|c=s" => \$uri,
140 "human-readable|human|h" => \$human,
141 "inodes|i" => \$inodes,
143 pod2usage (1) if $help;
145 my $g = Sys::Guestfs->new ();
146 my %h = $g->version ();
147 print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
151 # Open the guest handle.
157 $conn = Sys::Virt->new (readonly => 1, address => $uri);
159 $conn = Sys::Virt->new (readonly => 1);
162 my @doms = $conn->list_defined_domains ();
163 push @doms, $conn->list_domains ();
165 # https://bugzilla.redhat.com/show_bug.cgi?id=538041
166 @doms = grep { $_->get_id () != 0 } @doms;
168 my @domnames = map { $_->get_name () } @doms;
172 foreach (@domnames) {
173 eval { do_df ($_); };
187 $g = open_guest (\@_, address => $uri);
189 $g = open_guest (\@_);
194 my @partitions = get_partitions ($g);
196 # Think of a printable name for this domain. Just choose the
197 # first parameter passed to this function, which will work for
198 # most cases (it'll either be the domain name or the first disk
202 # Mount each partition in turn, and if mountable, do a statvfs on it.
203 foreach my $partition (@partitions) {
206 $g->mount_ro ($partition, "/");
207 %stat = $g->statvfs ("/");
210 print_stat ($domname, $partition, \%stat);
219 my $partition = shift;
222 my @cols = ($domname, $partition);
225 my $bsize = $stat->{bsize}; # block size
226 my $blocks = $stat->{blocks}; # total number of blocks
227 my $bfree = $stat->{bfree}; # blocks free (total)
228 my $bavail = $stat->{bavail}; # blocks free (for non-root users)
230 my $factor = $bsize / 1024;
232 push @cols, $blocks*$factor; # total 1K blocks
233 push @cols, ($blocks-$bfree)*$factor; # total 1K blocks used
234 push @cols, $bavail*$factor; # total 1K blocks available
236 push @cols, 100.0 - 100.0 * $bfree / $blocks;
239 $cols[2] = human_size ($cols[2]);
240 $cols[3] = human_size ($cols[3]);
241 $cols[4] = human_size ($cols[4]);
244 my $files = $stat->{files}; # total number of inodes
245 my $ffree = $stat->{ffree}; # inodes free (total)
246 my $favail = $stat->{favail}; # inodes free (for non-root users)
249 push @cols, $files-$ffree;
252 push @cols, 100.0 - 100.0 * $ffree / $files;
260 my @cols = (__"Virtual Machine", __"Filesystem");
263 push @cols, __"1K-blocks";
265 push @cols, __"Size";
267 push @cols, __"Used";
268 push @cols, __"Available";
269 push @cols, __"Use%";
271 push @cols, __"Inodes";
272 push @cols, __"IUsed";
273 push @cols, __"IFree";
274 push @cols, __"IUse%";
278 # ignore $cols[0] in this mode
279 printf "%-36s%10s %10s %10s %5s\n",
280 $cols[1], $cols[2], $cols[3], $cols[4], $cols[5];
282 print (join (",", @cols), "\n");
289 my $label = sprintf "%s:%s", $_[0], $_[1];
291 printf ("%-36s", $label);
292 print "\n"," "x36 if length ($label) > 36;
294 # Use 'ceil' on the percentage in order to emulate
295 # what df itself does.
296 my $percent = sprintf "%3d%%", ceil($_[5]);
298 printf ("%10s %10s %10s %5s\n", $_[2], $_[3], $_[4], $percent);
300 printf ("\"%s\",\"%s\",%d,%d,%d,%.1f%%\n", @_);
304 # Convert a number of 1K blocks to a human-readable number.
311 } elsif ($_ < 1024 * 1024) {
312 sprintf "%.1fM", ($_ / 1024);
314 sprintf "%.1fG", ($_ / 1024 / 1024);
318 =head1 NOTE ABOUT CSV FORMAT
320 Comma-separated values (CSV) is a deceptive format. It I<seems> like
321 it should be easy to parse, but it is definitely not easy to parse.
323 Myth: Just split fields at commas. Reality: This does I<not> work
324 reliably. This example has two columns:
328 Myth: Read the file one line at a time. Reality: This does I<not>
329 work reliably. This example has one row:
334 For shell scripts, use C<csvtool> (L<http://merjis.com/developers/csv>
335 also packaged in major Linux distributions).
337 For other languages, use a CSV processing library (eg. C<Text::CSV>
338 for Perl or Python's built-in csv library).
340 Most spreadsheets and databases can import CSV directly.
347 L<Sys::Guestfs::Lib(3)>,
349 L<http://libguestfs.org/>.
353 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
357 Copyright (C) 2009-2010 Red Hat Inc.
359 This program is free software; you can redistribute it and/or modify
360 it under the terms of the GNU General Public License as published by
361 the Free Software Foundation; either version 2 of the License, or
362 (at your option) any later version.
364 This program is distributed in the hope that it will be useful,
365 but WITHOUT ANY WARRANTY; without even the implied warranty of
366 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
367 GNU General Public License for more details.
369 You should have received a copy of the GNU General Public License
370 along with this program; if not, write to the Free Software
371 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.