X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=inspector%2Fvirt-inspector;h=9e12dc84f252c0b16d2198360d3fc945b7252b06;hp=24501fb32647b5d17c6e68dccf2fa0eee0bc24cf;hb=bf3b9e2e236b4dd2216200993ba39545ad5160bb;hpb=f30210cba89763a32cfbcbfd68ccfcec8d5300e4 diff --git a/inspector/virt-inspector b/inspector/virt-inspector index 24501fb..9e12dc8 100755 --- a/inspector/virt-inspector +++ b/inspector/virt-inspector @@ -146,6 +146,42 @@ if (@roots == 0) { 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 EoperatingsystemsE, and it contains +one or more EoperatingsystemE elements. You would only see +more than one EoperatingsystemE element if the virtual machine +is multi-boot, which is vanishingly rare in real world VMs. + +=head2 EoperatingsystemE + +In the EoperatingsystemE 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: + + + + /dev/sda2 + windows + i386 + windows + Windows 7 Enterprise + 6 + 1 + /Windows + +These fields are derived from the libguestfs inspection API, and +you can find more details in L. + +The ErootE 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); @@ -162,7 +198,7 @@ foreach $root (@roots) { $xml->startTag ("operatingsystem"); # Basic OS fields. - $xml->dataElement (root => $root); + $xml->dataElement (root => canonicalize ($root)); my ($s, $distro, $major_version); $s = $g->inspect_get_type ($root); @@ -201,6 +237,27 @@ foreach $root (@roots) { $xml->endTag ("operatingsystems"); $xml->end (); +=head2 EmountpointsE + +Un*x-like guests typically have multiple filesystems which are mounted +at various mountpoints, and these are described in the +EmountpointsE element which looks like this: + + + + ... + + / + /boot + + +As with ErootE, 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 $_; @@ -210,11 +267,36 @@ sub output_mountpoints $xml->startTag ("mountpoints"); foreach (@$fskeys) { - $xml->dataElement ("mountpoint", $_, dev => $fshash->{$_}); + $xml->dataElement ("mountpoint", $_, + dev => canonicalize ($fshash->{$_})); } $xml->endTag ("mountpoints"); } +=head2 EfilesystemsE + +EfilesystemsE is like EmountpointsE but covers I +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: + + + + ... + + + ext4 + + e6a4db1e-15c2-477b-ac2a-699181c396aa + + +The optional elements within EfilesystemE are the filesystem +type, the label, and the UUID. + +=cut + sub output_filesystems { local $_; @@ -223,8 +305,10 @@ sub output_filesystems $xml->startTag ("filesystems"); my @fses = $g->inspect_get_filesystems ($root); + @fses = sort @fses; foreach (@fses) { - $xml->startTag ("filesystem", dev => $_); + $xml->startTag ("filesystem", + dev => canonicalize ($_)); eval { my $type = $g->vfs_type ($_); @@ -250,6 +334,38 @@ sub output_filesystems $xml->endTag ("filesystems"); } +=head2 EapplicationsE + +The related elements Epackage_formatE, +Epackage_managementE and EapplicationsE 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. + +Epackage_formatE, if present, describes the packaging +system used. Typical values would be C and C. + +Epackage_managementE, if present, describes the package +manager. Typical values include C, C and C + +EapplicationsE lists the packages or applications +installed. + + + + ... + + + coreutils + 8.5 + 1 + + +(The version and release fields may not be available for +some package types). + +=cut + sub output_applications { local $_; @@ -261,14 +377,26 @@ sub output_applications # and package management. my ($package_format, $package_management); if (defined $distro) { - if ($distro eq "debian") { - $package_format = "dpkg"; + if ($distro eq "archlinux") { + $package_format = "pacman"; + $package_management = "pacman"; + } + elsif ($distro eq "debian" || $distro eq "ubuntu") { + $package_format = "deb"; $package_management = "apt"; } - elsif ($distro eq "fedora") { + elsif ($distro eq "fedora" || $distro eq "meego") { $package_format = "rpm"; $package_management = "yum"; } + elsif ($distro eq "gentoo") { + $package_format = "ebuild"; + $package_management = "portage"; + } + elsif ($distro eq "pardus") { + $package_format = "pisi"; + $package_management = "pisi"; + } elsif ($distro =~ /redhat/ || $distro =~ /rhel/) { if ($major_version >= 5) { $package_format = "rpm"; @@ -291,7 +419,9 @@ sub output_applications if ($package_format eq "rpm") { output_applications_rpm ($root); } - # else no we don't. + elsif ($package_format eq "deb") { + output_applications_deb ($root); + } } } @@ -347,6 +477,89 @@ sub output_applications_rpm } } +sub output_applications_deb +{ + local $_; + my $root = shift; + + my @applications; + + eval { + my ($fh, $filename) = tempfile (UNLINK => 1); + my $fddev = "/dev/fd/" . fileno ($fh); + $g->download ("/var/lib/dpkg/status", $fddev); + close $fh or die "close: $!"; + + # Read the file. Each package is separated by a blank line. + open FILE, $filename or die "$filename: $!"; + my ($name, $installed, $version, $release); + while () { + chomp; + if (/^Package: (.*)/) { + $name = $1; + } elsif (/^Status: .*\binstalled\b/) { + $installed = 1; + } elsif (/^Version: (.*?)-(.*)/) { + $version = $1; + $release = $2; + } elsif ($_ eq "") { + if ($installed && + defined $name && defined $version && defined $release) { + push @applications, [ $name, $version, $release ]; + } + $name = undef; + $installed = undef; + $version = undef; + $release = undef; + } + } + close FILE or die "$filename: $!"; + }; + if (!$@ && @applications > 0) { + @applications = sort { $a->[0] cmp $b->[0] } @applications; + $xml->startTag ("applications"); + foreach (@applications) { + $xml->startTag ("application"); + $xml->dataElement (name => $_->[0]); + $xml->dataElement (version => $_->[1]); + $xml->dataElement (release => $_->[2]); + $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 -- + + + ext4 + [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 @@ -361,6 +574,7 @@ L, L, L, L, +L, L. =head1 AUTHORS