mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
Remove inspection from the C library and switch to daemon/OCaml implementation.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 guest’s 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 guest’s 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." };
|
||||
|
||||
]
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
(* Please read generator/README first. *)
|
||||
|
||||
val non_daemon_functions : Types.action list
|
||||
val daemon_functions : Types.action list
|
||||
|
||||
@@ -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 = "\
|
||||
|
||||
@@ -19,3 +19,4 @@
|
||||
(* Please read generator/README first. *)
|
||||
|
||||
val non_daemon_functions : Types.action list
|
||||
val daemon_functions : Types.action list
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1 +1 @@
|
||||
479
|
||||
502
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
732
lib/inspect-fs.c
732
lib/inspect-fs.c
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
730
lib/inspect.c
730
lib/inspect.c
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user