From: Richard Jones Date: Tue, 28 Jul 2009 16:55:35 +0000 (+0100) Subject: Lib.pm: Add file_architecture command. X-Git-Tag: 1.0.65~10 X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=commitdiff_plain;h=1f65b900f0f17a700035dea9a76b910504f4507c Lib.pm: Add file_architecture command. This command detects the architecture of some types of binaries, libraries, kernel modules and initrd images. --- diff --git a/.gitignore b/.gitignore index d66ed99..f2064a3 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,8 @@ images/100kallzeroes images/100krandom images/10klines images/initrd +images/initrd-x86_64.img +images/initrd-x86_64.img.gz images/test.sqsh initramfs initramfs.timestamp @@ -123,6 +125,7 @@ missing *.o ocaml/bindtests ocaml/bindtests.ml +ocaml/dllmlguestfs.so ocaml/examples/lvs ocaml/guestfs_c_actions.c ocaml/guestfs.ml @@ -156,9 +159,9 @@ python/guestfs.pyc ruby/bindtests.rb ruby/ext/guestfs/extconf.h ruby/ext/guestfs/_guestfs.c +ruby/ext/guestfs/_guestfs.so ruby/ext/guestfs/mkmf.log ruby/Rakefile -*.so src/guestfs-actions.c src/guestfs-actions.h src/guestfs-bindtests.c @@ -166,6 +169,7 @@ src/guestfs_protocol.c src/guestfs_protocol.h src/guestfs_protocol.x src/guestfs-structs.h +src/.libs/libguestfs.so src/.pod2text.data src/stamp-generator stamp-h1 diff --git a/images/Makefile.am b/images/Makefile.am index 56a22fd..d4aed55 100644 --- a/images/Makefile.am +++ b/images/Makefile.am @@ -22,7 +22,18 @@ EXTRA_DIST = \ helloworld.tar \ helloworld.tar.gz \ mbr-ext2-empty.img.gz \ - empty known-1 known-2 known-3 + empty known-1 known-2 known-3 \ + bin-i586-dynamic \ + bin-sparc-dynamic \ + bin-win32.exe \ + bin-win64.exe \ + bin-x86_64-dynamic \ + lib-i586.so \ + lib-sparc.so \ + lib-win32.dll \ + lib-win64.dll \ + lib-x86_64.so + noinst_DATA = test.sqsh @@ -37,7 +48,17 @@ squash_files_src = \ $(srcdir)/empty \ $(srcdir)/known-1 \ $(srcdir)/known-2 \ - $(srcdir)/known-3 + $(srcdir)/known-3 \ + $(srcdir)/bin-i586-dynamic \ + $(srcdir)/bin-sparc-dynamic \ + $(srcdir)/bin-win32.exe \ + $(srcdir)/bin-win64.exe \ + $(srcdir)/bin-x86_64-dynamic \ + $(srcdir)/lib-i586.so \ + $(srcdir)/lib-sparc.so \ + $(srcdir)/lib-win32.dll \ + $(srcdir)/lib-win64.dll \ + $(srcdir)/lib-x86_64.so squash_files_build = \ $(builddir)/100kallzeroes \ @@ -45,7 +66,9 @@ squash_files_build = \ $(builddir)/100kallspaces \ $(builddir)/100krandom \ $(builddir)/10klines \ - $(builddir)/initrd + $(builddir)/initrd \ + $(builddir)/initrd-x86_64.img \ + $(builddir)/initrd-x86_64.img.gz squash_files = $(squash_files_src) $(squash_files_build) @@ -86,3 +109,18 @@ $(builddir)/initrd: empty known-1 known-2 known-3 rm -f $@ $@-t for f in $^; do echo $$f; done | cpio -o -H newc | gzip --best > $@-t mv $@-t $@ + +# Create a dummy initrd with a single file called 'bin/nash' which +# is used to test the Sys::Guestfs::Lib::file_architecture function. +$(builddir)/initrd-x86_64.img: bin-x86_64-dynamic + rm -rf bin $@ $@-t + mkdir bin + cp $< bin/nash + echo bin/nash | cpio -o -H newc > $@-t + mv $@-t $@ + rm -rf bin $@-t + +$(builddir)/initrd-x86_64.img.gz: initrd-x86_64.img + rm -f $@ $@-t + gzip --best -c $< > $@-t + mv $@-t $@ diff --git a/images/README-binfiles b/images/README-binfiles new file mode 100644 index 0000000..f99fc84 --- /dev/null +++ b/images/README-binfiles @@ -0,0 +1,13 @@ +The bin-* and lib-* files are used for testing the +Sys::Guestfs::Lib::file_architecture API. + +The bin-* files are generated from empty source files (ie. +"main(){}") on the respective architectures. + +The lib-* files are generated from a (really) empty source file called +lib.c which is linked into a library using gcc -shared on the +respective architectures. + +If you are concerned that these binary files "lack source" then you +can just remove them, but you may need to patch out tests in the perl/ +directory. diff --git a/images/bin-i586-dynamic b/images/bin-i586-dynamic new file mode 100755 index 0000000..4f77063 Binary files /dev/null and b/images/bin-i586-dynamic differ diff --git a/images/bin-sparc-dynamic b/images/bin-sparc-dynamic new file mode 100755 index 0000000..138839a Binary files /dev/null and b/images/bin-sparc-dynamic differ diff --git a/images/bin-win32.exe b/images/bin-win32.exe new file mode 100755 index 0000000..db6d575 Binary files /dev/null and b/images/bin-win32.exe differ diff --git a/images/bin-win64.exe b/images/bin-win64.exe new file mode 100755 index 0000000..98bddc0 Binary files /dev/null and b/images/bin-win64.exe differ diff --git a/images/bin-x86_64-dynamic b/images/bin-x86_64-dynamic new file mode 100755 index 0000000..033ac75 Binary files /dev/null and b/images/bin-x86_64-dynamic differ diff --git a/images/lib-i586.so b/images/lib-i586.so new file mode 100755 index 0000000..e82023a Binary files /dev/null and b/images/lib-i586.so differ diff --git a/images/lib-sparc.so b/images/lib-sparc.so new file mode 100755 index 0000000..7feec75 Binary files /dev/null and b/images/lib-sparc.so differ diff --git a/images/lib-win32.dll b/images/lib-win32.dll new file mode 100755 index 0000000..e1a2d2e Binary files /dev/null and b/images/lib-win32.dll differ diff --git a/images/lib-win64.dll b/images/lib-win64.dll new file mode 100755 index 0000000..ca94485 Binary files /dev/null and b/images/lib-win64.dll differ diff --git a/images/lib-x86_64.so b/images/lib-x86_64.so new file mode 100755 index 0000000..8cee4d2 Binary files /dev/null and b/images/lib-x86_64.so differ diff --git a/perl/lib/Sys/Guestfs/Lib.pm b/perl/lib/Sys/Guestfs/Lib.pm index bc8be9d..081b4b9 100644 --- a/perl/lib/Sys/Guestfs/Lib.pm +++ b/perl/lib/Sys/Guestfs/Lib.pm @@ -300,6 +300,163 @@ sub resolve_windows_path return $path; } +=head2 file_architecture + + $arch = file_architecture ($g, $path) + +The C function lets you get the architecture for a +particular binary or library in the guest. By "architecture" we mean +what processor it is compiled for (eg. C or C). + +The function works on at least the following types of files: + +=over 4 + +=item * + +many types of Un*x binary + +=item * + +many types of Un*x shared library + +=item * + +Windows Win32 and Win64 binaries + +=item * + +Windows Win32 and Win64 DLLs + +Win32 binaries and DLLs return C. + +Win64 binaries and DLLs return C. + +=item * + +Linux kernel modules + +=item * + +Linux new-style initrd images + +=item * + +some non-x86 Linux vmlinuz kernels + +=back + +What it can't do currently: + +=over 4 + +=item * + +static libraries (libfoo.a) + +=item * + +Linux old-style initrd as compressed ext2 filesystem (RHEL 3) + +=item * + +x86 Linux vmlinuz kernels + +x86 vmlinuz images (bzImage format) consist of a mix of 16-, 32- and +compressed code, and are horribly hard to unpack. If you want to find +the architecture of a kernel, use the architecture of the associated +initrd or kernel module(s) instead. + +=back + +=cut + +sub _elf_arch_to_canonical +{ + local $_ = shift; + + if ($_ eq "Intel 80386") { + return "i386"; + } elsif ($_ eq "Intel 80486") { + return "i486"; # probably not in the wild + } elsif ($_ eq "x86-64") { + return "x86_64"; + } elsif (/SPARC32/) { + return "sparc"; + } elsif (/SPARC V9/) { + return "sparc64"; + } elsif ($_ eq "IA-64") { + return "ia64"; + } elsif (/64.*PowerPC/) { + return "ppc64"; + } elsif (/PowerPC/) { + return "ppc"; + } else { + warn __x("returning non-canonical architecture type '{arch}'", + arch => $_); + return $_; + } +} + +my @_initrd_binaries = ("nash", "modprobe", "sh", "bash"); + +sub file_architecture +{ + local $_; + my $g = shift; + my $path = shift; + + # Our basic tool is 'file' ... + my $file = $g->file ($path); + + if ($file =~ /ELF.*(?:executable|shared object|relocatable), (.+?),/) { + # ELF executable or shared object. We need to convert + # what file(1) prints into the canonical form. + return _elf_arch_to_canonical ($1); + } elsif ($file =~ /PE32 executable/) { + return "i386"; # Win32 executable or DLL + } elsif ($file =~ /PE32\+ executable/) { + return "x86_64"; # Win64 executable or DLL + } + + elsif ($file =~ /cpio archive/) { + # Probably an initrd. + my $zcat = "cat"; + if ($file =~ /gzip/) { + $zcat = "zcat"; + } elsif ($file =~ /bzip2/) { + $zcat = "bzcat"; + } + + # Download and unpack it to find a binary file. + my $dir = tempdir (CLEANUP => 1); + $g->download ($path, "$dir/initrd"); + + my $bins = join " ", map { "bin/$_" } @_initrd_binaries; + my $cmd = "cd $dir && $zcat initrd | cpio -id $bins"; + my $r = system ($cmd); + die __x("cpio command failed: {error}", error => $?) + unless $r == 0; + + foreach my $bin (@_initrd_binaries) { + if (-f "$dir/bin/$bin") { + open PIPE, "file $dir/bin/$bin |"; + local $/ = undef; + $_ = ; + if (/ELF.*executable, (.+?),/) { + return _elf_arch_to_canonical ($1); + } + } + } + + die __x("file_architecture: no known binaries found in initrd image: {path}", + path => $path); + } + + die __x("file_architecture: unknown architecture: {path}", + path => $path); +} + =head1 OPERATING SYSTEM INSPECTION FUNCTIONS The functions in this section can be used to inspect the operating @@ -1094,8 +1251,8 @@ sub mount_operating_system $g->umount_all (); The C function inspects the mounted operating -system for installed applications, installed kernels, kernel modules -and more. +system for installed applications, installed kernels, kernel modules, +system architecture, and more. It adds extra keys to the existing C<%os> hash reflecting what it finds. These extra keys are: diff --git a/perl/t/500-lib-load.t b/perl/t/500-lib-load.t new file mode 100644 index 0000000..1407169 --- /dev/null +++ b/perl/t/500-lib-load.t @@ -0,0 +1,26 @@ +# libguestfs Perl bindings -*- perl -*- +# Copyright (C) 2009 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +use strict; +use warnings; +use Test::More tests => 1; + +use Sys::Guestfs; +use Sys::Guestfs::Lib; + +# Just check Lib can be loaded. +ok (1); diff --git a/perl/t/510-lib-file-arch.t b/perl/t/510-lib-file-arch.t new file mode 100644 index 0000000..14392e8 --- /dev/null +++ b/perl/t/510-lib-file-arch.t @@ -0,0 +1,62 @@ +# libguestfs Perl bindings -*- perl -*- +# Copyright (C) 2009 Red Hat Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +use strict; +use warnings; +use Test::More tests => 17; + +use Sys::Guestfs; +use Sys::Guestfs::Lib; + +my $h = Sys::Guestfs->new (); +ok ($h); + +$h->add_drive_ro ("../images/test.sqsh"); +ok (1); + +$h->launch (); +ok (1); +$h->wait_ready (); +ok (1); + +$h->mount_vfs ("ro", "squashfs", "/dev/sda", "/"); +ok (1); + +is (Sys::Guestfs::Lib::file_architecture ($h, "/bin-i586-dynamic"), + "i386"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/bin-sparc-dynamic"), + "sparc"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/bin-win32.exe"), + "i386"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/bin-win64.exe"), + "x86_64"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/bin-x86_64-dynamic"), + "x86_64"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/lib-i586.so"), + "i386"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/lib-sparc.so"), + "sparc"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/lib-win32.dll"), + "i386"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/lib-win64.dll"), + "x86_64"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/lib-x86_64.so"), + "x86_64"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/initrd-x86_64.img"), + "x86_64"); +is (Sys::Guestfs::Lib::file_architecture ($h, "/initrd-x86_64.img.gz"), + "x86_64");