New APIs for guest inspection.

This commit converts (some of) the Perl inspection code to C and
makes it available through core APIs.  The new APIs are:

inspect-os        - Does the inspection, returns list of OSes
inspect-get-*     - Get results of the inspection

where '*' is one of:

  type            - 'windows' or 'linux'
  distro          - Linux distro
  arch            - architecture
  product-name    - long product name string
  major-version
  minor-version   - major.minor version of OS
  mountpoints     - get a list of the mountpoints
  filesystems     - get all filesystems associated with the OS

This works for all existing supported Linux and Windows OSes.
This commit is contained in:
Richard Jones
2010-07-28 15:40:42 +01:00
parent 65e9ac4595
commit 8289aa1ad6
6 changed files with 1360 additions and 5 deletions

View File

@@ -131,7 +131,7 @@ libguestfs_la_SOURCES = \
proto.c \
libguestfs.syms
libguestfs_la_LIBADD = $(LIBPCRE) $(LIBMAGIC) $(LTLIBTHREAD) ../gnulib/lib/libgnu.la
libguestfs_la_LIBADD = $(HIVEX_LIBS) $(LIBPCRE) $(LIBMAGIC) $(LTLIBTHREAD) ../gnulib/lib/libgnu.la
# Make libguestfs include the convenience library.
noinst_LTLIBRARIES = libprotocol.la
@@ -139,6 +139,7 @@ libguestfs_la_LIBADD += libprotocol.la
libguestfs_la_CFLAGS = \
-DGUESTFS_DEFAULT_PATH='"$(libdir)/guestfs"' \
$(HIVEX_CFLAGS) \
$(WARN_CFLAGS) $(WERROR_CFLAGS)
libguestfs_la_CPPFLAGS = -I$(top_srcdir)/gnulib/lib

View File

@@ -1068,6 +1068,227 @@ initrd or kernel module(s) instead.
=back");
("inspect_os", (RStringList "roots", []), -1, [],
[],
"inspect disk and return list of operating systems found",
"\
This function uses other libguestfs functions and certain
heuristics to inspect the disk(s) (usually disks belonging to
a virtual machine), looking for operating systems.
The list returned is empty if no operating systems were found.
If one operating system was found, then this returns a list with
a single element, which is the name of the root filesystem of
this operating system. It is also possible for this function
to return a list containing more than one element, indicating
a dual-boot or multi-boot virtual machine, with each element being
the root filesystem of one of the operating systems.
You can pass the root string(s) returned to other
C<guestfs_inspect_get_*> functions in order to query further
information about each operating system, such as the name
and version.
This function uses other libguestfs features such as
C<guestfs_mount_ro> and C<guestfs_umount_all> in order to mount
and unmount filesystems and look at the contents. This should
be called with no disks currently mounted. The function may also
use Augeas, so any existing Augeas handle will be closed.
This function cannot decrypt encrypted disks. The caller
must do that first (supplying the necessary keys) if the
disk is encrypted.
Please read L<guestfs(3)/INSPECTION> for more details.");
("inspect_get_type", (RString "name", [Device "root"]), -1, [],
[],
"get type of inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns the type of the inspected operating system.
Currently defined types are:
=over 4
=item \"linux\"
Any Linux-based operating system.
=item \"windows\"
Any Microsoft Windows operating system.
=item \"unknown\"
The operating system type could not be determined.
=back
Future versions of libguestfs may return other strings here.
The caller should be prepared to handle any string.
Please read L<guestfs(3)/INSPECTION> for more details.");
("inspect_get_arch", (RString "arch", [Device "root"]), -1, [],
[],
"get architecture of inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns the architecture of the inspected operating system.
The possible return values are listed under
C<guestfs_file_architecture>.
If the architecture could not be determined, then the
string C<unknown> is returned.
Please read L<guestfs(3)/INSPECTION> for more details.");
("inspect_get_distro", (RString "distro", [Device "root"]), -1, [],
[],
"get distro of inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns the distro (distribution) of the inspected operating
system.
Currently defined distros are:
=over 4
=item \"debian\"
Debian or a Debian-derived distro such as Ubuntu.
=item \"fedora\"
Fedora.
=item \"redhat-based\"
Some Red Hat-derived distro.
=item \"rhel\"
Red Hat Enterprise Linux and some derivatives.
=item \"windows\"
Windows does not have distributions. This string is
returned if the OS type is Windows.
=item \"unknown\"
The distro could not be determined.
=back
Future versions of libguestfs may return other strings here.
The caller should be prepared to handle any string.
Please read L<guestfs(3)/INSPECTION> for more details.");
("inspect_get_major_version", (RInt "major", [Device "root"]), -1, [],
[],
"get major version of inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns the major version number of the inspected operating
system.
Windows uses a consistent versioning scheme which is I<not>
reflected in the popular public names used by the operating system.
Notably the operating system known as \"Windows 7\" is really
version 6.1 (ie. major = 6, minor = 1). You can find out the
real versions corresponding to releases of Windows by consulting
Wikipedia or MSDN.
If the version could not be determined, then C<0> is returned.
Please read L<guestfs(3)/INSPECTION> for more details.");
("inspect_get_minor_version", (RInt "minor", [Device "root"]), -1, [],
[],
"get minor version of inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns the minor version number of the inspected operating
system.
If the version could not be determined, then C<0> is returned.
Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_major_version>.");
("inspect_get_product_name", (RString "product", [Device "root"]), -1, [],
[],
"get product name of inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns the product name of the inspected operating
system. The product name is generally some freeform string
which can be displayed to the user, but should not be
parsed by programs.
If the product name could not be determined, then the
string C<unknown> is returned.
Please read L<guestfs(3)/INSPECTION> for more details.");
("inspect_get_mountpoints", (RHashtable "mountpoints", [Device "root"]), -1, [],
[],
"get mountpoints of inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns a hash of where we think the filesystems
associated with this operating system should be mounted.
Callers should note that this is at best an educated guess
made by reading configuration files such as C</etc/fstab>.
Each element in the returned hashtable has a key which
is the path of the mountpoint (eg. C</boot>) and a value
which is the filesystem that would be mounted there
(eg. C</dev/sda1>).
Non-mounted devices such as swap devices are I<not>
returned in this list.
Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_filesystems>.");
("inspect_get_filesystems", (RStringList "filesystems", [Device "root"]), -1, [],
[],
"get filesystems associated with inspected operating system",
"\
This function should only be called with a root device string
as returned by C<guestfs_inspect_os>.
This returns a list of all the filesystems that we think
are associated with this operating system. This includes
the root filesystem, other ordinary filesystems, and
non-mounted devices like swap partitions.
In the case of a multi-boot virtual machine, it is possible
for a filesystem to be shared between operating systems.
Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_mountpoints>.");
]
(* daemon_functions are any functions which cause some action

View File

@@ -131,6 +131,59 @@ struct guestfs_h
void * close_cb_data;
int msg_next_serial;
/* Information gathered by inspect_os. Must be freed by calling
* guestfs___free_inspect_info.
*/
struct inspect_fs *fses;
size_t nr_fses;
};
/* Per-filesystem data stored for inspect_os. */
enum inspect_fs_content {
FS_CONTENT_UNKNOWN = 0,
FS_CONTENT_LINUX_ROOT,
FS_CONTENT_WINDOWS_ROOT,
FS_CONTENT_LINUX_BOOT,
FS_CONTENT_LINUX_USR,
FS_CONTENT_LINUX_USR_LOCAL,
FS_CONTENT_LINUX_VAR,
};
enum inspect_os_type {
OS_TYPE_UNKNOWN = 0,
OS_TYPE_LINUX,
OS_TYPE_WINDOWS,
};
enum inspect_os_distro {
OS_DISTRO_UNKNOWN = 0,
OS_DISTRO_DEBIAN,
OS_DISTRO_FEDORA,
OS_DISTRO_REDHAT_BASED,
OS_DISTRO_RHEL,
OS_DISTRO_WINDOWS,
};
struct inspect_fs {
int is_root;
char *device;
int is_mountable;
int is_swap;
enum inspect_fs_content content;
enum inspect_os_type type;
enum inspect_os_distro distro;
char *product_name;
int major_version;
int minor_version;
char *arch;
struct inspect_fstab_entry *fstab;
size_t nr_fstab;
};
struct inspect_fstab_entry {
char *device;
char *mountpoint;
};
struct guestfs_message_header;
@@ -143,6 +196,7 @@ extern void *guestfs_safe_realloc (guestfs_h *g, void *ptr, int nbytes);
extern char *guestfs_safe_strdup (guestfs_h *g, const char *str);
extern char *guestfs_safe_strndup (guestfs_h *g, const char *str, size_t n);
extern void *guestfs_safe_memdup (guestfs_h *g, void *ptr, size_t size);
extern void guestfs___free_inspect_info (guestfs_h *g);
extern int guestfs___set_busy (guestfs_h *g);
extern int guestfs___end_busy (guestfs_h *g);
extern int guestfs___send (guestfs_h *g, int proc_nr, xdrproc_t xdrp, char *args);

View File

@@ -184,6 +184,8 @@ guestfs_close (guestfs_h *g)
if (g->close_cb)
g->close_cb (g, g->close_cb_data);
guestfs___free_inspect_info (g);
/* Try to sync if autosync flag is set. */
if (g->autosync && g->state == READY) {
guestfs_umount_all (g);

View File

@@ -160,9 +160,10 @@ you have to find out. Libguestfs can do that too: use
L</guestfs_list_partitions> and L</guestfs_lvs> to list possible
partitions and LVs, and either try mounting each to see what is
mountable, or else examine them with L</guestfs_vfs_type> or
L</guestfs_file>. But you might find it easier to look at higher level
programs built on top of libguestfs, in particular
L<virt-inspector(1)>.
L</guestfs_file>. Libguestfs also has a set of APIs for inspection of
disk images (see L</INSPECTION> below). But you might find it easier
to look at higher level programs built on top of libguestfs, in
particular L<virt-inspector(1)>.
To mount a disk image read-only, use L</guestfs_mount_ro>. There are
several other variations of the C<guestfs_mount_*> call.
@@ -481,6 +482,65 @@ Then close the mapper device by calling
L</guestfs_luks_close> on the C</dev/mapper/mapname>
device (I<not> the underlying encrypted block device).
=head2 INSPECTION
Libguestfs has APIs for inspecting an unknown disk image to find out
if it contains operating systems. (These APIs used to be in a
separate Perl-only library called L<Sys::Guestfs::Lib(3)> but since
version 1.5.3 the most frequently used part of this library has been
rewritten in C and moved into the core code).
Add all disks belonging to the unknown virtual machine and call
L</guestfs_launch> in the usual way.
Then call L</guestfs_inspect_os>. This function uses other libguestfs
calls and certain heuristics, and returns a list of operating systems
that were found. An empty list means none were found. A single
element is the root filesystem of the operating system. For dual- or
multi-boot guests, multiple roots can be returned, each one
corresponding to a separate operating system. (Multi-boot virtual
machines are extremely rare in the world of virtualization, but since
this scenario can happen, we have built libguestfs to deal with it.)
For each root, you can then call various C<guestfs_inspect_get_*>
functions to get additional details about that operating system. For
example, call L</guestfs_inspect_get_type> to return the string
C<windows> or C<linux> for Windows and Linux-based operating systems
respectively.
Un*x-like and Linux-based operating systems usually consist of several
filesystems which are mounted at boot time (for example, a separate
boot partition mounted on C</boot>). The inspection rules are able to
detect how filesystems correspond to mount points. Call
C<guestfs_inspect_get_mountpoints> to get this mapping. It might
return a hash table like this example:
/boot => /dev/sda1
/ => /dev/vg_guest/lv_root
/usr => /dev/vg_guest/lv_usr
The caller can then make calls to L</guestfs_mount_options> to
mount the filesystems as suggested.
Be careful to mount filesystems in the right order (eg. C</> before
C</usr>). Sorting the keys of the hash by length, shortest first,
should work.
Inspection currently only works for some common operating systems.
Contributors are welcome to send patches for other operating systems
that we currently cannot detect.
Encrypted disks must be opened before inspection. See
L</ENCRYPTED DISKS> for more details. The L</guestfs_inspect_os>
function just ignores any encrypted devices.
A note on the implementation: The call L</guestfs_inspect_os> performs
inspection and caches the results in the guest handle. Subsequent
calls to C<guestfs_inspect_get_*> return this cached information, but
I<do not> re-read the disks. If you change the content of the guest
disks, you can redo inspection by calling L</guestfs_inspect_os>
again.
=head2 SPECIAL CONSIDERATIONS FOR WINDOWS GUESTS
Libguestfs can mount NTFS partitions. It does this using the
@@ -495,7 +555,7 @@ that directory might be referred to as C</WINDOWS/System32>.
Drive letter mappings are outside the scope of libguestfs. You have
to use libguestfs to read the appropriate Windows Registry and
configuration files, to determine yourself how drives are mapped (see
also L<virt-inspector(1)>).
also L<hivex(3)> and L<virt-inspector(1)>).
Replacing backslash characters with forward slash characters is also
outside the scope of libguestfs, but something that you can easily do.

File diff suppressed because it is too large Load Diff