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.
124 my $readwrite = $params{rw};
127 if (ref ($first) eq "ARRAY") {
129 } elsif (ref ($first) eq "SCALAR") {
132 die "open_guest: first parameter must be a string or an arrayref"
139 die "guest image $_ does not exist or is not readable"
143 die "open_guest: no libvirt support (install Sys::Virt, XML::XPath and XML::XPath::XMLParser)"
144 unless exists $INC{"Sys/Virt.pm"} &&
145 exists $INC{"XML/XPath.pm"} &&
146 exists $INC{"XML/XPath/XMLParser.pm"};
148 die "open_guest: too many domains listed on command line"
151 $conn = Sys::Virt->new (readonly => 1, @_);
152 die "open_guest: cannot connect to libvirt" unless $conn;
154 my @doms = $conn->list_defined_domains ();
155 my $isitinactive = "an inactive libvirt domain";
156 unless ($readwrite) {
157 # In the case where we want read-only access to a domain,
158 # allow the user to specify an active domain too.
159 push @doms, $conn->list_domains ();
160 $isitinactive = "a libvirt domain";
163 if ($_->get_name () eq $images[0]) {
168 die "$images[0] is not the name of $isitinactive\n" unless $dom;
170 # Get the names of the image(s).
171 my $xml = $dom->get_xml_description ();
173 my $p = XML::XPath->new (xml => $xml);
174 my @disks = $p->findnodes ('//devices/disk/source/@dev');
175 @images = map { $_->getData } @disks;
178 # We've now got the list of @images, so feed them to libguestfs.
179 my $g = Sys::Guestfs->new ();
184 $g->add_drive_ro ($_);
188 return wantarray ? ($g, $conn, $dom) : $g
191 =head2 get_partitions
193 @partitions = get_partitions ($g);
195 This function takes an open libguestfs handle C<$g> and returns all
196 partitions and logical volumes found on it.
198 What is returned is everything that could contain a filesystem (or
199 swap). Physical volumes are excluded from the list, and so are any
200 devices which are partitioned (eg. C</dev/sda> would not be returned
201 if C</dev/sda1> exists).
209 my @partitions = $g->list_partitions ();
210 my @pvs = $g->pvs ();
211 @partitions = grep { ! is_pv ($_, @pvs) } @partitions;
213 my @lvs = $g->lvs ();
215 return sort (@lvs, @partitions);
223 return 1 if $_ eq $t;
228 =head2 resolve_windows_path
230 $path = resolve_windows_path ($g, $path);
232 $path = resolve_windows_path ($g, "/windows/system");
233 ==> "/WINDOWS/System"
234 or undef if no path exists
236 This function, which is specific to FAT/NTFS filesystems (ie. Windows
237 guests), lets you look up a case insensitive C<$path> in the
238 filesystem and returns the true, case sensitive path as required by
239 the underlying kernel or NTFS-3g driver.
241 If C<$path> does not exist then this function returns C<undef>.
243 The C<$path> parameter must begin with C</> character and be separated
244 by C</> characters. Do not use C<\>, drive names, etc.
248 sub resolve_windows_path
254 if (substr ($path, 0, 1) ne "/") {
255 warn "resolve_windows_path: path must start with a / character";
259 my @elems = split (/\//, $path);
262 # Start reconstructing the path at the top.
265 foreach my $dir (@elems) {
267 foreach ($g->ls ($path)) {
268 if (lc ($_) eq lc ($dir)) {
278 return undef unless $found;
284 =head1 OPERATING SYSTEM INSPECTION FUNCTIONS
286 The functions in this section can be used to inspect the operating
287 system(s) available inside a virtual machine image. For example, you
288 can find out if the VM is Linux or Windows, how the partitions are
289 meant to be mounted, and what applications are installed.
291 If you just want a simple command-line interface to this
292 functionality, use the L<virt-inspector(1)> tool. The documentation
293 below covers the case where you want to access this functionality from
296 Once you have the list of partitions (from C<get_partitions>) there
297 are several steps involved:
303 Look at each partition separately and find out what is on it.
305 The information you get back includes whether the partition contains a
306 filesystem or swapspace, what sort of filesystem (eg. ext3, ntfs), and
307 a first pass guess at the content of the filesystem (eg. Linux boot,
310 The result of this step is a C<%fs> hash of information, one hash for
313 See: C<inspect_partition>, C<inspect_all_partitions>
317 Work out the relationship between partitions.
319 In this step we work out how partitions are related to each other. In
320 the case of a single-boot VM, we work out how the partitions are
321 mounted in respect of each other (eg. C</dev/sda1> is mounted as
322 C</boot>). In the case of a multi-boot VM where there are several
323 roots, we may identify several operating system roots, and mountpoints
326 The result of this step is a single hash called C<%oses> which is
327 described in more detail below, but at the top level looks like:
330 '/dev/VG/Root1' => \%os1,
331 '/dev/VG/Root2' => \%os2,
337 '/' => '/dev/VG/Root1',
338 '/boot' => '/dev/sda1',
343 (example shows a multi-boot VM containing two root partitions).
345 See: C<inspect_operating_systems>
351 Previous to this point we've essentially been looking at each
352 partition in isolation. Now we construct a true guest filesystem by
353 mounting up all of the disks. Only once everything is mounted up can
354 we run commands in the OS context to do more detailed inspection.
356 See: C<mount_operating_system>
360 Check for kernels and applications.
362 This step now does more detailed inspection, where we can look for
363 kernels, applications and more installed in the guest.
365 The result of this is an enhanced C<%os> hash.
367 See: C<inspect_in_detail>
373 This library does not contain functions for generating output based on
374 the analysis steps above. Use a command line tool such as
375 L<virt-inspector(1)> to get useful output.
379 =head2 inspect_all_partitions
381 %fses = inspect_all_partitions ($g, \@partitions);
383 %fses = inspect_all_partitions ($g, \@partitions, use_windows_registry => 1);
385 This calls C<inspect_partition> for each partition in the list
388 The result is a hash which maps partition name to C<\%fs> hashref.
390 The contents of the C<%fs> hash and the meaning of the
391 C<use_windows_registry> flag are explained below.
395 sub inspect_all_partitions
401 return map { $_ => inspect_partition ($g, $_, @_) } @parts;
404 =head2 inspect_partition
406 \%fs = inspect_partition ($g, $partition);
408 \%fs = inspect_partition ($g, $partition, use_windows_registry => 1);
410 This function inspects the device named C<$partition> in isolation and
411 tries to determine what it is. It returns information such as whether
412 the partition is formatted, and with what, whether it is mountable,
413 and what it appears to contain (eg. a Windows root, or a Linux /usr).
415 If C<use_windows_registry> is set to 1, then we will try to download
416 and parse the content of the Windows registry (for Windows root
417 devices). However since this is an expensive and error-prone
418 operation, we don't do this by default. It also requires the external
419 program C<reged>, patched to remove numerous crashing bugs in the
422 The returned value is a hashref C<\%fs> which may contain the
423 following top-level keys (any key can be missing):
429 Filesystem type, eg. "ext2" or "ntfs"
433 Apparent filesystem OS, eg. "linux" or "windows"
437 If set, the partition is a swap partition.
449 If set, the partition could be mounted by libguestfs.
453 Filesystem content, if we could determine it. One of: "linux-grub",
454 "linux-root", "linux-usrlocal", "linux-usr", "windows-root".
458 (For Linux root partitions only).
459 Operating system distribution. One of: "fedora", "redhat",
464 (For root partitions only).
465 Operating system version.
469 (For Linux root partitions only).
470 The contents of the C</etc/fstab> file.
474 (For Windows root partitions only).
475 The contents of the C</boot.ini> (NTLDR) file.
479 The value is an arrayref, which is a list of Windows registry
480 file contents, in Windows C<.REG> format.
486 sub inspect_partition
490 my $dev = shift; # LV or partition name.
493 my $use_windows_registry = $params{use_windows_registry};
495 my %r; # Result hash.
497 # First try 'file(1)' on it.
498 my $file = $g->file ($dev);
499 if ($file =~ /ext2 filesystem data/) {
502 } elsif ($file =~ /ext3 filesystem data/) {
505 } elsif ($file =~ /ext4 filesystem data/) {
508 } elsif ($file =~ m{Linux/i386 swap file}) {
514 # If it's ext2/3/4, then we want the UUID and label.
515 if (exists $r{fstype} && $r{fstype} =~ /^ext/) {
516 $r{uuid} = $g->get_e2uuid ($dev);
517 $r{label} = $g->get_e2label ($dev);
520 # Try mounting it, fnarrr.
522 $r{is_mountable} = 1;
523 eval { $g->mount_ro ($dev, "/") };
525 # It's not mountable, probably empty or some format
526 # we don't understand.
527 $r{is_mountable} = 0;
532 if ($g->is_file ("/grub/menu.lst") ||
533 $g->is_file ("/grub/grub.conf")) {
534 $r{content} = "linux-grub";
535 check_grub ($g, \%r);
540 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
541 $g->is_file ("/etc/fstab")) {
542 $r{content} = "linux-root";
544 check_linux_root ($g, \%r);
549 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
550 $g->is_dir ("/share") && !$g->exists ("/local") &&
551 !$g->is_file ("/etc/fstab")) {
552 $r{content} = "linux-usrlocal";
557 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
558 $g->is_dir ("/share") && $g->exists ("/local") &&
559 !$g->is_file ("/etc/fstab")) {
560 $r{content} = "linux-usr";
565 if ($g->is_file ("/AUTOEXEC.BAT") ||
566 $g->is_file ("/autoexec.bat") ||
567 $g->is_dir ("/Program Files") ||
568 $g->is_dir ("/WINDOWS") ||
569 $g->is_file ("/boot.ini") ||
570 $g->is_file ("/ntldr")) {
571 $r{fstype} = "ntfs"; # XXX this is a guess
572 $r{fsos} = "windows";
573 $r{content} = "windows-root";
575 check_windows_root ($g, \%r, $use_windows_registry);
591 # Look into /etc to see if we recognise the operating system.
592 if ($g->is_file ("/etc/redhat-release")) {
593 $_ = $g->cat ("/etc/redhat-release");
594 if (/Fedora release (\d+\.\d+)/) {
595 $r->{osdistro} = "fedora";
596 $r->{osversion} = "$1"
597 } elsif (/(Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\d+).*Update (\d+)/) {
598 $r->{osdistro} = "redhat";
599 $r->{osversion} = "$2.$3";
600 } elsif (/(Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\d+(?:\.(\d+))?)/) {
601 $r->{osdistro} = "redhat";
602 $r->{osversion} = "$2";
604 $r->{osdistro} = "redhat";
606 } elsif ($g->is_file ("/etc/debian_version")) {
607 $_ = $g->cat ("/etc/debian_version");
609 $r->{osdistro} = "debian";
610 $r->{osversion} = "$1";
612 $r->{osdistro} = "debian";
616 # Parse the contents of /etc/fstab. This is pretty vital so
617 # we can determine where filesystems are supposed to be mounted.
618 eval "\$_ = \$g->cat ('/etc/fstab');";
620 my @lines = split /\n/;
623 my @fields = split /[ \t]+/;
625 my $spec = $fields[0]; # first column (dev/label/uuid)
626 my $file = $fields[1]; # second column (mountpoint)
627 if ($spec =~ m{^/} ||
628 $spec =~ m{^LABEL=} ||
629 $spec =~ m{^UUID=} ||
631 push @fstab, [$spec, $file]
635 $r->{fstab} = \@fstab if @fstab;
639 # We only support NT. The control file /boot.ini contains a list of
640 # Windows installations and their %systemroot%s in a simple text
643 # XXX We could parse this better. This won't work if /boot.ini is on
644 # a different drive from the %systemroot%, and in other unusual cases.
646 sub check_windows_root
651 my $use_windows_registry = shift;
653 my $boot_ini = resolve_windows_path ($g, "/boot.ini");
654 $r->{boot_ini} = $boot_ini;
656 if (defined $r->{boot_ini}) {
657 $_ = $g->cat ($boot_ini);
658 my @lines = split /\n/;
664 } elsif (m/^default=.*?\\(\w+)$/i) {
667 } elsif (m/\\(\w+)=/) {
673 if (defined $systemroot) {
674 $r->{systemroot} = resolve_windows_path ($g, "/$systemroot");
675 if (defined $r->{systemroot} && $use_windows_registry) {
676 check_windows_registry ($g, $r, $r->{systemroot});
682 sub check_windows_registry
687 my $systemroot = shift;
689 # Download the system registry files. Only download the
690 # interesting ones, and we don't bother with user profiles at all.
692 my $configdir = resolve_windows_path ($g, "$systemroot/system32/config");
693 if (defined $configdir) {
694 my $softwaredir = resolve_windows_path ($g, "$configdir/software");
695 if (defined $softwaredir) {
696 load_windows_registry ($g, $r, $softwaredir,
697 "HKEY_LOCAL_MACHINE\\SOFTWARE");
699 my $systemdir = resolve_windows_path ($g, "$configdir/system");
700 if (defined $systemdir) {
701 load_windows_registry ($g, $r, $systemdir,
702 "HKEY_LOCAL_MACHINE\\System");
707 sub load_windows_registry
715 my $dir = tempdir (CLEANUP => 1);
717 $g->download ($regfile, "$dir/reg");
719 # 'reged' command is particularly noisy. Redirect stdout and
720 # stderr to /dev/null temporarily.
721 open SAVEOUT, ">&STDOUT";
722 open SAVEERR, ">&STDERR";
723 open STDOUT, ">/dev/null";
724 open STDERR, ">/dev/null";
726 my @cmd = ("reged", "-x", "$dir/reg", "$prefix", "\\", "$dir/out");
727 my $res = system (@cmd);
731 open STDOUT, ">&SAVEOUT";
732 open STDERR, ">&SAVEERR";
737 warn "reged command failed: $?";
741 # Some versions of reged segfault on inputs. If that happens we
742 # may get no / partial output file. Anyway, if it exists, load
745 unless (open F, "$dir/out") {
746 warn "no output from reged command: $!";
749 { local $/ = undef; $content = <F>; }
753 @registry = @{$r->{registry}} if exists $r->{registry};
754 push @registry, $content;
755 $r->{registry} = \@registry;
764 # Grub version, if we care.
767 =head2 inspect_operating_systems
769 \%oses = inspect_operating_systems ($g, \%fses);
771 This function works out how partitions are related to each other. In
772 the case of a single-boot VM, we work out how the partitions are
773 mounted in respect of each other (eg. C</dev/sda1> is mounted as
774 C</boot>). In the case of a multi-boot VM where there are several
775 roots, we may identify several operating system roots, and mountpoints
778 This function returns a hashref C<\%oses> which at the top level looks
782 '/dev/VG/Root' => \%os,
785 (There can be multiple roots for a multi-boot VM).
787 The C<\%os> hash contains the following keys (any can be omitted):
793 Operating system type, eg. "linux", "windows".
797 Operating system distribution, eg. "debian".
801 Operating system version, eg. "4.0".
805 The value is a reference to the root partition C<%fs> hash.
809 The value is the name of the root partition (as a string).
814 The value is a hashref like this:
817 '/' => '/dev/VG/Root',
818 '/boot' => '/dev/sda1',
823 Filesystems (including swap devices and unmounted partitions).
824 The value is a hashref like this:
828 '/dev/VG/Root' => \%fs,
829 '/dev/VG/Swap' => \%fs,
836 sub inspect_operating_systems
844 foreach (sort keys %$fses) {
845 if ($fses->{$_}->{is_root}) {
850 get_os_version ($g, \%r);
851 assign_mount_points ($g, $fses, \%r);
865 $r->{os} = $r->{root}->{fsos} if exists $r->{root}->{fsos};
866 $r->{distro} = $r->{root}->{osdistro} if exists $r->{root}->{osdistro};
867 $r->{version} = $r->{root}->{osversion} if exists $r->{root}->{osversion};
870 sub assign_mount_points
877 $r->{mounts} = { "/" => $r->{root_device} };
878 $r->{filesystems} = { $r->{root_device} => $r->{root} };
880 # Use /etc/fstab if we have it to mount the rest.
881 if (exists $r->{root}->{fstab}) {
882 my @fstab = @{$r->{root}->{fstab}};
884 my ($spec, $file) = @$_;
886 my ($dev, $fs) = find_filesystem ($g, $fses, $spec);
888 $r->{mounts}->{$file} = $dev;
889 $r->{filesystems}->{$dev} = $fs;
890 if (exists $fs->{used}) {
901 # Find filesystem by device name, LABEL=.. or UUID=..
910 foreach (sort keys %$fses) {
911 if (exists $fses->{$_}->{label} &&
912 $fses->{$_}->{label} eq $label) {
913 return ($_, $fses->{$_});
916 warn "unknown filesystem label $label\n";
918 } elsif (/^UUID=(.*)/) {
920 foreach (sort keys %$fses) {
921 if (exists $fses->{$_}->{uuid} &&
922 $fses->{$_}->{uuid} eq $uuid) {
923 return ($_, $fses->{$_});
926 warn "unknown filesystem UUID $uuid\n";
929 return ($_, $fses->{$_}) if exists $fses->{$_};
931 # The following is to handle the case where an fstab entry specifies a
932 # specific device rather than its label or uuid, and the libguestfs
933 # appliance has named the device differently due to the use of a
935 # This will work as long as the underlying drivers recognise devices in
937 if (m{^/dev/hd(.*)} && exists $fses->{"/dev/sd$1"}) {
938 return ("/dev/sd$1", $fses->{"/dev/sd$1"});
940 if (m{^/dev/xvd(.*)} && exists $fses->{"/dev/sd$1"}) {
941 return ("/dev/sd$1", $fses->{"/dev/sd$1"});
943 if (m{^/dev/mapper/(.*)-(.*)$} && exists $fses->{"/dev/$1/$2"}) {
944 return ("/dev/$1/$2", $fses->{"/dev/$1/$2"});
947 return () if m{/dev/cdrom};
949 warn "unknown filesystem $_\n";
954 =head2 mount_operating_system
956 mount_operating_system ($g, \%os);
958 This function mounts the operating system described in the
959 C<%os> hash according to the C<mounts> table in that hash (see
960 C<inspect_operating_systems>).
962 The partitions are mounted read-only.
964 To reverse the effect of this call, use the standard
965 libguestfs API call C<$g-E<gt>umount_all ()>.
969 sub mount_operating_system
975 my $mounts = $os->{mounts};
977 # Have to mount / first. Luckily '/' is early in the ASCII
978 # character set, so this should be OK.
979 foreach (sort keys %$mounts) {
980 $g->mount_ro ($mounts->{$_}, $_)
981 if $_ ne "swap" && $_ ne "none" && ($_ eq '/' || $g->is_dir ($_));
985 =head2 inspect_in_detail
987 mount_operating_system ($g, \%os);
988 inspect_in_detail ($g, \%os);
991 The C<inspect_in_detail> function inspects the mounted operating
992 system for installed applications, installed kernels, kernel modules
995 It adds extra keys to the existing C<%os> hash reflecting what it
996 finds. These extra keys are:
1002 List of applications.
1008 =item modprobe_aliases
1011 The contents of the modprobe configuration.
1013 =item initrd_modules
1016 The kernel modules installed in the initrd. The value is
1017 a hashref of kernel version to list of modules.
1023 sub inspect_in_detail
1029 check_for_applications ($g, $os);
1030 check_for_kernels ($g, $os);
1031 if ($os->{os} eq "linux") {
1032 check_for_modprobe_aliases ($g, $os);
1033 check_for_initrd ($g, $os);
1037 sub check_for_applications
1045 my $osn = $os->{os};
1046 if ($osn eq "linux") {
1047 my $distro = $os->{distro};
1048 if (defined $distro && ($distro eq "redhat" || $distro eq "fedora")) {
1049 my @lines = $g->command_lines
1052 "--qf", "%{name} %{epoch} %{version} %{release} %{arch}\n"]);
1054 if (m/^(.*) (.*) (.*) (.*) (.*)$/) {
1056 $epoch = "" if $epoch eq "(none)";
1068 } elsif ($osn eq "windows") {
1070 # I worked out a general plan for this, but haven't
1071 # implemented it yet. We can iterate over /Program Files
1072 # looking for *.EXE files, which we download, then use
1073 # i686-pc-mingw32-windres on, to find the VERSIONINFO
1074 # section, which has a lot of useful information.
1077 $os->{apps} = \@apps;
1080 sub check_for_kernels
1088 my $osn = $os->{os};
1089 if ($osn eq "linux") {
1090 # Installed kernels will have a corresponding /lib/modules/<version>
1091 # directory, which is the easiest way to find out what kernels
1092 # are installed, and what modules are available.
1093 foreach ($g->ls ("/lib/modules")) {
1094 if ($g->is_dir ("/lib/modules/$_")) {
1096 $kernel{version} = $_;
1100 foreach ($g->find ("/lib/modules/$_")) {
1101 if (m,/([^/]+)\.ko$, || m,([^/]+)\.o$,) {
1106 $kernel{modules} = \@modules;
1108 push @kernels, \%kernel;
1112 } elsif ($osn eq "windows") {
1116 $os->{kernels} = \@kernels;
1119 # Check /etc/modprobe.conf to see if there are any specified
1120 # drivers associated with network (ethX) or hard drives. Normally
1121 # one might find something like:
1124 # alias scsi_hostadapter xenblk
1126 # XXX This doesn't look beyond /etc/modprobe.conf, eg. in /etc/modprobe.d/
1128 sub check_for_modprobe_aliases
1136 $success = $g->aug_init("/", 16);
1138 # Register /etc/modules.conf and /etc/conf.modules to the Modprobe lens
1140 @results = $g->aug_match("/augeas/load/Modprobe/incl");
1142 # Calculate the next index of /augeas/load/Modprobe/incl
1144 foreach ( @results ) {
1145 next unless m{/augeas/load/Modprobe/incl\[(\d*)]};
1146 $i = $1 + 1 if ($1 == $i);
1149 $success = $g->aug_set("/augeas/load/Modprobe/incl[$i]",
1150 "/etc/modules.conf");
1152 $success = $g->aug_set("/augeas/load/Modprobe/incl[$i]",
1153 "/etc/conf.modules");
1155 # Make augeas reload
1156 $success = $g->aug_load();
1158 my %modprobe_aliases;
1160 for my $pattern qw(/files/etc/conf.modules/alias
1161 /files/etc/modules.conf/alias
1162 /files/etc/modprobe.conf/alias
1163 /files/etc/modprobe.d/*/alias) {
1164 @results = $g->aug_match($pattern);
1166 for my $path ( @results ) {
1167 $path =~ m{^/files(.*)/alias(?:\[\d*\])?$}
1168 or die("$path doesn't match augeas pattern");
1172 $alias = $g->aug_get($path);
1175 $modulename = $g->aug_get($path.'/modulename');
1178 $aliasinfo{modulename} = $modulename;
1179 $aliasinfo{augeas} = $path;
1180 $aliasinfo{file} = $file;
1182 $modprobe_aliases{$alias} = \%aliasinfo;
1186 $os->{modprobe_aliases} = \%modprobe_aliases;
1189 # Get a listing of device drivers in any initrd corresponding to a
1190 # kernel. This is an indication of what can possibly be booted.
1192 sub check_for_initrd
1200 foreach my $initrd ($g->ls ("/boot")) {
1201 if ($initrd =~ m/^initrd-(.*)\.img$/ && $g->is_file ("/boot/$initrd")) {
1206 @modules = $g->initrd_list ("/boot/$initrd");
1209 @modules = grep { m,([^/]+)\.ko$, || m,([^/]+)\.o$, } @modules;
1210 $initrd_modules{$version} = \@modules
1212 warn "/boot/$initrd: could not read initrd format"
1217 $os->{initrd_modules} = \%initrd_modules;
1225 Copyright (C) 2009 Red Hat Inc.
1229 Please see the file COPYING.LIB for the full license.
1233 L<virt-inspector(1)>,
1236 L<http://libguestfs.org/>,
1238 L<http://libvirt.org/>,