tools: Specify format of disks (RHBZ#642934,CVE-2010-3851).
[libguestfs.git] / inspector / virt-inspector
1 #!/usr/bin/perl -w
2 # virt-inspector
3 # Copyright (C) 2009 Red Hat Inc.
4 #
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.
9 #
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.
14 #
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.
18
19 use warnings;
20 use strict;
21
22 use Sys::Guestfs;
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);
26 use Pod::Usage;
27 use Getopt::Long;
28 use Data::Dumper;
29 use XML::Writer;
30 use String::ShellQuote qw(shell_quote);
31 use Locale::TextDomain 'libguestfs';
32
33 # Optional:
34 eval "use YAML::Any;";
35
36 =encoding utf8
37
38 =head1 NAME
39
40 virt-inspector - Display OS version, kernel, drivers, mount points, applications, etc. in a virtual machine
41
42 =head1 SYNOPSIS
43
44  virt-inspector [--connect URI] domname
45
46  virt-inspector guest.img [guest.img ...]
47
48 =head1 DESCRIPTION
49
50 B<virt-inspector> examines a virtual machine and tries to determine
51 the version of the OS, the kernel version, what drivers are installed,
52 whether the virtual machine is fully virtualized (FV) or
53 para-virtualized (PV), what applications are installed and more.
54
55 Virt-inspector can produce output in several formats, including a
56 readable text report, and XML for feeding into other programs.
57
58 In the normal usage, use C<virt-inspector domname> where C<domname> is
59 the libvirt domain (see: C<virsh list --all>).
60
61 You can also run virt-inspector directly on disk images from a single
62 virtual machine.  Use C<virt-inspector guest.img>.  In rare cases a
63 domain has several block devices, in which case you should list them
64 one after another, with the first corresponding to the guest's
65 C</dev/sda>, the second to the guest's C</dev/sdb> and so on.
66
67 Virt-inspector can only inspect and report upon I<one domain at a
68 time>.  To inspect several virtual machines, you have to run
69 virt-inspector several times (for example, from a shell script
70 for-loop).
71
72 Because virt-inspector needs direct access to guest images, it won't
73 normally work over remote libvirt connections.
74
75 =head1 OPTIONS
76
77 =over 4
78
79 =cut
80
81 my $help;
82
83 =item B<--help>
84
85 Display brief help.
86
87 =cut
88
89 my $version;
90
91 =item B<--version>
92
93 Display version number and exit.
94
95 =cut
96
97 my $uri;
98
99 =item B<--connect URI> | B<-c URI>
100
101 If using libvirt, connect to the given I<URI>.  If omitted,
102 then we connect to the default libvirt hypervisor.
103
104 Libvirt is only used if you specify a C<domname> on the
105 command line.  If you specify guest block devices directly,
106 then libvirt is not used at all.
107
108 =cut
109
110 my $format;
111
112 =item B<--format> raw
113
114 Specify the format of disk images given on the command line.  If this
115 is omitted then the format is autodetected from the content of the
116 disk image.
117
118 If disk images are requested from libvirt, then this program asks
119 libvirt for this information.  In this case, the value of the format
120 parameter is ignored.
121
122 If working with untrusted raw-format guest disk images, you should
123 ensure the format is always specified.
124
125 =cut
126
127 my $output = "text";
128
129 =back
130
131 The following options select the output format.  Use only one of them.
132 The default is a readable text report.
133
134 =over 4
135
136 =item B<--text> (default)
137
138 Plain text report.
139
140 =item B<--none>
141
142 Produce no output at all.
143
144 =item B<--xml>
145
146 If you select I<--xml> then you get XML output which can be fed
147 to other programs.
148
149 =item B<--yaml>
150
151 If you select I<--yaml> then you get YAML output which can be fed
152 to other programs.
153
154 =item B<--perl>
155
156 If you select I<--perl> then you get Perl structures output which
157 can be used directly in another Perl program.
158
159 =item B<--fish>
160
161 =item B<--ro-fish>
162
163 If you select I<--fish> then we print a L<guestfish(1)> command
164 line which will automatically mount up the filesystems on the
165 correct mount points.  Try this for example:
166
167  guestfish $(virt-inspector --fish guest.img)
168
169 I<--ro-fish> is the same, but the I<--ro> option is passed to
170 guestfish so that the filesystems are mounted read-only.
171
172 =item B<--query>
173
174 In "query mode" we answer common questions about the guest, such
175 as whether it is fullvirt or needs a Xen hypervisor to run.
176
177 See section I<QUERY MODE> below.
178
179 =cut
180
181 my $windows_registry;
182
183 =item B<--windows-registry>
184
185 This flag is ignored for compatibility with earlier releases of the
186 software.
187
188 In this version, if L<Win::Hivex(3)> is available, then we attempt to
189 parse information out of the Registry for any Windows guest.
190
191 =back
192
193 =cut
194
195 GetOptions ("help|?" => \$help,
196             "version" => \$version,
197             "connect|c=s" => \$uri,
198             "format=s" => \$format,
199             "text" => sub { $output = "text" },
200             "none" => sub { $output = "none" },
201             "xml" => sub { $output = "xml" },
202             "yaml" => sub { $output = "yaml" },
203             "perl" => sub { $output = "perl" },
204             "fish" => sub { $output = "fish" },
205             "guestfish" => sub { $output = "fish" },
206             "ro-fish" => sub { $output = "ro-fish" },
207             "ro-guestfish" => sub { $output = "ro-fish" },
208             "query" => sub { $output = "query" },
209             "windows-registry" => \$windows_registry,
210     ) or pod2usage (2);
211 pod2usage (1) if $help;
212 if ($version) {
213     my $g = Sys::Guestfs->new ();
214     my %h = $g->version ();
215     print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
216     exit
217 }
218 pod2usage (__"virt-inspector: no image or VM names given") if @ARGV == 0;
219
220 my $rw = 0;
221
222 # XXX This is a bug: Originally we intended to open the guest with
223 # rw=>1 in order to tell Sys::Guestfs::Lib that we should disallow
224 # active domains.  However this also has the effect of opening the
225 # disk image in write mode, and in any case we don't use this option
226 # in guestfish any more since we moved all the inspection code into
227 # the core library.  We should drop the fish output modes completely.
228 $rw = 1 if $output eq "fish";
229
230 my $g;
231 my @images;
232 if ($uri) {
233     my ($conn, $dom);
234     ($g, $conn, $dom, @images) =
235         open_guest (\@ARGV, rw => $rw, address => $uri, format => $format);
236 } else {
237     my ($conn, $dom);
238     ($g, $conn, $dom, @images) =
239         open_guest (\@ARGV, rw => $rw, format => $format);
240 }
241
242 $g->launch ();
243
244 =head1 OUTPUT FORMAT
245
246  Operating system(s)
247  -------------------
248  Linux (distro + version)
249  Windows (version)
250     |
251     |
252     +--- Filesystems ---------- Installed apps --- Kernel & drivers
253          -----------            --------------     ----------------
254          mount point => device  List of apps       Extra information
255          mount point => device  and versions       about kernel(s)
256               ...                                  and drivers
257          swap => swap device
258          (plus lots of extra information
259          about each filesystem)
260
261 The output of virt-inspector is a complex two-level data structure.
262
263 At the top level is a list of the operating systems installed on the
264 guest.  (For the vast majority of guests, only a single OS is
265 installed.)  The data returned for the OS includes the name (Linux,
266 Windows), the distribution and version.
267
268 The diagram above shows what we return for each OS.
269
270 With the I<--xml> option the output is mapped into an XML document.
271 There is a RELAX-NG schema for this XML in the file
272 I<virt-inspector.rng> which normally ships with virt-inspector, or can
273 be found in the source.
274
275 With the I<--fish> or I<--ro-fish> option the mount points are mapped to
276 L<guestfish(1)> command line parameters, so that you can go in
277 afterwards and inspect the guest with everything mounted in the
278 right place.  For example:
279
280  guestfish $(virt-inspector --ro-fish guest.img)
281  ==> guestfish --ro -a guest.img -m /dev/VG/LV:/ -m /dev/sda1:/boot
282
283 =cut
284
285 # List of possible filesystems.
286 my @partitions = get_partitions ($g);
287
288 # Now query each one to build up a picture of what's in it.
289 my %fses =
290     inspect_all_partitions ($g, \@partitions);
291
292 #print "fses -----------\n";
293 #print Dumper(\%fses);
294
295 my $oses = inspect_operating_systems ($g, \%fses);
296
297 #print "oses -----------\n";
298 #print Dumper($oses);
299
300 # Mount up the disks so we can check for applications
301 # and kernels.  Skip this if the output is "*fish" because
302 # we don't need to know.
303
304 if ($output !~ /.*fish$/) {
305     my $root_dev;
306     foreach $root_dev (sort keys %$oses) {
307         my $os = $oses->{$root_dev};
308         mount_operating_system ($g, $os);
309         inspect_in_detail ($g, $os);
310         $g->umount_all ();
311     }
312 }
313
314 #----------------------------------------------------------------------
315 # Output.
316
317 if ($output eq "fish" || $output eq "ro-fish") {
318     my @osdevs = keys %$oses;
319     # This only works if there is a single OS.
320     die __"--fish output is only possible with a single OS\n" if @osdevs != 1;
321
322     my $root_dev = $osdevs[0];
323
324     if ($output eq "ro-fish") {
325         print "--ro ";
326     }
327
328     foreach (@images) {
329         unless (defined $_->[1]) {
330             printf "-a %s ", shell_quote ($_->[0]);
331         } else {
332             printf "--format %s -a %s ",
333               shell_quote ($_->[1]), shell_quote ($_->[0]);
334         }
335     }
336
337     my $mounts = $oses->{$root_dev}->{mounts};
338     # Have to mount / first.  Luckily '/' is early in the ASCII
339     # character set, so this should be OK.
340     foreach (sort keys %$mounts) {
341         if ($_ ne "swap" && $_ ne "none") {
342             printf "-m %s ", shell_quote ("$mounts->{$_}:$_");
343         }
344     }
345     print "\n"
346 }
347
348 # Perl output.
349 elsif ($output eq "perl") {
350     print Dumper(%$oses);
351 }
352
353 # YAML output
354 elsif ($output eq "yaml") {
355     die __"virt-inspector: no YAML support, try installing perl-YAML or libyaml-perl\n"
356         unless exists $INC{"YAML/Any.pm"};
357
358     print Dump(%$oses);
359 }
360
361 # Plain text output (the default).
362 elsif ($output eq "text") {
363     output_text ();
364 }
365
366 # XML output.
367 elsif ($output eq "xml") {
368     output_xml ();
369 }
370
371 # Query mode.
372 elsif ($output eq "query") {
373     output_query ();
374 }
375
376 sub output_text
377 {
378     output_text_os ($oses->{$_}) foreach sort keys %$oses;
379 }
380
381 sub output_text_os
382 {
383     my $os = shift;
384
385     print $os->{os}, " " if exists $os->{os};
386     print $os->{distro}, " " if exists $os->{distro};
387     print $os->{arch}, " " if exists $os->{arch};
388     print $os->{major_version} if exists $os->{major_version};
389     print ".", $os->{minor_version} if exists $os->{minor_version};
390     print " (", $os->{product_name}, ")" if exists $os->{product_name};
391     print " ";
392     print "on ", $os->{root_device}, ":\n";
393
394     print __"  Mountpoints:\n";
395     my $mounts = $os->{mounts};
396     foreach (sort keys %$mounts) {
397         printf "    %-30s %s\n", $mounts->{$_}, $_
398     }
399
400     print __"  Filesystems:\n";
401     my $filesystems = $os->{filesystems};
402     foreach (sort keys %$filesystems) {
403         print "    $_:\n";
404         print "      label: $filesystems->{$_}{label}\n"
405             if exists $filesystems->{$_}{label};
406         print "      UUID: $filesystems->{$_}{uuid}\n"
407             if exists $filesystems->{$_}{uuid};
408         print "      type: $filesystems->{$_}{fstype}\n"
409             if exists $filesystems->{$_}{fstype};
410         print "      content: $filesystems->{$_}{content}\n"
411             if exists $filesystems->{$_}{content};
412     }
413
414     if (exists $os->{modprobe_aliases}) {
415         my %aliases = %{$os->{modprobe_aliases}};
416         my @keys = sort keys %aliases;
417         if (@keys) {
418             print __"  Modprobe aliases:\n";
419             foreach (@keys) {
420                 printf "    %-30s %s\n", $_, $aliases{$_}->{modulename}
421             }
422         }
423     }
424
425     if (exists $os->{initrd_modules}) {
426         my %modvers = %{$os->{initrd_modules}};
427         my @keys = sort keys %modvers;
428         if (@keys) {
429             print __"  Initrd modules:\n";
430             foreach (@keys) {
431                 my @modules = @{$modvers{$_}};
432                 print "    $_:\n";
433                 print "      $_\n" foreach @modules;
434             }
435         }
436     }
437
438     print __"  Applications:\n";
439     my @apps =  @{$os->{apps}};
440     foreach (@apps) {
441         print "    $_->{name} $_->{version}\n"
442     }
443
444     if ($os->{kernels}) {
445         print __"  Kernels:\n";
446         my @kernels = @{$os->{kernels}};
447         foreach (@kernels) {
448             print "    $_->{version} ($_->{arch})\n";
449             my @modules = @{$_->{modules}};
450             foreach (@modules) {
451                 print "      $_\n";
452             }
453         }
454     }
455
456     if (exists $os->{root}->{registry}) {
457         print __"  Windows Registry entries:\n";
458         # These are just lumps of text - dump them out.
459         foreach (@{$os->{root}->{registry}}) {
460             print "$_\n";
461         }
462     }
463 }
464
465 sub output_xml
466 {
467     my $xml = new XML::Writer(DATA_MODE => 1, DATA_INDENT => 2);
468
469     $xml->startTag("operatingsystems");
470     output_xml_os ($oses->{$_}, $xml) foreach sort keys %$oses;
471     $xml->endTag("operatingsystems");
472
473     $xml->end();
474 }
475
476 sub output_xml_os
477 {
478     my ($os, $xml) = @_;
479
480     $xml->startTag("operatingsystem");
481
482     foreach ( [ "name" => "os" ],
483               [ "distro" => "distro" ],
484               [ "product_name" => "product_name" ],
485               [ "arch" => "arch" ],
486               [ "major_version" => "major_version" ],
487               [ "minor_version" => "minor_version" ],
488               [ "package_format" => "package_format" ],
489               [ "package_management" => "package_management" ],
490               [ "root" => "root_device" ] ) {
491         $xml->dataElement($_->[0], $os->{$_->[1]}) if exists $os->{$_->[1]};
492     }
493
494     $xml->startTag("mountpoints");
495     my $mounts = $os->{mounts};
496     foreach (sort keys %$mounts) {
497         $xml->dataElement("mountpoint", $_, "dev" => $mounts->{$_});
498     }
499     $xml->endTag("mountpoints");
500
501     $xml->startTag("filesystems");
502     my $filesystems = $os->{filesystems};
503     foreach (sort keys %$filesystems) {
504         $xml->startTag("filesystem", "dev" => $_);
505
506         foreach my $field ( [ "label" => "label" ],
507                             [ "uuid" => "uuid" ],
508                             [ "type" => "fstype" ],
509                             [ "content" => "content" ],
510                             [ "spec" => "spec" ] ) {
511             $xml->dataElement($field->[0], $filesystems->{$_}{$field->[1]})
512                 if exists $filesystems->{$_}{$field->[1]};
513         }
514
515         $xml->endTag("filesystem");
516     }
517     $xml->endTag("filesystems");
518
519     if (exists $os->{modprobe_aliases}) {
520         my %aliases = %{$os->{modprobe_aliases}};
521         my @keys = sort keys %aliases;
522         if (@keys) {
523             $xml->startTag("modprobealiases");
524             foreach (@keys) {
525                 $xml->startTag("alias", "device" => $_);
526
527                 foreach my $field ( [ "modulename" => "modulename" ],
528                                     [ "augeas" => "augeas" ],
529                                     [ "file" => "file" ] ) {
530                     $xml->dataElement($field->[0], $aliases{$_}->{$field->[1]});
531                 }
532
533                 $xml->endTag("alias");
534             }
535             $xml->endTag("modprobealiases");
536         }
537     }
538
539     if (exists $os->{initrd_modules}) {
540         my %modvers = %{$os->{initrd_modules}};
541         my @keys = sort keys %modvers;
542         if (@keys) {
543             $xml->startTag("initrds");
544             foreach (@keys) {
545                 my @modules = @{$modvers{$_}};
546                 $xml->startTag("initrd", "version" => $_);
547                 $xml->dataElement("module", $_) foreach @modules;
548                 $xml->endTag("initrd");
549             }
550             $xml->endTag("initrds");
551         }
552     }
553
554     $xml->startTag("applications");
555     my @apps =  @{$os->{apps}};
556     foreach (@apps) {
557         $xml->startTag("application");
558         $xml->dataElement("name", $_->{name});
559         $xml->dataElement("epoch", $_->{epoch}) if defined $_->{epoch};
560         $xml->dataElement("version", $_->{version});
561         $xml->dataElement("release", $_->{release});
562         $xml->dataElement("arch", $_->{arch});
563         $xml->endTag("application");
564     }
565     $xml->endTag("applications");
566
567     if(defined($os->{boot}) && defined($os->{boot}->{configs})) {
568         my $default = $os->{boot}->{default};
569         my $configs = $os->{boot}->{configs};
570
571         $xml->startTag("boot");
572         for(my $i = 0; $i < scalar(@$configs); $i++) {
573             my $config = $configs->[$i];
574
575             my @attrs = ();
576             push(@attrs, ("default" => 1)) if($default == $i);
577             $xml->startTag("config", @attrs);
578             $xml->dataElement("title", $config->{title});
579             $xml->dataElement("kernel", $config->{kernel}->{version})
580                 if(defined($config->{kernel}));
581             $xml->dataElement("cmdline", $config->{cmdline})
582                 if(defined($config->{cmdline}));
583             $xml->endTag("config");
584         }
585         $xml->endTag("boot");
586     }
587
588     if ($os->{kernels}) {
589         $xml->startTag("kernels");
590         my @kernels = @{$os->{kernels}};
591         foreach (@kernels) {
592             $xml->startTag("kernel",
593                            "version" => $_->{version},
594                            "arch" => $_->{arch});
595             $xml->startTag("modules");
596             my @modules = @{$_->{modules}};
597             foreach (@modules) {
598                 $xml->dataElement("module", $_);
599             }
600             $xml->endTag("modules");
601             $xml->dataElement("path", $_->{path}) if(defined($_->{path}));
602             $xml->dataElement("package", $_->{package}) if(defined($_->{package}));
603             $xml->endTag("kernel");
604         }
605         $xml->endTag("kernels");
606     }
607
608     if (exists $os->{root}->{registry}) {
609         $xml->startTag("windowsregistryentries");
610         # These are just lumps of text - dump them out.
611         foreach (@{$os->{root}->{registry}}) {
612             $xml->dataElement("windowsregistryentry", $_);
613         }
614         $xml->endTag("windowsregistryentries");
615     }
616
617     $xml->endTag("operatingsystem");
618 }
619
620 =head1 QUERY MODE
621
622 When you use C<virt-inspector --query>, the output is a series of
623 lines of the form:
624
625  windows=no
626  linux=yes
627  fullvirt=yes
628  xen_pv_drivers=no
629
630 (each answer is usually C<yes> or C<no>, or the line is completely
631 missing if we could not determine the answer at all).
632
633 If the guest is multiboot, you can get apparently conflicting answers
634 (eg. C<windows=yes> and C<linux=yes>, or a guest which is both
635 fullvirt and has a Xen PV kernel).  This is normal, and just means
636 that the guest can do both things, although it might require operator
637 intervention such as selecting a boot option when the guest is
638 booting.
639
640 This section describes the full range of answers possible.
641
642 =over 4
643
644 =cut
645
646 sub output_query
647 {
648     output_query_windows ();
649     output_query_linux ();
650     output_query_rhel ();
651     output_query_fedora ();
652     output_query_debian ();
653     output_query_fullvirt ();
654     output_query_xen_domU_kernel ();
655     output_query_xen_pv_drivers ();
656     output_query_virtio_drivers ();
657     output_query_kernel_arch ();
658     output_query_userspace_arch ();
659 }
660
661 =item windows=(yes|no)
662
663 Answer C<yes> if Microsoft Windows is installed in the guest.
664
665 =cut
666
667 sub output_query_windows
668 {
669     my $windows = "no";
670     foreach my $os (keys %$oses) {
671         $windows="yes" if $oses->{$os}->{os} eq "windows";
672     }
673     print "windows=$windows\n";
674 }
675
676 =item linux=(yes|no)
677
678 Answer C<yes> if a Linux kernel is installed in the guest.
679
680 =cut
681
682 sub output_query_linux
683 {
684     my $linux = "no";
685     foreach my $os (keys %$oses) {
686         $linux="yes" if $oses->{$os}->{os} eq "linux";
687     }
688     print "linux=$linux\n";
689 }
690
691 =item rhel=(yes|no)
692
693 Answer C<yes> if the guest contains Red Hat Enterprise Linux.
694
695 =cut
696
697 sub output_query_rhel
698 {
699     my $rhel = "no";
700     foreach my $os (keys %$oses) {
701         $rhel="yes" if ($oses->{$os}->{os} eq "linux" &&
702                         $oses->{$os}->{distro} eq "rhel");
703     }
704     print "rhel=$rhel\n";
705 }
706
707 =item fedora=(yes|no)
708
709 Answer C<yes> if the guest contains the Fedora Linux distribution.
710
711 =cut
712
713 sub output_query_fedora
714 {
715     my $fedora = "no";
716     foreach my $os (keys %$oses) {
717         $fedora="yes" if $oses->{$os}->{os} eq "linux" && $oses->{$os}->{distro} eq "fedora";
718     }
719     print "fedora=$fedora\n";
720 }
721
722 =item debian=(yes|no)
723
724 Answer C<yes> if the guest contains the Debian Linux distribution.
725
726 =cut
727
728 sub output_query_debian
729 {
730     my $debian = "no";
731     foreach my $os (keys %$oses) {
732         $debian="yes" if $oses->{$os}->{os} eq "linux" && $oses->{$os}->{distro} eq "debian";
733     }
734     print "debian=$debian\n";
735 }
736
737 =item fullvirt=(yes|no)
738
739 Answer C<yes> if there is at least one operating system kernel
740 installed in the guest which runs fully virtualized.  Such a guest
741 would require a hypervisor which supports full system virtualization.
742
743 =cut
744
745 sub output_query_fullvirt
746 {
747     # The assumption is full-virt, unless all installed kernels
748     # are identified as paravirt.
749     # XXX Fails on Windows guests.
750     foreach my $os (keys %$oses) {
751         foreach my $kernel (@{$oses->{$os}->{kernels}}) {
752             my $is_pv = $kernel->{version} =~ m/xen/;
753             unless ($is_pv) {
754                 print "fullvirt=yes\n";
755                 return;
756             }
757         }
758     }
759     print "fullvirt=no\n";
760 }
761
762 =item xen_domU_kernel=(yes|no)
763
764 Answer C<yes> if there is at least one Linux kernel installed in
765 the guest which is compiled as a Xen DomU (a Xen paravirtualized
766 guest).
767
768 =cut
769
770 sub output_query_xen_domU_kernel
771 {
772     foreach my $os (keys %$oses) {
773         foreach my $kernel (@{$oses->{$os}->{kernels}}) {
774             my $is_xen = $kernel->{version} =~ m/xen/;
775             if ($is_xen) {
776                 print "xen_domU_kernel=yes\n";
777                 return;
778             }
779         }
780     }
781     print "xen_domU_kernel=no\n";
782 }
783
784 =item xen_pv_drivers=(yes|no)
785
786 Answer C<yes> if the guest has Xen paravirtualized drivers installed
787 (usually the kernel itself will be fully virtualized, but the PV
788 drivers have been installed by the administrator for performance
789 reasons).
790
791 =cut
792
793 sub output_query_xen_pv_drivers
794 {
795     foreach my $os (keys %$oses) {
796         foreach my $kernel (@{$oses->{$os}->{kernels}}) {
797             foreach my $module (@{$kernel->{modules}}) {
798                 if ($module =~ m/xen-/) {
799                     print "xen_pv_drivers=yes\n";
800                     return;
801                 }
802             }
803         }
804     }
805     print "xen_pv_drivers=no\n";
806 }
807
808 =item virtio_drivers=(yes|no)
809
810 Answer C<yes> if the guest has virtio paravirtualized drivers
811 installed.  Virtio drivers are commonly used to improve the
812 performance of KVM.
813
814 =cut
815
816 sub output_query_virtio_drivers
817 {
818     foreach my $os (keys %$oses) {
819         foreach my $kernel (@{$oses->{$os}->{kernels}}) {
820             foreach my $module (@{$kernel->{modules}}) {
821                 if ($module =~ m/virtio_/) {
822                     print "virtio_drivers=yes\n";
823                     return;
824                 }
825             }
826         }
827     }
828     print "virtio_drivers=no\n";
829 }
830
831 =item userspace_arch=(x86_64|...)
832
833 Print the architecture of userspace.
834
835 NB. For multi-boot VMs this can print several lines.
836
837 =cut
838
839 sub output_query_userspace_arch
840 {
841     my %arches;
842
843     foreach my $os (keys %$oses) {
844         $arches{$oses->{$os}->{arch}} = 1 if exists $oses->{$os}->{arch};
845     }
846
847     foreach (sort keys %arches) {
848         print "userspace_arch=$_\n";
849     }
850 }
851
852 =item kernel_arch=(x86_64|...)
853
854 Print the architecture of the kernel.
855
856 NB. For multi-boot VMs this can print several lines.
857
858 =cut
859
860 sub output_query_kernel_arch
861 {
862     my %arches;
863
864     foreach my $os (keys %$oses) {
865         foreach my $kernel (@{$oses->{$os}->{kernels}}) {
866             $arches{$kernel->{arch}} = 1 if exists $kernel->{arch};
867         }
868     }
869
870     foreach (sort keys %arches) {
871         print "kernel_arch=$_\n";
872     }
873 }
874
875 =back
876
877 =head1 SHELL QUOTING
878
879 Libvirt guest names can contain arbitrary characters, some of which
880 have meaning to the shell such as C<#> and space.  You may need to
881 quote or escape these characters on the command line.  See the shell
882 manual page L<sh(1)> for details.
883
884 =head1 SEE ALSO
885
886 L<guestfs(3)>,
887 L<guestfish(1)>,
888 L<Sys::Guestfs(3)>,
889 L<Sys::Guestfs::Lib(3)>,
890 L<Sys::Virt(3)>,
891 L<http://libguestfs.org/>.
892
893 =head1 AUTHORS
894
895 Richard W.M. Jones L<http://people.redhat.com/~rjones/>
896
897 Matthew Booth L<mbooth@redhat.com>
898
899 =head1 COPYRIGHT
900
901 Copyright (C) 2009 Red Hat Inc.
902
903 This program is free software; you can redistribute it and/or modify
904 it under the terms of the GNU General Public License as published by
905 the Free Software Foundation; either version 2 of the License, or
906 (at your option) any later version.
907
908 This program is distributed in the hope that it will be useful,
909 but WITHOUT ANY WARRANTY; without even the implied warranty of
910 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
911 GNU General Public License for more details.
912
913 You should have received a copy of the GNU General Public License
914 along with this program; if not, write to the Free Software
915 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.