Remove inspection from the C library and switch to daemon/OCaml implementation.

This commit is contained in:
Richard W.M. Jones
2017-07-17 17:23:40 +01:00
parent 5aad7e779c
commit 3a00c4d179
17 changed files with 408 additions and 4938 deletions

View File

@@ -312,9 +312,6 @@ lib/guid.c
lib/handle.c
lib/info.c
lib/inspect-apps.c
lib/inspect-fs-unix.c
lib/inspect-fs-windows.c
lib/inspect-fs.c
lib/inspect-icon.c
lib/inspect.c
lib/journal.c

View File

@@ -51,6 +51,8 @@ let daemon_functions =
Actions_debug.daemon_functions @
Actions_hivex.daemon_functions @
Actions_hivex_deprecated.daemon_functions @
Actions_inspection.daemon_functions @
Actions_inspection_deprecated.daemon_functions @
Actions_tsk.daemon_functions @
Actions_yara.daemon_functions

View File

@@ -22,10 +22,11 @@ open Types
(* Inspection APIs. *)
let non_daemon_functions = [
let daemon_functions = [
{ defaults with
name = "inspect_os"; added = (1, 5, 3);
style = RStringList (RMountable, "roots"), [], [];
impl = OCaml "Inspect.inspect_os";
shortdesc = "inspect disk and return list of operating systems found";
longdesc = "\
This function uses other libguestfs functions and certain
@@ -60,9 +61,25 @@ Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_list_filesystems>." };
{ defaults with
name = "inspect_get_roots"; added = (1, 7, 3);
style = RStringList (RMountable, "roots"), [], [];
impl = OCaml "Inspect.inspect_get_roots";
shortdesc = "return list of operating systems found by last inspection";
longdesc = "\
This function is a convenient way to get the list of root
devices, as returned from a previous call to C<guestfs_inspect_os>,
but without redoing the whole inspection process.
This returns an empty list if either no root devices were
found or the caller has not called C<guestfs_inspect_os>.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_type"; added = (1, 5, 3);
style = RString (RPlainString, "name"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_type";
shortdesc = "get type of inspected operating system";
longdesc = "\
This returns the type of the inspected operating system.
@@ -116,6 +133,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_arch"; added = (1, 5, 3);
style = RString (RPlainString, "arch"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_arch";
shortdesc = "get architecture of inspected operating system";
longdesc = "\
This returns the architecture of the inspected operating system.
@@ -130,6 +148,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_distro"; added = (1, 5, 3);
style = RString (RPlainString, "distro"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_distro";
shortdesc = "get distro of inspected operating system";
longdesc = "\
This returns the distro (distribution) of the inspected operating
@@ -286,6 +305,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_major_version"; added = (1, 5, 3);
style = RInt "major", [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_major_version";
shortdesc = "get major version of inspected operating system";
longdesc = "\
This returns the major version number of the inspected operating
@@ -305,6 +325,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_minor_version"; added = (1, 5, 3);
style = RInt "minor", [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_minor_version";
shortdesc = "get minor version of inspected operating system";
longdesc = "\
This returns the minor version number of the inspected operating
@@ -318,6 +339,7 @@ See also C<guestfs_inspect_get_major_version>." };
{ defaults with
name = "inspect_get_product_name"; added = (1, 5, 3);
style = RString (RPlainString, "product"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_product_name";
shortdesc = "get product name of inspected operating system";
longdesc = "\
This returns the product name of the inspected operating
@@ -328,11 +350,167 @@ 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." };
{ defaults with
name = "inspect_get_windows_systemroot"; added = (1, 5, 25);
style = RString (RPlainString, "systemroot"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_windows_systemroot";
shortdesc = "get Windows systemroot of inspected operating system";
longdesc = "\
This returns the Windows systemroot of the inspected guest.
The systemroot is a directory path such as F</WINDOWS>.
This call assumes that the guest is Windows and that the
systemroot could be determined by inspection. If this is not
the case then an error is returned.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_package_format"; added = (1, 7, 5);
style = RString (RPlainString, "packageformat"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_package_format";
shortdesc = "get package format used by the operating system";
longdesc = "\
This function and C<guestfs_inspect_get_package_management> return
the package format and package management tool used by the
inspected operating system. For example for Fedora these
functions would return C<rpm> (package format), and
C<yum> or C<dnf> (package management).
This returns the string C<unknown> if we could not determine the
package format I<or> if the operating system does not have
a real packaging system (eg. Windows).
Possible strings include:
C<rpm>, C<deb>, C<ebuild>, C<pisi>, C<pacman>, C<pkgsrc>, C<apk>,
C<xbps>.
Future versions of libguestfs may return other strings.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_package_management"; added = (1, 7, 5);
style = RString (RPlainString, "packagemanagement"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_package_management";
shortdesc = "get package management tool used by the operating system";
longdesc = "\
C<guestfs_inspect_get_package_format> and this function return
the package format and package management tool used by the
inspected operating system. For example for Fedora these
functions would return C<rpm> (package format), and
C<yum> or C<dnf> (package management).
This returns the string C<unknown> if we could not determine the
package management tool I<or> if the operating system does not have
a real packaging system (eg. Windows).
Possible strings include: C<yum>, C<dnf>, C<up2date>,
C<apt> (for all Debian derivatives),
C<portage>, C<pisi>, C<pacman>, C<urpmi>, C<zypper>, C<apk>, C<xbps>.
Future versions of libguestfs may return other strings.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_hostname"; added = (1, 7, 9);
style = RString (RPlainString, "hostname"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_hostname";
shortdesc = "get hostname of the operating system";
longdesc = "\
This function returns the hostname of the operating system
as found by inspection of the guests configuration files.
If the hostname could not be determined, then the
string C<unknown> is returned.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_product_variant"; added = (1, 9, 13);
style = RString (RPlainString, "variant"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_product_variant";
shortdesc = "get product variant of inspected operating system";
longdesc = "\
This returns the product variant of the inspected operating
system.
For Windows guests, this returns the contents of the Registry key
C<HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion>
C<InstallationType> which is usually a string such as
C<Client> or C<Server> (other values are possible). This
can be used to distinguish consumer and enterprise versions
of Windows that have the same version number (for example,
Windows 7 and Windows 2008 Server are both version 6.1,
but the former is C<Client> and the latter is C<Server>).
For enterprise Linux guests, in future we intend this to return
the product variant such as C<Desktop>, C<Server> and so on. But
this is not implemented at present.
If the product variant could not be determined, then the
string C<unknown> is returned.
Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_product_name>,
C<guestfs_inspect_get_major_version>." };
{ defaults with
name = "inspect_get_windows_current_control_set"; added = (1, 9, 17);
style = RString (RPlainString, "controlset"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_windows_current_control_set";
shortdesc = "get Windows CurrentControlSet of inspected operating system";
longdesc = "\
This returns the Windows CurrentControlSet of the inspected guest.
The CurrentControlSet is a registry key name such as C<ControlSet001>.
This call assumes that the guest is Windows and that the
Registry could be examined by inspection. If this is not
the case then an error is returned.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_windows_software_hive"; added = (1, 35, 26);
style = RString (RPlainString, "path"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_windows_software_hive";
shortdesc = "get the path of the Windows software hive";
longdesc = "\
This returns the path to the hive (binary Windows Registry file)
corresponding to HKLM\\SOFTWARE.
This call assumes that the guest is Windows and that the guest
has a software hive file with the right name. If this is not the
case then an error is returned. This call does not check that the
hive is a valid Windows Registry hive.
You can use C<guestfs_hivex_open> to read or write to the hive.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_windows_system_hive"; added = (1, 35, 26);
style = RString (RPlainString, "path"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_windows_system_hive";
shortdesc = "get the path of the Windows system hive";
longdesc = "\
This returns the path to the hive (binary Windows Registry file)
corresponding to HKLM\\SYSTEM.
This call assumes that the guest is Windows and that the guest
has a system hive file with the right name. If this is not the
case then an error is returned. This call does not check that the
hive is a valid Windows Registry hive.
You can use C<guestfs_hivex_open> to read or write to the hive.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_mountpoints"; added = (1, 5, 3);
style = RHashtable (RPlainString, RMountable, "mountpoints"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_mountpoints";
shortdesc = "get mountpoints of inspected operating system";
longdesc = "\
This returns a hash of where we think the filesystems
@@ -364,6 +542,7 @@ See also C<guestfs_inspect_get_filesystems>." };
{ defaults with
name = "inspect_get_filesystems"; added = (1, 5, 3);
style = RStringList (RMountable, "filesystems"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_filesystems";
shortdesc = "get filesystems associated with inspected operating system";
longdesc = "\
This returns a list of all the filesystems that we think
@@ -378,77 +557,43 @@ Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_mountpoints>." };
{ defaults with
name = "inspect_get_windows_systemroot"; added = (1, 5, 25);
style = RString (RPlainString, "systemroot"), [String (Mountable, "root")], [];
shortdesc = "get Windows systemroot of inspected operating system";
name = "inspect_get_drive_mappings"; added = (1, 9, 17);
style = RHashtable (RPlainString, RDevice, "drives"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_drive_mappings";
shortdesc = "get drive letter mappings";
longdesc = "\
This returns the Windows systemroot of the inspected guest.
The systemroot is a directory path such as F</WINDOWS>.
This call is useful for Windows which uses a primitive system
of assigning drive letters (like F<C:\\>) to partitions.
This inspection API examines the Windows Registry to find out
how disks/partitions are mapped to drive letters, and returns
a hash table as in the example below:
This call assumes that the guest is Windows and that the
systemroot could be determined by inspection. If this is not
the case then an error is returned.
C => /dev/vda2
E => /dev/vdb1
F => /dev/vdc1
Please read L<guestfs(3)/INSPECTION> for more details." };
Note that keys are drive letters. For Windows, the key is
case insensitive and just contains the drive letter, without
the customary colon separator character.
{ defaults with
name = "inspect_get_roots"; added = (1, 7, 3);
style = RStringList (RMountable, "roots"), [], [];
shortdesc = "return list of operating systems found by last inspection";
longdesc = "\
This function is a convenient way to get the list of root
devices, as returned from a previous call to C<guestfs_inspect_os>,
but without redoing the whole inspection process.
In future we may support other operating systems that also used drive
letters, but the keys for those might not be case insensitive
and might be longer than 1 character. For example in OS-9,
hard drives were named C<h0>, C<h1> etc.
This returns an empty list if either no root devices were
found or the caller has not called C<guestfs_inspect_os>.
For Windows guests, currently only hard drive mappings are
returned. Removable disks (eg. DVD-ROMs) are ignored.
Please read L<guestfs(3)/INSPECTION> for more details." };
For guests that do not use drive mappings, or if the drive mappings
could not be determined, this returns an empty hash table.
{ defaults with
name = "inspect_get_package_format"; added = (1, 7, 5);
style = RString (RPlainString, "packageformat"), [String (Mountable, "root")], [];
shortdesc = "get package format used by the operating system";
longdesc = "\
This function and C<guestfs_inspect_get_package_management> return
the package format and package management tool used by the
inspected operating system. For example for Fedora these
functions would return C<rpm> (package format), and
C<yum> or C<dnf> (package management).
Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_mountpoints>,
C<guestfs_inspect_get_filesystems>." };
This returns the string C<unknown> if we could not determine the
package format I<or> if the operating system does not have
a real packaging system (eg. Windows).
Possible strings include:
C<rpm>, C<deb>, C<ebuild>, C<pisi>, C<pacman>, C<pkgsrc>, C<apk>,
C<xbps>.
Future versions of libguestfs may return other strings.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_package_management"; added = (1, 7, 5);
style = RString (RPlainString, "packagemanagement"), [String (Mountable, "root")], [];
shortdesc = "get package management tool used by the operating system";
longdesc = "\
C<guestfs_inspect_get_package_format> and this function return
the package format and package management tool used by the
inspected operating system. For example for Fedora these
functions would return C<rpm> (package format), and
C<yum> or C<dnf> (package management).
This returns the string C<unknown> if we could not determine the
package management tool I<or> if the operating system does not have
a real packaging system (eg. Windows).
Possible strings include: C<yum>, C<dnf>, C<up2date>,
C<apt> (for all Debian derivatives),
C<portage>, C<pisi>, C<pacman>, C<urpmi>, C<zypper>, C<apk>, C<xbps>.
Future versions of libguestfs may return other strings.
Please read L<guestfs(3)/INSPECTION> for more details." };
]
let non_daemon_functions = [
{ defaults with
name = "inspect_list_applications2"; added = (1, 19, 56);
style = RStructList ("applications2", "application2"), [String (Mountable, "root")], [];
@@ -552,95 +697,6 @@ If unavailable this is returned as an empty string C<\"\">.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_hostname"; added = (1, 7, 9);
style = RString (RPlainString, "hostname"), [String (Mountable, "root")], [];
shortdesc = "get hostname of the operating system";
longdesc = "\
This function returns the hostname of the operating system
as found by inspection of the guests configuration files.
If the hostname could not be determined, then the
string C<unknown> is returned.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_product_variant"; added = (1, 9, 13);
style = RString (RPlainString, "variant"), [String (Mountable, "root")], [];
shortdesc = "get product variant of inspected operating system";
longdesc = "\
This returns the product variant of the inspected operating
system.
For Windows guests, this returns the contents of the Registry key
C<HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion>
C<InstallationType> which is usually a string such as
C<Client> or C<Server> (other values are possible). This
can be used to distinguish consumer and enterprise versions
of Windows that have the same version number (for example,
Windows 7 and Windows 2008 Server are both version 6.1,
but the former is C<Client> and the latter is C<Server>).
For enterprise Linux guests, in future we intend this to return
the product variant such as C<Desktop>, C<Server> and so on. But
this is not implemented at present.
If the product variant could not be determined, then the
string C<unknown> is returned.
Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_product_name>,
C<guestfs_inspect_get_major_version>." };
{ defaults with
name = "inspect_get_windows_current_control_set"; added = (1, 9, 17);
style = RString (RPlainString, "controlset"), [String (Mountable, "root")], [];
shortdesc = "get Windows CurrentControlSet of inspected operating system";
longdesc = "\
This returns the Windows CurrentControlSet of the inspected guest.
The CurrentControlSet is a registry key name such as C<ControlSet001>.
This call assumes that the guest is Windows and that the
Registry could be examined by inspection. If this is not
the case then an error is returned.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_drive_mappings"; added = (1, 9, 17);
style = RHashtable (RPlainString, RDevice, "drives"), [String (Mountable, "root")], [];
shortdesc = "get drive letter mappings";
longdesc = "\
This call is useful for Windows which uses a primitive system
of assigning drive letters (like F<C:\\>) to partitions.
This inspection API examines the Windows Registry to find out
how disks/partitions are mapped to drive letters, and returns
a hash table as in the example below:
C => /dev/vda2
E => /dev/vdb1
F => /dev/vdc1
Note that keys are drive letters. For Windows, the key is
case insensitive and just contains the drive letter, without
the customary colon separator character.
In future we may support other operating systems that also used drive
letters, but the keys for those might not be case insensitive
and might be longer than 1 character. For example in OS-9,
hard drives were named C<h0>, C<h1> etc.
For Windows guests, currently only hard drive mappings are
returned. Removable disks (eg. DVD-ROMs) are ignored.
For guests that do not use drive mappings, or if the drive mappings
could not be determined, this returns an empty hash table.
Please read L<guestfs(3)/INSPECTION> for more details.
See also C<guestfs_inspect_get_mountpoints>,
C<guestfs_inspect_get_filesystems>." };
{ defaults with
name = "inspect_get_icon"; added = (1, 11, 12);
style = RBufferOut "icon", [String (Mountable, "root")], [OBool "favicon"; OBool "highquality"];
@@ -706,38 +762,4 @@ advice before using trademarks in applications.
=back" };
{ defaults with
name = "inspect_get_windows_software_hive"; added = (1, 35, 26);
style = RString (RPlainString, "path"), [String (Mountable, "root")], [];
shortdesc = "get the path of the Windows software hive";
longdesc = "\
This returns the path to the hive (binary Windows Registry file)
corresponding to HKLM\\SOFTWARE.
This call assumes that the guest is Windows and that the guest
has a software hive file with the right name. If this is not the
case then an error is returned. This call does not check that the
hive is a valid Windows Registry hive.
You can use C<guestfs_hivex_open> to read or write to the hive.
Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_get_windows_system_hive"; added = (1, 35, 26);
style = RString (RPlainString, "path"), [String (Mountable, "root")], [];
shortdesc = "get the path of the Windows system hive";
longdesc = "\
This returns the path to the hive (binary Windows Registry file)
corresponding to HKLM\\SYSTEM.
This call assumes that the guest is Windows and that the guest
has a system hive file with the right name. If this is not the
case then an error is returned. This call does not check that the
hive is a valid Windows Registry hive.
You can use C<guestfs_hivex_open> to read or write to the hive.
Please read L<guestfs(3)/INSPECTION> for more details." };
]

View File

@@ -19,3 +19,4 @@
(* Please read generator/README first. *)
val non_daemon_functions : Types.action list
val daemon_functions : Types.action list

View File

@@ -121,9 +121,13 @@ If unavailable this is returned as an empty string C<\"\">.
Please read L<guestfs(3)/INSPECTION> for more details." };
]
let daemon_functions = [
{ defaults with
name = "inspect_get_format"; added = (1, 9, 4);
style = RString (RPlainString, "format"), [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_get_format";
deprecated_by = Deprecated_no_replacement;
shortdesc = "get format of inspected operating system";
longdesc = "\
@@ -155,6 +159,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_live"; added = (1, 9, 4);
style = RBool "live", [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_is_live";
deprecated_by = Deprecated_no_replacement;
shortdesc = "get live flag for install disk";
longdesc = "\
@@ -165,6 +170,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_netinst"; added = (1, 9, 4);
style = RBool "netinst", [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_is_netinst";
deprecated_by = Deprecated_no_replacement;
shortdesc = "get netinst (network installer) flag for install disk";
longdesc = "\
@@ -175,6 +181,7 @@ Please read L<guestfs(3)/INSPECTION> for more details." };
{ defaults with
name = "inspect_is_multipart"; added = (1, 9, 4);
style = RBool "multipart", [String (Mountable, "root")], [];
impl = OCaml "Inspect.inspect_is_multipart";
deprecated_by = Deprecated_no_replacement;
shortdesc = "get multipart flag for install disk";
longdesc = "\

View File

@@ -19,3 +19,4 @@
(* Please read generator/README first. *)
val non_daemon_functions : Types.action list
val daemon_functions : Types.action list

View File

@@ -487,6 +487,29 @@ let proc_nr = [
477, "part_resize";
478, "hivex_value_utf8";
479, "hivex_value_string";
480, "inspect_os";
481, "inspect_get_roots";
482, "inspect_get_format";
483, "inspect_get_type";
484, "inspect_get_distro";
485, "inspect_get_package_format";
486, "inspect_get_package_management";
487, "inspect_get_product_name";
488, "inspect_get_product_variant";
489, "inspect_get_major_version";
490, "inspect_get_minor_version";
491, "inspect_get_arch";
492, "inspect_get_hostname";
493, "inspect_get_windows_systemroot";
494, "inspect_get_windows_software_hive";
495, "inspect_get_windows_system_hive";
496, "inspect_get_windows_current_control_set";
497, "inspect_is_live";
498, "inspect_is_netinst";
499, "inspect_is_multipart";
500, "inspect_get_mountpoints";
501, "inspect_get_filesystems";
502, "inspect_get_drive_mappings";
]
(* End of list. If adding a new entry, add it at the end of the list

View File

@@ -1 +1 @@
479
502

View File

@@ -95,9 +95,6 @@ libguestfs_la_SOURCES = \
info.c \
inspect.c \
inspect-apps.c \
inspect-fs.c \
inspect-fs-unix.c \
inspect-fs-windows.c \
inspect-icon.c \
journal.c \
launch.c \

View File

@@ -116,21 +116,6 @@
/* Some limits on what the inspection code will read, for safety. */
/* Small text configuration files.
*
* The upper limit is for general files that we grep or download. The
* largest such file is probably "txtsetup.sif" from Windows CDs
* (~500K). This number has to be larger than any legitimate file and
* smaller than the protocol message size.
*
* The lower limit is for files parsed by Augeas on the daemon side,
* where Augeas is running in reduced memory and can potentially
* create a lot of metadata so we really need to be careful about
* those.
*/
#define MAX_SMALL_FILE_SIZE (2 * 1000 * 1000)
#define MAX_AUGEAS_FILE_SIZE (100 * 1000)
/* Maximum RPM or dpkg database we will download to /tmp. RPM
* 'Packages' database can get very large: 70 MB is roughly the
* standard size for a new Fedora install, and after lots of package
@@ -470,12 +455,6 @@ struct guestfs_h {
struct event *events;
size_t nr_events;
/* Information gathered by inspect_os. Must be freed by calling
* guestfs_int_free_inspect_info.
*/
struct inspect_fs *fses;
size_t nr_fses;
/* Private data area. */
struct hash_table *pda;
struct pda_entry *pda_next;
@@ -536,133 +515,6 @@ struct version {
int v_micro;
};
/* Per-filesystem data stored for inspect_os. */
enum inspect_os_format {
OS_FORMAT_UNKNOWN = 0,
OS_FORMAT_INSTALLED,
OS_FORMAT_INSTALLER,
/* in future: supplemental disks */
};
enum inspect_os_type {
OS_TYPE_UNKNOWN = 0,
OS_TYPE_LINUX,
OS_TYPE_WINDOWS,
OS_TYPE_FREEBSD,
OS_TYPE_NETBSD,
OS_TYPE_HURD,
OS_TYPE_DOS,
OS_TYPE_OPENBSD,
OS_TYPE_MINIX,
};
enum inspect_os_distro {
OS_DISTRO_UNKNOWN = 0,
OS_DISTRO_DEBIAN,
OS_DISTRO_FEDORA,
OS_DISTRO_REDHAT_BASED,
OS_DISTRO_RHEL,
OS_DISTRO_WINDOWS,
OS_DISTRO_PARDUS,
OS_DISTRO_ARCHLINUX,
OS_DISTRO_GENTOO,
OS_DISTRO_UBUNTU,
OS_DISTRO_MEEGO,
OS_DISTRO_LINUX_MINT,
OS_DISTRO_MANDRIVA,
OS_DISTRO_SLACKWARE,
OS_DISTRO_CENTOS,
OS_DISTRO_SCIENTIFIC_LINUX,
OS_DISTRO_TTYLINUX,
OS_DISTRO_MAGEIA,
OS_DISTRO_OPENSUSE,
OS_DISTRO_BUILDROOT,
OS_DISTRO_CIRROS,
OS_DISTRO_FREEDOS,
OS_DISTRO_SUSE_BASED,
OS_DISTRO_SLES,
OS_DISTRO_OPENBSD,
OS_DISTRO_ORACLE_LINUX,
OS_DISTRO_FREEBSD,
OS_DISTRO_NETBSD,
OS_DISTRO_COREOS,
OS_DISTRO_ALPINE_LINUX,
OS_DISTRO_ALTLINUX,
OS_DISTRO_FRUGALWARE,
OS_DISTRO_PLD_LINUX,
OS_DISTRO_VOID_LINUX,
};
enum inspect_os_package_format {
OS_PACKAGE_FORMAT_UNKNOWN = 0,
OS_PACKAGE_FORMAT_RPM,
OS_PACKAGE_FORMAT_DEB,
OS_PACKAGE_FORMAT_PACMAN,
OS_PACKAGE_FORMAT_EBUILD,
OS_PACKAGE_FORMAT_PISI,
OS_PACKAGE_FORMAT_PKGSRC,
OS_PACKAGE_FORMAT_APK,
OS_PACKAGE_FORMAT_XBPS,
};
enum inspect_os_package_management {
OS_PACKAGE_MANAGEMENT_UNKNOWN = 0,
OS_PACKAGE_MANAGEMENT_YUM,
OS_PACKAGE_MANAGEMENT_UP2DATE,
OS_PACKAGE_MANAGEMENT_APT,
OS_PACKAGE_MANAGEMENT_PACMAN,
OS_PACKAGE_MANAGEMENT_PORTAGE,
OS_PACKAGE_MANAGEMENT_PISI,
OS_PACKAGE_MANAGEMENT_URPMI,
OS_PACKAGE_MANAGEMENT_ZYPPER,
OS_PACKAGE_MANAGEMENT_DNF,
OS_PACKAGE_MANAGEMENT_APK,
OS_PACKAGE_MANAGEMENT_XBPS,
};
enum inspect_os_role {
OS_ROLE_UNKNOWN = 0,
OS_ROLE_ROOT,
OS_ROLE_USR,
};
/**
* The inspection code maintains one of these structures per mountable
* filesystem found in the disk image. The struct (or structs) which
* have the C<role> attribute set to C<OS_ROLE_ROOT> are inspection roots,
* each corresponding to a single guest. Note that a filesystem can be
* shared between multiple guests.
*/
struct inspect_fs {
enum inspect_os_role role;
char *mountable;
enum inspect_os_type type;
enum inspect_os_distro distro;
enum inspect_os_package_format package_format;
enum inspect_os_package_management package_management;
char *product_name;
char *product_variant;
struct version version;
char *arch;
char *hostname;
char *windows_systemroot;
char *windows_software_hive;
char *windows_system_hive;
char *windows_current_control_set;
char **drive_mappings;
enum inspect_os_format format;
int is_live_disk;
int is_netinst_disk;
int is_multipart_disk;
struct inspect_fstab_entry *fstab;
size_t nr_fstab;
};
struct inspect_fstab_entry {
char *mountable;
char *mountpoint;
};
struct guestfs_message_header;
struct guestfs_message_error;
struct guestfs_progress;
@@ -854,40 +706,9 @@ extern int guestfs_int_set_backend (guestfs_h *g, const char *method);
} while (0)
/* inspect.c */
extern void guestfs_int_free_inspect_info (guestfs_h *g);
extern char *guestfs_int_download_to_tmp (guestfs_h *g, const char *filename, const char *basename, uint64_t max_size);
extern int guestfs_int_parse_unsigned_int (guestfs_h *g, const char *str);
extern int guestfs_int_parse_unsigned_int_ignore_trailing (guestfs_h *g, const char *str);
extern struct inspect_fs *guestfs_int_search_for_root (guestfs_h *g, const char *root);
extern int guestfs_int_is_partition (guestfs_h *g, const char *partition);
/* inspect-fs.c */
extern int guestfs_int_is_file_nocase (guestfs_h *g, const char *);
extern int guestfs_int_is_dir_nocase (guestfs_h *g, const char *);
extern int guestfs_int_check_for_filesystem_on (guestfs_h *g,
const char *mountable);
extern int guestfs_int_parse_major_minor (guestfs_h *g, struct inspect_fs *fs);
extern char *guestfs_int_first_line_of_file (guestfs_h *g, const char *filename);
extern int guestfs_int_first_egrep_of_file (guestfs_h *g, const char *filename, const char *eregex, int iflag, char **ret);
extern void guestfs_int_check_package_format (guestfs_h *g, struct inspect_fs *fs);
extern void guestfs_int_check_package_management (guestfs_h *g, struct inspect_fs *fs);
extern void guestfs_int_merge_fs_inspections (guestfs_h *g, struct inspect_fs *dst, struct inspect_fs *src);
/* inspect-fs-unix.c */
extern int guestfs_int_check_linux_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_linux_usr (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_freebsd_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_netbsd_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_openbsd_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_hurd_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_minix_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_coreos_root (guestfs_h *g, struct inspect_fs *fs);
extern int guestfs_int_check_coreos_usr (guestfs_h *g, struct inspect_fs *fs);
/* inspect-fs-windows.c */
extern char *guestfs_int_case_sensitive_path_silently (guestfs_h *g, const char *);
extern char * guestfs_int_get_windows_systemroot (guestfs_h *g);
extern int guestfs_int_check_windows_root (guestfs_h *g, struct inspect_fs *fs, char *windows_systemroot);
/* dbdump.c */
typedef int (*guestfs_int_db_dump_callback) (guestfs_h *g, const unsigned char *key, size_t keylen, const unsigned char *value, size_t valuelen, void *opaque);

View File

@@ -369,7 +369,6 @@ guestfs_close (guestfs_h *g)
guestfs_int_free_fuse (g);
#endif
guestfs_int_free_inspect_info (g);
guestfs_int_free_drives (g);
for (hp = g->hv_params; hp; hp = hp_next) {

View File

@@ -46,12 +46,12 @@
#include "structs-cleanups.h"
#ifdef DB_DUMP
static struct guestfs_application2_list *list_applications_rpm (guestfs_h *g, struct inspect_fs *fs);
static struct guestfs_application2_list *list_applications_rpm (guestfs_h *g, const char *root);
#endif
static struct guestfs_application2_list *list_applications_deb (guestfs_h *g, struct inspect_fs *fs);
static struct guestfs_application2_list *list_applications_pacman (guestfs_h *g, struct inspect_fs *fs);
static struct guestfs_application2_list *list_applications_apk (guestfs_h *g, struct inspect_fs *fs);
static struct guestfs_application2_list *list_applications_windows (guestfs_h *g, struct inspect_fs *fs);
static struct guestfs_application2_list *list_applications_deb (guestfs_h *g, const char *root);
static struct guestfs_application2_list *list_applications_pacman (guestfs_h *g, const char *root);
static struct guestfs_application2_list *list_applications_apk (guestfs_h *g, const char *root);
static struct guestfs_application2_list *list_applications_windows (guestfs_h *g, const char *root);
static void add_application (guestfs_h *g, struct guestfs_application2_list *, const char *name, const char *display_name, int32_t epoch, const char *version, const char *release, const char *arch, const char *install_path, const char *publisher, const char *url, const char *source, const char *summary, const char *description);
static void sort_applications (struct guestfs_application2_list *);
@@ -109,67 +109,44 @@ struct guestfs_application2_list *
guestfs_impl_inspect_list_applications2 (guestfs_h *g, const char *root)
{
struct guestfs_application2_list *ret = NULL;
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
CLEANUP_FREE char *type = NULL;
CLEANUP_FREE char *package_format = NULL;
type = guestfs_inspect_get_type (g, root);
if (!type)
return NULL;
package_format = guestfs_inspect_get_package_format (g, root);
if (!package_format)
return NULL;
/* Presently we can only list applications for installed disks. It
* is possible in future to get lists of packages from installers.
*/
if (fs->format == OS_FORMAT_INSTALLED) {
switch (fs->type) {
case OS_TYPE_LINUX:
case OS_TYPE_HURD:
switch (fs->package_format) {
case OS_PACKAGE_FORMAT_RPM:
if (STREQ (type, "linux") || STREQ (type, "hurd")) {
if (STREQ (package_format, "rpm")) {
#ifdef DB_DUMP
ret = list_applications_rpm (g, fs);
if (ret == NULL)
return NULL;
#endif
break;
case OS_PACKAGE_FORMAT_DEB:
ret = list_applications_deb (g, fs);
if (ret == NULL)
return NULL;
break;
case OS_PACKAGE_FORMAT_PACMAN:
ret = list_applications_pacman (g, fs);
if (ret == NULL)
return NULL;
break;
case OS_PACKAGE_FORMAT_APK:
ret = list_applications_apk (g, fs);
if (ret == NULL)
return NULL;
break;
case OS_PACKAGE_FORMAT_EBUILD:
case OS_PACKAGE_FORMAT_PISI:
case OS_PACKAGE_FORMAT_PKGSRC:
case OS_PACKAGE_FORMAT_XBPS:
case OS_PACKAGE_FORMAT_UNKNOWN:
; /* nothing */
}
break;
case OS_TYPE_WINDOWS:
ret = list_applications_windows (g, fs);
ret = list_applications_rpm (g, root);
if (ret == NULL)
return NULL;
break;
case OS_TYPE_FREEBSD:
case OS_TYPE_MINIX:
case OS_TYPE_NETBSD:
case OS_TYPE_DOS:
case OS_TYPE_OPENBSD:
case OS_TYPE_UNKNOWN:
; /* nothing */
#endif
}
else if (STREQ (package_format, "deb")) {
ret = list_applications_deb (g, root);
if (ret == NULL)
return NULL;
}
else if (STREQ (package_format, "pacman")) {
ret = list_applications_pacman (g, root);
if (ret == NULL)
return NULL;
}
else if (STREQ (package_format, "apk")) {
ret = list_applications_apk (g, root);
if (ret == NULL)
return NULL;
}
}
else if (STREQ (type, "windows")) {
ret = list_applications_windows (g, root);
if (ret == NULL)
return NULL;
}
if (ret == NULL) {
@@ -386,7 +363,7 @@ read_package (guestfs_h *g,
#pragma GCC diagnostic pop
static struct guestfs_application2_list *
list_applications_rpm (guestfs_h *g, struct inspect_fs *fs)
list_applications_rpm (guestfs_h *g, const char *root)
{
CLEANUP_FREE char *Name = NULL, *Packages = NULL;
struct rpm_names_list list = { .names = NULL, .len = 0 };
@@ -437,7 +414,7 @@ list_applications_rpm (guestfs_h *g, struct inspect_fs *fs)
#endif /* defined DB_DUMP */
static struct guestfs_application2_list *
list_applications_deb (guestfs_h *g, struct inspect_fs *fs)
list_applications_deb (guestfs_h *g, const char *root)
{
CLEANUP_FREE char *status = NULL;
struct guestfs_application2_list *apps = NULL, *ret = NULL;
@@ -594,7 +571,7 @@ list_applications_deb (guestfs_h *g, struct inspect_fs *fs)
}
static struct guestfs_application2_list *
list_applications_pacman (guestfs_h *g, struct inspect_fs *fs)
list_applications_pacman (guestfs_h *g, const char *root)
{
CLEANUP_FREE char *desc_file = NULL, *fname = NULL, *line = NULL;
CLEANUP_FREE_DIRENT_LIST struct guestfs_dirent_list *local_db = NULL;
@@ -725,7 +702,7 @@ list_applications_pacman (guestfs_h *g, struct inspect_fs *fs)
}
static struct guestfs_application2_list *
list_applications_apk (guestfs_h *g, struct inspect_fs *fs)
list_applications_apk (guestfs_h *g, const char *root)
{
CLEANUP_FREE char *installed = NULL, *line = NULL;
struct guestfs_application2_list *apps = NULL, *ret = NULL;
@@ -843,14 +820,15 @@ list_applications_apk (guestfs_h *g, struct inspect_fs *fs)
static void list_applications_windows_from_path (guestfs_h *g, struct guestfs_application2_list *apps, const char **path, size_t path_len);
static struct guestfs_application2_list *
list_applications_windows (guestfs_h *g, struct inspect_fs *fs)
list_applications_windows (guestfs_h *g, const char *root)
{
struct guestfs_application2_list *ret = NULL;
if (!fs->windows_software_hive)
CLEANUP_FREE char *software_hive =
guestfs_inspect_get_windows_software_hive (g, root);
if (!software_hive)
return NULL;
if (guestfs_hivex_open (g, fs->windows_software_hive,
if (guestfs_hivex_open (g, software_hive,
GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose,
GUESTFS_HIVEX_OPEN_UNSAFE, 1,
-1) == -1)

File diff suppressed because it is too large Load Diff

View File

@@ -1,739 +0,0 @@
/* libguestfs
* Copyright (C) 2010-2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <iconv.h>
#include <inttypes.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#ifdef HAVE_SYS_ENDIAN_H
#include <sys/endian.h>
#endif
#if defined __APPLE__ && defined __MACH__
#include <libkern/OSByteOrder.h>
#define le32toh(x) OSSwapLittleToHostInt32(x)
#define le64toh(x) OSSwapLittleToHostInt64(x)
#endif
#include <pcre.h>
#include "c-ctype.h"
#include "ignore-value.h"
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
#include "structs-cleanups.h"
COMPILE_REGEXP (re_windows_version, "^(\\d+)\\.(\\d+)", 0)
COMPILE_REGEXP (re_boot_ini_os_header, "^\\[operating systems\\]\\s*$", 0)
COMPILE_REGEXP (re_boot_ini_os,
"^(multi|scsi)\\((\\d+)\\)disk\\((\\d+)\\)rdisk\\((\\d+)\\)partition\\((\\d+)\\)([^=]+)=", 0)
static int check_windows_arch (guestfs_h *g, struct inspect_fs *fs);
static int check_windows_registry_paths (guestfs_h *g, struct inspect_fs *fs);
static int check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs);
static int check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs);
static char *map_registry_disk_blob (guestfs_h *g, const void *blob);
static char *map_registry_disk_blob_gpt (guestfs_h *g, const void *blob);
static char *extract_guid_from_registry_blob (guestfs_h *g, const void *blob);
/* XXX Handling of boot.ini in the Perl version was pretty broken. It
* essentially didn't do anything for modern Windows guests.
* Therefore I've omitted all that code.
*/
/* Try to find Windows systemroot using some common locations.
*
* Notes:
*
* (1) We check for some directories inside to see if it is a real
* systemroot, and not just a directory that happens to have the same
* name.
*
* (2) If a Windows guest has multiple disks and applications are
* installed on those other disks, then those other disks will contain
* "/Program Files" and "/System Volume Information". Those would
* *not* be Windows root disks. (RHBZ#674130)
*/
static int
is_systemroot (guestfs_h *const g, const char *systemroot)
{
CLEANUP_FREE char *path1 = NULL, *path2 = NULL, *path3 = NULL;
path1 = safe_asprintf (g, "%s/system32", systemroot);
if (!guestfs_int_is_dir_nocase (g, path1))
return 0;
path2 = safe_asprintf (g, "%s/system32/config", systemroot);
if (!guestfs_int_is_dir_nocase (g, path2))
return 0;
path3 = safe_asprintf (g, "%s/system32/cmd.exe", systemroot);
if (!guestfs_int_is_file_nocase (g, path3))
return 0;
return 1;
}
char *
guestfs_int_get_windows_systemroot (guestfs_h *g)
{
/* Check a predefined list of common windows system root locations */
static const char *systemroots[] =
{ "/windows", "/winnt", "/win32", "/win", "/reactos", NULL };
for (size_t i = 0; i < sizeof systemroots / sizeof systemroots[0]; ++i) {
char *systemroot =
guestfs_int_case_sensitive_path_silently (g, systemroots[i]);
if (!systemroot)
continue;
if (is_systemroot (g, systemroot)) {
debug (g, "windows %%SYSTEMROOT%% = %s", systemroot);
return systemroot;
} else {
free (systemroot);
}
}
/* If the fs contains boot.ini, check it for non-standard
* systemroot locations */
CLEANUP_FREE char *boot_ini_path =
guestfs_int_case_sensitive_path_silently (g, "/boot.ini");
if (boot_ini_path && guestfs_is_file (g, boot_ini_path) > 0) {
CLEANUP_FREE_STRING_LIST char **boot_ini =
guestfs_read_lines (g, boot_ini_path);
if (!boot_ini) {
debug (g, "error reading %s", boot_ini_path);
return NULL;
}
int found_os = 0;
for (char **i = boot_ini; *i != NULL; i++) {
CLEANUP_FREE char *controller_type = NULL;
CLEANUP_FREE char *controller = NULL;
CLEANUP_FREE char *disk = NULL;
CLEANUP_FREE char *rdisk = NULL;
CLEANUP_FREE char *partition = NULL;
CLEANUP_FREE char *path = NULL;
char *line = *i;
if (!found_os) {
if (match (g, line, re_boot_ini_os_header)) {
found_os = 1;
continue;
}
}
/* See http://support.microsoft.com/kb/102873 for a discussion
* of what this line means */
if (match6 (g, line, re_boot_ini_os, &controller_type,
&controller, &disk, &rdisk, &partition, &path))
{
/* The Windows system root may be on any disk. However, there
* are currently (at least) 2 practical problems preventing us
* from locating it on another disk:
*
* 1. We don't have enough metadata about the disks we were
* given to know if what controller they were on and what
* index they had.
*
* 2. The way inspection of filesystems currently works, we
* can't mark another filesystem, which we may have already
* inspected, to be inspected for a specific Windows system
* root.
*
* Solving 1 properly would require a new API at a minimum. We
* might be able to fudge something practical without this,
* though, e.g. by looking at the <partition>th partition of
* every disk for the specific windows root.
*
* Solving 2 would probably require a significant refactoring
* of the way filesystems are inspected. We should probably do
* this some time.
*
* For the moment, we ignore all partition information and
* assume the system root is on the current partition. In
* practice, this will normally be correct.
*/
/* Swap backslashes for forward slashes in the system root
* path */
for (char *j = path; *j != '\0'; j++) {
if (*j == '\\') *j = '/';
}
char *systemroot = guestfs_int_case_sensitive_path_silently (g, path);
if (systemroot && is_systemroot (g, systemroot)) {
debug (g, "windows %%SYSTEMROOT%% = %s", systemroot);
return systemroot;
} else {
free (systemroot);
}
}
}
}
return NULL; /* not found */
}
int
guestfs_int_check_windows_root (guestfs_h *g, struct inspect_fs *fs,
char *const systemroot)
{
fs->type = OS_TYPE_WINDOWS;
fs->distro = OS_DISTRO_WINDOWS;
/* Freed by guestfs_int_free_inspect_info. */
fs->windows_systemroot = systemroot;
if (check_windows_arch (g, fs) == -1)
return -1;
/* Get system and software registry paths. */
if (check_windows_registry_paths (g, fs) == -1)
return -1;
/* Product name and version. */
if (check_windows_software_registry (g, fs) == -1)
return -1;
/* Hostname. */
if (check_windows_system_registry (g, fs) == -1)
return -1;
return 0;
}
static int
check_windows_arch (guestfs_h *g, struct inspect_fs *fs)
{
CLEANUP_FREE char *cmd_exe =
safe_asprintf (g, "%s/system32/cmd.exe", fs->windows_systemroot);
/* Should exist because of previous check above in get_windows_systemroot. */
CLEANUP_FREE char *cmd_exe_path = guestfs_case_sensitive_path (g, cmd_exe);
if (!cmd_exe_path)
return -1;
char *arch = guestfs_file_architecture (g, cmd_exe_path);
if (!arch)
return -1;
fs->arch = arch; /* freed by guestfs_int_free_inspect_info */
return 0;
}
static int
check_windows_registry_paths (guestfs_h *g, struct inspect_fs *fs)
{
int r;
CLEANUP_FREE char *software = NULL, *system = NULL;
if (!fs->windows_systemroot)
return 0;
software = safe_asprintf (g, "%s/system32/config/software",
fs->windows_systemroot);
fs->windows_software_hive = guestfs_case_sensitive_path (g, software);
if (!fs->windows_software_hive)
return -1;
r = guestfs_is_file (g, fs->windows_software_hive);
if (r == -1) {
free (fs->windows_software_hive);
fs->windows_software_hive = NULL;
return -1;
}
if (r == 0) { /* doesn't exist, or not a file */
free (fs->windows_software_hive);
fs->windows_software_hive = NULL;
/*FALLTHROUGH*/
}
system = safe_asprintf (g, "%s/system32/config/system",
fs->windows_systemroot);
fs->windows_system_hive = guestfs_case_sensitive_path (g, system);
if (!fs->windows_system_hive)
return -1;
r = guestfs_is_file (g, fs->windows_system_hive);
if (r == -1) {
free (fs->windows_system_hive);
fs->windows_system_hive = NULL;
return -1;
}
if (r == 0) { /* doesn't exist, or not a file */
free (fs->windows_system_hive);
fs->windows_system_hive = NULL;
/*FALLTHROUGH*/
}
return 0;
}
/* At the moment, pull just the ProductName and version numbers from
* the registry. In future there is a case for making many more
* registry fields available to callers.
*/
static int
check_windows_software_registry (guestfs_h *g, struct inspect_fs *fs)
{
int ret = -1;
int64_t node;
const char *hivepath[] =
{ "Microsoft", "Windows NT", "CurrentVersion" };
size_t i;
CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL;
bool ignore_currentversion = false;
/* If the software hive doesn't exist, just accept that we cannot
* find product_name etc.
*/
if (!fs->windows_software_hive)
return 0;
if (guestfs_hivex_open (g, fs->windows_software_hive,
GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose,
GUESTFS_HIVEX_OPEN_UNSAFE, 1,
-1) == -1)
return -1;
node = guestfs_hivex_root (g);
for (i = 0; node > 0 && i < sizeof hivepath / sizeof hivepath[0]; ++i)
node = guestfs_hivex_node_get_child (g, node, hivepath[i]);
if (node == -1)
goto out;
if (node == 0) {
perrorf (g, "hivex: cannot locate HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
goto out;
}
values = guestfs_hivex_node_values (g, node);
for (i = 0; i < values->len; ++i) {
const int64_t value = values->val[i].hivex_value_h;
CLEANUP_FREE char *key = guestfs_hivex_value_key (g, value);
if (key == NULL)
goto out;
if (STRCASEEQ (key, "ProductName")) {
fs->product_name = guestfs_hivex_value_string (g, value);
if (!fs->product_name)
goto out;
}
else if (STRCASEEQ (key, "CurrentMajorVersionNumber")) {
size_t vsize;
const int64_t vtype = guestfs_hivex_value_type (g, value);
CLEANUP_FREE char *vbuf = guestfs_hivex_value_value (g, value, &vsize);
if (vbuf == NULL)
goto out;
if (vtype != 4 || vsize != 4) {
error (g, "hivex: expected CurrentVersion\\%s to be a DWORD field",
"CurrentMajorVersionNumber");
goto out;
}
fs->version.v_major = le32toh (*(int32_t *)vbuf);
/* Ignore CurrentVersion if we see it after this key. */
ignore_currentversion = true;
}
else if (STRCASEEQ (key, "CurrentMinorVersionNumber")) {
size_t vsize;
const int64_t vtype = guestfs_hivex_value_type (g, value);
CLEANUP_FREE char *vbuf = guestfs_hivex_value_value (g, value, &vsize);
if (vbuf == NULL)
goto out;
if (vtype != 4 || vsize != 4) {
error (g, "hivex: expected CurrentVersion\\%s to be a DWORD field",
"CurrentMinorVersionNumber");
goto out;
}
fs->version.v_minor = le32toh (*(int32_t *)vbuf);
/* Ignore CurrentVersion if we see it after this key. */
ignore_currentversion = true;
}
else if (!ignore_currentversion && STRCASEEQ (key, "CurrentVersion")) {
CLEANUP_FREE char *version = guestfs_hivex_value_string (g, value);
if (!version)
goto out;
if (guestfs_int_version_from_x_y_re (g, &fs->version, version,
re_windows_version) == -1)
goto out;
}
else if (STRCASEEQ (key, "InstallationType")) {
fs->product_variant = guestfs_hivex_value_string (g, value);
if (!fs->product_variant)
goto out;
}
}
ret = 0;
out:
guestfs_hivex_close (g);
return ret;
}
static int
check_windows_system_registry (guestfs_h *g, struct inspect_fs *fs)
{
static const char gpt_prefix[] = "DMIO:ID:";
int ret = -1;
int64_t root, node, value;
CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values = NULL;
CLEANUP_FREE_HIVEX_VALUE_LIST struct guestfs_hivex_value_list *values2 = NULL;
int32_t dword;
size_t i, count;
CLEANUP_FREE void *buf = NULL;
size_t buflen;
const char *hivepath[] =
{ NULL /* current control set */, "Services", "Tcpip", "Parameters" };
/* If the system hive doesn't exist, just accept that we cannot
* find hostname etc.
*/
if (!fs->windows_system_hive)
return 0;
if (guestfs_hivex_open (g, fs->windows_system_hive,
GUESTFS_HIVEX_OPEN_VERBOSE, g->verbose,
GUESTFS_HIVEX_OPEN_UNSAFE, 1,
-1) == -1)
goto out;
root = guestfs_hivex_root (g);
if (root == 0)
goto out;
/* Get the CurrentControlSet. */
node = guestfs_hivex_node_get_child (g, root, "Select");
if (node == -1)
goto out;
if (node == 0) {
error (g, "hivex: could not locate HKLM\\SYSTEM\\Select");
goto out;
}
value = guestfs_hivex_node_get_value (g, node, "Current");
if (value == -1)
goto out;
if (value == 0) {
error (g, "hivex: HKLM\\System\\Select Default entry not found");
goto out;
}
/* XXX Should check the type. */
buf = guestfs_hivex_value_value (g, value, &buflen);
if (buflen != 4) {
error (g, "hivex: HKLM\\System\\Select\\Current expected to be DWORD");
goto out;
}
dword = le32toh (*(int32_t *)buf);
fs->windows_current_control_set = safe_asprintf (g, "ControlSet%03d", dword);
/* Get the drive mappings.
* This page explains the contents of HKLM\System\MountedDevices:
* http://www.goodells.net/multiboot/partsigs.shtml
*/
node = guestfs_hivex_node_get_child (g, root, "MountedDevices");
if (node == -1)
goto out;
if (node == 0)
/* Not found: skip getting drive letter mappings (RHBZ#803664). */
goto skip_drive_letter_mappings;
values = guestfs_hivex_node_values (g, node);
/* Count how many DOS drive letter mappings there are. This doesn't
* ignore removable devices, so it overestimates, but that doesn't
* matter because it just means we'll allocate a few bytes extra.
*/
for (i = count = 0; i < values->len; ++i) {
CLEANUP_FREE char *key =
guestfs_hivex_value_key (g, values->val[i].hivex_value_h);
if (key == NULL)
goto out;
if (STRCASEEQLEN (key, "\\DosDevices\\", 12) &&
c_isalpha (key[12]) && key[13] == ':')
count++;
}
fs->drive_mappings = safe_calloc (g, 2*count + 1, sizeof (char *));
for (i = count = 0; i < values->len; ++i) {
const int64_t v = values->val[i].hivex_value_h;
CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v);
if (key == NULL)
goto out;
if (STRCASEEQLEN (key, "\\DosDevices\\", 12) &&
c_isalpha (key[12]) && key[13] == ':') {
/* Get the binary value. Is it a fixed disk? */
CLEANUP_FREE char *blob = NULL;
char *device;
int64_t type;
bool is_gpt;
size_t len;
type = guestfs_hivex_value_type (g, v);
blob = guestfs_hivex_value_value (g, v, &len);
is_gpt = memcmp (blob, gpt_prefix, 8) == 0;
if (blob != NULL && type == 3 && (len == 12 || is_gpt)) {
/* Try to map the blob to a known disk and partition. */
if (is_gpt)
device = map_registry_disk_blob_gpt (g, blob);
else
device = map_registry_disk_blob (g, blob);
if (device != NULL) {
fs->drive_mappings[count++] = safe_strndup (g, &key[12], 1);
fs->drive_mappings[count++] = device;
}
}
}
}
skip_drive_letter_mappings:;
/* Get the hostname. */
hivepath[0] = fs->windows_current_control_set;
for (node = root, i = 0;
node > 0 && i < sizeof hivepath / sizeof hivepath[0];
++i) {
node = guestfs_hivex_node_get_child (g, node, hivepath[i]);
}
if (node == -1)
goto out;
if (node == 0) {
perrorf (g, "hivex: cannot locate HKLM\\SYSTEM\\%s\\Services\\Tcpip\\Parameters",
fs->windows_current_control_set);
goto out;
}
values2 = guestfs_hivex_node_values (g, node);
if (values2 == NULL)
goto out;
for (i = 0; i < values2->len; ++i) {
const int64_t v = values2->val[i].hivex_value_h;
CLEANUP_FREE char *key = guestfs_hivex_value_key (g, v);
if (key == NULL)
goto out;
if (STRCASEEQ (key, "Hostname")) {
fs->hostname = guestfs_hivex_value_string (g, v);
if (!fs->hostname)
goto out;
}
/* many other interesting fields here ... */
}
ret = 0;
out:
guestfs_hivex_close (g);
return ret;
}
/* Windows Registry HKLM\SYSTEM\MountedDevices uses a blob of data
* to store partitions. This blob is described here:
* http://www.goodells.net/multiboot/partsigs.shtml
* The following function maps this blob to a libguestfs partition
* name, if possible.
*/
static char *
map_registry_disk_blob (guestfs_h *g, const void *blob)
{
CLEANUP_FREE_STRING_LIST char **devices = NULL;
CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *partitions = NULL;
size_t i, j, len;
uint64_t part_offset;
/* First 4 bytes are the disk ID. Search all devices to find the
* disk with this disk ID.
*/
devices = guestfs_list_devices (g);
if (devices == NULL)
return NULL;
for (i = 0; devices[i] != NULL; ++i) {
/* Read the disk ID. */
CLEANUP_FREE char *diskid =
guestfs_pread_device (g, devices[i], 4, 0x01b8, &len);
if (diskid == NULL)
continue;
if (len < 4)
continue;
if (memcmp (diskid, blob, 4) == 0) /* found it */
goto found_disk;
}
return NULL;
found_disk:
/* Next 8 bytes are the offset of the partition in bytes(!) given as
* a 64 bit little endian number. Luckily it's easy to get the
* partition byte offset from guestfs_part_list.
*/
memcpy (&part_offset, (char *) blob + 4, sizeof (part_offset));
part_offset = le64toh (part_offset);
partitions = guestfs_part_list (g, devices[i]);
if (partitions == NULL)
return NULL;
for (j = 0; j < partitions->len; ++j) {
if (partitions->val[j].part_start == part_offset) /* found it */
goto found_partition;
}
return NULL;
found_partition:
/* Construct the full device name. */
return safe_asprintf (g, "%s%d", devices[i], partitions->val[j].part_num);
}
/* Matches Windows registry HKLM\SYSYTEM\MountedDevices\DosDevices blob to
* to libguestfs GPT partition device. For GPT disks, the blob is made of
* "DMIO:ID:" prefix followed by the GPT partition GUID.
*/
static char *
map_registry_disk_blob_gpt (guestfs_h *g, const void *blob)
{
CLEANUP_FREE_STRING_LIST char **parts = NULL;
CLEANUP_FREE char *blob_guid = extract_guid_from_registry_blob (g, blob);
size_t i;
parts = guestfs_list_partitions (g);
if (parts == NULL)
return NULL;
for (i = 0; parts[i] != NULL; ++i) {
CLEANUP_FREE char *fs_guid = NULL;
int partnum;
CLEANUP_FREE char *device = NULL;
CLEANUP_FREE char *type = NULL;
partnum = guestfs_part_to_partnum (g, parts[i]);
if (partnum == -1)
continue;
device = guestfs_part_to_dev (g, parts[i]);
if (device == NULL)
continue;
type = guestfs_part_get_parttype (g, device);
if (type == NULL)
continue;
if (STRCASENEQ (type, "gpt"))
continue;
/* get the GPT parition GUID from the partition block device */
fs_guid = guestfs_part_get_gpt_guid (g, device, partnum);
if (fs_guid == NULL)
continue;
/* if both GUIDs match, we have found the mapping for our device */
if (STRCASEEQ (fs_guid, blob_guid))
return safe_strdup (g, parts[i]);
}
return NULL;
}
/* Extracts the binary GUID stored in blob from Windows registry
* HKLM\SYSTYEM\MountedDevices\DosDevices value and converts it to a
* GUID string so that it can be matched against libguestfs partition
* device GPT GUID.
*/
static char *
extract_guid_from_registry_blob (guestfs_h *g, const void *blob)
{
char guid_bytes[16];
uint32_t data1;
uint16_t data2, data3;
uint64_t data4;
/* get the GUID bytes from blob (skip 8 byte "DMIO:ID:" prefix) */
memcpy (&guid_bytes, (char *) blob + 8, sizeof (guid_bytes));
/* copy relevant sections from blob to respective ints */
memcpy (&data1, guid_bytes, sizeof (data1));
memcpy (&data2, guid_bytes + 4, sizeof (data2));
memcpy (&data3, guid_bytes + 6, sizeof (data3));
memcpy (&data4, guid_bytes + 8, sizeof (data4));
/* ensure proper endianness */
data1 = le32toh (data1);
data2 = le16toh (data2);
data3 = le16toh (data3);
data4 = be64toh (data4);
return safe_asprintf (g,
"%08" PRIX32 "-%04" PRIX16 "-%04" PRIX16 "-%04" PRIX64 "-%012" PRIX64,
data1, data2, data3, data4 >> 48, data4 & 0xffffffffffff);
}
/* NB: This function DOES NOT test for the existence of the file. It
* will return non-NULL even if the file/directory does not exist.
* You have to call guestfs_is_file{,_opts} etc.
*/
char *
guestfs_int_case_sensitive_path_silently (guestfs_h *g, const char *path)
{
char *ret;
guestfs_push_error_handler (g, NULL, NULL);
ret = guestfs_case_sensitive_path (g, path);
guestfs_pop_error_handler (g);
return ret;
}

View File

@@ -1,732 +0,0 @@
/* libguestfs
* Copyright (C) 2010-2012 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libintl.h>
#ifdef HAVE_ENDIAN_H
#include <endian.h>
#endif
#include <pcre.h>
#include "ignore-value.h"
#include "xstrtol.h"
#include "guestfs.h"
#include "guestfs-internal.h"
#include "structs-cleanups.h"
static int check_filesystem (guestfs_h *g, const char *mountable,
const struct guestfs_internal_mountable *m,
int whole_device);
static void extend_fses (guestfs_h *g);
static int get_partition_context (guestfs_h *g, const char *partition, int *partnum_ret, int *nr_partitions_ret);
static int is_symlink_to (guestfs_h *g, const char *file, const char *wanted_target);
/* Find out if 'device' contains a filesystem. If it does, add
* another entry in g->fses.
*/
int
guestfs_int_check_for_filesystem_on (guestfs_h *g, const char *mountable)
{
CLEANUP_FREE char *vfs_type = NULL;
int is_swap, r;
struct inspect_fs *fs;
CLEANUP_FREE_INTERNAL_MOUNTABLE struct guestfs_internal_mountable *m = NULL;
int whole_device = 0;
/* Get vfs-type in order to check if it's a Linux(?) swap device.
* If there's an error we should ignore it, so to do that we have to
* temporarily replace the error handler with a null one.
*/
guestfs_push_error_handler (g, NULL, NULL);
vfs_type = guestfs_vfs_type (g, mountable);
guestfs_pop_error_handler (g);
is_swap = vfs_type && STREQ (vfs_type, "swap");
debug (g, "check_for_filesystem_on: %s (%s)",
mountable, vfs_type ? vfs_type : "failed to get vfs type");
if (is_swap) {
extend_fses (g);
fs = &g->fses[g->nr_fses-1];
fs->mountable = safe_strdup (g, mountable);
return 0;
}
m = guestfs_internal_parse_mountable (g, mountable);
if (m == NULL)
return -1;
/* If it's a whole device, see if it is an install ISO. */
if (m->im_type == MOUNTABLE_DEVICE) {
whole_device = guestfs_is_whole_device (g, m->im_device);
if (whole_device == -1) {
return -1;
}
}
/* Try mounting the device. As above, ignore errors. */
guestfs_push_error_handler (g, NULL, NULL);
if (vfs_type && STREQ (vfs_type, "ufs")) { /* Hack for the *BSDs. */
/* FreeBSD fs is a variant of ufs called ufs2 ... */
r = guestfs_mount_vfs (g, "ro,ufstype=ufs2", "ufs", mountable, "/");
if (r == -1)
/* while NetBSD and OpenBSD use another variant labeled 44bsd */
r = guestfs_mount_vfs (g, "ro,ufstype=44bsd", "ufs", mountable, "/");
} else {
r = guestfs_mount_ro (g, mountable, "/");
}
guestfs_pop_error_handler (g);
if (r == -1)
return 0;
/* Do the rest of the checks. */
r = check_filesystem (g, mountable, m, whole_device);
/* Unmount the filesystem. */
if (guestfs_umount_all (g) == -1)
return -1;
return r;
}
static int
check_filesystem (guestfs_h *g, const char *mountable,
const struct guestfs_internal_mountable *m,
int whole_device)
{
int partnum = -1, nr_partitions = -1;
/* Not CLEANUP_FREE, as it will be cleaned up with inspection info */
char *windows_systemroot = NULL;
extend_fses (g);
if (!whole_device && m->im_type == MOUNTABLE_DEVICE &&
guestfs_int_is_partition (g, m->im_device)) {
if (get_partition_context (g, m->im_device,
&partnum, &nr_partitions) == -1)
return -1;
}
struct inspect_fs *fs = &g->fses[g->nr_fses-1];
fs->mountable = safe_strdup (g, mountable);
/* Optimize some of the tests by avoiding multiple tests of the same thing. */
const int is_dir_etc = guestfs_is_dir (g, "/etc") > 0;
const int is_dir_bin = guestfs_is_dir (g, "/bin") > 0;
const int is_dir_share = guestfs_is_dir (g, "/share") > 0;
/* Grub /boot? */
if (guestfs_is_file (g, "/grub/menu.lst") > 0 ||
guestfs_is_file (g, "/grub/grub.conf") > 0 ||
guestfs_is_file (g, "/grub2/grub.cfg") > 0)
;
/* FreeBSD root? */
else if (is_dir_etc &&
is_dir_bin &&
guestfs_is_file (g, "/etc/freebsd-update.conf") > 0 &&
guestfs_is_file (g, "/etc/fstab") > 0) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
if (guestfs_int_check_freebsd_root (g, fs) == -1)
return -1;
}
/* NetBSD root? */
else if (is_dir_etc &&
is_dir_bin &&
guestfs_is_file (g, "/netbsd") > 0 &&
guestfs_is_file (g, "/etc/fstab") > 0 &&
guestfs_is_file (g, "/etc/release") > 0) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
if (guestfs_int_check_netbsd_root (g, fs) == -1)
return -1;
}
/* OpenBSD root? */
else if (is_dir_etc &&
is_dir_bin &&
guestfs_is_file (g, "/bsd") > 0 &&
guestfs_is_file (g, "/etc/fstab") > 0 &&
guestfs_is_file (g, "/etc/motd") > 0) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
if (guestfs_int_check_openbsd_root (g, fs) == -1)
return -1;
}
/* Hurd root? */
else if (guestfs_is_file (g, "/hurd/console") > 0 &&
guestfs_is_file (g, "/hurd/hello") > 0 &&
guestfs_is_file (g, "/hurd/null") > 0) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED; /* XXX could be more specific */
if (guestfs_int_check_hurd_root (g, fs) == -1)
return -1;
}
/* Minix root? */
else if (is_dir_etc &&
is_dir_bin &&
guestfs_is_file (g, "/service/vm") > 0 &&
guestfs_is_file (g, "/etc/fstab") > 0 &&
guestfs_is_file (g, "/etc/version") > 0) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
if (guestfs_int_check_minix_root (g, fs) == -1)
return -1;
}
/* Linux root? */
else if (is_dir_etc &&
(is_dir_bin ||
is_symlink_to (g, "/bin", "usr/bin") > 0) &&
(guestfs_is_file (g, "/etc/fstab") > 0 ||
guestfs_is_file (g, "/etc/hosts") > 0)) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
if (guestfs_int_check_linux_root (g, fs) == -1)
return -1;
}
/* CoreOS root? */
else if (is_dir_etc &&
guestfs_is_dir (g, "/root") > 0 &&
guestfs_is_dir (g, "/home") > 0 &&
guestfs_is_dir (g, "/usr") > 0 &&
guestfs_is_file (g, "/etc/coreos/update.conf") > 0) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
if (guestfs_int_check_coreos_root (g, fs) == -1)
return -1;
}
/* Linux /usr/local? */
else if (is_dir_etc &&
is_dir_bin &&
is_dir_share &&
guestfs_is_dir (g, "/local") == 0 &&
guestfs_is_file (g, "/etc/fstab") == 0)
;
/* Linux /usr? */
else if (is_dir_etc &&
is_dir_bin &&
is_dir_share &&
guestfs_is_dir (g, "/local") > 0 &&
guestfs_is_file (g, "/etc/fstab") == 0) {
if (guestfs_int_check_linux_usr (g, fs) == -1)
return -1;
}
/* CoreOS /usr? */
else if (is_dir_bin &&
is_dir_share &&
guestfs_is_dir (g, "/local") > 0 &&
guestfs_is_dir (g, "/share/coreos") > 0) {
if (guestfs_int_check_coreos_usr (g, fs) == -1)
return -1;
}
/* Linux /var? */
else if (guestfs_is_dir (g, "/log") > 0 &&
guestfs_is_dir (g, "/run") > 0 &&
guestfs_is_dir (g, "/spool") > 0)
;
/* Windows root? */
else if ((windows_systemroot = guestfs_int_get_windows_systemroot (g)) != NULL)
{
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
if (guestfs_int_check_windows_root (g, fs, windows_systemroot) == -1)
return -1;
}
/* Windows volume with installed applications (but not root)? */
else if (guestfs_int_is_dir_nocase (g, "/System Volume Information") > 0 &&
guestfs_int_is_dir_nocase (g, "/Program Files") > 0)
;
/* Windows volume (but not root)? */
else if (guestfs_int_is_dir_nocase (g, "/System Volume Information") > 0)
;
/* FreeDOS? */
else if (guestfs_int_is_dir_nocase (g, "/FDOS") > 0 &&
guestfs_int_is_file_nocase (g, "/FDOS/FREEDOS.BSS") > 0) {
fs->role = OS_ROLE_ROOT;
fs->format = OS_FORMAT_INSTALLED;
fs->type = OS_TYPE_DOS;
fs->distro = OS_DISTRO_FREEDOS;
/* FreeDOS is a mix of 16 and 32 bit, but assume it requires a
* 32 bit i386 processor.
*/
fs->arch = safe_strdup (g, "i386");
}
/* The above code should have set fs->type and fs->distro fields, so
* we can now guess the package management system.
*/
guestfs_int_check_package_format (g, fs);
guestfs_int_check_package_management (g, fs);
return 0;
}
static void
extend_fses (guestfs_h *g)
{
const size_t n = g->nr_fses + 1;
struct inspect_fs *p;
p = safe_realloc (g, g->fses, n * sizeof (struct inspect_fs));
g->fses = p;
g->nr_fses = n;
memset (&g->fses[n-1], 0, sizeof (struct inspect_fs));
}
/* Given a partition (eg. /dev/sda2) then return the partition number
* (eg. 2) and the total number of other partitions.
*/
static int
get_partition_context (guestfs_h *g, const char *partition,
int *partnum_ret, int *nr_partitions_ret)
{
int partnum, nr_partitions;
CLEANUP_FREE char *device = NULL;
CLEANUP_FREE_PARTITION_LIST struct guestfs_partition_list *partitions = NULL;
partnum = guestfs_part_to_partnum (g, partition);
if (partnum == -1)
return -1;
device = guestfs_part_to_dev (g, partition);
if (device == NULL)
return -1;
partitions = guestfs_part_list (g, device);
if (partitions == NULL)
return -1;
nr_partitions = partitions->len;
*partnum_ret = partnum;
*nr_partitions_ret = nr_partitions;
return 0;
}
static int
is_symlink_to (guestfs_h *g, const char *file, const char *wanted_target)
{
CLEANUP_FREE char *target = NULL;
if (guestfs_is_symlink (g, file) == 0)
return 0;
target = guestfs_readlink (g, file);
/* This should not fail, but play safe. */
if (target == NULL)
return 0;
return STREQ (target, wanted_target);
}
int
guestfs_int_is_file_nocase (guestfs_h *g, const char *path)
{
CLEANUP_FREE char *p = NULL;
int r;
p = guestfs_int_case_sensitive_path_silently (g, path);
if (!p)
return 0;
r = guestfs_is_file (g, p);
return r > 0;
}
int
guestfs_int_is_dir_nocase (guestfs_h *g, const char *path)
{
CLEANUP_FREE char *p = NULL;
int r;
p = guestfs_int_case_sensitive_path_silently (g, path);
if (!p)
return 0;
r = guestfs_is_dir (g, p);
return r > 0;
}
/* Parse generic MAJOR.MINOR from the fs->product_name string. */
int
guestfs_int_parse_major_minor (guestfs_h *g, struct inspect_fs *fs)
{
if (guestfs_int_version_from_x_y (g, &fs->version, fs->product_name) == -1)
return -1;
return 0;
}
/* At the moment, package format and package management is just a
* simple function of the distro and version.v_major fields, so these
* can never return an error. We might be cleverer in future.
*/
void
guestfs_int_check_package_format (guestfs_h *g, struct inspect_fs *fs)
{
switch (fs->distro) {
case OS_DISTRO_FEDORA:
case OS_DISTRO_MEEGO:
case OS_DISTRO_REDHAT_BASED:
case OS_DISTRO_RHEL:
case OS_DISTRO_MAGEIA:
case OS_DISTRO_MANDRIVA:
case OS_DISTRO_SUSE_BASED:
case OS_DISTRO_OPENSUSE:
case OS_DISTRO_SLES:
case OS_DISTRO_CENTOS:
case OS_DISTRO_SCIENTIFIC_LINUX:
case OS_DISTRO_ORACLE_LINUX:
case OS_DISTRO_ALTLINUX:
fs->package_format = OS_PACKAGE_FORMAT_RPM;
break;
case OS_DISTRO_DEBIAN:
case OS_DISTRO_UBUNTU:
case OS_DISTRO_LINUX_MINT:
fs->package_format = OS_PACKAGE_FORMAT_DEB;
break;
case OS_DISTRO_ARCHLINUX:
fs->package_format = OS_PACKAGE_FORMAT_PACMAN;
break;
case OS_DISTRO_GENTOO:
fs->package_format = OS_PACKAGE_FORMAT_EBUILD;
break;
case OS_DISTRO_PARDUS:
fs->package_format = OS_PACKAGE_FORMAT_PISI;
break;
case OS_DISTRO_ALPINE_LINUX:
fs->package_format = OS_PACKAGE_FORMAT_APK;
break;
case OS_DISTRO_VOID_LINUX:
fs->package_format = OS_PACKAGE_FORMAT_XBPS;
break;
case OS_DISTRO_SLACKWARE:
case OS_DISTRO_TTYLINUX:
case OS_DISTRO_COREOS:
case OS_DISTRO_WINDOWS:
case OS_DISTRO_BUILDROOT:
case OS_DISTRO_CIRROS:
case OS_DISTRO_FREEDOS:
case OS_DISTRO_FREEBSD:
case OS_DISTRO_NETBSD:
case OS_DISTRO_OPENBSD:
case OS_DISTRO_FRUGALWARE:
case OS_DISTRO_PLD_LINUX:
case OS_DISTRO_UNKNOWN:
fs->package_format = OS_PACKAGE_FORMAT_UNKNOWN;
break;
}
}
void
guestfs_int_check_package_management (guestfs_h *g, struct inspect_fs *fs)
{
switch (fs->distro) {
case OS_DISTRO_MEEGO:
fs->package_management = OS_PACKAGE_MANAGEMENT_YUM;
break;
case OS_DISTRO_FEDORA:
/* If Fedora >= 22 and dnf is installed, say "dnf". */
if (guestfs_int_version_ge (&fs->version, 22, 0, 0) &&
guestfs_is_file_opts (g, "/usr/bin/dnf",
GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0)
fs->package_management = OS_PACKAGE_MANAGEMENT_DNF;
else if (guestfs_int_version_ge (&fs->version, 1, 0, 0))
fs->package_management = OS_PACKAGE_MANAGEMENT_YUM;
else
/* Probably parsing the release file failed, see RHBZ#1332025. */
fs->package_management = OS_PACKAGE_MANAGEMENT_UNKNOWN;
break;
case OS_DISTRO_REDHAT_BASED:
case OS_DISTRO_RHEL:
case OS_DISTRO_CENTOS:
case OS_DISTRO_SCIENTIFIC_LINUX:
case OS_DISTRO_ORACLE_LINUX:
if (guestfs_int_version_ge (&fs->version, 5, 0, 0))
fs->package_management = OS_PACKAGE_MANAGEMENT_YUM;
else if (guestfs_int_version_ge (&fs->version, 2, 0, 0))
fs->package_management = OS_PACKAGE_MANAGEMENT_UP2DATE;
else
/* Probably parsing the release file failed, see RHBZ#1332025. */
fs->package_management = OS_PACKAGE_MANAGEMENT_UNKNOWN;
break;
case OS_DISTRO_DEBIAN:
case OS_DISTRO_UBUNTU:
case OS_DISTRO_LINUX_MINT:
case OS_DISTRO_ALTLINUX:
fs->package_management = OS_PACKAGE_MANAGEMENT_APT;
break;
case OS_DISTRO_ARCHLINUX:
fs->package_management = OS_PACKAGE_MANAGEMENT_PACMAN;
break;
case OS_DISTRO_GENTOO:
fs->package_management = OS_PACKAGE_MANAGEMENT_PORTAGE;
break;
case OS_DISTRO_PARDUS:
fs->package_management = OS_PACKAGE_MANAGEMENT_PISI;
break;
case OS_DISTRO_MAGEIA:
case OS_DISTRO_MANDRIVA:
fs->package_management = OS_PACKAGE_MANAGEMENT_URPMI;
break;
case OS_DISTRO_SUSE_BASED:
case OS_DISTRO_OPENSUSE:
case OS_DISTRO_SLES:
fs->package_management = OS_PACKAGE_MANAGEMENT_ZYPPER;
break;
case OS_DISTRO_ALPINE_LINUX:
fs->package_management = OS_PACKAGE_MANAGEMENT_APK;
break;
case OS_DISTRO_VOID_LINUX:
fs->package_management = OS_PACKAGE_MANAGEMENT_XBPS;
break;
case OS_DISTRO_SLACKWARE:
case OS_DISTRO_TTYLINUX:
case OS_DISTRO_COREOS:
case OS_DISTRO_WINDOWS:
case OS_DISTRO_BUILDROOT:
case OS_DISTRO_CIRROS:
case OS_DISTRO_FREEDOS:
case OS_DISTRO_FREEBSD:
case OS_DISTRO_NETBSD:
case OS_DISTRO_OPENBSD:
case OS_DISTRO_FRUGALWARE:
case OS_DISTRO_PLD_LINUX:
case OS_DISTRO_UNKNOWN:
fs->package_management = OS_PACKAGE_MANAGEMENT_UNKNOWN;
break;
}
}
/* Get the first line of a small file, without any trailing newline
* character.
*
* NOTE: If the file is completely empty or begins with a '\n'
* character, this returns an empty string (not NULL). The caller
* will usually need to check for this case.
*/
char *
guestfs_int_first_line_of_file (guestfs_h *g, const char *filename)
{
char **lines = NULL; /* sic: not CLEANUP_FREE_STRING_LIST */
int64_t size;
char *ret;
/* Don't trust guestfs_head_n not to break with very large files.
* Check the file size is something reasonable first.
*/
size = guestfs_filesize (g, filename);
if (size == -1)
/* guestfs_filesize failed and has already set error in handle */
return NULL;
if (size > MAX_SMALL_FILE_SIZE) {
error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
filename, size);
return NULL;
}
lines = guestfs_head_n (g, 1, filename);
if (lines == NULL)
return NULL;
if (lines[0] == NULL) {
guestfs_int_free_string_list (lines);
/* Empty file: Return an empty string as explained above. */
return safe_strdup (g, "");
}
/* lines[1] should be NULL because of '1' argument above ... */
ret = lines[0]; /* caller frees */
free (lines);
return ret;
}
/* Get the first matching line (using egrep [-i]) of a small file,
* without any trailing newline character.
*
* Returns: 1 = returned a line (in *ret)
* 0 = no match
* -1 = error
*/
int
guestfs_int_first_egrep_of_file (guestfs_h *g, const char *filename,
const char *eregex, int iflag, char **ret)
{
char **lines;
int64_t size;
size_t i;
struct guestfs_grep_opts_argv optargs;
/* Don't trust guestfs_grep not to break with very large files.
* Check the file size is something reasonable first.
*/
size = guestfs_filesize (g, filename);
if (size == -1)
/* guestfs_filesize failed and has already set error in handle */
return -1;
if (size > MAX_SMALL_FILE_SIZE) {
error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
filename, size);
return -1;
}
optargs.bitmask = GUESTFS_GREP_OPTS_EXTENDED_BITMASK;
optargs.extended = 1;
if (iflag) {
optargs.bitmask |= GUESTFS_GREP_OPTS_INSENSITIVE_BITMASK;
optargs.insensitive = 1;
}
lines = guestfs_grep_opts_argv (g, eregex, filename, &optargs);
if (lines == NULL)
return -1;
if (lines[0] == NULL) {
guestfs_int_free_string_list (lines);
return 0;
}
*ret = lines[0]; /* caller frees */
/* free up any other matches and the array itself */
for (i = 1; lines[i] != NULL; ++i)
free (lines[i]);
free (lines);
return 1;
}
/* Merge the missing OS inspection information found on the src inspect_fs into
* the ones of the dst inspect_fs. This function is useful if the inspection
* information for an OS are gathered by inspecting multiple filesystems.
*/
void
guestfs_int_merge_fs_inspections (guestfs_h *g, struct inspect_fs *dst, struct inspect_fs *src)
{
size_t n, i, old;
struct inspect_fstab_entry *fstab = NULL;
char ** mappings = NULL;
if (dst->type == 0)
dst->type = src->type;
if (dst->distro == 0)
dst->distro = src->distro;
if (dst->package_format == 0)
dst->package_format = src->package_format;
if (dst->package_management == 0)
dst->package_management = src->package_management;
if (dst->product_name == NULL) {
dst->product_name = src->product_name;
src->product_name = NULL;
}
if (dst->product_variant == NULL) {
dst->product_variant= src->product_variant;
src->product_variant = NULL;
}
if (version_is_null (&dst->version))
dst->version = src->version;
if (dst->arch == NULL) {
dst->arch = src->arch;
src->arch = NULL;
}
if (dst->hostname == NULL) {
dst->hostname = src->hostname;
src->hostname = NULL;
}
if (dst->windows_systemroot == NULL) {
dst->windows_systemroot = src->windows_systemroot;
src->windows_systemroot = NULL;
}
if (dst->windows_current_control_set == NULL) {
dst->windows_current_control_set = src->windows_current_control_set;
src->windows_current_control_set = NULL;
}
if (src->drive_mappings != NULL) {
if (dst->drive_mappings == NULL) {
/* Adopt the drive mappings of src */
dst->drive_mappings = src->drive_mappings;
src->drive_mappings = NULL;
} else {
n = 0;
for (; dst->drive_mappings[n] != NULL; n++)
;
old = n;
for (; src->drive_mappings[n] != NULL; n++)
;
/* Merge the src mappings to dst */
mappings = safe_realloc (g, dst->drive_mappings,(n + 1) * sizeof (char *));
for (i = old; i < n; i++)
mappings[i] = src->drive_mappings[i - old];
mappings[n] = NULL;
dst->drive_mappings = mappings;
free(src->drive_mappings);
src->drive_mappings = NULL;
}
}
if (src->nr_fstab > 0) {
n = dst->nr_fstab + src->nr_fstab;
fstab = safe_realloc (g, dst->fstab, n * sizeof (struct inspect_fstab_entry));
for (i = 0; i < src->nr_fstab; i++) {
fstab[dst->nr_fstab + i].mountable = src->fstab[i].mountable;
fstab[dst->nr_fstab + i].mountpoint = src->fstab[i].mountpoint;
}
free(src->fstab);
src->fstab = NULL;
src->nr_fstab = 0;
dst->fstab = fstab;
dst->nr_fstab = n;
}
}

View File

@@ -51,22 +51,24 @@
* An icon was found. 'ret' points to the icon buffer, and *size_r
* is the size.
*/
static char *icon_favicon (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_fedora (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_rhel (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_debian (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_ubuntu (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_mageia (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_opensuse (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_favicon (guestfs_h *g, const char *type, size_t *size_r);
static char *icon_fedora (guestfs_h *g, size_t *size_r);
static char *icon_rhel (guestfs_h *g, int major, size_t *size_r);
static char *icon_debian (guestfs_h *g, size_t *size_r);
static char *icon_ubuntu (guestfs_h *g, size_t *size_r);
static char *icon_mageia (guestfs_h *g, size_t *size_r);
static char *icon_opensuse (guestfs_h *g, size_t *size_r);
#if CAN_DO_CIRROS
static char *icon_cirros (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_cirros (guestfs_h *g, size_t *size_r);
#endif
static char *icon_voidlinux (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_altlinux (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_voidlinux (guestfs_h *g, size_t *size_r);
static char *icon_altlinux (guestfs_h *g, size_t *size_r);
#if CAN_DO_WINDOWS
static char *icon_windows (guestfs_h *g, struct inspect_fs *fs, size_t *size_r);
static char *icon_windows (guestfs_h *g, const char *root, size_t *size_r);
#endif
static char *case_sensitive_path_silently (guestfs_h *g, const char *path);
/* Dummy static object. */
static char *NOT_FOUND = (char *) "not_found";
@@ -82,13 +84,17 @@ char *
guestfs_impl_inspect_get_icon (guestfs_h *g, const char *root, size_t *size_r,
const struct guestfs_inspect_get_icon_argv *optargs)
{
struct inspect_fs *fs;
char *r = NOT_FOUND;
int favicon, highquality;
size_t size;
CLEANUP_FREE char *type = NULL;
CLEANUP_FREE char *distro = NULL;
fs = guestfs_int_search_for_root (g, root);
if (!fs)
type = guestfs_inspect_get_type (g, root);
if (!type)
return NULL;
distro = guestfs_inspect_get_distro (g, root);
if (!distro)
return NULL;
/* Get optargs, or defaults. */
@@ -106,7 +112,7 @@ guestfs_impl_inspect_get_icon (guestfs_h *g, const char *root, size_t *size_r,
/* Try looking for a favicon first. */
if (favicon) {
r = icon_favicon (g, fs, &size);
r = icon_favicon (g, type, &size);
if (!r)
return NULL;
@@ -120,96 +126,52 @@ guestfs_impl_inspect_get_icon (guestfs_h *g, const char *root, size_t *size_r,
/* Favicon failed, so let's try a method based on the detected operating
* system.
*/
switch (fs->type) {
case OS_TYPE_LINUX:
case OS_TYPE_HURD:
switch (fs->distro) {
case OS_DISTRO_FEDORA:
r = icon_fedora (g, fs, &size);
break;
case OS_DISTRO_RHEL:
case OS_DISTRO_REDHAT_BASED:
case OS_DISTRO_CENTOS:
case OS_DISTRO_SCIENTIFIC_LINUX:
case OS_DISTRO_ORACLE_LINUX:
r = icon_rhel (g, fs, &size);
break;
case OS_DISTRO_DEBIAN:
r = icon_debian (g, fs, &size);
break;
case OS_DISTRO_UBUNTU:
if (!highquality)
r = icon_ubuntu (g, fs, &size);
break;
case OS_DISTRO_MAGEIA:
r = icon_mageia (g, fs, &size);
break;
case OS_DISTRO_SUSE_BASED:
case OS_DISTRO_OPENSUSE:
case OS_DISTRO_SLES:
r = icon_opensuse (g, fs, &size);
break;
case OS_DISTRO_CIRROS:
#if CAN_DO_CIRROS
r = icon_cirros (g, fs, &size);
#endif
break;
case OS_DISTRO_VOID_LINUX:
r = icon_voidlinux (g, fs, &size);
break;
case OS_DISTRO_ALTLINUX:
r = icon_altlinux (g, fs, &size);
break;
/* These are just to keep gcc warnings happy. */
case OS_DISTRO_ARCHLINUX:
case OS_DISTRO_BUILDROOT:
case OS_DISTRO_COREOS:
case OS_DISTRO_FREEDOS:
case OS_DISTRO_GENTOO:
case OS_DISTRO_LINUX_MINT:
case OS_DISTRO_MANDRIVA:
case OS_DISTRO_MEEGO:
case OS_DISTRO_PARDUS:
case OS_DISTRO_SLACKWARE:
case OS_DISTRO_TTYLINUX:
case OS_DISTRO_WINDOWS:
case OS_DISTRO_FREEBSD:
case OS_DISTRO_NETBSD:
case OS_DISTRO_OPENBSD:
case OS_DISTRO_ALPINE_LINUX:
case OS_DISTRO_FRUGALWARE:
case OS_DISTRO_PLD_LINUX:
case OS_DISTRO_UNKNOWN:
; /* nothing */
if (STREQ (type, "linux") || STREQ (type, "hurd")) {
if (STREQ (distro, "fedora")) {
r = icon_fedora (g, &size);
}
break;
case OS_TYPE_WINDOWS:
else if (STREQ (distro, "rhel") ||
STREQ (distro, "redhat-based") ||
STREQ (distro, "centos") ||
STREQ (distro, "scientificlinux") ||
STREQ (distro, "oraclelinux")) {
r = icon_rhel (g, guestfs_inspect_get_major_version (g, root), &size);
}
else if (STREQ (distro, "debian")) {
r = icon_debian (g, &size);
}
else if (STREQ (distro, "ubuntu")) {
if (!highquality)
r = icon_ubuntu (g, &size);
}
else if (STREQ (distro, "mageia")) {
r = icon_mageia (g, &size);
}
else if (STREQ (distro, "suse-based") ||
STREQ (distro, "opensuse") ||
STREQ (distro, "sles")) {
r = icon_opensuse (g, &size);
}
else if (STREQ (distro, "cirros")) {
#if CAN_DO_CIRROS
r = icon_cirros (g, &size);
#endif
}
else if (STREQ (distro, "voidlinux")) {
r = icon_voidlinux (g, &size);
}
else if (STREQ (distro, "altlinux")) {
r = icon_altlinux (g, &size);
}
}
else if (STREQ (type, "windows")) {
#if CAN_DO_WINDOWS
/* We don't know how to get high quality icons from a Windows guest,
* so disable this if high quality was specified.
*/
if (!highquality)
r = icon_windows (g, fs, &size);
r = icon_windows (g, root, &size);
#endif
break;
case OS_TYPE_FREEBSD:
case OS_TYPE_NETBSD:
case OS_TYPE_DOS:
case OS_TYPE_OPENBSD:
case OS_TYPE_MINIX:
case OS_TYPE_UNKNOWN:
; /* nothing */
}
if (r == NOT_FOUND) {
@@ -229,8 +191,7 @@ guestfs_impl_inspect_get_icon (guestfs_h *g, const char *root, size_t *size_r,
* If it is, download and return it.
*/
static char *
get_png (guestfs_h *g, struct inspect_fs *fs, const char *filename,
size_t *size_r, size_t max_size)
get_png (guestfs_h *g, const char *filename, size_t *size_r, size_t max_size)
{
char *ret;
CLEANUP_FREE char *real = NULL;
@@ -285,20 +246,20 @@ get_png (guestfs_h *g, struct inspect_fs *fs, const char *filename,
* it has a reasonable size and format.
*/
static char *
icon_favicon (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_favicon (guestfs_h *g, const char *type, size_t *size_r)
{
char *ret;
char *filename = safe_strdup (g, "/etc/favicon.png");
if (fs->type == OS_TYPE_WINDOWS) {
char *f = guestfs_int_case_sensitive_path_silently (g, filename);
if (STREQ (type, "windows")) {
char *f = case_sensitive_path_silently (g, filename);
if (f) {
free (filename);
filename = f;
}
}
ret = get_png (g, fs, filename, size_r, 0);
ret = get_png (g, filename, size_r, 0);
free (filename);
return ret;
}
@@ -309,9 +270,9 @@ icon_favicon (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
#define FEDORA_ICON "/usr/share/icons/hicolor/96x96/apps/fedora-logo-icon.png"
static char *
icon_fedora (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_fedora (guestfs_h *g, size_t *size_r)
{
return get_png (g, fs, FEDORA_ICON, size_r, 0);
return get_png (g, FEDORA_ICON, size_r, 0);
}
/* RHEL 3, 4:
@@ -330,28 +291,28 @@ icon_fedora (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
* RHEL clones have different sizes.
*/
static char *
icon_rhel (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_rhel (guestfs_h *g, int major, size_t *size_r)
{
const char *shadowman;
if (!guestfs_int_version_ge (&fs->version, 7, 0, 0))
if (major < 7)
shadowman = "/usr/share/pixmaps/redhat/shadowman-transparent.png";
else
shadowman = "/usr/share/pixmaps/fedora-logo-sprite.png";
return get_png (g, fs, shadowman, size_r, 102400);
return get_png (g, shadowman, size_r, 102400);
}
#define DEBIAN_ICON "/usr/share/pixmaps/debian-logo.png"
static char *
icon_debian (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_debian (guestfs_h *g, size_t *size_r)
{
return get_png (g, fs, DEBIAN_ICON, size_r, 2048);
return get_png (g, DEBIAN_ICON, size_r, 2048);
}
static char *
icon_ubuntu (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_ubuntu (guestfs_h *g, size_t *size_r)
{
const char *icons[] = {
"/usr/share/icons/gnome/24x24/places/ubuntu-logo.png",
@@ -366,7 +327,7 @@ icon_ubuntu (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
char *ret;
for (i = 0; icons[i] != NULL; ++i) {
ret = get_png (g, fs, icons[i], size_r, 2048);
ret = get_png (g, icons[i], size_r, 2048);
if (ret == NULL)
return NULL;
if (ret != NOT_FOUND)
@@ -378,17 +339,17 @@ icon_ubuntu (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
#define MAGEIA_ICON "/usr/share/icons/mageia.png"
static char *
icon_mageia (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_mageia (guestfs_h *g, size_t *size_r)
{
return get_png (g, fs, MAGEIA_ICON, size_r, 2048);
return get_png (g, MAGEIA_ICON, size_r, 2048);
}
#define OPENSUSE_ICON "/usr/share/icons/hicolor/24x24/apps/distributor.png"
static char *
icon_opensuse (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_opensuse (guestfs_h *g, size_t *size_r)
{
return get_png (g, fs, OPENSUSE_ICON, size_r, 2048);
return get_png (g, OPENSUSE_ICON, size_r, 2048);
}
#if CAN_DO_CIRROS
@@ -397,7 +358,7 @@ icon_opensuse (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
#define CIRROS_LOGO "/usr/share/cirros/logo"
static char *
icon_cirros (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_cirros (guestfs_h *g, size_t *size_r)
{
char *ret;
CLEANUP_FREE char *type = NULL;
@@ -450,17 +411,17 @@ icon_cirros (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
#define VOIDLINUX_ICON "/usr/share/void-artwork/void-logo.png"
static char *
icon_voidlinux (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_voidlinux (guestfs_h *g, size_t *size_r)
{
return get_png (g, fs, VOIDLINUX_ICON, size_r, 20480);
return get_png (g, VOIDLINUX_ICON, size_r, 20480);
}
#define ALTLINUX_ICON "/usr/share/icons/hicolor/48x48/apps/altlinux.png"
static char *
icon_altlinux (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_altlinux (guestfs_h *g, size_t *size_r)
{
return get_png (g, fs, ALTLINUX_ICON, size_r, 20480);
return get_png (g, ALTLINUX_ICON, size_r, 20480);
}
#if CAN_DO_WINDOWS
@@ -481,7 +442,7 @@ icon_altlinux (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
*/
static char *
icon_windows_xp (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_windows_xp (guestfs_h *g, const char *systemroot, size_t *size_r)
{
CLEANUP_FREE char *filename = NULL;
CLEANUP_FREE char *filename_case = NULL;
@@ -492,7 +453,7 @@ icon_windows_xp (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
char *ret;
/* Download %systemroot%\explorer.exe */
filename = safe_asprintf (g, "%s/explorer.exe", fs->windows_systemroot);
filename = safe_asprintf (g, "%s/explorer.exe", systemroot);
filename_case = guestfs_case_sensitive_path (g, filename);
if (filename_case == NULL)
return NULL;
@@ -543,7 +504,7 @@ static const char *win7_explorer[] = {
};
static char *
icon_windows_7 (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_windows_7 (guestfs_h *g, const char *systemroot, size_t *size_r)
{
size_t i;
CLEANUP_FREE char *filename_case = NULL;
@@ -556,11 +517,10 @@ icon_windows_7 (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
for (i = 0; win7_explorer[i] != NULL; ++i) {
CLEANUP_FREE char *filename = NULL;
filename = safe_asprintf (g, "%s/%s",
fs->windows_systemroot, win7_explorer[i]);
filename = safe_asprintf (g, "%s/%s", systemroot, win7_explorer[i]);
free (filename_case);
filename_case = guestfs_int_case_sensitive_path_silently (g, filename);
filename_case = case_sensitive_path_silently (g, filename);
if (filename_case == NULL)
continue;
@@ -609,14 +569,14 @@ icon_windows_7 (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
* - /Windows/System32/slui.exe --type=14 group icon #2
*/
static char *
icon_windows_8 (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_windows_8 (guestfs_h *g, size_t *size_r)
{
CLEANUP_FREE char *filename_case = NULL;
CLEANUP_FREE char *filename_downloaded = NULL;
int r;
char *ret;
filename_case = guestfs_int_case_sensitive_path_silently
filename_case = case_sensitive_path_silently
(g, "/ProgramData/Microsoft/Windows Live/WLive48x48.png");
if (filename_case == NULL)
return NOT_FOUND; /* Not an error since a parent dir might not exist. */
@@ -641,25 +601,46 @@ icon_windows_8 (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
}
static char *
icon_windows (guestfs_h *g, struct inspect_fs *fs, size_t *size_r)
icon_windows (guestfs_h *g, const char *root, size_t *size_r)
{
if (fs->windows_systemroot == NULL)
CLEANUP_FREE char *systemroot =
guestfs_inspect_get_windows_systemroot (g, root);
int major = guestfs_inspect_get_major_version (g, root);
int minor = guestfs_inspect_get_minor_version (g, root);
if (systemroot == NULL)
return NOT_FOUND;
/* Windows XP. */
if (fs->version.v_major == 5 && fs->version.v_minor == 1)
return icon_windows_xp (g, fs, size_r);
if (major == 5 && minor == 1)
return icon_windows_xp (g, systemroot, size_r);
/* Windows 7. */
else if (fs->version.v_major == 6 && fs->version.v_minor == 1)
return icon_windows_7 (g, fs, size_r);
else if (major == 6 && minor == 1)
return icon_windows_7 (g, systemroot, size_r);
/* Windows 8. */
else if (fs->version.v_major == 6 && fs->version.v_minor == 2)
return icon_windows_8 (g, fs, size_r);
else if (major == 6 && minor == 2)
return icon_windows_8 (g, size_r);
/* Not (yet) a supported version of Windows. */
else return NOT_FOUND;
}
#endif /* CAN_DO_WINDOWS */
/* NB: This function DOES NOT test for the existence of the file. It
* will return non-NULL even if the file/directory does not exist.
* You have to call guestfs_is_file{,_opts} etc.
*/
static char *
case_sensitive_path_silently (guestfs_h *g, const char *path)
{
char *ret;
guestfs_push_error_handler (g, NULL, NULL);
ret = guestfs_case_sensitive_path (g, path);
guestfs_pop_error_handler (g);
return ret;
}

View File

@@ -16,11 +16,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* This file, and the other C<lib/inspect*.c> files, handle
* inspection. See L<guestfs(3)/INSPECTION>.
*/
#include <config.h>
#include <stdio.h>
@@ -44,688 +39,6 @@
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
COMPILE_REGEXP (re_primary_partition, "^/dev/(?:h|s|v)d.[1234]$", 0)
static void check_for_duplicated_bsd_root (guestfs_h *g);
static void collect_coreos_inspection_info (guestfs_h *g);
static void collect_linux_inspection_info (guestfs_h *g);
static void collect_linux_inspection_info_for (guestfs_h *g, struct inspect_fs *root);
/**
* The main inspection API.
*/
char **
guestfs_impl_inspect_os (guestfs_h *g)
{
CLEANUP_FREE_STRING_LIST char **fses = NULL;
char **fs, **ret;
/* Remove any information previously stored in the handle. */
guestfs_int_free_inspect_info (g);
if (guestfs_umount_all (g) == -1)
return NULL;
/* Iterate over all detected filesystems. Inspect each one in turn
* and add that information to the handle.
*/
fses = guestfs_list_filesystems (g);
if (fses == NULL) return NULL;
for (fs = fses; *fs; fs += 2) {
if (guestfs_int_check_for_filesystem_on (g, *fs)) {
guestfs_int_free_inspect_info (g);
return NULL;
}
}
/* The OS inspection information for CoreOS are gathered by inspecting
* multiple filesystems. Gather all the inspected information in the
* inspect_fs struct of the root filesystem.
*/
collect_coreos_inspection_info (g);
/* Check if the same filesystem was listed twice as root in g->fses.
* This may happen for the *BSD root partition where an MBR partition
* is a shadow of the real root partition probably /dev/sda5
*/
check_for_duplicated_bsd_root (g);
/* For Linux guests with a separate /usr filesyste, merge some of the
* inspected information in that partition to the inspect_fs struct
* of the root filesystem.
*/
collect_linux_inspection_info (g);
/* At this point we have, in the handle, a list of all filesystems
* found and data about each one. Now we assemble the list of
* filesystems which are root devices and return that to the user.
* Fall through to guestfs_inspect_get_roots to do that.
*/
ret = guestfs_inspect_get_roots (g);
if (ret == NULL)
guestfs_int_free_inspect_info (g);
return ret;
}
/**
* Traverse through the filesystem list and find out if it contains
* the C</> and C</usr> filesystems of a CoreOS image. If this is the
* case, sum up all the collected information on the root fs.
*/
static void
collect_coreos_inspection_info (guestfs_h *g)
{
size_t i;
struct inspect_fs *root = NULL, *usr = NULL;
for (i = 0; i < g->nr_fses; ++i) {
struct inspect_fs *fs = &g->fses[i];
if (fs->distro == OS_DISTRO_COREOS && fs->role == OS_ROLE_ROOT)
root = fs;
}
if (root == NULL)
return;
for (i = 0; i < g->nr_fses; ++i) {
struct inspect_fs *fs = &g->fses[i];
if (fs->distro != OS_DISTRO_COREOS || fs->role != OS_ROLE_USR)
continue;
/* CoreOS is designed to contain 2 /usr partitions (USR-A, USR-B):
* https://coreos.com/docs/sdk-distributors/sdk/disk-partitions/
* One is active and one passive. During the initial boot, the passive
* partition is empty and it gets filled up when an update is performed.
* Then, when the system reboots, the boot loader is instructed to boot
* from the passive partition. If both partitions are valid, we cannot
* determine which the active and which the passive is, unless we peep into
* the boot loader. As a workaround, we check the OS versions and pick the
* one with the higher version as active.
*/
if (usr && guestfs_int_version_cmp_ge (&usr->version, &fs->version))
continue;
usr = fs;
}
if (usr == NULL)
return;
guestfs_int_merge_fs_inspections (g, root, usr);
}
/**
* Traverse through the filesystems and find the /usr filesystem for
* the specified C<root>: if found, merge its basic inspection details
* to the root when they were set (i.e. because the /usr had os-release
* or other ways to identify the OS).
*/
static void
collect_linux_inspection_info_for (guestfs_h *g, struct inspect_fs *root)
{
size_t i;
struct inspect_fs *usr = NULL;
for (i = 0; i < g->nr_fses; ++i) {
struct inspect_fs *fs = &g->fses[i];
size_t j;
if (!(fs->distro == root->distro || fs->distro == OS_DISTRO_UNKNOWN) ||
fs->role != OS_ROLE_USR)
continue;
for (j = 0; j < root->nr_fstab; ++j) {
if (STREQ (fs->mountable, root->fstab[j].mountable)) {
usr = fs;
goto got_usr;
}
}
}
assert (usr == NULL);
return;
got_usr:
/* If the version information in /usr is not null, then most probably
* there was an os-release file there, so reset what is in root
* and pick the results from /usr.
*/
if (!version_is_null (&usr->version)) {
root->distro = OS_DISTRO_UNKNOWN;
free (root->product_name);
root->product_name = NULL;
}
guestfs_int_merge_fs_inspections (g, root, usr);
}
/**
* Traverse through the filesystem list and find out if it contains
* the C</> and C</usr> filesystems of a Linux image (but not CoreOS,
* for which there is a separate C<collect_coreos_inspection_info>).
* If this is the case, sum up all the collected information on each
* root fs from the respective /usr filesystems.
*/
static void
collect_linux_inspection_info (guestfs_h *g)
{
size_t i;
for (i = 0; i < g->nr_fses; ++i) {
struct inspect_fs *fs = &g->fses[i];
if (fs->distro != OS_DISTRO_COREOS && fs->role == OS_ROLE_ROOT)
collect_linux_inspection_info_for (g, fs);
}
}
/**
* On *BSD systems, sometimes F</dev/sda[1234]> is a shadow of the
* real root filesystem that is probably F</dev/sda5> (see:
* L<http://www.freebsd.org/doc/handbook/disk-organization.html>)
*/
static void
check_for_duplicated_bsd_root (guestfs_h *g)
{
size_t i;
struct inspect_fs *bsd_primary = NULL;
for (i = 0; i < g->nr_fses; ++i) {
bool is_bsd;
struct inspect_fs *fs = &g->fses[i];
is_bsd =
fs->type == OS_TYPE_FREEBSD ||
fs->type == OS_TYPE_NETBSD ||
fs->type == OS_TYPE_OPENBSD;
if (fs->role == OS_ROLE_ROOT && is_bsd &&
match (g, fs->mountable, re_primary_partition)) {
bsd_primary = fs;
continue;
}
if (fs->role == OS_ROLE_ROOT && bsd_primary &&
bsd_primary->type == fs->type) {
/* remove the root role from the bsd_primary */
bsd_primary->role = OS_ROLE_UNKNOWN;
bsd_primary->format = OS_FORMAT_UNKNOWN;
return;
}
}
}
static int
compare_strings (const void *vp1, const void *vp2)
{
const char *s1 = * (char * const *) vp1;
const char *s2 = * (char * const *) vp2;
return strcmp (s1, s2);
}
char **
guestfs_impl_inspect_get_roots (guestfs_h *g)
{
size_t i;
DECLARE_STRINGSBUF (ret);
/* NB. Doesn't matter if g->nr_fses == 0. We just return an empty
* list in this case.
*/
for (i = 0; i < g->nr_fses; ++i) {
if (g->fses[i].role == OS_ROLE_ROOT)
guestfs_int_add_string (g, &ret, g->fses[i].mountable);
}
guestfs_int_end_stringsbuf (g, &ret);
qsort (ret.argv, ret.size-1, sizeof (char *), compare_strings);
return ret.argv;
}
char *
guestfs_impl_inspect_get_type (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
char *ret = NULL;
if (!fs)
return NULL;
switch (fs->type) {
case OS_TYPE_DOS: ret = safe_strdup (g, "dos"); break;
case OS_TYPE_FREEBSD: ret = safe_strdup (g, "freebsd"); break;
case OS_TYPE_HURD: ret = safe_strdup (g, "hurd"); break;
case OS_TYPE_LINUX: ret = safe_strdup (g, "linux"); break;
case OS_TYPE_MINIX: ret = safe_strdup (g, "minix"); break;
case OS_TYPE_NETBSD: ret = safe_strdup (g, "netbsd"); break;
case OS_TYPE_OPENBSD: ret = safe_strdup (g, "openbsd"); break;
case OS_TYPE_WINDOWS: ret = safe_strdup (g, "windows"); break;
case OS_TYPE_UNKNOWN: ret = safe_strdup (g, "unknown"); break;
}
if (ret == NULL)
abort ();
return ret;
}
char *
guestfs_impl_inspect_get_arch (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
return safe_strdup (g, fs->arch ? : "unknown");
}
char *
guestfs_impl_inspect_get_distro (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
char *ret = NULL;
if (!fs)
return NULL;
switch (fs->distro) {
case OS_DISTRO_ALPINE_LINUX: ret = safe_strdup (g, "alpinelinux"); break;
case OS_DISTRO_ALTLINUX: ret = safe_strdup (g, "altlinux"); break;
case OS_DISTRO_ARCHLINUX: ret = safe_strdup (g, "archlinux"); break;
case OS_DISTRO_BUILDROOT: ret = safe_strdup (g, "buildroot"); break;
case OS_DISTRO_CENTOS: ret = safe_strdup (g, "centos"); break;
case OS_DISTRO_CIRROS: ret = safe_strdup (g, "cirros"); break;
case OS_DISTRO_COREOS: ret = safe_strdup (g, "coreos"); break;
case OS_DISTRO_DEBIAN: ret = safe_strdup (g, "debian"); break;
case OS_DISTRO_FEDORA: ret = safe_strdup (g, "fedora"); break;
case OS_DISTRO_FREEBSD: ret = safe_strdup (g, "freebsd"); break;
case OS_DISTRO_FREEDOS: ret = safe_strdup (g, "freedos"); break;
case OS_DISTRO_FRUGALWARE: ret = safe_strdup (g, "frugalware"); break;
case OS_DISTRO_GENTOO: ret = safe_strdup (g, "gentoo"); break;
case OS_DISTRO_LINUX_MINT: ret = safe_strdup (g, "linuxmint"); break;
case OS_DISTRO_MAGEIA: ret = safe_strdup (g, "mageia"); break;
case OS_DISTRO_MANDRIVA: ret = safe_strdup (g, "mandriva"); break;
case OS_DISTRO_MEEGO: ret = safe_strdup (g, "meego"); break;
case OS_DISTRO_NETBSD: ret = safe_strdup (g, "netbsd"); break;
case OS_DISTRO_OPENBSD: ret = safe_strdup (g, "openbsd"); break;
case OS_DISTRO_OPENSUSE: ret = safe_strdup (g, "opensuse"); break;
case OS_DISTRO_ORACLE_LINUX: ret = safe_strdup (g, "oraclelinux"); break;
case OS_DISTRO_PARDUS: ret = safe_strdup (g, "pardus"); break;
case OS_DISTRO_PLD_LINUX: ret = safe_strdup (g, "pldlinux"); break;
case OS_DISTRO_REDHAT_BASED: ret = safe_strdup (g, "redhat-based"); break;
case OS_DISTRO_RHEL: ret = safe_strdup (g, "rhel"); break;
case OS_DISTRO_SCIENTIFIC_LINUX: ret = safe_strdup (g, "scientificlinux"); break;
case OS_DISTRO_SLACKWARE: ret = safe_strdup (g, "slackware"); break;
case OS_DISTRO_SLES: ret = safe_strdup (g, "sles"); break;
case OS_DISTRO_SUSE_BASED: ret = safe_strdup (g, "suse-based"); break;
case OS_DISTRO_TTYLINUX: ret = safe_strdup (g, "ttylinux"); break;
case OS_DISTRO_WINDOWS: ret = safe_strdup (g, "windows"); break;
case OS_DISTRO_UBUNTU: ret = safe_strdup (g, "ubuntu"); break;
case OS_DISTRO_VOID_LINUX: ret = safe_strdup (g, "voidlinux"); break;
case OS_DISTRO_UNKNOWN: ret = safe_strdup (g, "unknown"); break;
}
if (ret == NULL)
abort ();
return ret;
}
int
guestfs_impl_inspect_get_major_version (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return -1;
return fs->version.v_major;
}
int
guestfs_impl_inspect_get_minor_version (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return -1;
return fs->version.v_minor;
}
char *
guestfs_impl_inspect_get_product_name (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
return safe_strdup (g, fs->product_name ? : "unknown");
}
char *
guestfs_impl_inspect_get_product_variant (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
return safe_strdup (g, fs->product_variant ? : "unknown");
}
char *
guestfs_impl_inspect_get_windows_systemroot (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
if (!fs->windows_systemroot) {
error (g, _("not a Windows guest, or systemroot could not be determined"));
return NULL;
}
return safe_strdup (g, fs->windows_systemroot);
}
char *
guestfs_impl_inspect_get_windows_software_hive (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
if (!fs->windows_software_hive) {
error (g, _("not a Windows guest, or software hive not found"));
return NULL;
}
return safe_strdup (g, fs->windows_software_hive);
}
char *
guestfs_impl_inspect_get_windows_system_hive (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
if (!fs->windows_system_hive) {
error (g, _("not a Windows guest, or system hive not found"));
return NULL;
}
return safe_strdup (g, fs->windows_system_hive);
}
char *
guestfs_impl_inspect_get_windows_current_control_set (guestfs_h *g,
const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
if (!fs->windows_current_control_set) {
error (g, _("not a Windows guest, or CurrentControlSet could not be determined"));
return NULL;
}
return safe_strdup (g, fs->windows_current_control_set);
}
char *
guestfs_impl_inspect_get_format (guestfs_h *g, const char *root)
{
char *ret = NULL;
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
switch (fs->format) {
case OS_FORMAT_INSTALLED: ret = safe_strdup (g, "installed"); break;
case OS_FORMAT_INSTALLER: ret = safe_strdup (g, "installer"); break;
case OS_FORMAT_UNKNOWN: ret = safe_strdup (g, "unknown"); break;
}
if (ret == NULL)
abort ();
return ret;
}
int
guestfs_impl_inspect_is_live (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return -1;
return fs->is_live_disk;
}
int
guestfs_impl_inspect_is_netinst (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return -1;
return fs->is_netinst_disk;
}
int
guestfs_impl_inspect_is_multipart (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return -1;
return fs->is_multipart_disk;
}
char **
guestfs_impl_inspect_get_mountpoints (guestfs_h *g, const char *root)
{
char **ret;
size_t i, count, nr;
struct inspect_fs *fs;
fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
#define CRITERION(fs, i) fs->fstab[i].mountpoint[0] == '/'
nr = fs->nr_fstab;
if (nr == 0)
count = 1;
else {
count = 0;
for (i = 0; i < nr; ++i)
if (CRITERION (fs, i))
count++;
}
/* Hashtables have 2N+1 entries. */
ret = calloc (2*count+1, sizeof (char *));
if (ret == NULL) {
perrorf (g, "calloc");
return NULL;
}
/* If no fstab information (Windows) return just the root. */
if (nr == 0) {
ret[0] = safe_strdup (g, "/");
ret[1] = safe_strdup (g, root);
ret[2] = NULL;
return ret;
}
count = 0;
for (i = 0; i < nr; ++i)
if (CRITERION (fs, i)) {
ret[2*count] = safe_strdup (g, fs->fstab[i].mountpoint);
ret[2*count+1] = safe_strdup (g, fs->fstab[i].mountable);
count++;
}
#undef CRITERION
return ret;
}
char **
guestfs_impl_inspect_get_filesystems (guestfs_h *g, const char *root)
{
char **ret;
size_t i, nr;
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
nr = fs->nr_fstab;
ret = calloc (nr == 0 ? 2 : nr+1, sizeof (char *));
if (ret == NULL) {
perrorf (g, "calloc");
return NULL;
}
/* If no fstab information (Windows) return just the root. */
if (nr == 0) {
ret[0] = safe_strdup (g, root);
ret[1] = NULL;
return ret;
}
for (i = 0; i < nr; ++i)
ret[i] = safe_strdup (g, fs->fstab[i].mountable);
return ret;
}
char **
guestfs_impl_inspect_get_drive_mappings (guestfs_h *g, const char *root)
{
DECLARE_STRINGSBUF (ret);
size_t i;
struct inspect_fs *fs;
fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
if (fs->drive_mappings) {
for (i = 0; fs->drive_mappings[i] != NULL; ++i)
guestfs_int_add_string (g, &ret, fs->drive_mappings[i]);
}
guestfs_int_end_stringsbuf (g, &ret);
return ret.argv;
}
char *
guestfs_impl_inspect_get_package_format (guestfs_h *g, const char *root)
{
char *ret = NULL;
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
switch (fs->package_format) {
case OS_PACKAGE_FORMAT_RPM: ret = safe_strdup (g, "rpm"); break;
case OS_PACKAGE_FORMAT_DEB: ret = safe_strdup (g, "deb"); break;
case OS_PACKAGE_FORMAT_PACMAN: ret = safe_strdup (g, "pacman"); break;
case OS_PACKAGE_FORMAT_EBUILD: ret = safe_strdup (g, "ebuild"); break;
case OS_PACKAGE_FORMAT_PISI: ret = safe_strdup (g, "pisi"); break;
case OS_PACKAGE_FORMAT_PKGSRC: ret = safe_strdup (g, "pkgsrc"); break;
case OS_PACKAGE_FORMAT_APK: ret = safe_strdup (g, "apk"); break;
case OS_PACKAGE_FORMAT_XBPS: ret = safe_strdup (g, "xbps"); break;
case OS_PACKAGE_FORMAT_UNKNOWN:
ret = safe_strdup (g, "unknown");
break;
}
if (ret == NULL)
abort ();
return ret;
}
char *
guestfs_impl_inspect_get_package_management (guestfs_h *g, const char *root)
{
char *ret = NULL;
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
switch (fs->package_management) {
case OS_PACKAGE_MANAGEMENT_APK: ret = safe_strdup (g, "apk"); break;
case OS_PACKAGE_MANAGEMENT_APT: ret = safe_strdup (g, "apt"); break;
case OS_PACKAGE_MANAGEMENT_DNF: ret = safe_strdup (g, "dnf"); break;
case OS_PACKAGE_MANAGEMENT_PACMAN: ret = safe_strdup (g, "pacman"); break;
case OS_PACKAGE_MANAGEMENT_PISI: ret = safe_strdup (g, "pisi"); break;
case OS_PACKAGE_MANAGEMENT_PORTAGE: ret = safe_strdup (g, "portage"); break;
case OS_PACKAGE_MANAGEMENT_UP2DATE: ret = safe_strdup (g, "up2date"); break;
case OS_PACKAGE_MANAGEMENT_URPMI: ret = safe_strdup (g, "urpmi"); break;
case OS_PACKAGE_MANAGEMENT_XBPS: ret = safe_strdup (g, "xbps"); break;
case OS_PACKAGE_MANAGEMENT_YUM: ret = safe_strdup (g, "yum"); break;
case OS_PACKAGE_MANAGEMENT_ZYPPER: ret = safe_strdup (g, "zypper"); break;
case OS_PACKAGE_MANAGEMENT_UNKNOWN:
ret = safe_strdup (g, "unknown");
break;
}
if (ret == NULL)
abort ();
return ret;
}
char *
guestfs_impl_inspect_get_hostname (guestfs_h *g, const char *root)
{
struct inspect_fs *fs = guestfs_int_search_for_root (g, root);
if (!fs)
return NULL;
return safe_strdup (g, fs->hostname ? : "unknown");
}
void
guestfs_int_free_inspect_info (guestfs_h *g)
{
size_t i, j;
for (i = 0; i < g->nr_fses; ++i) {
free (g->fses[i].mountable);
free (g->fses[i].product_name);
free (g->fses[i].product_variant);
free (g->fses[i].arch);
free (g->fses[i].hostname);
free (g->fses[i].windows_systemroot);
free (g->fses[i].windows_software_hive);
free (g->fses[i].windows_system_hive);
free (g->fses[i].windows_current_control_set);
for (j = 0; j < g->fses[i].nr_fstab; ++j) {
free (g->fses[i].fstab[j].mountable);
free (g->fses[i].fstab[j].mountpoint);
}
free (g->fses[i].fstab);
if (g->fses[i].drive_mappings)
guestfs_int_free_string_list (g->fses[i].drive_mappings);
}
free (g->fses);
g->nr_fses = 0;
g->fses = NULL;
}
/**
* Download a guest file to a local temporary file. The file is
* cached in the temporary directory, and is not downloaded again.
@@ -818,46 +131,3 @@ guestfs_int_parse_unsigned_int_ignore_trailing (guestfs_h *g, const char *str)
}
return ret;
}
struct inspect_fs *
guestfs_int_search_for_root (guestfs_h *g, const char *root)
{
size_t i;
if (g->nr_fses == 0) {
error (g, _("no inspection data: call guestfs_inspect_os first"));
return NULL;
}
for (i = 0; i < g->nr_fses; ++i) {
struct inspect_fs *fs = &g->fses[i];
if (fs->role == OS_ROLE_ROOT && STREQ (root, fs->mountable))
return fs;
}
error (g, _("%s: root device not found: only call this function with a root device previously returned by guestfs_inspect_os"),
root);
return NULL;
}
int
guestfs_int_is_partition (guestfs_h *g, const char *partition)
{
CLEANUP_FREE char *device = NULL;
guestfs_push_error_handler (g, NULL, NULL);
if ((device = guestfs_part_to_dev (g, partition)) == NULL) {
guestfs_pop_error_handler (g);
return 0;
}
if (guestfs_device_index (g, device) == -1) {
guestfs_pop_error_handler (g);
return 0;
}
guestfs_pop_error_handler (g);
return 1;
}