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;
24 use File::Temp qw/tempdir/;
27 eval "use Sys::Virt;";
28 eval "use XML::XPath;";
29 eval "use XML::XPath::XMLParser;";
35 Sys::Guestfs::Lib - Useful functions for using libguestfs from Perl
39 use Sys::Guestfs::Lib qw(open_guest inspect_all_partitions ...);
41 $g = open_guest ($name);
43 %fses = inspect_all_partitions ($g, \@partitions);
45 (and many more calls - see the rest of this manpage)
49 C<Sys::Guestfs::Lib> is an extra library of useful functions for using
50 the libguestfs API from Perl. It also provides tighter integration
53 The basic libguestfs API is not covered by this manpage. Please refer
54 instead to L<Sys::Guestfs(3)> and L<guestfs(3)>. The libvirt API is
55 also not covered. For that, see L<Sys::Virt(3)>.
57 =head1 BASIC FUNCTIONS
63 use vars qw(@EXPORT_OK @ISA);
66 @EXPORT_OK = qw(open_guest get_partitions resolve_windows_path
67 inspect_all_partitions inspect_partition
68 inspect_operating_systems mount_operating_system inspect_in_detail);
72 $g = open_guest ($name);
74 $g = open_guest ($name, rw => 1, ...);
76 $g = open_guest ($name, address => $uri, ...);
78 $g = open_guest ([$img1, $img2, ...], address => $uri, ...);
80 ($g, $conn, $dom) = open_guest ($name);
82 This function opens a libguestfs handle for either the libvirt domain
83 called C<$name>, or the disk image called C<$name>. Any disk images
84 found through libvirt or specified explicitly are attached to the
87 The C<Sys::Guestfs> handle C<$g> is returned, or if there was an error
88 it throws an exception. To catch errors, wrap the call in an eval
91 The first parameter is either a string referring to a libvirt domain
92 or a disk image, or (if a guest has several disk images) an arrayref
93 C<[$img1, $img2, ...]>.
95 The handle is I<read-only> by default. Use the optional parameter
96 C<rw =E<gt> 1> to open a read-write handle. However if you open a
97 read-write handle, this function will refuse to use active libvirt
100 The handle is still in the config state when it is returned, so you
101 have to call C<$g-E<gt>launch ()> and C<$g-E<gt>wait_ready>.
103 The optional C<address> parameter can be added to specify the libvirt
104 URI. In addition, L<Sys::Virt(3)> lists other parameters which are
105 passed through to C<Sys::Virt-E<gt>new> unchanged.
107 The implicit libvirt handle is closed after this function, I<unless>
108 you call the function in C<wantarray> context, in which case the
109 function returns a tuple of: the open libguestfs handle, the open
110 libvirt handle, and the open libvirt domain handle. (This is useful
111 if you want to do other things like pulling the XML description of the
112 guest). Note that if this is a straight disk image, then C<$conn> and
113 C<$dom> will be C<undef>.
115 If the C<Sys::Virt> module is not available, then libvirt is bypassed,
116 and this function can only open disk images.
126 my $readwrite = $params{rw};
129 if (ref ($first) eq "ARRAY") {
131 } elsif (ref ($first) eq "SCALAR") {
134 die "open_guest: first parameter must be a string or an arrayref"
141 die "guest image $_ does not exist or is not readable"
145 die "open_guest: no libvirt support (install Sys::Virt, XML::XPath and XML::XPath::XMLParser)"
146 unless exists $INC{"Sys/Virt.pm"} &&
147 exists $INC{"XML/XPath.pm"} &&
148 exists $INC{"XML/XPath/XMLParser.pm"};
150 die "open_guest: too many domains listed on command line"
153 $conn = Sys::Virt->new (readonly => 1, @_);
154 die "open_guest: cannot connect to libvirt" unless $conn;
156 my @doms = $conn->list_defined_domains ();
157 my $isitinactive = "an inactive libvirt domain";
158 unless ($readwrite) {
159 # In the case where we want read-only access to a domain,
160 # allow the user to specify an active domain too.
161 push @doms, $conn->list_domains ();
162 $isitinactive = "a libvirt domain";
165 if ($_->get_name () eq $images[0]) {
170 die "$images[0] is not the name of $isitinactive\n" unless $dom;
172 # Get the names of the image(s).
173 my $xml = $dom->get_xml_description ();
175 my $p = XML::XPath->new (xml => $xml);
176 my @disks = $p->findnodes ('//devices/disk/source/@dev');
177 push (@disks, $p->findnodes ('//devices/disk/source/@file'));
178 @images = map { $_->getData } @disks;
181 # We've now got the list of @images, so feed them to libguestfs.
182 my $g = Sys::Guestfs->new ();
187 $g->add_drive_ro ($_);
191 return wantarray ? ($g, $conn, $dom) : $g
194 =head2 get_partitions
196 @partitions = get_partitions ($g);
198 This function takes an open libguestfs handle C<$g> and returns all
199 partitions and logical volumes found on it.
201 What is returned is everything that could contain a filesystem (or
202 swap). Physical volumes are excluded from the list, and so are any
203 devices which are partitioned (eg. C</dev/sda> would not be returned
204 if C</dev/sda1> exists).
212 my @partitions = $g->list_partitions ();
213 my @pvs = $g->pvs ();
214 @partitions = grep { ! _is_pv ($_, @pvs) } @partitions;
216 my @lvs = $g->lvs ();
218 return sort (@lvs, @partitions);
226 return 1 if $_ eq $t;
231 =head2 resolve_windows_path
233 $path = resolve_windows_path ($g, $path);
235 $path = resolve_windows_path ($g, "/windows/system");
236 ==> "/WINDOWS/System"
237 or undef if no path exists
239 This function, which is specific to FAT/NTFS filesystems (ie. Windows
240 guests), lets you look up a case insensitive C<$path> in the
241 filesystem and returns the true, case sensitive path as required by
242 the underlying kernel or NTFS-3g driver.
244 If C<$path> does not exist then this function returns C<undef>.
246 The C<$path> parameter must begin with C</> character and be separated
247 by C</> characters. Do not use C<\>, drive names, etc.
251 sub resolve_windows_path
257 if (substr ($path, 0, 1) ne "/") {
258 warn "resolve_windows_path: path must start with a / character";
262 my @elems = split (/\//, $path);
265 # Start reconstructing the path at the top.
268 foreach my $dir (@elems) {
270 foreach ($g->ls ($path)) {
271 if (lc ($_) eq lc ($dir)) {
281 return undef unless $found;
287 =head1 OPERATING SYSTEM INSPECTION FUNCTIONS
289 The functions in this section can be used to inspect the operating
290 system(s) available inside a virtual machine image. For example, you
291 can find out if the VM is Linux or Windows, how the partitions are
292 meant to be mounted, and what applications are installed.
294 If you just want a simple command-line interface to this
295 functionality, use the L<virt-inspector(1)> tool. The documentation
296 below covers the case where you want to access this functionality from
299 Once you have the list of partitions (from C<get_partitions>) there
300 are several steps involved:
306 Look at each partition separately and find out what is on it.
308 The information you get back includes whether the partition contains a
309 filesystem or swapspace, what sort of filesystem (eg. ext3, ntfs), and
310 a first pass guess at the content of the filesystem (eg. Linux boot,
313 The result of this step is a C<%fs> hash of information, one hash for
316 See: C<inspect_partition>, C<inspect_all_partitions>
320 Work out the relationship between partitions.
322 In this step we work out how partitions are related to each other. In
323 the case of a single-boot VM, we work out how the partitions are
324 mounted in respect of each other (eg. C</dev/sda1> is mounted as
325 C</boot>). In the case of a multi-boot VM where there are several
326 roots, we may identify several operating system roots, and mountpoints
329 The result of this step is a single hash called C<%oses> which is
330 described in more detail below, but at the top level looks like:
333 '/dev/VG/Root1' => \%os1,
334 '/dev/VG/Root2' => \%os2,
340 '/' => '/dev/VG/Root1',
341 '/boot' => '/dev/sda1',
346 (example shows a multi-boot VM containing two root partitions).
348 See: C<inspect_operating_systems>
354 Previous to this point we've essentially been looking at each
355 partition in isolation. Now we construct a true guest filesystem by
356 mounting up all of the disks. Only once everything is mounted up can
357 we run commands in the OS context to do more detailed inspection.
359 See: C<mount_operating_system>
363 Check for kernels and applications.
365 This step now does more detailed inspection, where we can look for
366 kernels, applications and more installed in the guest.
368 The result of this is an enhanced C<%os> hash.
370 See: C<inspect_in_detail>
376 This library does not contain functions for generating output based on
377 the analysis steps above. Use a command line tool such as
378 L<virt-inspector(1)> to get useful output.
382 =head2 inspect_all_partitions
384 %fses = inspect_all_partitions ($g, \@partitions);
386 %fses = inspect_all_partitions ($g, \@partitions, use_windows_registry => 1);
388 This calls C<inspect_partition> for each partition in the list
391 The result is a hash which maps partition name to C<\%fs> hashref.
393 The contents of the C<%fs> hash and the meaning of the
394 C<use_windows_registry> flag are explained below.
398 sub inspect_all_partitions
404 return map { $_ => inspect_partition ($g, $_, @_) } @parts;
407 =head2 inspect_partition
409 \%fs = inspect_partition ($g, $partition);
411 \%fs = inspect_partition ($g, $partition, use_windows_registry => 1);
413 This function inspects the device named C<$partition> in isolation and
414 tries to determine what it is. It returns information such as whether
415 the partition is formatted, and with what, whether it is mountable,
416 and what it appears to contain (eg. a Windows root, or a Linux /usr).
418 If C<use_windows_registry> is set to 1, then we will try to download
419 and parse the content of the Windows registry (for Windows root
420 devices). However since this is an expensive and error-prone
421 operation, we don't do this by default. It also requires the external
422 program C<reged>, patched to remove numerous crashing bugs in the
425 The returned value is a hashref C<\%fs> which may contain the
426 following top-level keys (any key can be missing):
432 Filesystem type, eg. "ext2" or "ntfs"
436 Apparent filesystem OS, eg. "linux" or "windows"
440 If set, the partition is a swap partition.
452 If set, the partition could be mounted by libguestfs.
456 Filesystem content, if we could determine it. One of: "linux-grub",
457 "linux-root", "linux-usrlocal", "linux-usr", "windows-root".
461 (For Linux root partitions only).
462 Operating system distribution. One of: "fedora", "redhat",
467 (For root partitions only).
468 Operating system version.
472 (For Linux root partitions only).
473 The contents of the C</etc/fstab> file.
477 (For Windows root partitions only).
478 The contents of the C</boot.ini> (NTLDR) file.
482 The value is an arrayref, which is a list of Windows registry
483 file contents, in Windows C<.REG> format.
489 sub inspect_partition
493 my $dev = shift; # LV or partition name.
496 my $use_windows_registry = $params{use_windows_registry};
498 my %r; # Result hash.
500 # First try 'file(1)' on it.
501 my $file = $g->file ($dev);
502 if ($file =~ /ext2 filesystem data/) {
505 } elsif ($file =~ /ext3 filesystem data/) {
508 } elsif ($file =~ /ext4 filesystem data/) {
511 } elsif ($file =~ m{Linux/i386 swap file}) {
517 # If it's ext2/3/4, then we want the UUID and label.
518 if (exists $r{fstype} && $r{fstype} =~ /^ext/) {
519 $r{uuid} = $g->get_e2uuid ($dev);
520 $r{label} = $g->get_e2label ($dev);
523 # Try mounting it, fnarrr.
525 $r{is_mountable} = 1;
526 eval { $g->mount_ro ($dev, "/") };
528 # It's not mountable, probably empty or some format
529 # we don't understand.
530 $r{is_mountable} = 0;
535 if ($g->is_file ("/grub/menu.lst") ||
536 $g->is_file ("/grub/grub.conf")) {
537 $r{content} = "linux-grub";
538 _check_grub ($g, \%r);
543 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
544 $g->is_file ("/etc/fstab")) {
545 $r{content} = "linux-root";
547 _check_linux_root ($g, \%r);
552 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
553 $g->is_dir ("/share") && !$g->exists ("/local") &&
554 !$g->is_file ("/etc/fstab")) {
555 $r{content} = "linux-usrlocal";
560 if ($g->is_dir ("/etc") && $g->is_dir ("/bin") &&
561 $g->is_dir ("/share") && $g->exists ("/local") &&
562 !$g->is_file ("/etc/fstab")) {
563 $r{content} = "linux-usr";
568 if ($g->is_file ("/AUTOEXEC.BAT") ||
569 $g->is_file ("/autoexec.bat") ||
570 $g->is_dir ("/Program Files") ||
571 $g->is_dir ("/WINDOWS") ||
572 $g->is_file ("/boot.ini") ||
573 $g->is_file ("/ntldr")) {
574 $r{fstype} = "ntfs"; # XXX this is a guess
575 $r{fsos} = "windows";
576 $r{content} = "windows-root";
578 _check_windows_root ($g, \%r, $use_windows_registry);
588 sub _check_linux_root
594 # Look into /etc to see if we recognise the operating system.
595 if ($g->is_file ("/etc/redhat-release")) {
596 $_ = $g->cat ("/etc/redhat-release");
597 if (/Fedora release (\d+\.\d+)/) {
598 $r->{osdistro} = "fedora";
599 $r->{osversion} = "$1"
600 } elsif (/(Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\d+).*Update (\d+)/) {
601 $r->{osdistro} = "redhat";
602 $r->{osversion} = "$2.$3";
603 } elsif (/(Red Hat Enterprise Linux|CentOS|Scientific Linux).*release (\d+(?:\.(\d+))?)/) {
604 $r->{osdistro} = "redhat";
605 $r->{osversion} = "$2";
607 $r->{osdistro} = "redhat";
609 } elsif ($g->is_file ("/etc/debian_version")) {
610 $_ = $g->cat ("/etc/debian_version");
612 $r->{osdistro} = "debian";
613 $r->{osversion} = "$1";
615 $r->{osdistro} = "debian";
619 # Parse the contents of /etc/fstab. This is pretty vital so
620 # we can determine where filesystems are supposed to be mounted.
621 eval "\$_ = \$g->cat ('/etc/fstab');";
623 my @lines = split /\n/;
626 my @fields = split /[ \t]+/;
628 my $spec = $fields[0]; # first column (dev/label/uuid)
629 my $file = $fields[1]; # second column (mountpoint)
630 if ($spec =~ m{^/} ||
631 $spec =~ m{^LABEL=} ||
632 $spec =~ m{^UUID=} ||
634 push @fstab, [$spec, $file]
638 $r->{fstab} = \@fstab if @fstab;
642 # We only support NT. The control file /boot.ini contains a list of
643 # Windows installations and their %systemroot%s in a simple text
646 # XXX We could parse this better. This won't work if /boot.ini is on
647 # a different drive from the %systemroot%, and in other unusual cases.
649 sub _check_windows_root
654 my $use_windows_registry = shift;
656 my $boot_ini = resolve_windows_path ($g, "/boot.ini");
657 $r->{boot_ini} = $boot_ini;
659 if (defined $r->{boot_ini}) {
660 $_ = $g->cat ($boot_ini);
661 my @lines = split /\n/;
667 } elsif (m/^default=.*?\\(\w+)$/i) {
670 } elsif (m/\\(\w+)=/) {
676 if (defined $systemroot) {
677 $r->{systemroot} = resolve_windows_path ($g, "/$systemroot");
678 if (defined $r->{systemroot} && $use_windows_registry) {
679 _check_windows_registry ($g, $r, $r->{systemroot});
685 sub _check_windows_registry
690 my $systemroot = shift;
692 # Download the system registry files. Only download the
693 # interesting ones, and we don't bother with user profiles at all.
695 my $configdir = resolve_windows_path ($g, "$systemroot/system32/config");
696 if (defined $configdir) {
697 my $softwaredir = resolve_windows_path ($g, "$configdir/software");
698 if (defined $softwaredir) {
699 _load_windows_registry ($g, $r, $softwaredir,
700 "HKEY_LOCAL_MACHINE\\SOFTWARE");
702 my $systemdir = resolve_windows_path ($g, "$configdir/system");
703 if (defined $systemdir) {
704 _load_windows_registry ($g, $r, $systemdir,
705 "HKEY_LOCAL_MACHINE\\System");
710 sub _load_windows_registry
718 my $dir = tempdir (CLEANUP => 1);
720 $g->download ($regfile, "$dir/reg");
722 # 'reged' command is particularly noisy. Redirect stdout and
723 # stderr to /dev/null temporarily.
724 open SAVEOUT, ">&STDOUT";
725 open SAVEERR, ">&STDERR";
726 open STDOUT, ">/dev/null";
727 open STDERR, ">/dev/null";
729 my @cmd = ("reged", "-x", "$dir/reg", "$prefix", "\\", "$dir/out");
730 my $res = system (@cmd);
734 open STDOUT, ">&SAVEOUT";
735 open STDERR, ">&SAVEERR";
740 warn "reged command failed: $?";
744 # Some versions of reged segfault on inputs. If that happens we
745 # may get no / partial output file. Anyway, if it exists, load
748 unless (open F, "$dir/out") {
749 warn "no output from reged command: $!";
752 { local $/ = undef; $content = <F>; }
756 @registry = @{$r->{registry}} if exists $r->{registry};
757 push @registry, $content;
758 $r->{registry} = \@registry;
767 # Grub version, if we care.
770 =head2 inspect_operating_systems
772 \%oses = inspect_operating_systems ($g, \%fses);
774 This function works out how partitions are related to each other. In
775 the case of a single-boot VM, we work out how the partitions are
776 mounted in respect of each other (eg. C</dev/sda1> is mounted as
777 C</boot>). In the case of a multi-boot VM where there are several
778 roots, we may identify several operating system roots, and mountpoints
781 This function returns a hashref C<\%oses> which at the top level looks
785 '/dev/VG/Root' => \%os,
788 (There can be multiple roots for a multi-boot VM).
790 The C<\%os> hash contains the following keys (any can be omitted):
796 Operating system type, eg. "linux", "windows".
800 Operating system distribution, eg. "debian".
804 Operating system version, eg. "4.0".
808 The value is a reference to the root partition C<%fs> hash.
812 The value is the name of the root partition (as a string).
817 The value is a hashref like this:
820 '/' => '/dev/VG/Root',
821 '/boot' => '/dev/sda1',
826 Filesystems (including swap devices and unmounted partitions).
827 The value is a hashref like this:
831 '/dev/VG/Root' => \%fs,
832 '/dev/VG/Swap' => \%fs,
839 sub inspect_operating_systems
847 foreach (sort keys %$fses) {
848 if ($fses->{$_}->{is_root}) {
853 _get_os_version ($g, \%r);
854 _assign_mount_points ($g, $fses, \%r);
868 $r->{os} = $r->{root}->{fsos} if exists $r->{root}->{fsos};
869 $r->{distro} = $r->{root}->{osdistro} if exists $r->{root}->{osdistro};
870 $r->{version} = $r->{root}->{osversion} if exists $r->{root}->{osversion};
873 sub _assign_mount_points
880 $r->{mounts} = { "/" => $r->{root_device} };
881 $r->{filesystems} = { $r->{root_device} => $r->{root} };
883 # Use /etc/fstab if we have it to mount the rest.
884 if (exists $r->{root}->{fstab}) {
885 my @fstab = @{$r->{root}->{fstab}};
887 my ($spec, $file) = @$_;
889 my ($dev, $fs) = _find_filesystem ($g, $fses, $spec);
891 $r->{mounts}->{$file} = $dev;
892 $r->{filesystems}->{$dev} = $fs;
893 if (exists $fs->{used}) {
904 # Find filesystem by device name, LABEL=.. or UUID=..
913 foreach (sort keys %$fses) {
914 if (exists $fses->{$_}->{label} &&
915 $fses->{$_}->{label} eq $label) {
916 return ($_, $fses->{$_});
919 warn "unknown filesystem label $label\n";
921 } elsif (/^UUID=(.*)/) {
923 foreach (sort keys %$fses) {
924 if (exists $fses->{$_}->{uuid} &&
925 $fses->{$_}->{uuid} eq $uuid) {
926 return ($_, $fses->{$_});
929 warn "unknown filesystem UUID $uuid\n";
932 return ($_, $fses->{$_}) if exists $fses->{$_};
934 # The following is to handle the case where an fstab entry specifies a
935 # specific device rather than its label or uuid, and the libguestfs
936 # appliance has named the device differently due to the use of a
938 # This will work as long as the underlying drivers recognise devices in
940 if (m{^/dev/hd(.*)} && exists $fses->{"/dev/sd$1"}) {
941 return ("/dev/sd$1", $fses->{"/dev/sd$1"});
943 if (m{^/dev/xvd(.*)} && exists $fses->{"/dev/sd$1"}) {
944 return ("/dev/sd$1", $fses->{"/dev/sd$1"});
946 if (m{^/dev/mapper/(.*)-(.*)$} && exists $fses->{"/dev/$1/$2"}) {
947 return ("/dev/$1/$2", $fses->{"/dev/$1/$2"});
950 return () if m{/dev/cdrom};
952 warn "unknown filesystem $_\n";
957 =head2 mount_operating_system
959 mount_operating_system ($g, \%os);
961 This function mounts the operating system described in the
962 C<%os> hash according to the C<mounts> table in that hash (see
963 C<inspect_operating_systems>).
965 The partitions are mounted read-only.
967 To reverse the effect of this call, use the standard
968 libguestfs API call C<$g-E<gt>umount_all ()>.
972 sub mount_operating_system
978 my $mounts = $os->{mounts};
980 # Have to mount / first. Luckily '/' is early in the ASCII
981 # character set, so this should be OK.
982 foreach (sort keys %$mounts) {
983 $g->mount_ro ($mounts->{$_}, $_)
984 if $_ ne "swap" && $_ ne "none" && ($_ eq '/' || $g->is_dir ($_));
988 =head2 inspect_in_detail
990 mount_operating_system ($g, \%os);
991 inspect_in_detail ($g, \%os);
994 The C<inspect_in_detail> function inspects the mounted operating
995 system for installed applications, installed kernels, kernel modules
998 It adds extra keys to the existing C<%os> hash reflecting what it
999 finds. These extra keys are:
1005 List of applications.
1011 =item modprobe_aliases
1014 The contents of the modprobe configuration.
1016 =item initrd_modules
1019 The kernel modules installed in the initrd. The value is
1020 a hashref of kernel version to list of modules.
1026 sub inspect_in_detail
1032 _check_for_applications ($g, $os);
1033 _check_for_kernels ($g, $os);
1034 if ($os->{os} eq "linux") {
1035 _check_for_modprobe_aliases ($g, $os);
1036 _check_for_initrd ($g, $os);
1040 sub _check_for_applications
1048 my $osn = $os->{os};
1049 if ($osn eq "linux") {
1050 my $distro = $os->{distro};
1051 if (defined $distro && ($distro eq "redhat" || $distro eq "fedora")) {
1052 my @lines = $g->command_lines
1055 "--qf", "%{name} %{epoch} %{version} %{release} %{arch}\n"]);
1057 if (m/^(.*) (.*) (.*) (.*) (.*)$/) {
1059 $epoch = "" if $epoch eq "(none)";
1071 } elsif ($osn eq "windows") {
1073 # I worked out a general plan for this, but haven't
1074 # implemented it yet. We can iterate over /Program Files
1075 # looking for *.EXE files, which we download, then use
1076 # i686-pc-mingw32-windres on, to find the VERSIONINFO
1077 # section, which has a lot of useful information.
1080 $os->{apps} = \@apps;
1083 sub _check_for_kernels
1091 my $osn = $os->{os};
1092 if ($osn eq "linux") {
1093 # Installed kernels will have a corresponding /lib/modules/<version>
1094 # directory, which is the easiest way to find out what kernels
1095 # are installed, and what modules are available.
1096 foreach ($g->ls ("/lib/modules")) {
1097 if ($g->is_dir ("/lib/modules/$_")) {
1099 $kernel{version} = $_;
1103 foreach ($g->find ("/lib/modules/$_")) {
1104 if (m,/([^/]+)\.ko$, || m,([^/]+)\.o$,) {
1109 $kernel{modules} = \@modules;
1111 push @kernels, \%kernel;
1115 } elsif ($osn eq "windows") {
1119 $os->{kernels} = \@kernels;
1122 # Check /etc/modprobe.conf to see if there are any specified
1123 # drivers associated with network (ethX) or hard drives. Normally
1124 # one might find something like:
1127 # alias scsi_hostadapter xenblk
1129 # XXX This doesn't look beyond /etc/modprobe.conf, eg. in /etc/modprobe.d/
1131 sub _check_for_modprobe_aliases
1139 $success = $g->aug_init("/", 16);
1141 # Register /etc/modules.conf and /etc/conf.modules to the Modprobe lens
1143 @results = $g->aug_match("/augeas/load/Modprobe/incl");
1145 # Calculate the next index of /augeas/load/Modprobe/incl
1147 foreach ( @results ) {
1148 next unless m{/augeas/load/Modprobe/incl\[(\d*)]};
1149 $i = $1 + 1 if ($1 == $i);
1152 $success = $g->aug_set("/augeas/load/Modprobe/incl[$i]",
1153 "/etc/modules.conf");
1155 $success = $g->aug_set("/augeas/load/Modprobe/incl[$i]",
1156 "/etc/conf.modules");
1158 # Make augeas reload
1159 $success = $g->aug_load();
1161 my %modprobe_aliases;
1163 for my $pattern qw(/files/etc/conf.modules/alias
1164 /files/etc/modules.conf/alias
1165 /files/etc/modprobe.conf/alias
1166 /files/etc/modprobe.d/*/alias) {
1167 @results = $g->aug_match($pattern);
1169 for my $path ( @results ) {
1170 $path =~ m{^/files(.*)/alias(?:\[\d*\])?$}
1171 or die("$path doesn't match augeas pattern");
1175 $alias = $g->aug_get($path);
1178 $modulename = $g->aug_get($path.'/modulename');
1181 $aliasinfo{modulename} = $modulename;
1182 $aliasinfo{augeas} = $path;
1183 $aliasinfo{file} = $file;
1185 $modprobe_aliases{$alias} = \%aliasinfo;
1189 $os->{modprobe_aliases} = \%modprobe_aliases;
1192 # Get a listing of device drivers in any initrd corresponding to a
1193 # kernel. This is an indication of what can possibly be booted.
1195 sub _check_for_initrd
1203 foreach my $initrd ($g->ls ("/boot")) {
1204 if ($initrd =~ m/^initrd-(.*)\.img$/ && $g->is_file ("/boot/$initrd")) {
1209 @modules = $g->initrd_list ("/boot/$initrd");
1212 @modules = grep { m,([^/]+)\.ko$, || m,([^/]+)\.o$, } @modules;
1213 $initrd_modules{$version} = \@modules
1215 warn "/boot/$initrd: could not read initrd format"
1220 $os->{initrd_modules} = \%initrd_modules;
1228 Copyright (C) 2009 Red Hat Inc.
1232 Please see the file COPYING.LIB for the full license.
1236 L<virt-inspector(1)>,
1239 L<http://libguestfs.org/>,
1241 L<http://libvirt.org/>,