2 # Copyright (C) 2009 Red Hat Inc.
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2 of the License, or (at your option) any later version.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 package Sys::Guestfs::Lib;
26 eval "use Sys::Virt;";
27 eval "use XML::XPath;";
28 eval "use XML::XPath::XMLParser;";
34 Sys::Guestfs::Lib - Useful functions for using libguestfs from Perl
38 use Sys::Guestfs::Lib qw(open_guest inspect_all_partitions ...);
40 $g = open_guest ($name);
42 %fses = inspect_all_partitions ($g, \@partitions);
44 (and many more calls - see the rest of this manpage)
48 C<Sys::Guestfs::Lib> is an extra library of useful functions for using
49 the libguestfs API from Perl. It also provides tighter integration
52 The basic libguestfs API is not covered by this manpage. Please refer
53 instead to L<Sys::Guestfs(3)> and L<guestfs(3)>. The libvirt API is
54 also not covered. For that, see L<Sys::Virt(3)>.
56 =head1 BASIC FUNCTIONS
62 use vars qw(@EXPORT_OK @ISA);
65 @EXPORT_OK = qw(open_guest get_partitions resolve_windows_path
66 inspect_all_partitions inspect_partition
67 inspect_operating_systems mount_operating_system inspect_in_detail);
71 $g = open_guest ($name);
73 $g = open_guest ($name, rw => 1, ...);
75 $g = open_guest ($name, address => $uri, ...);
77 $g = open_guest ([$img1, $img2, ...], address => $uri, ...);
79 ($g, $conn, $dom) = open_guest ($name);
81 This function opens a libguestfs handle for either the libvirt domain
82 called C<$name>, or the disk image called C<$name>. Any disk images
83 found through libvirt or specified explicitly are attached to the
86 The C<Sys::Guestfs> handle C<$g> is returned, or if there was an error
87 it throws an exception. To catch errors, wrap the call in an eval
90 The first parameter is either a string referring to a libvirt domain
91 or a disk image, or (if a guest has several disk images) an arrayref
92 C<[$img1, $img2, ...]>.
94 The handle is I<read-only> by default. Use the optional parameter
95 C<rw =E<gt> 1> to open a read-write handle. However if you open a
96 read-write handle, this function will refuse to use active libvirt
99 The handle is still in the config state when it is returned, so you
100 have to call C<$g-E<gt>launch ()> and C<$g-E<gt>wait_ready>.
102 The optional C<address> parameter can be added to specify the libvirt
103 URI. In addition, L<Sys::Virt(3)> lists other parameters which are
104 passed through to C<Sys::Virt-E<gt>new> unchanged.
106 The implicit libvirt handle is closed after this function, I<unless>
107 you call the function in C<wantarray> context, in which case the
108 function returns a tuple of: the open libguestfs handle, the open
109 libvirt handle, and the open libvirt domain handle. (This is useful
110 if you want to do other things like pulling the XML description of the
111 guest). Note that if this is a straight disk image, then C<$conn> and
112 C<$dom> will be C<undef>.
114 If the C<Sys::Virt> module is not available, then libvirt is bypassed,
115 and this function can only open disk images.
125 my $readwrite = $params{rw};
128 if (ref ($first) eq "ARRAY") {
130 } elsif (ref ($first) eq "SCALAR") {
133 die "open_guest: first parameter must be a string or an arrayref"
140 die "guest image $_ does not exist or is not readable"
144 die "open_guest: no libvirt support (install Sys::Virt, XML::XPath and XML::XPath::XMLParser)"
145 unless exists $INC{"Sys/Virt.pm"} &&
146 exists $INC{"XML/XPath.pm"} &&
147 exists $INC{"XML/XPath/XMLParser.pm"};
149 die "open_guest: too many domains listed on command line"
152 $conn = Sys::Virt->new (readonly => 1, @_);
153 die "open_guest: cannot connect to libvirt" unless $conn;
155 my @doms = $conn->list_defined_domains ();
156 my $isitinactive = "an inactive libvirt domain";
157 unless ($readwrite) {
158 # In the case where we want read-only access to a domain,
159 # allow the user to specify an active domain too.
160 push @doms, $conn->list_domains ();
161 $isitinactive = "a libvirt domain";
164 if ($_->get_name () eq $images[0]) {
169 die "$images[0] is not the name of $isitinactive\n" unless $dom;
171 # Get the names of the image(s).
172 my $xml = $dom->get_xml_description ();
174 my $p = XML::XPath->new (xml => $xml);
175 my @disks = $p->findnodes ('//devices/disk/source/@dev');
176 @images = map { $_->getData } @disks;
179 # We've now got the list of @images, so feed them to libguestfs.
180 my $g = Sys::Guestfs->new ();
185 $g->add_drive_ro ($_);
189 return wantarray ? ($g, $conn, $dom) : $g
192 =head2 get_partitions
194 @partitions = get_partitions ($g);
196 This function takes an open libguestfs handle C<$g> and returns all
197 partitions and logical volumes found on it.
199 What is returned is everything that could contain a filesystem (or
200 swap). Physical volumes are excluded from the list, and so are any
201 devices which are partitioned (eg. C</dev/sda> would not be returned
202 if C</dev/sda1> exists).
210 my @partitions = $g->list_partitions ();
211 my @pvs = $g->pvs ();
212 @partitions = grep { ! _is_pv ($_, @pvs) } @partitions;
214 my @lvs = $g->lvs ();
216 return sort (@lvs, @partitions);
224 return 1 if $_ eq $t;
229 =head2 resolve_windows_path
231 $path = resolve_windows_path ($g, $path);
233 $path = resolve_windows_path ($g, "/windows/system");
234 ==> "/WINDOWS/System"
235 or undef if no path exists
237 This function, which is specific to FAT/NTFS filesystems (ie. Windows
238 guests), lets you look up a case insensitive C<$path> in the
239 filesystem and returns the true, case sensitive path as required by
240 the underlying kernel or NTFS-3g driver.
242 If C<$path> does not exist then this function returns C<undef>.
244 The C<$path> parameter must begin with C</> character and be separated
245 by C</> characters. Do not use C<\>, drive names, etc.
249 sub resolve_windows_path
255 if (substr ($path, 0, 1) ne "/") {
256 warn "resolve_windows_path: path must start with a / character";
260 my @elems = split (/\//, $path);
263 # Start reconstructing the path at the top.
266 foreach my $dir (@elems) {
268 foreach ($g->ls ($path)) {
269 if (lc ($_) eq lc ($dir)) {
279 return undef unless $found;
285 =head1 OPERATING SYSTEM INSPECTION FUNCTIONS
287 The functions in this section can be used to inspect the operating
288 system(s) available inside a virtual machine image. For example, you
289 can find out if the VM is Linux or Windows, how the partitions are
290 meant to be mounted, and what applications are installed.
292 If you just want a simple command-line interface to this
293 functionality, use the L<virt-inspector(1)> tool. The documentation
294 below covers the case where you want to access this functionality from
297 Once you have the list of partitions (from C<get_partitions>) there
298 are several steps involved:
304 Look at each partition separately and find out what is on it.
306 The information you get back includes whether the partition contains a
307 filesystem or swapspace, what sort of filesystem (eg. ext3, ntfs), and
308 a first pass guess at the content of the filesystem (eg. Linux boot,
311 The result of this step is a C<%fs> hash of information, one hash for
314 See: C<inspect_partition>, C<inspect_all_partitions>
318 Work out the relationship between partitions.
320 In this step we work out how partitions are related to each other. In
321 the case of a single-boot VM, we work out how the partitions are
322 mounted in respect of each other (eg. C</dev/sda1> is mounted as
323 C</boot>). In the case of a multi-boot VM where there are several
324 roots, we may identify several operating system roots, and mountpoints
327 The result of this step is a single hash called C<%oses> which is
328 described in more detail below, but at the top level looks like:
331 '/dev/VG/Root1' => \%os1,
332 '/dev/VG/Root2' => \%os2,
338 '/' => '/dev/VG/Root1',
339 '/boot' => '/dev/sda1',
344 (example shows a multi-boot VM containing two root partitions).
346 See: C<inspect_operating_systems>
352 Previous to this point we've essentially been looking at each
353 partition in isolation. Now we construct a true guest filesystem by
354 mounting up all of the disks. Only once everything is mounted up can
355 we run commands in the OS context to do more detailed inspection.
357 See: C<mount_operating_system>
361 Check for kernels and applications.
363 This step now does more detailed inspection, where we can look for
364 kernels, applications and more installed in the guest.
366 The result of this is an enhanced C<%os> hash.
368 See: C<inspect_in_detail>
374 This library does not contain functions for generating output based on
375 the analysis steps above. Use a command line tool such as
376 L<virt-inspector(1)> to get useful output.
380 =head2 inspect_all_partitions
382 %fses = inspect_all_partitions ($g, \@partitions);
384 %fses = inspect_all_partitions ($g, \@partitions, use_windows_registry => 1);
386 This calls C<inspect_partition> for each partition in the list
389 The result is a hash which maps partition name to C<\%fs> hashref.
391 The contents of the C<%fs> hash and the meaning of the
392 C<use_windows_registry> flag are explained below.
396 sub inspect_all_partitions
402 return map { $_ => inspect_partition ($g, $_, @_) } @parts;
405 =head2 inspect_partition
407 \%fs = inspect_partition ($g, $partition);
409 \%fs = inspect_partition ($g, $partition, use_windows_registry => 1);
411 This function inspects the device named C<$partition> in isolation and
412 tries to determine what it is. It returns information such as whether
413 the partition is formatted, and with what, whether it is mountable,
414 and what it appears to contain (eg. a Windows root, or a Linux /usr).
416 If C<use_windows_registry> is set to 1, then we will try to download
417 and parse the content of the Windows registry (for Windows root
418 devices). However since this is an expensive and error-prone
419 operation, we don't do this by default. It also requires the external
420 program C<reged>, patched to remove numerous crashing bugs in the
423 The returned value is a hashref C<\%fs> which may contain the
424 following top-level keys (any key can be missing):
430 Filesystem type, eg. "ext2" or "ntfs"
434 Apparent filesystem OS, eg. "linux" or "windows"
438 If set, the partition is a swap partition.
450 If set, the partition could be mounted by libguestfs.
454 Filesystem content, if we could determine it. One of: "linux-grub",
455 "linux-root", "linux-usrlocal", "linux-usr", "windows-root".
459 (For Linux root partitions only).
460 Operating system distribution. One of: "fedora", "redhat",
465 (For root partitions only).
466 Operating system version.
470 (For Linux root partitions only).
471 The contents of the C</etc/fstab> file.
475 (For Windows root partitions only).
476 The contents of the C</boot.ini> (NTLDR) file.
480 The value is an arrayref, which is a list of Windows registry
481 file contents, in Windows C<.REG> format.
487 sub inspect_partition
491 my $dev = shift; # LV or partition name.
494 my $use_windows_registry = $params{use_windows_registry};
496 my %r; # Result hash.
498 # First try 'file(1)' on it.
499 my $file = $g->file ($dev);
500 if ($file =~ /ext2 filesystem data/) {
503 } elsif ($file =~ /ext3 filesystem data/) {
506 } elsif ($file =~ /ext4 filesystem data/) {
509 } elsif ($file =~ m{Linux/i386 swap file}) {
515 # If it's ext2/3/4, then we want the UUID and label.
516 if (exists $r{fstype} && $r{fstype} =~ /^ext/) {
517 $r{uuid} = $g->get_e2uuid ($dev);
518 $r{label} = $g->get_e2label ($dev);
521 # Try mounting it, fnarrr.
523 $r{is_mountable} = 1;
524 eval { $g->mount_ro ($dev, "/") };
526 # It's not mountable, probably empty or some format
527 # we don't understand.
528 $r{is_mountable} = 0;
533 if ($g->is_file ("/grub/menu.lst") ||
534 $g->is_file ("/grub/grub.conf")) {
535 $r{content} = "linux-grub";
536 _check_grub ($g, \%r);
541 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
542 $g->is_file ("/etc/fstab")) {
543 $r{content} = "linux-root";
545 _check_linux_root ($g, \%r);
550 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
551 $g->is_dir ("/share") && !$g->exists ("/local") &&
552 !$g->is_file ("/etc/fstab")) {
553 $r{content} = "linux-usrlocal";
558 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
559 $g->is_dir ("/share") && $g->exists ("/local") &&
560 !$g->is_file ("/etc/fstab")) {
561 $r{content} = "linux-usr";
566 if ($g->is_file ("/AUTOEXEC.BAT") ||
567 $g->is_file ("/autoexec.bat") ||
568 $g->is_dir ("/Program Files") ||
569 $g->is_dir ("/WINDOWS") ||
570 $g->is_file ("/boot.ini") ||
571 $g->is_file ("/ntldr")) {
572 $r{fstype} = "ntfs"; # XXX this is a guess
573 $r{fsos} = "windows";
574 $r{content} = "windows-root";
576 _check_windows_root ($g, \%r, $use_windows_registry);
586 sub _check_linux_root
592 # Look into /etc to see if we recognise the operating system.
593 if ($g->is_file ("/etc/redhat-release")) {
594 $_ = $g->cat ("/etc/redhat-release");
595 if (/Fedora release (\d+\.\d+)/) {
596 $r->{osdistro} = "fedora";
597 $r->{osversion} = "$1"
598 } elsif (/(Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\d+).*Update (\d+)/) {
599 $r->{osdistro} = "redhat";
600 $r->{osversion} = "$2.$3";
601 } elsif (/(Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\d+(?:\.(\d+))?)/) {
602 $r->{osdistro} = "redhat";
603 $r->{osversion} = "$2";
605 $r->{osdistro} = "redhat";
607 } elsif ($g->is_file ("/etc/debian_version")) {
608 $_ = $g->cat ("/etc/debian_version");
610 $r->{osdistro} = "debian";
611 $r->{osversion} = "$1";
613 $r->{osdistro} = "debian";
617 # Parse the contents of /etc/fstab. This is pretty vital so
618 # we can determine where filesystems are supposed to be mounted.
619 eval "\$_ = \$g->cat ('/etc/fstab');";
621 my @lines = split /\n/;
624 my @fields = split /[ \t]+/;
626 my $spec = $fields[0]; # first column (dev/label/uuid)
627 my $file = $fields[1]; # second column (mountpoint)
628 if ($spec =~ m{^/} ||
629 $spec =~ m{^LABEL=} ||
630 $spec =~ m{^UUID=} ||
632 push @fstab, [$spec, $file]
636 $r->{fstab} = \@fstab if @fstab;
640 # We only support NT. The control file /boot.ini contains a list of
641 # Windows installations and their %systemroot%s in a simple text
644 # XXX We could parse this better. This won't work if /boot.ini is on
645 # a different drive from the %systemroot%, and in other unusual cases.
647 sub _check_windows_root
652 my $use_windows_registry = shift;
654 my $boot_ini = resolve_windows_path ($g, "/boot.ini");
655 $r->{boot_ini} = $boot_ini;
657 if (defined $r->{boot_ini}) {
658 $_ = $g->cat ($boot_ini);
659 my @lines = split /\n/;
665 } elsif (m/^default=.*?\\(\w+)$/i) {
668 } elsif (m/\\(\w+)=/) {
674 if (defined $systemroot) {
675 $r->{systemroot} = resolve_windows_path ($g, "/$systemroot");
676 if (defined $r->{systemroot} && $use_windows_registry) {
677 _check_windows_registry ($g, $r, $r->{systemroot});
683 sub _check_windows_registry
688 my $systemroot = shift;
690 # Download the system registry files. Only download the
691 # interesting ones, and we don't bother with user profiles at all.
693 my $configdir = resolve_windows_path ($g, "$systemroot/system32/config");
694 if (defined $configdir) {
695 my $softwaredir = resolve_windows_path ($g, "$configdir/software");
696 if (defined $softwaredir) {
697 _load_windows_registry ($g, $r, $softwaredir,
698 "HKEY_LOCAL_MACHINE\\SOFTWARE");
700 my $systemdir = resolve_windows_path ($g, "$configdir/system");
701 if (defined $systemdir) {
702 _load_windows_registry ($g, $r, $systemdir,
703 "HKEY_LOCAL_MACHINE\\System");
708 sub _load_windows_registry
716 my $dir = tempdir (CLEANUP => 1);
718 $g->download ($regfile, "$dir/reg");
720 # 'reged' command is particularly noisy. Redirect stdout and
721 # stderr to /dev/null temporarily.
722 open SAVEOUT, ">&STDOUT";
723 open SAVEERR, ">&STDERR";
724 open STDOUT, ">/dev/null";
725 open STDERR, ">/dev/null";
727 my @cmd = ("reged", "-x", "$dir/reg", "$prefix", "\\", "$dir/out");
728 my $res = system (@cmd);
732 open STDOUT, ">&SAVEOUT";
733 open STDERR, ">&SAVEERR";
738 warn "reged command failed: $?";
742 # Some versions of reged segfault on inputs. If that happens we
743 # may get no / partial output file. Anyway, if it exists, load
746 unless (open F, "$dir/out") {
747 warn "no output from reged command: $!";
750 { local $/ = undef; $content = <F>; }
754 @registry = @{$r->{registry}} if exists $r->{registry};
755 push @registry, $content;
756 $r->{registry} = \@registry;
765 # Grub version, if we care.
768 =head2 inspect_operating_systems
770 \%oses = inspect_operating_systems ($g, \%fses);
772 This function works out how partitions are related to each other. In
773 the case of a single-boot VM, we work out how the partitions are
774 mounted in respect of each other (eg. C</dev/sda1> is mounted as
775 C</boot>). In the case of a multi-boot VM where there are several
776 roots, we may identify several operating system roots, and mountpoints
779 This function returns a hashref C<\%oses> which at the top level looks
783 '/dev/VG/Root' => \%os,
786 (There can be multiple roots for a multi-boot VM).
788 The C<\%os> hash contains the following keys (any can be omitted):
794 Operating system type, eg. "linux", "windows".
798 Operating system distribution, eg. "debian".
802 Operating system version, eg. "4.0".
806 The value is a reference to the root partition C<%fs> hash.
810 The value is the name of the root partition (as a string).
815 The value is a hashref like this:
818 '/' => '/dev/VG/Root',
819 '/boot' => '/dev/sda1',
824 Filesystems (including swap devices and unmounted partitions).
825 The value is a hashref like this:
829 '/dev/VG/Root' => \%fs,
830 '/dev/VG/Swap' => \%fs,
837 sub inspect_operating_systems
845 foreach (sort keys %$fses) {
846 if ($fses->{$_}->{is_root}) {
851 _get_os_version ($g, \%r);
852 _assign_mount_points ($g, $fses, \%r);
866 $r->{os} = $r->{root}->{fsos} if exists $r->{root}->{fsos};
867 $r->{distro} = $r->{root}->{osdistro} if exists $r->{root}->{osdistro};
868 $r->{version} = $r->{root}->{osversion} if exists $r->{root}->{osversion};
871 sub _assign_mount_points
878 $r->{mounts} = { "/" => $r->{root_device} };
879 $r->{filesystems} = { $r->{root_device} => $r->{root} };
881 # Use /etc/fstab if we have it to mount the rest.
882 if (exists $r->{root}->{fstab}) {
883 my @fstab = @{$r->{root}->{fstab}};
885 my ($spec, $file) = @$_;
887 my ($dev, $fs) = _find_filesystem ($g, $fses, $spec);
889 $r->{mounts}->{$file} = $dev;
890 $r->{filesystems}->{$dev} = $fs;
891 if (exists $fs->{used}) {
902 # Find filesystem by device name, LABEL=.. or UUID=..
911 foreach (sort keys %$fses) {
912 if (exists $fses->{$_}->{label} &&
913 $fses->{$_}->{label} eq $label) {
914 return ($_, $fses->{$_});
917 warn "unknown filesystem label $label\n";
919 } elsif (/^UUID=(.*)/) {
921 foreach (sort keys %$fses) {
922 if (exists $fses->{$_}->{uuid} &&
923 $fses->{$_}->{uuid} eq $uuid) {
924 return ($_, $fses->{$_});
927 warn "unknown filesystem UUID $uuid\n";
930 return ($_, $fses->{$_}) if exists $fses->{$_};
932 # The following is to handle the case where an fstab entry specifies a
933 # specific device rather than its label or uuid, and the libguestfs
934 # appliance has named the device differently due to the use of a
936 # This will work as long as the underlying drivers recognise devices in
938 if (m{^/dev/hd(.*)} && exists $fses->{"/dev/sd$1"}) {
939 return ("/dev/sd$1", $fses->{"/dev/sd$1"});
941 if (m{^/dev/xvd(.*)} && exists $fses->{"/dev/sd$1"}) {
942 return ("/dev/sd$1", $fses->{"/dev/sd$1"});
944 if (m{^/dev/mapper/(.*)-(.*)$} && exists $fses->{"/dev/$1/$2"}) {
945 return ("/dev/$1/$2", $fses->{"/dev/$1/$2"});
948 return () if m{/dev/cdrom};
950 warn "unknown filesystem $_\n";
955 =head2 mount_operating_system
957 mount_operating_system ($g, \%os);
959 This function mounts the operating system described in the
960 C<%os> hash according to the C<mounts> table in that hash (see
961 C<inspect_operating_systems>).
963 The partitions are mounted read-only.
965 To reverse the effect of this call, use the standard
966 libguestfs API call C<$g-E<gt>umount_all ()>.
970 sub mount_operating_system
976 my $mounts = $os->{mounts};
978 # Have to mount / first. Luckily '/' is early in the ASCII
979 # character set, so this should be OK.
980 foreach (sort keys %$mounts) {
981 $g->mount_ro ($mounts->{$_}, $_)
982 if $_ ne "swap" && $_ ne "none" && ($_ eq '/' || $g->is_dir ($_));
986 =head2 inspect_in_detail
988 mount_operating_system ($g, \%os);
989 inspect_in_detail ($g, \%os);
992 The C<inspect_in_detail> function inspects the mounted operating
993 system for installed applications, installed kernels, kernel modules
996 It adds extra keys to the existing C<%os> hash reflecting what it
997 finds. These extra keys are:
1003 List of applications.
1009 =item modprobe_aliases
1012 The contents of the modprobe configuration.
1014 =item initrd_modules
1017 The kernel modules installed in the initrd. The value is
1018 a hashref of kernel version to list of modules.
1024 sub inspect_in_detail
1030 _check_for_applications ($g, $os);
1031 _check_for_kernels ($g, $os);
1032 if ($os->{os} eq "linux") {
1033 _check_for_modprobe_aliases ($g, $os);
1034 _check_for_initrd ($g, $os);
1038 sub _check_for_applications
1046 my $osn = $os->{os};
1047 if ($osn eq "linux") {
1048 my $distro = $os->{distro};
1049 if (defined $distro && ($distro eq "redhat" || $distro eq "fedora")) {
1050 my @lines = $g->command_lines
1053 "--qf", "%{name} %{epoch} %{version} %{release} %{arch}\n"]);
1055 if (m/^(.*) (.*) (.*) (.*) (.*)$/) {
1057 $epoch = "" if $epoch eq "(none)";
1069 } elsif ($osn eq "windows") {
1071 # I worked out a general plan for this, but haven't
1072 # implemented it yet. We can iterate over /Program Files
1073 # looking for *.EXE files, which we download, then use
1074 # i686-pc-mingw32-windres on, to find the VERSIONINFO
1075 # section, which has a lot of useful information.
1078 $os->{apps} = \@apps;
1081 sub _check_for_kernels
1089 my $osn = $os->{os};
1090 if ($osn eq "linux") {
1091 # Installed kernels will have a corresponding /lib/modules/<version>
1092 # directory, which is the easiest way to find out what kernels
1093 # are installed, and what modules are available.
1094 foreach ($g->ls ("/lib/modules")) {
1095 if ($g->is_dir ("/lib/modules/$_")) {
1097 $kernel{version} = $_;
1101 foreach ($g->find ("/lib/modules/$_")) {
1102 if (m,/([^/]+)\.ko$, || m,([^/]+)\.o$,) {
1107 $kernel{modules} = \@modules;
1109 push @kernels, \%kernel;
1113 } elsif ($osn eq "windows") {
1117 $os->{kernels} = \@kernels;
1120 # Check /etc/modprobe.conf to see if there are any specified
1121 # drivers associated with network (ethX) or hard drives. Normally
1122 # one might find something like:
1125 # alias scsi_hostadapter xenblk
1127 # XXX This doesn't look beyond /etc/modprobe.conf, eg. in /etc/modprobe.d/
1129 sub _check_for_modprobe_aliases
1137 $success = $g->aug_init("/", 16);
1139 # Register /etc/modules.conf and /etc/conf.modules to the Modprobe lens
1141 @results = $g->aug_match("/augeas/load/Modprobe/incl");
1143 # Calculate the next index of /augeas/load/Modprobe/incl
1145 foreach ( @results ) {
1146 next unless m{/augeas/load/Modprobe/incl\[(\d*)]};
1147 $i = $1 + 1 if ($1 == $i);
1150 $success = $g->aug_set("/augeas/load/Modprobe/incl[$i]",
1151 "/etc/modules.conf");
1153 $success = $g->aug_set("/augeas/load/Modprobe/incl[$i]",
1154 "/etc/conf.modules");
1156 # Make augeas reload
1157 $success = $g->aug_load();
1159 my %modprobe_aliases;
1161 for my $pattern qw(/files/etc/conf.modules/alias
1162 /files/etc/modules.conf/alias
1163 /files/etc/modprobe.conf/alias
1164 /files/etc/modprobe.d/*/alias) {
1165 @results = $g->aug_match($pattern);
1167 for my $path ( @results ) {
1168 $path =~ m{^/files(.*)/alias(?:\[\d*\])?$}
1169 or die("$path doesn't match augeas pattern");
1173 $alias = $g->aug_get($path);
1176 $modulename = $g->aug_get($path.'/modulename');
1179 $aliasinfo{modulename} = $modulename;
1180 $aliasinfo{augeas} = $path;
1181 $aliasinfo{file} = $file;
1183 $modprobe_aliases{$alias} = \%aliasinfo;
1187 $os->{modprobe_aliases} = \%modprobe_aliases;
1190 # Get a listing of device drivers in any initrd corresponding to a
1191 # kernel. This is an indication of what can possibly be booted.
1193 sub _check_for_initrd
1201 foreach my $initrd ($g->ls ("/boot")) {
1202 if ($initrd =~ m/^initrd-(.*)\.img$/ && $g->is_file ("/boot/$initrd")) {
1207 @modules = $g->initrd_list ("/boot/$initrd");
1210 @modules = grep { m,([^/]+)\.ko$, || m,([^/]+)\.o$, } @modules;
1211 $initrd_modules{$version} = \@modules
1213 warn "/boot/$initrd: could not read initrd format"
1218 $os->{initrd_modules} = \%initrd_modules;
1226 Copyright (C) 2009 Red Hat Inc.
1230 Please see the file COPYING.LIB for the full license.
1234 L<virt-inspector(1)>,
1237 L<http://libguestfs.org/>,
1239 L<http://libvirt.org/>,