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);
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) {
# Basic OS fields.
$xml->dataElement (root => canonicalize ($root));
- my ($s, $distro, $major_version);
+ 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";
- $distro = $g->inspect_get_distro ($root);
- $xml->dataElement (distro => $distro) if $distro 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";
- $major_version = $g->inspect_get_major_version ($root);
- $xml->dataElement (major_version => $major_version);
+ $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);
output_filesystems ($root);
# Package format / management and applications.
- output_applications ($root, $distro, $major_version);
+ output_applications ($root);
$xml->endTag("operatingsystem");
$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 $_;
$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 $_;
$xml->startTag ("filesystems");
my @fses = $g->inspect_get_filesystems ($root);
+ @fses = sort @fses;
foreach (@fses) {
$xml->startTag ("filesystem",
dev => canonicalize ($_));
$xml->endTag ("filesystems");
}
-sub output_applications
-{
- local $_;
- my $root = shift;
- my $distro = shift;
- my $major_version = shift;
-
- # Based on the distro, take a guess at the package format
- # and package management.
- my ($package_format, $package_management);
- if (defined $distro) {
- if ($distro eq "debian") {
- $package_format = "dpkg";
- $package_management = "apt";
- }
- elsif ($distro eq "fedora") {
- $package_format = "rpm";
- $package_management = "yum";
- }
- elsif ($distro =~ /redhat/ || $distro =~ /rhel/) {
- if ($major_version >= 5) {
- $package_format = "rpm";
- $package_management = "yum";
- } else {
- $package_format = "rpm";
- $package_management = "up2date";
- }
- }
- # else unknown.
- }
+=head2 E<lt>applicationsE<gt>
- $xml->dataElement (package_format => $package_format)
- if defined $package_format;
- $xml->dataElement (package_management => $package_management)
- if defined $package_management;
+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.
- # Do we know how to get a list of applications?
- if (defined $package_format) {
- if ($package_format eq "rpm") {
- output_applications_rpm ($root);
- }
- # else no we don't.
- }
-}
+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.
-sub output_applications_rpm
+ <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;
- # Previous virt-inspector ran the 'rpm' program from the guest.
- # This is insecure, and unnecessary because we can get the same
- # information directly from the RPM database.
-
- my @applications;
+ my @apps = $g->inspect_list_applications ($root);
- eval {
- my ($fh, $filename) = tempfile (UNLINK => 1);
- my $fddev = "/dev/fd/" . fileno ($fh);
- $g->download ("/var/lib/rpm/Name", $fddev);
- close $fh or die "close: $!";
-
- # Read the database with the Berkeley DB dump tool.
- my $cmd = "db_dump -p '$filename'";
- open PIPE, "$cmd |" or die "close: $!";
- while (<PIPE>) {
- chomp;
- last if /^HEADER=END$/;
- }
- while (<PIPE>) {
- chomp;
- last if /^DATA=END$/;
-
- # First character on each data line is a space.
- if (length $_ > 0 && substr ($_, 0, 1) eq ' ') {
- $_ = substr ($_, 1);
- }
- # Name should never contain non-printable chars.
- die "name contains non-printable chars" if /\\/;
- push @applications, $_;
-
- $_ = <PIPE>; # discard value
- }
- close PIPE or die "close: $!";
- };
- if (!$@ && @applications > 0) {
- @applications = sort @applications;
+ if (@apps) {
$xml->startTag ("applications");
- foreach (@applications) {
+ foreach (@apps) {
$xml->startTag ("application");
- $xml->dataElement (name => $_);
+ $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");
$_;
}
+=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
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