---
docs/C_SOURCE_FILES | 3 -
generator/actions.ml | 2 +
generator/actions_inspection.ml | 394 ++---
generator/actions_inspection.mli | 1 +
generator/actions_inspection_deprecated.ml | 7 +
generator/actions_inspection_deprecated.mli | 1 +
generator/proc_nr.ml | 23 +
lib/MAX_PROC_NR | 2 +-
lib/Makefile.am | 3 -
lib/guestfs-internal.h | 179 ---
lib/handle.c | 1 -
lib/inspect-apps.c | 112 +-
lib/inspect-fs-unix.c | 2158 ---------------------------
lib/inspect-fs-windows.c | 739 ---------
lib/inspect-fs.c | 732 ---------
lib/inspect-icon.c | 251 ++--
lib/inspect.c | 730 ---------
17 files changed, 404 insertions(+), 4934 deletions(-)
diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES
index 08a965892..4b09d474b 100644
--- a/docs/C_SOURCE_FILES
+++ b/docs/C_SOURCE_FILES
@@ -309,9 +309,6 @@ lib/handle.c
lib/hivex.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
diff --git a/generator/actions.ml b/generator/actions.ml
index 75742397a..515096881 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -51,6 +51,8 @@ let daemon_functions =
Actions_core_deprecated.daemon_functions @
Actions_debug.daemon_functions @
Actions_hivex.daemon_functions @
+ Actions_inspection.daemon_functions @
+ Actions_inspection_deprecated.daemon_functions @
Actions_tsk.daemon_functions @
Actions_yara.daemon_functions
diff --git a/generator/actions_inspection.ml b/generator/actions_inspection.ml
index cd8b9da18..d67d00833 100644
--- a/generator/actions_inspection.ml
+++ b/generator/actions_inspection.ml
@@ -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
@@ -61,8 +62,24 @@ 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
@@ -331,8 +353,164 @@ 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.
-
-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_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).
+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 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).
+For Windows guests, currently only hard drive mappings are
+returned. Removable disks (eg. DVD-ROMs) are ignored.
-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).
+For guests that do not use drive mappings, or if the drive mappings
+could not be determined, this returns an empty hash table.
-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.
+See also C<guestfs_inspect_get_mountpoints>,
+C<guestfs_inspect_get_filesystems>." };
-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")], [];
@@ -553,95 +698,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"];
shortdesc = "get the icon corresponding to this operating system";
@@ -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." };
-
]
diff --git a/generator/actions_inspection.mli b/generator/actions_inspection.mli
index 327f7aa4f..06b8116c4 100644
--- a/generator/actions_inspection.mli
+++ b/generator/actions_inspection.mli
@@ -19,3 +19,4 @@
(* Please read generator/README first. *)
val non_daemon_functions : Types.action list
+val daemon_functions : Types.action list
diff --git a/generator/actions_inspection_deprecated.ml
b/generator/actions_inspection_deprecated.ml
index 7c34cb1a8..c3e76ff7b 100644
--- a/generator/actions_inspection_deprecated.ml
+++ b/generator/actions_inspection_deprecated.ml
@@ -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 = "\
diff --git a/generator/actions_inspection_deprecated.mli
b/generator/actions_inspection_deprecated.mli
index 327f7aa4f..06b8116c4 100644
--- a/generator/actions_inspection_deprecated.mli
+++ b/generator/actions_inspection_deprecated.mli
@@ -19,3 +19,4 @@
(* Please read generator/README first. *)
val non_daemon_functions : Types.action list
+val daemon_functions : Types.action list
diff --git a/generator/proc_nr.ml b/generator/proc_nr.ml
index dec02f5fa..0a41f9c24 100644
--- a/generator/proc_nr.ml
+++ b/generator/proc_nr.ml
@@ -484,6 +484,29 @@ let proc_nr = [
474, "internal_yara_scan";
475, "file_architecture";
476, "list_filesystems";
+477, "inspect_os";
+478, "inspect_get_roots";
+479, "inspect_get_format";
+480, "inspect_get_type";
+481, "inspect_get_distro";
+482, "inspect_get_package_format";
+483, "inspect_get_package_management";
+484, "inspect_get_product_name";
+485, "inspect_get_product_variant";
+486, "inspect_get_major_version";
+487, "inspect_get_minor_version";
+488, "inspect_get_arch";
+489, "inspect_get_hostname";
+490, "inspect_get_windows_systemroot";
+491, "inspect_get_windows_software_hive";
+492, "inspect_get_windows_system_hive";
+493, "inspect_get_windows_current_control_set";
+494, "inspect_is_live";
+495, "inspect_is_netinst";
+496, "inspect_is_multipart";
+497, "inspect_get_mountpoints";
+498, "inspect_get_filesystems";
+499, "inspect_get_drive_mappings";
]
(* End of list. If adding a new entry, add it at the end of the list
diff --git a/lib/MAX_PROC_NR b/lib/MAX_PROC_NR
index b86395733..761fcd3ac 100644
--- a/lib/MAX_PROC_NR
+++ b/lib/MAX_PROC_NR
@@ -1 +1 @@
-476
+499
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 83b33ac8d..185828cc7 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -96,9 +96,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 \
diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h
index 585dac706..185a13df4 100644
--- a/lib/guestfs-internal.h
+++ b/lib/guestfs-internal.h
@@ -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);
diff --git a/lib/handle.c b/lib/handle.c
index 91f5f755d..57fda24b1 100644
--- a/lib/handle.c
+++ b/lib/handle.c
@@ -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) {
diff --git a/lib/inspect-apps.c b/lib/inspect-apps.c
index 3196a9d0b..2a0e2beba 100644
--- a/lib/inspect-apps.c
+++ b/lib/inspect-apps.c
@@ -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,68 +109,45 @@ 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;
+ ret = list_applications_rpm (g, root);
+ 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);
+ }
+ 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;
- 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 */
}
}
+ else if (STREQ (type, "windows")) {
+ ret = list_applications_windows (g, root);
+ if (ret == NULL)
+ return NULL;
+ }
if (ret == NULL) {
/* Don't know how to do inspection. Not an error, return an
@@ -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)
diff --git a/lib/inspect-fs-unix.c b/lib/inspect-fs-unix.c
deleted file mode 100644
index 9b6bfbf38..000000000
--- a/lib/inspect-fs-unix.c
+++ /dev/null
@@ -1,2158 +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 <inttypes.h>
-#include <unistd.h>
-#include <string.h>
-#include <libintl.h>
-#include <errno.h>
-
-#ifdef HAVE_ENDIAN_H
-#include <endian.h>
-#endif
-
-#include "c-ctype.h"
-#include "ignore-value.h"
-#include "hash-pjw.h"
-
-#include "guestfs.h"
-#include "guestfs-internal.h"
-
-COMPILE_REGEXP (re_fedora, "Fedora release (\\d+)", 0)
-COMPILE_REGEXP (re_rhel_old, "Red Hat.*release (\\d+).*Update (\\d+)", 0)
-COMPILE_REGEXP (re_rhel, "Red Hat.*release (\\d+)\\.(\\d+)", 0)
-COMPILE_REGEXP (re_rhel_no_minor, "Red Hat.*release (\\d+)", 0)
-COMPILE_REGEXP (re_centos_old, "CentOS.*release (\\d+).*Update (\\d+)", 0)
-COMPILE_REGEXP (re_centos, "CentOS.*release (\\d+)\\.(\\d+)", 0)
-COMPILE_REGEXP (re_centos_no_minor, "CentOS.*release (\\d+)", 0)
-COMPILE_REGEXP (re_scientific_linux_old,
- "Scientific Linux.*release (\\d+).*Update (\\d+)", 0)
-COMPILE_REGEXP (re_scientific_linux,
- "Scientific Linux.*release (\\d+)\\.(\\d+)", 0)
-COMPILE_REGEXP (re_scientific_linux_no_minor,
- "Scientific Linux.*release (\\d+)", 0)
-COMPILE_REGEXP (re_oracle_linux_old,
- "Oracle Linux.*release (\\d+).*Update (\\d+)", 0)
-COMPILE_REGEXP (re_oracle_linux,
- "Oracle Linux.*release (\\d+)\\.(\\d+)", 0)
-COMPILE_REGEXP (re_oracle_linux_no_minor, "Oracle Linux.*release (\\d+)", 0)
-COMPILE_REGEXP (re_xdev, "^/dev/(h|s|v|xv)d([a-z]+)(\\d*)$", 0)
-COMPILE_REGEXP (re_cciss, "^/dev/(cciss/c\\d+d\\d+)(?:p(\\d+))?$", 0)
-COMPILE_REGEXP (re_mdN, "^(/dev/md\\d+)$", 0)
-COMPILE_REGEXP (re_freebsd_mbr,
- "^/dev/(ada{0,1}|vtbd)(\\d+)s(\\d+)([a-z])$", 0)
-COMPILE_REGEXP (re_freebsd_gpt, "^/dev/(ada{0,1}|vtbd)(\\d+)p(\\d+)$", 0)
-COMPILE_REGEXP (re_diskbyid, "^/dev/disk/by-id/.*-part(\\d+)$", 0)
-COMPILE_REGEXP (re_netbsd, "^NetBSD (\\d+)\\.(\\d+)", 0)
-COMPILE_REGEXP (re_opensuse, "^(openSUSE|SuSE Linux|SUSE LINUX) ", 0)
-COMPILE_REGEXP (re_sles, "^SUSE (Linux|LINUX) Enterprise ", 0)
-COMPILE_REGEXP (re_nld, "^Novell Linux Desktop ", 0)
-COMPILE_REGEXP (re_opensuse_version, "^VERSION = (\\d+)\\.(\\d+)", 0)
-COMPILE_REGEXP (re_sles_version, "^VERSION = (\\d+)", 0)
-COMPILE_REGEXP (re_sles_patchlevel, "^PATCHLEVEL = (\\d+)", 0)
-COMPILE_REGEXP (re_minix, "^(\\d+)\\.(\\d+)(\\.(\\d+))?", 0)
-COMPILE_REGEXP (re_hurd_dev, "^/dev/(h)d(\\d+)s(\\d+)$", 0)
-COMPILE_REGEXP (re_openbsd, "^OpenBSD (\\d+|\\?)\\.(\\d+|\\?)", 0)
-COMPILE_REGEXP (re_openbsd_duid, "^[0-9a-f]{16}\\.[a-z]", 0)
-COMPILE_REGEXP (re_openbsd_dev, "^/dev/(s|w)d([0-9])([a-z])$", 0)
-COMPILE_REGEXP (re_netbsd_dev, "^/dev/(l|s)d([0-9])([a-z])$", 0)
-COMPILE_REGEXP (re_altlinux, "
(?:(\\d+)(?:\\.(\\d+)(?:[\\.\\d]+)?)?)\\s+\\((?:[^)]+)\\)$", 0)
-COMPILE_REGEXP (re_frugalware, "Frugalware (\\d+)\\.(\\d+)", 0)
-COMPILE_REGEXP (re_pldlinux, "(\\d+)\\.(\\d+) PLD Linux", 0)
-
-static void check_architecture (guestfs_h *g, struct inspect_fs *fs);
-static int check_hostname_unix (guestfs_h *g, struct inspect_fs *fs);
-static int check_hostname_redhat (guestfs_h *g, struct inspect_fs *fs);
-static int check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs);
-static int check_fstab (guestfs_h *g, struct inspect_fs *fs);
-static void add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
- const char *mountable, const char *mp);
-static char *resolve_fstab_device (guestfs_h *g, const char *spec,
- Hash_table *md_map,
- enum inspect_os_type os_type);
-static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char
**configfiles, int (*f) (guestfs_h *, struct inspect_fs *));
-static void canonical_mountpoint (char *mp);
-
-/* Hash structure for uuid->path lookups */
-typedef struct md_uuid {
- uint32_t uuid[4];
- char *path;
-} md_uuid;
-
-static size_t uuid_hash(const void *x, size_t table_size);
-static bool uuid_cmp(const void *x, const void *y);
-static void md_uuid_free(void *x);
-
-static int parse_uuid(const char *str, uint32_t *uuid);
-
-/* Hash structure for path(mdadm)->path(appliance) lookup */
-typedef struct {
- char *mdadm;
- char *app;
-} mdadm_app;
-
-static size_t mdadm_app_hash(const void *x, size_t table_size);
-static bool mdadm_app_cmp(const void *x, const void *y);
-static void mdadm_app_free(void *x);
-
-static ssize_t map_app_md_devices (guestfs_h *g, Hash_table **map);
-static int map_md_devices(guestfs_h *g, Hash_table **map);
-
-/* Set fs->product_name to the first line of the release file. */
-static int
-parse_release_file (guestfs_h *g, struct inspect_fs *fs,
- const char *release_filename)
-{
- fs->product_name = guestfs_int_first_line_of_file (g, release_filename);
- if (fs->product_name == NULL)
- return -1;
- if (STREQ (fs->product_name, "")) {
- free (fs->product_name);
- fs->product_name = NULL;
- error (g, _("release file %s is empty or malformed"), release_filename);
- return -1;
- }
- return 0;
-}
-
-/* Parse a os-release file.
- *
- * Only few fields are parsed, falling back to the usual detection if we
- * cannot read all of them.
- *
- * For the format of os-release, see also:
- *
http://www.freedesktop.org/software/systemd/man/os-release.html
- */
-static int
-parse_os_release (guestfs_h *g, struct inspect_fs *fs, const char *filename)
-{
- int64_t size;
- CLEANUP_FREE_STRING_LIST char **lines = NULL;
- size_t i;
- enum inspect_os_distro distro = OS_DISTRO_UNKNOWN;
- CLEANUP_FREE char *product_name = NULL;
- struct version version;
- guestfs_int_version_from_values (&version, -1, -1, 0);
-
- /* Don't trust guestfs_read_lines 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;
- }
-
- lines = guestfs_read_lines (g, filename);
- if (lines == NULL)
- return -1;
-
- for (i = 0; lines[i] != NULL; ++i) {
- const char *line = lines[i];
- const char *value;
- size_t value_len;
-
- if (line[0] == '#')
- continue;
-
- value = strchr (line, '=');
- if (value == NULL)
- continue;
-
- ++value;
- value_len = strlen (line) - (value - line);
- if (value_len > 1 && value[0] == '"' &&
value[value_len-1] == '"') {
- ++value;
- value_len -= 2;
- }
-
-#define VALUE_IS(a) STREQLEN(value, a, value_len)
- if (STRPREFIX (line, "ID=")) {
- if (VALUE_IS ("alpine"))
- distro = OS_DISTRO_ALPINE_LINUX;
- else if (VALUE_IS ("altlinux"))
- distro = OS_DISTRO_ALTLINUX;
- else if (VALUE_IS ("arch"))
- distro = OS_DISTRO_ARCHLINUX;
- else if (VALUE_IS ("centos"))
- distro = OS_DISTRO_CENTOS;
- else if (VALUE_IS ("coreos"))
- distro = OS_DISTRO_COREOS;
- else if (VALUE_IS ("debian"))
- distro = OS_DISTRO_DEBIAN;
- else if (VALUE_IS ("fedora"))
- distro = OS_DISTRO_FEDORA;
- else if (VALUE_IS ("frugalware"))
- distro = OS_DISTRO_FRUGALWARE;
- else if (VALUE_IS ("mageia"))
- distro = OS_DISTRO_MAGEIA;
- else if (VALUE_IS ("opensuse"))
- distro = OS_DISTRO_OPENSUSE;
- else if (VALUE_IS ("pld"))
- distro = OS_DISTRO_PLD_LINUX;
- else if (VALUE_IS ("rhel"))
- distro = OS_DISTRO_RHEL;
- else if (VALUE_IS ("sles") || VALUE_IS ("sled"))
- distro = OS_DISTRO_SLES;
- else if (VALUE_IS ("ubuntu"))
- distro = OS_DISTRO_UBUNTU;
- else if (VALUE_IS ("void"))
- distro = OS_DISTRO_VOID_LINUX;
- } else if (STRPREFIX (line, "PRETTY_NAME=")) {
- free (product_name);
- product_name = safe_strndup (g, value, value_len);
- } else if (STRPREFIX (line, "VERSION_ID=")) {
- CLEANUP_FREE char *buf =
- safe_asprintf (g, "%.*s", (int) value_len, value);
- if (guestfs_int_version_from_x_y_or_x (g, &version, buf) == -1)
- return -1;
- }
-#undef VALUE_IS
- }
-
- /* If we haven't got all the fields, exit right away. */
- if (distro == OS_DISTRO_UNKNOWN || product_name == NULL)
- return 0;
-
- if (version.v_major == -1 || version.v_minor == -1) {
- /* Void Linux has no VERSION_ID (yet), but since it's a rolling
- * distro and has no other version/release-like file. */
- if (distro == OS_DISTRO_VOID_LINUX)
- version_init_null (&version);
- else
- return 0;
- }
-
- /* Apparently, os-release in Debian and CentOS does not provide the full
- * version number in VERSION_ID, but just the "major" part of it.
- * Hence, if version.v_minor is 0, act as there was no information in
- * os-release, which will continue the inspection using the release files
- * as done previously.
- */
- if ((distro == OS_DISTRO_DEBIAN || distro == OS_DISTRO_CENTOS) &&
- version.v_minor == 0)
- return 0;
-
- /* We got everything, so set the fields and report the inspection
- * was successful.
- */
- fs->distro = distro;
- fs->product_name = product_name;
- product_name = NULL;
- fs->version = version;
-
- return 1;
-}
-
-/* Ubuntu has /etc/lsb-release containing:
- * DISTRIB_ID=Ubuntu # Distro
- * DISTRIB_RELEASE=10.04 # Version
- * DISTRIB_CODENAME=lucid
- * DISTRIB_DESCRIPTION="Ubuntu 10.04.1 LTS" # Product name
- *
- * [Ubuntu-derived ...] Linux Mint was found to have this:
- * DISTRIB_ID=LinuxMint
- * DISTRIB_RELEASE=10
- * DISTRIB_CODENAME=julia
- * DISTRIB_DESCRIPTION="Linux Mint 10 Julia"
- * Linux Mint also has /etc/linuxmint/info with more information,
- * but we can use the LSB file.
- *
- * Mandriva has:
- * LSB_VERSION=lsb-4.0-amd64:lsb-4.0-noarch
- * DISTRIB_ID=MandrivaLinux
- * DISTRIB_RELEASE=2010.1
- * DISTRIB_CODENAME=Henry_Farman
- * DISTRIB_DESCRIPTION="Mandriva Linux 2010.1"
- * Mandriva also has a normal release file called /etc/mandriva-release.
- *
- * CoreOS has a /etc/lsb-release link to /usr/share/coreos/lsb-release containing:
- * DISTRIB_ID=CoreOS
- * DISTRIB_RELEASE=647.0.0
- * DISTRIB_CODENAME="Red Dog"
- * DISTRIB_DESCRIPTION="CoreOS 647.0.0"
- */
-static int
-parse_lsb_release (guestfs_h *g, struct inspect_fs *fs, const char *filename)
-{
- int64_t size;
- CLEANUP_FREE_STRING_LIST char **lines = NULL;
- size_t i;
- int r = 0;
-
- /* 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 -1;
- if (size > MAX_SMALL_FILE_SIZE) {
- error (g, _("size of %s is unreasonably large (%" PRIi64 "
bytes)"),
- filename, size);
- return -1;
- }
-
- lines = guestfs_head_n (g, 10, filename);
- if (lines == NULL)
- return -1;
-
- for (i = 0; lines[i] != NULL; ++i) {
- if (fs->distro == 0 &&
- STREQ (lines[i], "DISTRIB_ID=Ubuntu")) {
- fs->distro = OS_DISTRO_UBUNTU;
- r = 1;
- }
- else if (fs->distro == 0 &&
- STREQ (lines[i], "DISTRIB_ID=LinuxMint")) {
- fs->distro = OS_DISTRO_LINUX_MINT;
- r = 1;
- }
- else if (fs->distro == 0 &&
- STREQ (lines[i], "DISTRIB_ID=MandrivaLinux")) {
- fs->distro = OS_DISTRO_MANDRIVA;
- r = 1;
- }
- else if (fs->distro == 0 &&
- STREQ (lines[i], "DISTRIB_ID=\"Mageia\"")) {
- fs->distro = OS_DISTRO_MAGEIA;
- r = 1;
- }
- else if (fs->distro == 0 &&
- STREQ (lines[i], "DISTRIB_ID=CoreOS")) {
- fs->distro = OS_DISTRO_COREOS;
- r = 1;
- }
- else if (STRPREFIX (lines[i], "DISTRIB_RELEASE=")) {
- if (guestfs_int_version_from_x_y_or_x (g, &fs->version, &lines[i][16])
== -1)
- return -1;
- }
- else if (fs->product_name == NULL &&
- (STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=\"") ||
- STRPREFIX (lines[i], "DISTRIB_DESCRIPTION='"))) {
- const size_t len = strlen (lines[i]) - 21 - 1;
- fs->product_name = safe_strndup (g, &lines[i][21], len);
- r = 1;
- }
- else if (fs->product_name == NULL &&
- STRPREFIX (lines[i], "DISTRIB_DESCRIPTION=")) {
- const size_t len = strlen (lines[i]) - 20;
- fs->product_name = safe_strndup (g, &lines[i][20], len);
- r = 1;
- }
- }
-
- /* The unnecessary construct in the next line is required to
- * workaround -Wstrict-overflow warning in gcc 4.5.1.
- */
- return r ? 1 : 0;
-}
-
-static int
-parse_suse_release (guestfs_h *g, struct inspect_fs *fs, const char *filename)
-{
- int64_t size;
- CLEANUP_FREE_STRING_LIST char **lines = NULL;
- int r = -1;
-
- /* 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 -1;
- if (size > MAX_SMALL_FILE_SIZE) {
- error (g, _("size of %s is unreasonably large (%" PRIi64 "
bytes)"),
- filename, size);
- return -1;
- }
-
- lines = guestfs_head_n (g, 10, filename);
- if (lines == NULL)
- return -1;
-
- if (lines[0] == NULL)
- goto out;
-
- /* First line is dist release name */
- fs->product_name = safe_strdup (g, lines[0]);
-
- /* Match SLES first because openSuSE regex overlaps some SLES release strings */
- if (match (g, fs->product_name, re_sles) || match (g, fs->product_name, re_nld))
{
- char *major, *minor;
-
- fs->distro = OS_DISTRO_SLES;
-
- /* Second line contains version string */
- if (lines[1] == NULL)
- goto out;
- major = match1 (g, lines[1], re_sles_version);
- if (major == NULL)
- goto out;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1)
- goto out;
-
- /* Third line contains service pack string */
- if (lines[2] == NULL)
- goto out;
- minor = match1 (g, lines[2], re_sles_patchlevel);
- if (minor == NULL)
- goto out;
- fs->version.v_minor = guestfs_int_parse_unsigned_int (g, minor);
- free (minor);
- if (fs->version.v_minor == -1)
- goto out;
- }
- else if (match (g, fs->product_name, re_opensuse)) {
- fs->distro = OS_DISTRO_OPENSUSE;
-
- /* Second line contains version string */
- if (lines[1] == NULL)
- goto out;
- if (guestfs_int_version_from_x_y_re (g, &fs->version, lines[1],
- re_opensuse_version) == -1)
- goto out;
- }
-
- r = 0;
-
- out:
- return r;
-}
-
-/* The currently mounted device is known to be a Linux root. Try to
- * determine from this the distro, version, etc. Also parse
- * /etc/fstab to determine the arrangement of mountpoints and
- * associated devices.
- */
-int
-guestfs_int_check_linux_root (guestfs_h *g, struct inspect_fs *fs)
-{
- int r;
- char *major, *minor;
-
- fs->type = OS_TYPE_LINUX;
-
- if (guestfs_is_file_opts (g, "/etc/os-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- r = parse_os_release (g, fs, "/etc/os-release");
- if (r == -1) /* error */
- return -1;
- if (r == 1) /* ok - detected the release from this file */
- goto skip_release_checks;
- }
-
- if (guestfs_is_file_opts (g, "/etc/lsb-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- r = parse_lsb_release (g, fs, "/etc/lsb-release");
- if (r == -1) /* error */
- return -1;
- if (r == 1) /* ok - detected the release from this file */
- goto skip_release_checks;
- }
-
- /* RHEL-based distros include a "/etc/redhat-release" file, hence their
- * checks need to be performed before the Red-Hat one.
- */
- if (guestfs_is_file_opts (g, "/etc/oracle-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
-
- fs->distro = OS_DISTRO_ORACLE_LINUX;
-
- if (parse_release_file (g, fs, "/etc/oracle-release") == -1)
- return -1;
-
- if (match2 (g, fs->product_name, re_oracle_linux_old, &major, &minor) ||
- match2 (g, fs->product_name, re_oracle_linux, &major, &minor)) {
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1) {
- free (minor);
- return -1;
- }
- fs->version.v_minor = guestfs_int_parse_unsigned_int (g, minor);
- free (minor);
- if (fs->version.v_minor == -1)
- return -1;
- } else if ((major = match1 (g, fs->product_name, re_oracle_linux_no_minor)) !=
NULL) {
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1)
- return -1;
- fs->version.v_minor = 0;
- }
- }
- else if (guestfs_is_file_opts (g, "/etc/centos-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_CENTOS;
-
- if (parse_release_file (g, fs, "/etc/centos-release") == -1)
- return -1;
-
- if (match2 (g, fs->product_name, re_centos_old, &major, &minor) ||
- match2 (g, fs->product_name, re_centos, &major, &minor)) {
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1) {
- free (minor);
- return -1;
- }
- fs->version.v_minor = guestfs_int_parse_unsigned_int (g, minor);
- free (minor);
- if (fs->version.v_minor == -1)
- return -1;
- }
- else if ((major = match1 (g, fs->product_name, re_centos_no_minor)) != NULL) {
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1)
- return -1;
- fs->version.v_minor = 0;
- }
- }
- else if (guestfs_is_file_opts (g, "/etc/altlinux-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_ALTLINUX;
-
- if (parse_release_file (g, fs, "/etc/altlinux-release") == -1)
- return -1;
-
- if (guestfs_int_version_from_x_y_re (g, &fs->version, fs->product_name,
- re_altlinux) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/redhat-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_REDHAT_BASED; /* Something generic Red Hat-like. */
-
- if (parse_release_file (g, fs, "/etc/redhat-release") == -1)
- return -1;
-
- if ((major = match1 (g, fs->product_name, re_fedora)) != NULL) {
- fs->distro = OS_DISTRO_FEDORA;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1)
- return -1;
- }
- else if (match2 (g, fs->product_name, re_rhel_old, &major, &minor) ||
- match2 (g, fs->product_name, re_rhel, &major, &minor)) {
- fs->distro = OS_DISTRO_RHEL;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1) {
- free (minor);
- return -1;
- }
- fs->version.v_minor = guestfs_int_parse_unsigned_int (g, minor);
- free (minor);
- if (fs->version.v_minor == -1)
- return -1;
- }
- else if ((major = match1 (g, fs->product_name, re_rhel_no_minor)) != NULL) {
- fs->distro = OS_DISTRO_RHEL;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1)
- return -1;
- fs->version.v_minor = 0;
- }
- else if (match2 (g, fs->product_name, re_centos_old, &major, &minor) ||
- match2 (g, fs->product_name, re_centos, &major, &minor)) {
- fs->distro = OS_DISTRO_CENTOS;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1) {
- free (minor);
- return -1;
- }
- fs->version.v_minor = guestfs_int_parse_unsigned_int (g, minor);
- free (minor);
- if (fs->version.v_minor == -1)
- return -1;
- }
- else if ((major = match1 (g, fs->product_name, re_centos_no_minor)) != NULL) {
- fs->distro = OS_DISTRO_CENTOS;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1)
- return -1;
- fs->version.v_minor = 0;
- }
- else if (match2 (g, fs->product_name, re_scientific_linux_old, &major,
&minor) ||
- match2 (g, fs->product_name, re_scientific_linux, &major,
&minor)) {
- fs->distro = OS_DISTRO_SCIENTIFIC_LINUX;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1) {
- free (minor);
- return -1;
- }
- fs->version.v_minor = guestfs_int_parse_unsigned_int (g, minor);
- free (minor);
- if (fs->version.v_minor == -1)
- return -1;
- }
- else if ((major = match1 (g, fs->product_name, re_scientific_linux_no_minor)) !=
NULL) {
- fs->distro = OS_DISTRO_SCIENTIFIC_LINUX;
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- free (major);
- if (fs->version.v_major == -1)
- return -1;
- fs->version.v_minor = 0;
- }
- }
- else if (guestfs_is_file_opts (g, "/etc/debian_version",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_DEBIAN;
-
- if (parse_release_file (g, fs, "/etc/debian_version") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/pardus-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_PARDUS;
-
- if (parse_release_file (g, fs, "/etc/pardus-release") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/arch-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_ARCHLINUX;
-
- /* /etc/arch-release file is empty and I can't see a way to
- * determine the actual release or product string.
- */
- }
- else if (guestfs_is_file_opts (g, "/etc/gentoo-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_GENTOO;
-
- if (parse_release_file (g, fs, "/etc/gentoo-release") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/meego-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_MEEGO;
-
- if (parse_release_file (g, fs, "/etc/meego-release") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/slackware-version",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_SLACKWARE;
-
- if (parse_release_file (g, fs, "/etc/slackware-version") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/ttylinux-target",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_TTYLINUX;
-
- if (parse_release_file (g, fs, "/etc/ttylinux-target") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/SuSE-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_SUSE_BASED;
-
- if (parse_suse_release (g, fs, "/etc/SuSE-release") == -1)
- return -1;
-
- }
- /* CirrOS versions providing a own version file.
- */
- else if (guestfs_is_file_opts (g, "/etc/cirros/version",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_CIRROS;
-
- if (parse_release_file (g, fs, "/etc/cirros/version") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- /* Buildroot (
http://buildroot.net) is an embedded Linux distro
- * toolkit. It is used by specific distros such as Cirros.
- */
- else if (guestfs_is_file_opts (g, "/etc/br-version",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- if (guestfs_is_file_opts (g, "/usr/share/cirros/logo",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0)
- fs->distro = OS_DISTRO_CIRROS;
- else
- fs->distro = OS_DISTRO_BUILDROOT;
-
- /* /etc/br-version has the format YYYY.MM[-git/hg/svn release] */
- if (parse_release_file (g, fs, "/etc/br-version") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/alpine-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_ALPINE_LINUX;
-
- if (parse_release_file (g, fs, "/etc/alpine-release") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/frugalware-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_FRUGALWARE;
-
- if (parse_release_file (g, fs, "/etc/frugalware-release") == -1)
- return -1;
-
- if (guestfs_int_version_from_x_y_re (g, &fs->version, fs->product_name,
- re_frugalware) == -1)
- return -1;
- }
- else if (guestfs_is_file_opts (g, "/etc/pld-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_PLD_LINUX;
-
- if (parse_release_file (g, fs, "/etc/pld-release") == -1)
- return -1;
-
- if (guestfs_int_version_from_x_y_re (g, &fs->version, fs->product_name,
- re_pldlinux) == -1)
- return -1;
- }
-
- skip_release_checks:;
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- /* We already know /etc/fstab exists because it's part of the test
- * for Linux root above. We must now parse this file to determine
- * which filesystems are used by the operating system and how they
- * are mounted.
- */
- const char *configfiles[] = { "/etc/fstab", "/etc/mdadm.conf", NULL
};
- if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
- return -1;
-
- /* Determine hostname. */
- if (check_hostname_unix (g, fs) == -1)
- return -1;
-
- return 0;
-}
-
-/* The currently mounted device looks like a Linux /usr. */
-int
-guestfs_int_check_linux_usr (guestfs_h *g, struct inspect_fs *fs)
-{
- int r;
-
- fs->type = OS_TYPE_LINUX;
- fs->role = OS_ROLE_USR;
-
- if (guestfs_is_file_opts (g, "/lib/os-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- r = parse_os_release (g, fs, "/lib/os-release");
- if (r == -1) /* error */
- return -1;
- if (r == 1) /* ok - detected the release from this file */
- goto skip_release_checks;
- }
-
- skip_release_checks:;
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- return 0;
-}
-
-/* The currently mounted device is known to be a FreeBSD root. */
-int
-guestfs_int_check_freebsd_root (guestfs_h *g, struct inspect_fs *fs)
-{
- fs->type = OS_TYPE_FREEBSD;
- fs->distro = OS_DISTRO_FREEBSD;
-
- /* FreeBSD has no authoritative version file. The version number is
- * in /etc/motd, which the system administrator might edit, but
- * we'll use that anyway.
- */
-
- if (guestfs_is_file_opts (g, "/etc/motd",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- if (parse_release_file (g, fs, "/etc/motd") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- /* We already know /etc/fstab exists because it's part of the test above. */
- const char *configfiles[] = { "/etc/fstab", NULL };
- if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
- return -1;
-
- /* Determine hostname. */
- if (check_hostname_unix (g, fs) == -1)
- return -1;
-
- return 0;
-}
-
-/* The currently mounted device is maybe to be a *BSD root. */
-int
-guestfs_int_check_netbsd_root (guestfs_h *g, struct inspect_fs *fs)
-{
-
- if (guestfs_is_file_opts (g, "/etc/release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- int result;
- if (parse_release_file (g, fs, "/etc/release") == -1)
- return -1;
-
- result = guestfs_int_version_from_x_y_re (g, &fs->version,
- fs->product_name, re_netbsd);
- if (result == -1) {
- return -1;
- } else if (result == 1) {
- fs->type = OS_TYPE_NETBSD;
- fs->distro = OS_DISTRO_NETBSD;
- }
- } else {
- return -1;
- }
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- /* We already know /etc/fstab exists because it's part of the test above. */
- const char *configfiles[] = { "/etc/fstab", NULL };
- if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
- return -1;
-
- /* Determine hostname. */
- if (check_hostname_unix (g, fs) == -1)
- return -1;
-
- return 0;
-}
-
-/* The currently mounted device may be an OpenBSD root. */
-int
-guestfs_int_check_openbsd_root (guestfs_h *g, struct inspect_fs *fs)
-{
- if (guestfs_is_file_opts (g, "/etc/motd",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- CLEANUP_FREE char *major = NULL, *minor = NULL;
-
- /* The first line of this file gets automatically updated at boot. */
- if (parse_release_file (g, fs, "/etc/motd") == -1)
- return -1;
-
- if (match2 (g, fs->product_name, re_openbsd, &major, &minor)) {
- fs->type = OS_TYPE_OPENBSD;
- fs->distro = OS_DISTRO_OPENBSD;
-
- /* Before the first boot, the first line will look like this:
- *
- * OpenBSD ?.? (UNKNOWN)
- */
- if ((fs->product_name[8] != '?') && (fs->product_name[10] !=
'?')) {
- fs->version.v_major = guestfs_int_parse_unsigned_int (g, major);
- if (fs->version.v_major == -1)
- return -1;
-
- fs->version.v_minor = guestfs_int_parse_unsigned_int (g, minor);
- if (fs->version.v_minor == -1)
- return -1;
- }
- }
- } else {
- return -1;
- }
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- /* We already know /etc/fstab exists because it's part of the test above. */
- const char *configfiles[] = { "/etc/fstab", NULL };
- if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
- return -1;
-
- /* Determine hostname. */
- if (check_hostname_unix (g, fs) == -1)
- return -1;
-
- return 0;
-}
-
-/* The currently mounted device may be a Hurd root. Hurd has distros
- * just like Linux.
- */
-int
-guestfs_int_check_hurd_root (guestfs_h *g, struct inspect_fs *fs)
-{
- fs->type = OS_TYPE_HURD;
-
- if (guestfs_is_file_opts (g, "/etc/debian_version",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- fs->distro = OS_DISTRO_DEBIAN;
-
- if (parse_release_file (g, fs, "/etc/debian_version") == -1)
- return -1;
-
- if (guestfs_int_parse_major_minor (g, fs) == -1)
- return -1;
- }
-
- /* Arch Hurd also exists, but inconveniently it doesn't have
- * the normal /etc/arch-release file. XXX
- */
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- if (guestfs_is_file (g, "/etc/fstab") > 0) {
- const char *configfiles[] = { "/etc/fstab", NULL };
- if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
- return -1;
- }
-
- /* Determine hostname. */
- if (check_hostname_unix (g, fs) == -1)
- return -1;
-
- return 0;
-}
-
-/* The currently mounted device is maybe to be a Minix root. */
-int
-guestfs_int_check_minix_root (guestfs_h *g, struct inspect_fs *fs)
-{
- fs->type = OS_TYPE_MINIX;
-
- if (guestfs_is_file_opts (g, "/etc/version",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- if (parse_release_file (g, fs, "/etc/version") == -1)
- return -1;
-
- if (guestfs_int_version_from_x_y_re (g, &fs->version, fs->product_name,
- re_minix) == -1)
- return -1;
- } else {
- return -1;
- }
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- /* TODO: enable fstab inspection once resolve_fstab_device implements
- * the proper mapping from the Minix device names to the appliance names
- */
-
- /* Determine hostname. */
- if (check_hostname_unix (g, fs) == -1)
- return -1;
-
- return 0;
-}
-
-/* The currently mounted device is a CoreOS root. From this partition we can
- * only determine the hostname. All immutable OS files are under a separate
- * read-only /usr partition.
- */
-int
-guestfs_int_check_coreos_root (guestfs_h *g, struct inspect_fs *fs)
-{
- fs->type = OS_TYPE_LINUX;
- fs->distro = OS_DISTRO_COREOS;
-
- /* Determine hostname. */
- if (check_hostname_unix (g, fs) == -1)
- return -1;
-
- /* CoreOS does not contain /etc/fstab to determine the mount points.
- * Associate this filesystem with the "/" mount point.
- */
- add_fstab_entry (g, fs, fs->mountable, "/");
-
- return 0;
-}
-
-/* The currently mounted device looks like a CoreOS /usr. In CoreOS
- * the read-only /usr contains the OS version. The /etc/os-release is a
- * link to /usr/share/coreos/os-release.
- */
-int
-guestfs_int_check_coreos_usr (guestfs_h *g, struct inspect_fs *fs)
-{
- int r;
-
- fs->type = OS_TYPE_LINUX;
- fs->distro = OS_DISTRO_COREOS;
- fs->role = OS_ROLE_USR;
-
- if (guestfs_is_file_opts (g, "/lib/os-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- r = parse_os_release (g, fs, "/lib/os-release");
- if (r == -1) /* error */
- return -1;
- if (r == 1) /* ok - detected the release from this file */
- goto skip_release_checks;
- }
-
- if (guestfs_is_file_opts (g, "/share/coreos/lsb-release",
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- r = parse_lsb_release (g, fs, "/share/coreos/lsb-release");
- if (r == -1) /* error */
- return -1;
- }
-
- skip_release_checks:;
-
- /* Determine the architecture. */
- check_architecture (g, fs);
-
- /* CoreOS does not contain /etc/fstab to determine the mount points.
- * Associate this filesystem with the "/usr" mount point.
- */
- add_fstab_entry (g, fs, fs->mountable, "/usr");
-
- return 0;
-}
-
-static void
-check_architecture (guestfs_h *g, struct inspect_fs *fs)
-{
- const char *binaries[] =
- { "/bin/bash", "/bin/ls", "/bin/echo",
"/bin/rm", "/bin/sh" };
- size_t i;
- char *arch = NULL;
-
- for (i = 0; i < sizeof binaries / sizeof binaries[0]; ++i) {
- /* Allow symlinks when checking the binaries:,so in case they are
- * relative ones (which can be resolved within the same partition),
- * then we can check the architecture of their target.
- */
- if (guestfs_is_file_opts (g, binaries[i],
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- CLEANUP_FREE char *resolved = NULL;
-
- /* Ignore errors from realpath and file_architecture calls. */
- guestfs_push_error_handler (g, NULL, NULL);
- resolved = guestfs_realpath (g, binaries[i]);
- /* If is_file above succeeded realpath should too, but better
- * be safe than sorry.
- */
- if (resolved)
- arch = guestfs_file_architecture (g, resolved);
- guestfs_pop_error_handler (g);
-
- if (arch) {
- /* String will be owned by handle, freed by
- * guestfs_int_free_inspect_info.
- */
- fs->arch = arch;
- break;
- }
- }
- }
-}
-
-/* Try several methods to determine the hostname from a Linux or
- * FreeBSD guest. Note that type and distro have been set, so we can
- * use that information to direct the search.
- */
-static int
-check_hostname_unix (guestfs_h *g, struct inspect_fs *fs)
-{
- switch (fs->type) {
- case OS_TYPE_LINUX:
- case OS_TYPE_HURD:
- /* Red Hat-derived would be in /etc/sysconfig/network or
- * /etc/hostname (RHEL 7+, F18+). Debian-derived in the file
- * /etc/hostname. Very old Debian and SUSE use /etc/HOSTNAME.
- * It's best to just look for each of these files in turn, rather
- * than try anything clever based on distro.
- */
- if (guestfs_is_file (g, "/etc/HOSTNAME")) {
- fs->hostname = guestfs_int_first_line_of_file (g, "/etc/HOSTNAME");
- if (fs->hostname == NULL)
- return -1;
- if (STREQ (fs->hostname, "")) {
- free (fs->hostname);
- fs->hostname = NULL;
- }
- }
-
- if (!fs->hostname && guestfs_is_file (g, "/etc/hostname")) {
- fs->hostname = guestfs_int_first_line_of_file (g, "/etc/hostname");
- if (fs->hostname == NULL)
- return -1;
- if (STREQ (fs->hostname, "")) {
- free (fs->hostname);
- fs->hostname = NULL;
- }
- }
-
- if (!fs->hostname && guestfs_is_file (g,
"/etc/sysconfig/network")) {
- const char *configfiles[] = { "/etc/sysconfig/network", NULL };
- if (inspect_with_augeas (g, fs, configfiles,
- check_hostname_redhat) == -1)
- return -1;
- }
- break;
-
- case OS_TYPE_FREEBSD:
- case OS_TYPE_NETBSD:
- /* /etc/rc.conf contains the hostname, but there is no Augeas lens
- * for this file.
- */
- if (guestfs_is_file (g, "/etc/rc.conf")) {
- if (check_hostname_freebsd (g, fs) == -1)
- return -1;
- }
- break;
-
- case OS_TYPE_OPENBSD:
- if (guestfs_is_file (g, "/etc/myname")) {
- fs->hostname = guestfs_int_first_line_of_file (g, "/etc/myname");
- if (fs->hostname == NULL)
- return -1;
- if (STREQ (fs->hostname, "")) {
- free (fs->hostname);
- fs->hostname = NULL;
- }
- }
- break;
-
- case OS_TYPE_MINIX:
- if (guestfs_is_file (g, "/etc/hostname.file")) {
- fs->hostname = guestfs_int_first_line_of_file (g,
"/etc/hostname.file");
- if (fs->hostname == NULL)
- return -1;
- if (STREQ (fs->hostname, "")) {
- free (fs->hostname);
- fs->hostname = NULL;
- }
- }
- break;
-
- case OS_TYPE_WINDOWS: /* not here, see check_windows_system_registry */
- case OS_TYPE_DOS:
- case OS_TYPE_UNKNOWN:
- /* nothing */;
- }
-
- return 0;
-}
-
-/* Parse the hostname from /etc/sysconfig/network. This must be
- * called from the inspect_with_augeas wrapper. Note that F18+ and
- * RHEL7+ use /etc/hostname just like Debian.
- */
-static int
-check_hostname_redhat (guestfs_h *g, struct inspect_fs *fs)
-{
- char *hostname;
-
- /* Errors here are not fatal (RHBZ#726739), since it could be
- * just missing HOSTNAME field in the file.
- */
- guestfs_push_error_handler (g, NULL, NULL);
- hostname = guestfs_aug_get (g, "/files/etc/sysconfig/network/HOSTNAME");
- guestfs_pop_error_handler (g);
-
- /* This is freed by guestfs_int_free_inspect_info. Note that hostname
- * could be NULL because we ignored errors above.
- */
- fs->hostname = hostname;
- return 0;
-}
-
-/* Parse the hostname from /etc/rc.conf. On FreeBSD this file
- * contains comments, blank lines and:
- * hostname="freebsd8.example.com"
- * ifconfig_re0="DHCP"
- * keymap="uk.iso"
- * sshd_enable="YES"
- */
-static int
-check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs)
-{
- const char *filename = "/etc/rc.conf";
- int64_t size;
- CLEANUP_FREE_STRING_LIST char **lines = NULL;
- size_t i;
-
- /* Don't trust guestfs_read_lines 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;
- }
-
- lines = guestfs_read_lines (g, filename);
- if (lines == NULL)
- return -1;
-
- for (i = 0; lines[i] != NULL; ++i) {
- if (STRPREFIX (lines[i], "hostname=\"") ||
- STRPREFIX (lines[i], "hostname='")) {
- const size_t len = strlen (lines[i]) - 10 - 1;
- fs->hostname = safe_strndup (g, &lines[i][10], len);
- break;
- } else if (STRPREFIX (lines[i], "hostname=")) {
- const size_t len = strlen (lines[i]) - 9;
- fs->hostname = safe_strndup (g, &lines[i][9], len);
- break;
- }
- }
-
- return 0;
-}
-
-static int
-check_fstab (guestfs_h *g, struct inspect_fs *fs)
-{
- CLEANUP_FREE_STRING_LIST char **entries = NULL;
- char **entry;
- char augpath[256];
- CLEANUP_HASH_FREE Hash_table *md_map = NULL;
- bool is_bsd = (fs->type == OS_TYPE_FREEBSD ||
- fs->type == OS_TYPE_NETBSD ||
- fs->type == OS_TYPE_OPENBSD);
-
- /* Generate a map of MD device paths listed in /etc/mdadm.conf to MD device
- * paths in the guestfs appliance */
- if (map_md_devices (g, &md_map) == -1) return -1;
-
- entries = guestfs_aug_match (g, "/files/etc/fstab/*[label() !=
'#comment']");
- if (entries == NULL)
- return -1;
-
- for (entry = entries; *entry != NULL; entry++) {
- CLEANUP_FREE char *spec = NULL;
- CLEANUP_FREE char *mp = NULL;
- CLEANUP_FREE char *mountable = NULL;
- CLEANUP_FREE char *vfstype = NULL;
-
- snprintf (augpath, sizeof augpath, "%s/spec", *entry);
- spec = guestfs_aug_get (g, augpath);
- if (spec == NULL)
- return -1;
-
- /* Ignore /dev/fd (floppy disks) (RHBZ#642929) and CD-ROM drives.
- *
- * /dev/iso9660/FREEBSD_INSTALL can be found in FreeBSDs installation
- * discs.
- */
- if ((STRPREFIX (spec, "/dev/fd") && c_isdigit (spec[7])) ||
- (STRPREFIX (spec, "/dev/cd") && c_isdigit (spec[7])) ||
- STREQ (spec, "/dev/floppy") ||
- STREQ (spec, "/dev/cdrom") ||
- STRPREFIX (spec, "/dev/iso9660/"))
- continue;
-
- snprintf (augpath, sizeof augpath, "%s/file", *entry);
- mp = guestfs_aug_get (g, augpath);
- if (mp == NULL)
- return -1;
-
- /* Canonicalize the path, so "///usr//local//" -> "/usr/local"
*/
- canonical_mountpoint (mp);
-
- /* Ignore certain mountpoints. */
- if (STRPREFIX (mp, "/dev/") ||
- STREQ (mp, "/dev") ||
- STRPREFIX (mp, "/media/") ||
- STRPREFIX (mp, "/proc/") ||
- STREQ (mp, "/proc") ||
- STRPREFIX (mp, "/selinux/") ||
- STREQ (mp, "/selinux") ||
- STRPREFIX (mp, "/sys/") ||
- STREQ (mp, "/sys"))
- continue;
-
- /* Resolve UUID= and LABEL= to the actual device. */
- if (STRPREFIX (spec, "UUID=")) {
- CLEANUP_FREE char *s = guestfs_int_shell_unquote (&spec[5]);
- if (s == NULL) { perrorf (g, "guestfs_int_shell_unquote"); return -1; }
- mountable = guestfs_findfs_uuid (g, s);
- }
- else if (STRPREFIX (spec, "LABEL=")) {
- CLEANUP_FREE char *s = guestfs_int_shell_unquote (&spec[6]);
- if (s == NULL) { perrorf (g, "guestfs_int_shell_unquote"); return -1; }
- mountable = guestfs_findfs_label (g, s);
- }
- /* Ignore "/.swap" (Pardus) and pseudo-devices like "tmpfs". */
- else if (STREQ (spec, "/dev/root") || (is_bsd && STREQ (mp,
"/")))
- /* Resolve /dev/root to the current device.
- * Do the same for the / partition of the *BSD systems, since the
- * BSD -> Linux device translation is not straight forward.
- */
- mountable = safe_strdup (g, fs->mountable);
- else if (STRPREFIX (spec, "/dev/"))
- /* Resolve guest block device names. */
- mountable = resolve_fstab_device (g, spec, md_map, fs->type);
- else if (match (g, spec, re_openbsd_duid)) {
- /* In OpenBSD's fstab you can specify partitions on a disk by appending a
- * period and a partition letter to a Disklable Unique Identifier. The
- * DUID is a 16 hex digit field found in the OpenBSD's altered BSD
- * disklabel. For more info see here:
- *
http://www.openbsd.org/faq/faq14.html#intro
- */
- char device[10]; /* /dev/sd[0-9][a-z] */
- char part = spec[17];
-
- /* We cannot peep into disklables, we can only assume that this is the
- * first disk.
- */
- snprintf(device, 10, "%s%c", "/dev/sd0", part);
- mountable = resolve_fstab_device (g, device, md_map, fs->type);
- }
-
- /* If we haven't resolved the device successfully by this point,
- * we don't care, just ignore it.
- */
- if (mountable == NULL)
- continue;
-
- snprintf (augpath, sizeof augpath, "%s/vfstype", *entry);
- vfstype = guestfs_aug_get (g, augpath);
- if (vfstype == NULL) return -1;
-
- if (STREQ (vfstype, "btrfs")) {
- size_t i;
-
- snprintf (augpath, sizeof augpath, "%s/opt", *entry);
- CLEANUP_FREE_STRING_LIST char **opts = guestfs_aug_match (g, augpath);
- if (opts == NULL) return -1;
-
- for (i = 0; opts[i] != NULL; ++i) {
- CLEANUP_FREE char *optname = NULL, *optvalue = NULL, *subvol = NULL;
- char *old_mountable;
-
- optname = guestfs_aug_get (g, opts[i]);
- if (optname == NULL) return -1;
-
- if (STREQ (optname, "subvol")) {
- optvalue = safe_asprintf (g, "%s/value", opts[i]);
-
- subvol = guestfs_aug_get (g, optvalue);
- if (subvol == NULL) return -1;
-
- old_mountable = mountable;
- mountable = safe_asprintf (g, "btrfsvol:%s/%s", mountable, subvol);
- free (old_mountable);
- }
- }
- }
-
- add_fstab_entry (g, fs, mountable, mp);
- }
-
- return 0;
-}
-
-/* Add a filesystem and possibly a mountpoint entry for
- * the root filesystem 'fs'.
- *
- * 'spec' is the fstab spec field, which might be a device name or a
- * pseudodevice or 'UUID=...' or 'LABEL=...'.
- *
- * 'mp' is the mount point, which could also be 'swap' or
'none'.
- */
-static void
-add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
- const char *mountable, const char *mountpoint)
-{
- /* Add this to the fstab entry in 'fs'.
- * Note these are further filtered by guestfs_inspect_get_mountpoints
- * and guestfs_inspect_get_filesystems.
- */
- const size_t n = fs->nr_fstab + 1;
- struct inspect_fstab_entry *p;
-
- p = safe_realloc (g, fs->fstab, n * sizeof (struct inspect_fstab_entry));
-
- fs->fstab = p;
- fs->nr_fstab = n;
-
- /* These are owned by the handle and freed by guestfs_int_free_inspect_info. */
- fs->fstab[n-1].mountable = safe_strdup (g, mountable);
- fs->fstab[n-1].mountpoint = safe_strdup (g, mountpoint);
-
- debug (g, "fstab: mountable=%s mountpoint=%s", mountable, mountpoint);
-}
-
-/* Compute a uuid hash as a simple xor of of its 4 32bit components */
-static size_t
-uuid_hash(const void *x, size_t table_size)
-{
- const md_uuid *a = x;
- size_t h, i;
-
- h = a->uuid[0];
- for (i = 1; i < 4; i++) {
- h ^= a->uuid[i];
- }
-
- return h % table_size;
-}
-
-static bool
-uuid_cmp(const void *x, const void *y)
-{
- const md_uuid *a = x;
- const md_uuid *b = y;
- size_t i;
-
- for (i = 0; i < 1; i++) {
- if (a->uuid[i] != b->uuid[i]) return 0;
- }
-
- return 1;
-}
-
-static void
-md_uuid_free(void *x)
-{
- md_uuid *a = x;
- free(a->path);
- free(a);
-}
-
-/* Taken from parse_uuid in mdadm */
-static int
-parse_uuid (const char *str, uint32_t *uuid)
-{
- size_t hit = 0; /* number of Hex digIT */
- char c;
- size_t i;
- int n;
-
- for (i = 0; i < 4; i++)
- uuid[i] = 0;
-
- while ((c = *str++)) {
- if (c >= '0' && c <= '9')
- n = c - '0';
- else if (c >= 'a' && c <= 'f')
- n = 10 + c - 'a';
- else if (c >= 'A' && c <= 'F')
- n = 10 + c - 'A';
- else if (strchr (":. -", c))
- continue;
- else
- return -1;
-
- if (hit < 32) {
- uuid[hit / 8] <<= 4;
- uuid[hit / 8] += n;
- }
- hit++;
- }
- if (hit == 32) return 0;
-
- return -1;
-}
-
-/* Create a mapping of uuids to appliance md device names */
-static ssize_t
-map_app_md_devices (guestfs_h *g, Hash_table **map)
-{
- CLEANUP_FREE_STRING_LIST char **mds = NULL;
- size_t n = 0;
- char **md;
-
- /* A hash mapping uuids to md device names */
- *map = hash_initialize(16, NULL, uuid_hash, uuid_cmp, md_uuid_free);
- if (*map == NULL) g->abort_cb();
-
- mds = guestfs_list_md_devices(g);
- if (mds == NULL) goto error;
-
- for (md = mds; *md != NULL; md++) {
- char **i;
- CLEANUP_FREE_STRING_LIST char **detail = guestfs_md_detail (g, *md);
- if (detail == NULL) goto error;
-
- /* Iterate over keys until we find uuid */
- for (i = detail; *i != NULL; i += 2) {
- if (STREQ(*i, "uuid")) break;
- }
-
- /* We found it */
- if (*i) {
- md_uuid *entry;
-
- /* Next item is the uuid value */
- i++;
-
- entry = safe_malloc(g, sizeof(md_uuid));
- entry->path = safe_strdup(g, *md);
-
- if (parse_uuid(*i, entry->uuid) == -1) {
- /* Invalid UUID is weird, but not fatal. */
- debug(g, "inspect-os: guestfs_md_detail returned invalid "
- "uuid for %s: %s", *md, *i);
- md_uuid_free(entry);
- continue;
- }
-
- const void *matched = NULL;
- switch (hash_insert_if_absent(*map, entry, &matched)) {
- case -1:
- g->abort_cb();
-
- case 0:
- /* Duplicate uuid in for md device is weird, but not fatal. */
- debug(g, "inspect-os: md devices %s and %s have the same uuid",
- ((md_uuid *)matched)->path, entry->path);
- md_uuid_free(entry);
- break;
-
- default:
- n++;
- }
- }
- }
-
- return n;
-
- error:
- hash_free (*map); *map = NULL;
-
- return -1;
-}
-
-static size_t
-mdadm_app_hash(const void *x, size_t table_size)
-{
- const mdadm_app *a = x;
- return hash_pjw(a->mdadm, table_size);
-}
-
-static bool
-mdadm_app_cmp(const void *x, const void *y)
-{
- const mdadm_app *a = x;
- const mdadm_app *b = y;
-
- return STREQ (a->mdadm, b->mdadm);
-}
-
-static void
-mdadm_app_free(void *x)
-{
- mdadm_app *a = x;
- free(a->mdadm);
- free(a->app);
- free(a);
-}
-
-/* Get a map of md device names in mdadm.conf to their device names in the
- * appliance */
-static int
-map_md_devices(guestfs_h *g, Hash_table **map)
-{
- CLEANUP_HASH_FREE Hash_table *app_map = NULL;
- CLEANUP_FREE_STRING_LIST char **matches = NULL;
- ssize_t n_app_md_devices;
-
- *map = NULL;
-
- /* Get a map of md device uuids to their device names in the appliance */
- n_app_md_devices = map_app_md_devices (g, &app_map);
- if (n_app_md_devices == -1) goto error;
-
- /* Nothing to do if there are no md devices */
- if (n_app_md_devices == 0)
- return 0;
-
- /* Get all arrays listed in mdadm.conf */
- matches = guestfs_aug_match(g, "/files/etc/mdadm.conf/array");
- if (!matches) goto error;
-
- /* Log a debug message if we've got md devices, but nothing in mdadm.conf */
- if (matches[0] == NULL) {
- debug(g, "Appliance has MD devices, but augeas returned no array matches "
- "in mdadm.conf");
- return 0;
- }
-
- *map = hash_initialize(16, NULL, mdadm_app_hash, mdadm_app_cmp,
- mdadm_app_free);
- if (!*map) g->abort_cb();
-
- for (char **m = matches; *m != NULL; m++) {
- /* Get device name and uuid for each array */
- CLEANUP_FREE char *dev_path = safe_asprintf (g, "%s/devicename", *m);
- char *dev = guestfs_aug_get (g, dev_path);
- if (!dev) goto error;
-
- CLEANUP_FREE char *uuid_path = safe_asprintf (g, "%s/uuid", *m);
- CLEANUP_FREE char *uuid = guestfs_aug_get (g, uuid_path);
- if (!uuid) {
- free (dev);
- continue;
- }
-
- /* Parse the uuid into an md_uuid structure so we can look it up in the
- * uuid->appliance device map */
- md_uuid mdadm;
- mdadm.path = dev;
- if (parse_uuid(uuid, mdadm.uuid) == -1) {
- /* Invalid uuid. Weird, but not fatal. */
- debug(g, "inspect-os: mdadm.conf contains invalid uuid for %s: %s",
- dev, uuid);
- free (dev);
- continue;
- }
-
- /* If there's a corresponding uuid in the appliance, create a new
- * entry in the transitive map */
- md_uuid *app = hash_lookup(app_map, &mdadm);
- if (app) {
- mdadm_app *entry = safe_malloc(g, sizeof(mdadm_app));
- entry->mdadm = dev;
- entry->app = safe_strdup(g, app->path);
-
- switch (hash_insert_if_absent(*map, entry, NULL)) {
- case -1:
- g->abort_cb();
-
- case 0:
- /* Duplicate uuid in for md device is weird, but not fatal. */
- debug(g, "inspect-os: mdadm.conf contains multiple entries for %s",
- app->path);
- mdadm_app_free(entry);
- continue;
- }
- } else
- free (dev);
- }
-
- return 0;
-
- error:
- if (*map) hash_free (*map);
-
- return -1;
-}
-
-static int
-resolve_fstab_device_xdev (guestfs_h *g, const char *type, const char *disk,
- const char *part, char **device_ret)
-{
- CLEANUP_FREE char *name = NULL;
- char *device;
- CLEANUP_FREE_STRING_LIST char **devices = NULL;
- size_t i, count;
- struct drive *drv;
- const char *p;
-
- /* type: (h|s|v|xv)
- * disk: ([a-z]+)
- * part: (\d*)
- */
-
- devices = guestfs_list_devices (g);
- if (devices == NULL)
- return -1;
-
- /* Check any hints we were passed for a non-heuristic mapping */
- name = safe_asprintf (g, "%sd%s", type, disk);
- ITER_DRIVES (g, i, drv) {
- if (drv->name && STREQ (drv->name, name)) {
- device = safe_asprintf (g, "%s%s", devices[i], part);
- if (!guestfs_int_is_partition (g, device)) {
- free (device);
- return 0;
- }
- *device_ret = device;
- break;
- }
- }
-
- /* Guess the appliance device name if we didn't find a matching hint */
- if (!*device_ret) {
- /* Count how many disks the libguestfs appliance has */
- for (count = 0; devices[count] != NULL; count++)
- ;
-
- /* Calculate the numerical index of the disk */
- i = disk[0] - 'a';
- for (p = disk + 1; *p != '\0'; p++) {
- i += 1; i *= 26;
- i += *p - 'a';
- }
-
- /* Check the index makes sense wrt the number of disks the appliance has.
- * If it does, map it to an appliance disk.
- */
- if (i < count) {
- device = safe_asprintf (g, "%s%s", devices[i], part);
- if (!guestfs_int_is_partition (g, device)) {
- free (device);
- return 0;
- }
- *device_ret = device;
- }
- }
-
- return 0;
-}
-
-static int
-resolve_fstab_device_cciss (guestfs_h *g, const char *disk, const char *part,
- char **device_ret)
-{
- char *device;
- CLEANUP_FREE_STRING_LIST char **devices = NULL;
- size_t i;
- struct drive *drv;
-
- /* disk: (cciss/c\d+d\d+)
- * part: (\d+)?
- */
-
- devices = guestfs_list_devices (g);
- if (devices == NULL)
- return -1;
-
- /* Check any hints we were passed for a non-heuristic mapping */
- ITER_DRIVES (g, i, drv) {
- if (drv->name && STREQ (drv->name, disk)) {
- if (part) {
- device = safe_asprintf (g, "%s%s", devices[i], part);
- if (!guestfs_int_is_partition (g, device)) {
- free (device);
- return 0;
- }
- *device_ret = device;
- }
- else
- *device_ret = safe_strdup (g, devices[i]);
- break;
- }
- }
-
- /* We don't try to guess mappings for cciss devices */
- return 0;
-}
-
-static int
-resolve_fstab_device_diskbyid (guestfs_h *g, const char *part,
- char **device_ret)
-{
- int nr_devices;
- char *device;
-
- /* For /dev/disk/by-id there is a limit to what we can do because
- * original SCSI ID information has likely been lost. This
- * heuristic will only work for guests that have a single block
- * device.
- *
- * So the main task here is to make sure the assumptions above are
- * true.
- *
- * XXX Use hints from virt-p2v if available.
- * See also:
https://bugzilla.redhat.com/show_bug.cgi?id=836573#c3
- */
-
- nr_devices = guestfs_nr_devices (g);
- if (nr_devices == -1)
- return -1;
-
- /* If #devices isn't 1, give up trying to translate this fstab entry. */
- if (nr_devices != 1)
- return 0;
-
- /* Make the partition name and check it exists. */
- device = safe_asprintf (g, "/dev/sda%s", part);
- if (!guestfs_int_is_partition (g, device)) {
- free (device);
- return 0;
- }
-
- *device_ret = device;
- return 0;
-}
-
-/* Resolve block device name to the libguestfs device name, eg.
- * /dev/xvdb1 => /dev/vdb1; and /dev/mapper/VG-LV => /dev/VG/LV. This
- * assumes that disks were added in the same order as they appear to
- * the real VM, which is a reasonable assumption to make. Return
- * anything we don't recognize unchanged.
- */
-static char *
-resolve_fstab_device (guestfs_h *g, const char *spec, Hash_table *md_map,
- enum inspect_os_type os_type)
-{
- char *device = NULL;
- char *type, *slice, *disk, *part;
- int r;
-
- if (STRPREFIX (spec, "/dev/mapper/")) {
- /* LVM2 does some strange munging on /dev/mapper paths for VGs and
- * LVs which contain '-' character:
- *
- * ><fs> lvcreate LV--test VG--test 32
- * ><fs> debug ls /dev/mapper
- * VG----test-LV----test
- *
- * This makes it impossible to reverse those paths directly, so
- * we have implemented lvm_canonical_lv_name in the daemon.
- */
- guestfs_push_error_handler (g, NULL, NULL);
- device = guestfs_lvm_canonical_lv_name (g, spec);
- guestfs_pop_error_handler (g);
- if (device == NULL) {
- if (guestfs_last_errno (g) == ENOENT) {
- /* Ignore devices that don't exist. (RHBZ#811872) */
- } else {
- guestfs_int_error_errno (g, guestfs_last_errno (g), "%s",
guestfs_last_error (g));
- return NULL;
- }
- }
- }
- else if (match3 (g, spec, re_xdev, &type, &disk, &part)) {
- r = resolve_fstab_device_xdev (g, type, disk, part, &device);
- free (type);
- free (disk);
- free (part);
- if (r == -1)
- return NULL;
- }
- else if (match2 (g, spec, re_cciss, &disk, &part)) {
- r = resolve_fstab_device_cciss (g, disk, part, &device);
- free (disk);
- free (part);
- if (r == -1)
- return NULL;
- }
- else if (md_map && (disk = match1 (g, spec, re_mdN)) != NULL) {
- mdadm_app entry;
- entry.mdadm = disk;
-
- mdadm_app *app = hash_lookup (md_map, &entry);
- if (app) device = safe_strdup (g, app->app);
-
- free (disk);
- }
- else if (match3 (g, spec, re_freebsd_gpt, &type, &disk, &part)) {
- /* If the FreeBSD disk contains GPT partitions, the translation to Linux
- * device names is straight forward. Partitions on a virtio disk are
- * prefixed with vtbd. IDE hard drives used to be prefixed with ad and now
- * are with ada.
- */
- const int disk_i = guestfs_int_parse_unsigned_int (g, disk);
- const int part_i = guestfs_int_parse_unsigned_int (g, part);
- free (type);
- free (disk);
- free (part);
-
- if (disk_i != -1 && disk_i <= 26 && part_i > 0 &&
part_i <= 128)
- device = safe_asprintf (g, "/dev/sd%c%d", disk_i + 'a', part_i);
- }
- else if (match4 (g, spec, re_freebsd_mbr, &type, &disk, &slice, &part))
{
- /* FreeBSD disks are organized quite differently. See:
- *
http://www.freebsd.org/doc/handbook/disk-organization.html
- * FreeBSD "partitions" are exposed as quasi-extended partitions
- * numbered from 5 in Linux. I have no idea what happens when you
- * have multiple "slices" (the FreeBSD term for MBR partitions).
- */
- const int disk_i = guestfs_int_parse_unsigned_int (g, disk);
- const int slice_i = guestfs_int_parse_unsigned_int (g, slice);
- int part_i = part[0] - 'a' /* counting from 0 */;
- free (type);
- free (disk);
- free (slice);
- free (part);
-
- if (part_i > 2)
- /* Partition 'c' has the size of the enclosing slice. Not mapped under
Linux. */
- part_i -= 1;
-
- if (disk_i != -1 && disk_i <= 26 &&
- slice_i > 0 && slice_i <= 1 /* > 4 .. see comment above */
&&
- part_i >= 0 && part_i < 25) {
- device = safe_asprintf (g, "/dev/sd%c%d", disk_i + 'a', part_i +
5);
- }
- }
- else if ((os_type == OS_TYPE_NETBSD) &&
- match3 (g, spec, re_netbsd_dev, &type, &disk, &part)) {
- const int disk_i = guestfs_int_parse_unsigned_int (g, disk);
- int part_i = part[0] - 'a'; /* counting from 0 */
- free (type);
- free (disk);
- free (part);
-
- if (part_i > 3)
- /* Partition 'c' is the disklabel partition and 'd' the hard disk
itself.
- * Not mapped under Linux.
- */
- part_i -= 2;
-
- if (disk_i != -1 && part_i >= 0 && part_i < 24)
- device = safe_asprintf (g, "/dev/sd%c%d", disk_i + 'a', part_i +
5);
- }
- else if ((os_type == OS_TYPE_OPENBSD) &&
- match3 (g, spec, re_openbsd_dev, &type, &disk, &part)) {
- const int disk_i = guestfs_int_parse_unsigned_int (g, disk);
- int part_i = part[0] - 'a'; /* counting from 0 */
- free (type);
- free (disk);
- free (part);
-
- if (part_i > 2)
- /* Partition 'c' is the hard disk itself. Not mapped under Linux */
- part_i -= 1;
-
- /* In OpenBSD MAXPARTITIONS is defined to 16 for all architectures */
- if (disk_i != -1 && part_i >= 0 && part_i < 15)
- device = safe_asprintf (g, "/dev/sd%c%d", disk_i + 'a', part_i +
5);
- }
- else if ((part = match1 (g, spec, re_diskbyid)) != NULL) {
- r = resolve_fstab_device_diskbyid (g, part, &device);
- free (part);
- if (r == -1)
- return NULL;
- }
- else if (match3 (g, spec, re_hurd_dev, &type, &disk, &part)) {
- /* Hurd disk devices are like /dev/hdNsM, where hdN is the
- * N-th disk and M is the M-th partition on that disk.
- * Turn the disk number into a letter-based identifier, so
- * we can resolve it easily.
- */
- const int disk_i = guestfs_int_parse_unsigned_int (g, disk);
- const char disk_as_letter[2] = { disk_i + 'a', 0 };
- r = resolve_fstab_device_xdev (g, type, disk_as_letter, part, &device);
- free (type);
- free (disk);
- free (part);
- if (r == -1)
- return NULL;
- }
-
- /* Didn't match device pattern, return original spec unchanged. */
- if (device == NULL)
- device = safe_strdup (g, spec);
-
- return device;
-}
-
-static char *make_augeas_path_expression (guestfs_h *g, const char **configfiles);
-
-/* Call 'f' with Augeas opened and having parsed 'configfiles' (these
- * files must exist). As a security measure, this bails if any file
- * is too large for a reasonable configuration file. After the call
- * to 'f' the Augeas handle is closed.
- */
-static int
-inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs,
- const char **configfiles,
- int (*f) (guestfs_h *, struct inspect_fs *))
-{
- size_t i;
- int64_t size;
- int r;
- CLEANUP_FREE char *pathexpr = NULL;
- CLEANUP_FREE_STRING_LIST char **matches = NULL;
- char **match;
-
- /* Security: Refuse to do this if a config file is too large. */
- for (i = 0; configfiles[i] != NULL; ++i) {
- if (guestfs_is_file_opts (g, configfiles[i],
- GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) == 0)
- continue;
-
- size = guestfs_filesize (g, configfiles[i]);
- if (size == -1)
- /* guestfs_filesize failed and has already set error in handle */
- return -1;
- if (size > MAX_AUGEAS_FILE_SIZE) {
- error (g, _("size of %s is unreasonably large (%" PRIi64 "
bytes)"),
- configfiles[i], size);
- return -1;
- }
- }
-
- if (guestfs_aug_init (g, "/", 16|32 /* AUG_SAVE_NOOP|AUG_NO_LOAD */) == -1)
- return -1;
-
- r = -1;
-
- /* Tell Augeas to only load configfiles and no other files. This
- * prevents a rogue guest from performing a denial of service attack
- * by having large, over-complicated configuration files which are
- * unrelated to the task at hand. (Thanks Dominic Cleal).
- * Note this requires Augeas >= 1.0.0 because of RHBZ#975412.
- */
- pathexpr = make_augeas_path_expression (g, configfiles);
- if (guestfs_aug_rm (g, pathexpr) == -1)
- goto out;
-
- if (guestfs_aug_load (g) == -1)
- goto out;
-
- /* Check that augeas did not get a parse error for any of the configfiles,
- * otherwise we are silently missing information.
- */
- matches = guestfs_aug_match (g, "/augeas/files//error");
- for (match = matches; *match != NULL; ++match) {
- for (i = 0; configfiles[i] != NULL; ++i) {
- CLEANUP_FREE char *errorpath =
- safe_asprintf (g, "/augeas/files%s/error", configfiles[i]);
-
- if (STREQ (*match, errorpath)) {
- /* Get the various error details. */
- guestfs_push_error_handler (g, NULL, NULL);
- CLEANUP_FREE char *messagepath =
- safe_asprintf (g, "%s/message", errorpath);
- CLEANUP_FREE char *message = guestfs_aug_get (g, messagepath);
- CLEANUP_FREE char *linepath =
- safe_asprintf (g, "%s/line", errorpath);
- CLEANUP_FREE char *line = guestfs_aug_get (g, linepath);
- CLEANUP_FREE char *charpath =
- safe_asprintf (g, "%s/char", errorpath);
- CLEANUP_FREE char *charp = guestfs_aug_get (g, charpath);
- guestfs_pop_error_handler (g);
-
- error (g, _("%s:%s:%s: augeas parse failure: %s"),
- configfiles[i],
- line ? : "<none>",
- charp ? : "<none>",
- message ? : "<none>");
- goto out;
- }
- }
- }
-
- r = f (g, fs);
-
- out:
- guestfs_aug_close (g);
-
- return r;
-}
-
-/* Explained here:
https://bugzilla.redhat.com/show_bug.cgi?id=975412#c0 */
-static char *
-make_augeas_path_expression (guestfs_h *g, const char **configfiles)
-{
- size_t i;
- size_t nr_files;
- CLEANUP_FREE_STRING_LIST char **subexprs = NULL;
- CLEANUP_FREE char *subexpr = NULL;
- char *ret;
-
- nr_files = guestfs_int_count_strings ((char **) configfiles);
- subexprs = safe_malloc (g, sizeof (char *) * (nr_files + 1));
-
- for (i = 0; i < nr_files; ++i) {
- subexprs[i] = /* v NB trailing '/' after filename */
- safe_asprintf (g, "\"%s/\" !~ regexp('^') + glob(incl) +
regexp('/.*')",
- configfiles[i]);
- }
- subexprs[nr_files] = NULL;
-
- subexpr = guestfs_int_join_strings (" and ", subexprs);
- if (subexpr == NULL)
- g->abort_cb ();
-
- ret = safe_asprintf (g, "/augeas/load/*[ %s ]", subexpr);
- debug (g, "augeas pathexpr = %s", ret);
- return ret;
-}
-
-/* Canonicalize the path, so "///usr//local//" -> "/usr/local"
- *
- * The path is modified in place because the result is always
- * the same length or shorter than the argument passed.
- */
-static void
-canonical_mountpoint (char *s)
-{
- size_t len = strlen (s);
- char *orig = s;
-
- s = strchr (s, '/');
- while (s != NULL && *s != 0) {
- char *pos = s + 1;
- char *p = pos;
- /* Find how many consecutive slashes are there after the one found,
- * and shift the characters after them accordingly. */
- while (*p == '/')
- ++p;
- if (p - pos > 0) {
- memmove (pos, p, len - (p - orig) + 1);
- len -= p - pos;
- }
-
- s = strchr (pos, '/');
- }
- /* Ignore the trailing slash, but avoid removing it for "/". */
- if (len > 1 && orig[len-1] == '/')
- --len;
- orig[len] = 0;
-}
diff --git a/lib/inspect-fs-windows.c b/lib/inspect-fs-windows.c
deleted file mode 100644
index 34f33c908..000000000
--- a/lib/inspect-fs-windows.c
+++ /dev/null
@@ -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_utf8 (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_utf8 (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_utf8 (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_utf8 (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;
-}
diff --git a/lib/inspect-fs.c b/lib/inspect-fs.c
deleted file mode 100644
index 54f9a281a..000000000
--- a/lib/inspect-fs.c
+++ /dev/null
@@ -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;
- }
-}
diff --git a/lib/inspect-icon.c b/lib/inspect-icon.c
index 89f5da082..f4f5f0660 100644
--- a/lib/inspect-icon.c
+++ b/lib/inspect-icon.c
@@ -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 (STREQ (type, "linux") || STREQ (type, "hurd")) {
+ if (STREQ (distro, "fedora")) {
+ r = icon_fedora (g, &size);
+ }
+ 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, 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:
+ 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, fs, &size);
+ r = icon_cirros (g, &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 */
}
- break;
-
- case OS_TYPE_WINDOWS:
+ 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;
+}
diff --git a/lib/inspect.c b/lib/inspect.c
index f4ad192a9..501074316 100644
--- a/lib/inspect.c
+++ b/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;
-}
--
2.13.2