mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
daemon: Implement inspection of Linux and other Unix-like operating systems.
This is essentially a line-for-line translation of the C inspection code.
This commit is contained in:
363
daemon/inspect_fs.ml
Normal file
363
daemon/inspect_fs.ml
Normal file
@@ -0,0 +1,363 @@
|
||||
(* guestfs-inspection
|
||||
* Copyright (C) 2009-2017 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*)
|
||||
|
||||
open Printf
|
||||
|
||||
open Std_utils
|
||||
|
||||
open Mountable
|
||||
open Inspect_types
|
||||
open Inspect_utils
|
||||
|
||||
let rec check_for_filesystem_on mountable vfs_type =
|
||||
if verbose () then
|
||||
eprintf "check_for_filesystem_on: %s (%s)\n%!"
|
||||
(Mountable.to_string mountable) vfs_type;
|
||||
|
||||
let role =
|
||||
let is_swap = vfs_type = "swap" in
|
||||
if is_swap then
|
||||
Some RoleSwap
|
||||
else (
|
||||
(* Try mounting the device. Ignore errors if we can't do this. *)
|
||||
let mounted =
|
||||
if vfs_type = "ufs" then ( (* Hack for the *BSDs. *)
|
||||
(* FreeBSD fs is a variant of ufs called ufs2 ... *)
|
||||
try
|
||||
Mount.mount_vfs (Some "ro,ufstype=ufs2") (Some "ufs")
|
||||
mountable "/";
|
||||
true
|
||||
with _ ->
|
||||
(* while NetBSD and OpenBSD use another variant labeled 44bsd *)
|
||||
try
|
||||
Mount.mount_vfs (Some "ro,ufstype=44bsd") (Some "ufs")
|
||||
mountable "/";
|
||||
true
|
||||
with _ -> false
|
||||
) else (
|
||||
try Mount.mount_ro mountable "/";
|
||||
true
|
||||
with _ -> false
|
||||
) in
|
||||
if not mounted then None
|
||||
else (
|
||||
let role = check_filesystem mountable in
|
||||
Mount.umount_all ();
|
||||
role
|
||||
)
|
||||
) in
|
||||
|
||||
match role with
|
||||
| None -> None
|
||||
| Some role ->
|
||||
Some { fs_location = { mountable = mountable; vfs_type = vfs_type };
|
||||
role = role }
|
||||
|
||||
(* When this function is called, the filesystem is mounted on sysroot (). *)
|
||||
and check_filesystem mountable =
|
||||
let role = ref `Other in
|
||||
(* The following struct is mutated in place by callees. However we
|
||||
* need to make a copy of the object here so we don't mutate the
|
||||
* null_inspection_data struct!
|
||||
*)
|
||||
let data = null_inspection_data () in
|
||||
|
||||
let debug_matching what =
|
||||
if verbose () then
|
||||
eprintf "check_filesystem: %s matched %s\n%!"
|
||||
(Mountable.to_string mountable) what
|
||||
in
|
||||
|
||||
(* Grub /boot? *)
|
||||
if Is.is_file "/grub/menu.lst" ||
|
||||
Is.is_file "/grub/grub.conf" ||
|
||||
Is.is_file "/grub2/grub.cfg" then (
|
||||
debug_matching "Grub /boot";
|
||||
()
|
||||
)
|
||||
(* FreeBSD root? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
Is.is_dir "/bin" &&
|
||||
Is.is_file "/etc/freebsd-update.conf" &&
|
||||
Is.is_file "/etc/fstab" then (
|
||||
debug_matching "FreeBSD root";
|
||||
role := `Root;
|
||||
Inspect_fs_unix.check_freebsd_root mountable data
|
||||
)
|
||||
(* NetBSD root? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
Is.is_dir "/bin" &&
|
||||
Is.is_file "/netbsd" &&
|
||||
Is.is_file "/etc/fstab" &&
|
||||
Is.is_file "/etc/release" then (
|
||||
debug_matching "NetBSD root";
|
||||
role := `Root;
|
||||
Inspect_fs_unix.check_netbsd_root mountable data;
|
||||
)
|
||||
(* OpenBSD root? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
Is.is_dir "/bin" &&
|
||||
Is.is_file "/bsd" &&
|
||||
Is.is_file "/etc/fstab" &&
|
||||
Is.is_file "/etc/motd" then (
|
||||
debug_matching "OpenBSD root";
|
||||
role := `Root;
|
||||
Inspect_fs_unix.check_openbsd_root mountable data;
|
||||
)
|
||||
(* Hurd root? *)
|
||||
else if Is.is_file "/hurd/console" &&
|
||||
Is.is_file "/hurd/hello" &&
|
||||
Is.is_file "/hurd/null" then (
|
||||
debug_matching "Hurd root";
|
||||
role := `Root;
|
||||
Inspect_fs_unix.check_hurd_root mountable data;
|
||||
)
|
||||
(* Minix root? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
Is.is_dir "/bin" &&
|
||||
Is.is_file "/service/vm" &&
|
||||
Is.is_file "/etc/fstab" &&
|
||||
Is.is_file "/etc/version" then (
|
||||
debug_matching "Minix root";
|
||||
role := `Root;
|
||||
Inspect_fs_unix.check_minix_root data;
|
||||
)
|
||||
(* Linux root? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
(Is.is_dir "/bin" ||
|
||||
is_symlink_to "/bin" "usr/bin") &&
|
||||
(Is.is_file "/etc/fstab" ||
|
||||
Is.is_file "/etc/hosts") then (
|
||||
debug_matching "Linux root";
|
||||
role := `Root;
|
||||
Inspect_fs_unix.check_linux_root mountable data;
|
||||
)
|
||||
(* CoreOS root? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
Is.is_dir "/root" &&
|
||||
Is.is_dir "/home" &&
|
||||
Is.is_dir "/usr" &&
|
||||
Is.is_file "/etc/coreos/update.conf" then (
|
||||
debug_matching "CoreOS root";
|
||||
role := `Root;
|
||||
Inspect_fs_unix.check_coreos_root mountable data;
|
||||
)
|
||||
(* Linux /usr/local? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
Is.is_dir "/bin" &&
|
||||
Is.is_dir "/share" &&
|
||||
not (Is.is_dir "/local") &&
|
||||
not (Is.is_file "/etc/fstab") then (
|
||||
debug_matching "Linux /usr/local";
|
||||
()
|
||||
)
|
||||
(* Linux /usr? *)
|
||||
else if Is.is_dir "/etc" &&
|
||||
Is.is_dir "/bin" &&
|
||||
Is.is_dir "/share" &&
|
||||
Is.is_dir "/local" &&
|
||||
not (Is.is_file "/etc/fstab") then (
|
||||
debug_matching "Linux /usr";
|
||||
role := `Usr;
|
||||
Inspect_fs_unix.check_linux_usr data;
|
||||
)
|
||||
(* CoreOS /usr? *)
|
||||
else if Is.is_dir "/bin" &&
|
||||
Is.is_dir "/share" &&
|
||||
Is.is_dir "/local" &&
|
||||
Is.is_dir "/share/coreos" then (
|
||||
debug_matching "CoreOS /usr";
|
||||
role := `Usr;
|
||||
Inspect_fs_unix.check_coreos_usr mountable data;
|
||||
)
|
||||
(* Linux /var? *)
|
||||
else if Is.is_dir "/log" &&
|
||||
Is.is_dir "/run" &&
|
||||
Is.is_dir "/spool" then (
|
||||
debug_matching "Linux /var";
|
||||
()
|
||||
)
|
||||
(* Windows volume with installed applications (but not root)? *)
|
||||
else if is_dir_nocase "/System Volume Information" &&
|
||||
is_dir_nocase "/Program Files" then (
|
||||
debug_matching "Windows volume with installed applications";
|
||||
()
|
||||
)
|
||||
(* Windows volume (but not root)? *)
|
||||
else if is_dir_nocase "/System Volume Information" then (
|
||||
debug_matching "Windows volume without installed applications";
|
||||
()
|
||||
)
|
||||
(* FreeDOS? *)
|
||||
else if is_dir_nocase "/FDOS" &&
|
||||
is_file_nocase "/FDOS/FREEDOS.BSS" then (
|
||||
debug_matching "FreeDOS";
|
||||
role := `Root;
|
||||
data.os_type <- Some OS_TYPE_DOS;
|
||||
data.distro <- Some DISTRO_FREEDOS;
|
||||
(* FreeDOS is a mix of 16 and 32 bit, but
|
||||
* assume it requires a 32 bit i386 processor.
|
||||
*)
|
||||
data.arch <- Some "i386"
|
||||
)
|
||||
(* None of the above. *)
|
||||
else (
|
||||
debug_matching "no known OS partition"
|
||||
);
|
||||
|
||||
(* The above code should have set [data.os_type] and [data.distro]
|
||||
* fields, so we can now guess the package management system.
|
||||
*)
|
||||
data.package_format <- check_package_format data;
|
||||
data.package_management <- check_package_management data;
|
||||
|
||||
match !role with
|
||||
| `Root -> Some (RoleRoot data)
|
||||
| `Usr -> Some (RoleUsr data)
|
||||
| `Other -> Some RoleOther
|
||||
|
||||
and is_symlink_to file wanted_target =
|
||||
if not (Is.is_symlink file) then false
|
||||
else Link.readlink file = wanted_target
|
||||
|
||||
(* At the moment, package format and package management are just a
|
||||
* simple function of the [distro] and [version[0]] fields, so these
|
||||
* can never return an error. We might be cleverer in future.
|
||||
*)
|
||||
and check_package_format { distro = distro } =
|
||||
match distro with
|
||||
| None -> None
|
||||
| Some DISTRO_FEDORA
|
||||
| Some DISTRO_MEEGO
|
||||
| Some DISTRO_REDHAT_BASED
|
||||
| Some DISTRO_RHEL
|
||||
| Some DISTRO_MAGEIA
|
||||
| Some DISTRO_MANDRIVA
|
||||
| Some DISTRO_SUSE_BASED
|
||||
| Some DISTRO_OPENSUSE
|
||||
| Some DISTRO_SLES
|
||||
| Some DISTRO_CENTOS
|
||||
| Some DISTRO_SCIENTIFIC_LINUX
|
||||
| Some DISTRO_ORACLE_LINUX
|
||||
| Some DISTRO_ALTLINUX ->
|
||||
Some PACKAGE_FORMAT_RPM
|
||||
| Some DISTRO_DEBIAN
|
||||
| Some DISTRO_UBUNTU
|
||||
| Some DISTRO_LINUX_MINT ->
|
||||
Some PACKAGE_FORMAT_DEB
|
||||
| Some DISTRO_ARCHLINUX ->
|
||||
Some PACKAGE_FORMAT_PACMAN
|
||||
| Some DISTRO_GENTOO ->
|
||||
Some PACKAGE_FORMAT_EBUILD
|
||||
| Some DISTRO_PARDUS ->
|
||||
Some PACKAGE_FORMAT_PISI
|
||||
| Some DISTRO_ALPINE_LINUX ->
|
||||
Some PACKAGE_FORMAT_APK
|
||||
| Some DISTRO_VOID_LINUX ->
|
||||
Some PACKAGE_FORMAT_XBPS
|
||||
| Some DISTRO_SLACKWARE
|
||||
| Some DISTRO_TTYLINUX
|
||||
| Some DISTRO_COREOS
|
||||
| Some DISTRO_WINDOWS
|
||||
| Some DISTRO_BUILDROOT
|
||||
| Some DISTRO_CIRROS
|
||||
| Some DISTRO_FREEDOS
|
||||
| Some DISTRO_FREEBSD
|
||||
| Some DISTRO_NETBSD
|
||||
| Some DISTRO_OPENBSD
|
||||
| Some DISTRO_FRUGALWARE
|
||||
| Some DISTRO_PLD_LINUX ->
|
||||
None
|
||||
|
||||
and check_package_management { distro = distro; version = version } =
|
||||
let major = match version with None -> 0 | Some (major, _) -> major in
|
||||
match distro with
|
||||
| None -> None
|
||||
|
||||
| Some DISTRO_MEEGO ->
|
||||
Some PACKAGE_MANAGEMENT_YUM
|
||||
|
||||
| Some DISTRO_FEDORA ->
|
||||
(* If Fedora >= 22 and dnf is installed, say "dnf". *)
|
||||
if major >= 22 && Is.is_file ~followsymlinks:true "/usr/bin/dnf" then
|
||||
Some PACKAGE_MANAGEMENT_DNF
|
||||
else if major >= 1 then
|
||||
Some PACKAGE_MANAGEMENT_YUM
|
||||
else
|
||||
(* Probably parsing the release file failed, see RHBZ#1332025. *)
|
||||
None
|
||||
|
||||
| Some DISTRO_REDHAT_BASED
|
||||
| Some DISTRO_RHEL
|
||||
| Some DISTRO_CENTOS
|
||||
| Some DISTRO_SCIENTIFIC_LINUX
|
||||
| Some DISTRO_ORACLE_LINUX ->
|
||||
if major >= 8 then
|
||||
Some PACKAGE_MANAGEMENT_DNF
|
||||
else if major >= 5 then
|
||||
Some PACKAGE_MANAGEMENT_YUM
|
||||
else if major >= 2 then
|
||||
Some PACKAGE_MANAGEMENT_UP2DATE
|
||||
else
|
||||
(* Probably parsing the release file failed, see RHBZ#1332025. *)
|
||||
None
|
||||
|
||||
| Some DISTRO_DEBIAN
|
||||
| Some DISTRO_UBUNTU
|
||||
| Some DISTRO_LINUX_MINT
|
||||
| Some DISTRO_ALTLINUX ->
|
||||
Some PACKAGE_MANAGEMENT_APT
|
||||
|
||||
| Some DISTRO_ARCHLINUX ->
|
||||
Some PACKAGE_MANAGEMENT_PACMAN
|
||||
|
||||
| Some DISTRO_GENTOO ->
|
||||
Some PACKAGE_MANAGEMENT_PORTAGE
|
||||
|
||||
| Some DISTRO_PARDUS ->
|
||||
Some PACKAGE_MANAGEMENT_PISI
|
||||
|
||||
| Some DISTRO_MAGEIA
|
||||
| Some DISTRO_MANDRIVA ->
|
||||
Some PACKAGE_MANAGEMENT_URPMI
|
||||
|
||||
| Some DISTRO_SUSE_BASED
|
||||
| Some DISTRO_OPENSUSE
|
||||
| Some DISTRO_SLES ->
|
||||
Some PACKAGE_MANAGEMENT_ZYPPER
|
||||
|
||||
| Some DISTRO_ALPINE_LINUX ->
|
||||
Some PACKAGE_MANAGEMENT_APK
|
||||
|
||||
| Some DISTRO_VOID_LINUX ->
|
||||
Some PACKAGE_MANAGEMENT_XBPS;
|
||||
|
||||
| Some DISTRO_SLACKWARE
|
||||
| Some DISTRO_TTYLINUX
|
||||
| Some DISTRO_COREOS
|
||||
| Some DISTRO_WINDOWS
|
||||
| Some DISTRO_BUILDROOT
|
||||
| Some DISTRO_CIRROS
|
||||
| Some DISTRO_FREEDOS
|
||||
| Some DISTRO_FREEBSD
|
||||
| Some DISTRO_NETBSD
|
||||
| Some DISTRO_OPENBSD
|
||||
| Some DISTRO_FRUGALWARE
|
||||
| Some DISTRO_PLD_LINUX ->
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user