inspector: Rewrite virt-inspector in C.
[libguestfs.git] / inspector / virt-inspector
diff --git a/inspector/virt-inspector b/inspector/virt-inspector
deleted file mode 100755 (executable)
index c721b1d..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-#!/usr/bin/perl -w
-# virt-inspector
-# Copyright (C) 2010 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-use warnings;
-use strict;
-
-use Sys::Guestfs;
-use Sys::Guestfs::Lib qw(open_guest);
-use Pod::Usage;
-use Getopt::Long;
-use File::Temp qw/tempfile/;
-use File::Basename;
-use XML::Writer;
-use Locale::TextDomain 'libguestfs';
-
-=encoding utf8
-
-=head1 NAME
-
-virt-inspector - Display operating system version and other information about a virtual machine
-
-=head1 SYNOPSIS
-
- virt-inspector [--connect URI] domname
-
- virt-inspector guest.img [guest.img ...]
-
-=head1 DESCRIPTION
-
-B<virt-inspector> examines a virtual machine or disk image and tries
-to determine the version of the operating system and other information
-about the virtual machine.
-
-Virt-inspector produces XML output for feeding into other programs.
-
-In the normal usage, use C<virt-inspector domname> where C<domname> is
-the libvirt domain (see: C<virsh list --all>).
-
-You can also run virt-inspector directly on disk images from a single
-virtual machine.  Use C<virt-inspector guest.img>.  In rare cases a
-domain has several block devices, in which case you should list them
-one after another, with the first corresponding to the guest's
-C</dev/sda>, the second to the guest's C</dev/sdb> and so on.
-
-Virt-inspector can only inspect and report upon I<one domain at a
-time>.  To inspect several virtual machines, you have to run
-virt-inspector several times (for example, from a shell script
-for-loop).
-
-Because virt-inspector needs direct access to guest images, it won't
-normally work over remote libvirt connections.
-
-=head1 OPTIONS
-
-=over 4
-
-=cut
-
-my $help;
-
-=item B<--help>
-
-Display brief help.
-
-=cut
-
-my $version;
-
-=item B<--version>
-
-Display version number and exit.
-
-=cut
-
-my $uri;
-
-=item B<--connect URI> | B<-c URI>
-
-If using libvirt, connect to the given I<URI>.  If omitted,
-then we connect to the default libvirt hypervisor.
-
-Libvirt is only used if you specify a C<domname> on the
-command line.  If you specify guest block devices directly,
-then libvirt is not used at all.
-
-=cut
-
-my $format;
-
-=item B<--format> raw
-
-Specify the format of disk images given on the command line.  If this
-is omitted then the format is autodetected from the content of the
-disk image.
-
-If disk images are requested from libvirt, then this program asks
-libvirt for this information.  In this case, the value of the format
-parameter is ignored.
-
-If working with untrusted raw-format guest disk images, you should
-ensure the format is always specified.
-
-=back
-
-=cut
-
-GetOptions ("help|?" => \$help,
-            "version" => \$version,
-            "connect|c=s" => \$uri,
-            "format=s" => \$format,
-    ) or pod2usage (2);
-pod2usage (1) if $help;
-if ($version) {
-    my $g = Sys::Guestfs->new ();
-    my %h = $g->version ();
-    print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
-    exit
-}
-pod2usage (__"virt-inspector: no image or VM names given") if @ARGV == 0;
-
-my @args = (\@ARGV);
-push @args, address => $uri if defined $uri;
-push @args, format => $format if defined $format;
-my $g = open_guest (@args);
-
-$g->launch ();
-
-my @roots = $g->inspect_os ();
-if (@roots == 0) {
-    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",
-            prog => basename ($0));
-}
-
-=head1 XML FORMAT
-
-The virt-inspector XML is described precisely in a RELAX NG schema
-which is supplied with libguestfs.  This section is just an overview.
-
-The top-level element is E<lt>operatingsystemsE<gt>, and it contains
-one or more E<lt>operatingsystemE<gt> elements.  You would only see
-more than one E<lt>operatingsystemE<gt> element if the virtual machine
-is multi-boot, which is vanishingly rare in real world VMs.
-
-=head2 E<lt>operatingsystemE<gt>
-
-In the E<lt>operatingsystemE<gt> tag are various optional fields that
-describe the operating system, its architecture, the descriptive
-"product name" string, the type of OS and so on, as in this example:
-
- <operatingsystems>
-   <operatingsystem>
-     <root>/dev/sda2</root>
-     <name>windows</name>
-     <arch>i386</arch>
-     <distro>windows</distro>
-     <product_name>Windows 7 Enterprise</product_name>
-     <major_version>6</major_version>
-     <minor_version>1</minor_version>
-     <windows_systemroot>/Windows</windows_systemroot>
-
-These fields are derived from the libguestfs inspection API, and
-you can find more details in L<guestfs(3)/INSPECTION>.
-
-The E<lt>rootE<gt> element is the root filesystem device, but from the
-point of view of libguestfs (block devices may have completely
-different names inside the VM itself).
-
-=cut
-
-# Start the XML output.
-my $xml = new XML::Writer (DATA_MODE => 1, DATA_INDENT => 2);
-
-$xml->startTag ("operatingsystems");
-
-my $root;
-foreach $root (@roots) {
-    # Note that output_applications requires the filesystems
-    # to be mounted up.
-    my %fses = $g->inspect_get_mountpoints ($root);
-    my @fses = sort { length $a <=> length $b } keys %fses;
-    foreach (@fses) {
-        $g->mount_ro ($fses{$_}, $_);
-    }
-
-    $xml->startTag ("operatingsystem");
-
-    # Basic OS fields.
-    $xml->dataElement (root => canonicalize ($root));
-
-    my $s;
-    $s = $g->inspect_get_type ($root);
-    $xml->dataElement (name => $s) if $s ne "unknown";
-    $s = $g->inspect_get_arch ($root);
-    $xml->dataElement (arch => $s) if $s ne "unknown";
-    $s = $g->inspect_get_distro ($root);
-    $xml->dataElement (distro => $s) if $s ne "unknown";
-    $s = $g->inspect_get_product_name ($root);
-    $xml->dataElement (product_name => $s) if $s ne "unknown";
-    $s = $g->inspect_get_major_version ($root);
-    $xml->dataElement (major_version => $s);
-    $s = $g->inspect_get_minor_version ($root);
-    $xml->dataElement (minor_version => $s);
-    $s = $g->inspect_get_package_format ($root);
-    $xml->dataElement (package_format => $s) if $s ne "unknown";
-    $s = $g->inspect_get_package_management ($root);
-    $xml->dataElement (package_management => $s) if $s ne "unknown";
-
-    eval {
-        $s = $g->inspect_get_windows_systemroot ($root);
-        $xml->dataElement (windows_systemroot => $s);
-    };
-
-    # Mountpoints.
-    output_mountpoints ($root, \@fses, \%fses);
-
-    # Filesystems.
-    output_filesystems ($root);
-
-    # Package format / management and applications.
-    output_applications ($root);
-
-    $xml->endTag("operatingsystem");
-
-    $g->umount_all ();
-}
-
-# End the XML output.
-$xml->endTag ("operatingsystems");
-$xml->end ();
-
-=head2 E<lt>mountpointsE<gt>
-
-Un*x-like guests typically have multiple filesystems which are mounted
-at various mountpoints, and these are described in the
-E<lt>mountpointsE<gt> element which looks like this:
-
- <operatingsystems>
-   <operatingsystem>
-     ...
-     <mountpoints>
-       <mountpoint dev="/dev/vg_f13x64/lv_root">/</mountpoint>
-       <mountpoint dev="/dev/sda1">/boot</mountpoint>
-     </mountpoints>
-
-As with E<lt>rootE<gt>, devices are from the point of view of
-libguestfs, and may have completely different names inside the guest.
-Only mountable filesystems appear in this list, not things like swap
-devices.
-
-=cut
-
-sub output_mountpoints
-{
-    local $_;
-    my $root = shift;
-    my $fskeys = shift;
-    my $fshash = shift;
-
-    $xml->startTag ("mountpoints");
-    foreach (@$fskeys) {
-        $xml->dataElement ("mountpoint", $_,
-                           dev => canonicalize ($fshash->{$_}));
-    }
-    $xml->endTag ("mountpoints");
-}
-
-=head2 E<lt>filesystemsE<gt>
-
-E<lt>filesystemsE<gt> is like E<lt>mountpointsE<gt> but covers I<all>
-filesystems belonging to the guest, including swap and empty
-partitions.  (In the rare case of a multi-boot guest, it covers
-filesystems belonging to this OS or shared by this OS and other OSes).
-
-You might see something like this:
-
- <operatingsystems>
-   <operatingsystem>
-     ...
-     <filesystems>
-       <filesystem dev="/dev/vg_f13x64/lv_root">
-         <type>ext4</type>
-         <label>Fedora-13-x86_64</label>
-         <uuid>e6a4db1e-15c2-477b-ac2a-699181c396aa</uuid>
-       </filesystem>
-
-The optional elements within E<lt>filesystemE<gt> are the filesystem
-type, the label, and the UUID.
-
-=cut
-
-sub output_filesystems
-{
-    local $_;
-    my $root = shift;
-
-    $xml->startTag ("filesystems");
-
-    my @fses = $g->inspect_get_filesystems ($root);
-    @fses = sort @fses;
-    foreach (@fses) {
-        $xml->startTag ("filesystem",
-                        dev => canonicalize ($_));
-
-        eval {
-            my $type = $g->vfs_type ($_);
-            $xml->dataElement (type => $type)
-                if defined $type && $type ne "";
-        };
-
-        eval {
-            my $label = $g->vfs_label ($_);
-            $xml->dataElement (label => $label)
-                if defined $label && $label ne "";
-        };
-
-        eval {
-            my $uuid = $g->vfs_uuid ($_);
-            $xml->dataElement (uuid => $uuid)
-                if defined $uuid && $uuid ne "";
-        };
-
-        $xml->endTag ("filesystem");
-    }
-
-    $xml->endTag ("filesystems");
-}
-
-=head2 E<lt>applicationsE<gt>
-
-The related elements E<lt>package_formatE<gt>,
-E<lt>package_managementE<gt> and E<lt>applicationsE<gt> describe
-applications installed in the virtual machine.  At the moment we are
-only able to list RPMs and Debian packages installed, but in future we
-will support other Linux distros and Windows.
-
-E<lt>package_formatE<gt>, if present, describes the packaging
-system used.  Typical values would be C<rpm> and C<deb>.
-
-E<lt>package_managementE<gt>, if present, describes the package
-manager.  Typical values include C<yum>, C<up2date> and C<apt>
-
-E<lt>applicationsE<gt> lists the packages or applications
-installed.
-
- <operatingsystems>
-   <operatingsystem>
-     ...
-     <applications>
-       <application>
-         <name>coreutils</name>
-         <version>8.5</version>
-         <release>1</release>
-       </application>
-
-The version and release fields may not be available for some types
-guests.  Other fields are possible, see
-L<guestfs(3)/guestfs_inspect_list_applications>.
-
-=cut
-
-sub output_applications
-{
-    local $_;
-    my $root = shift;
-
-    my @apps = $g->inspect_list_applications ($root);
-
-    if (@apps) {
-        $xml->startTag ("applications");
-        foreach (@apps) {
-            $xml->startTag ("application");
-            $xml->dataElement (name => $_->{app_name});
-            $xml->dataElement (display_name => $_->{app_display_name})
-                if $_->{app_display_name} ne "";
-            $xml->dataElement (epoch => $_->{app_epoch})
-                if $_->{app_epoch} != 0;
-            $xml->dataElement (version => $_->{app_version})
-                if $_->{app_version} ne "";
-            $xml->dataElement (release => $_->{app_release})
-                if $_->{app_release} ne "";
-            $xml->dataElement (install_path => $_->{app_install_path})
-                if $_->{app_install_path} ne "";
-            $xml->dataElement (publisher => $_->{app_publisher})
-                if $_->{app_publisher} ne "";
-            $xml->dataElement (url => $_->{app_url})
-                if $_->{app_url} ne "";
-            $xml->dataElement (source_package => $_->{app_source_package})
-                if $_->{app_source_package} ne "";
-            $xml->dataElement (summary => $_->{app_summary})
-                if $_->{app_summary} ne "";
-            $xml->dataElement (description => $_->{app_description})
-                if $_->{app_description} ne "";
-            $xml->endTag ("application");
-        }
-        $xml->endTag ("applications");
-    }
-}
-
-# The reverse of device name translation, see
-# BLOCK DEVICE NAMING in guestfs(3).
-sub canonicalize
-{
-    local $_ = shift;
-
-    if (m{^/dev/[hv]d([a-z]\d)$}) {
-        return "/dev/sd$1";
-    }
-    $_;
-}
-
-=head1 USING XPATH
-
-You can use the XPath query language, and/or the xpath tool, in order
-to select parts of the XML.
-
-For example:
-
- $ virt-inspector Guest | xpath //filesystems
- Found 1 nodes:
- -- NODE --
- <filesystems>
-      <filesystem dev="/dev/vg_f13x64/lv_root">
-        <type>ext4</type>
- [etc]
-
- $ virt-inspector Guest | \
-     xpath "string(//filesystem[@dev='/dev/sda1']/type)"
- Query didn't return a nodeset. Value: ext4
-
-=head1 SHELL QUOTING
-
-Libvirt guest names can contain arbitrary characters, some of which
-have meaning to the shell such as C<#> and space.  You may need to
-quote or escape these characters on the command line.  See the shell
-manual page L<sh(1)> for details.
-
-=head1 SEE ALSO
-
-L<guestfs(3)>,
-L<guestfish(1)>,
-L<Sys::Guestfs(3)>,
-L<Sys::Guestfs::Lib(3)>,
-L<Sys::Virt(3)>,
-L<http://www.w3.org/TR/xpath/>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHORS
-
-=over 4
-
-=item *
-
-Richard W.M. Jones L<http://people.redhat.com/~rjones/>
-
-=item *
-
-Matthew Booth L<mbooth@redhat.com>
-
-=back
-
-=head1 COPYRIGHT
-
-Copyright (C) 2010 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., 675 Mass Ave, Cambridge, MA 02139, USA.