Define the types which will be used to communicate between the different parts of the inspection code. The main types are:
fs corresponds to ‘struct inspect_fs’ in C code root no direct correspondence with the C code, but in the C code, ‘inspect_fs’ was overloaded to store roots inspection_data the inspection data which is incrementally collected about each filesystem as we perform inspection steps Other types have simple and obvious correspondences with the equivalent C code. Add some utility function which will be used by inspection. Note that this commit has no effect on its own, it just links extra dead code into the daemon. --- daemon/Makefile.am | 4 + daemon/inspect_types.ml | 314 +++++++++++++++++++++++++++++++++++++++++++++++ daemon/inspect_types.mli | 182 +++++++++++++++++++++++++++ daemon/inspect_utils.ml | 187 ++++++++++++++++++++++++++++ daemon/inspect_utils.mli | 53 ++++++++ 5 files changed, 740 insertions(+) diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 3e8bdb44f..51737e511 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -252,6 +252,8 @@ SOURCES_MLI = \ file.mli \ filearch.mli \ findfs.mli \ + inspect_types.mli \ + inspect_utils.mli \ is.mli \ ldm.mli \ link.mli \ @@ -287,6 +289,8 @@ SOURCES_ML = \ parted.ml \ listfs.ml \ realpath.ml \ + inspect_types.ml \ + inspect_utils.ml \ callbacks.ml \ daemon.ml diff --git a/daemon/inspect_types.ml b/daemon/inspect_types.ml new file mode 100644 index 000000000..4570349ba --- /dev/null +++ b/daemon/inspect_types.ml @@ -0,0 +1,314 @@ +(* 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 + +type fs = { + fs_location : location; + role : role; (** Special cases: root filesystem or /usr *) +} +and root = { + root_location : location; + inspection_data : inspection_data; +} +and location = { + mountable : Mountable.t; (** The device name or other mountable object.*) + vfs_type : string; (** Returned from [vfs_type] API. *) +} + +and role = + | RoleRoot of inspection_data + | RoleUsr of inspection_data + | RoleSwap + | RoleOther +and inspection_data = { + mutable os_type : os_type option; + mutable distro : distro option; + mutable package_format : package_format option; + mutable package_management : package_management option; + mutable product_name : string option; + mutable product_variant : string option; + mutable version : version option; + mutable arch : string option; + mutable hostname : string option; + mutable fstab : fstab_entry list; + mutable windows_systemroot : string option; + mutable windows_software_hive : string option; + mutable windows_system_hive : string option; + mutable windows_current_control_set : string option; + mutable drive_mappings : drive_mapping list; +} +and os_type = + | OS_TYPE_DOS + | OS_TYPE_FREEBSD + | OS_TYPE_HURD + | OS_TYPE_LINUX + | OS_TYPE_MINIX + | OS_TYPE_NETBSD + | OS_TYPE_OPENBSD + | OS_TYPE_WINDOWS +and distro = + | DISTRO_ALPINE_LINUX + | DISTRO_ALTLINUX + | DISTRO_ARCHLINUX + | DISTRO_BUILDROOT + | DISTRO_CENTOS + | DISTRO_CIRROS + | DISTRO_COREOS + | DISTRO_DEBIAN + | DISTRO_FEDORA + | DISTRO_FREEBSD + | DISTRO_FREEDOS + | DISTRO_FRUGALWARE + | DISTRO_GENTOO + | DISTRO_LINUX_MINT + | DISTRO_MAGEIA + | DISTRO_MANDRIVA + | DISTRO_MEEGO + | DISTRO_NETBSD + | DISTRO_OPENBSD + | DISTRO_OPENSUSE + | DISTRO_ORACLE_LINUX + | DISTRO_PARDUS + | DISTRO_PLD_LINUX + | DISTRO_REDHAT_BASED + | DISTRO_RHEL + | DISTRO_SCIENTIFIC_LINUX + | DISTRO_SLACKWARE + | DISTRO_SLES + | DISTRO_SUSE_BASED + | DISTRO_TTYLINUX + | DISTRO_UBUNTU + | DISTRO_VOID_LINUX + | DISTRO_WINDOWS +and package_format = + | PACKAGE_FORMAT_APK + | PACKAGE_FORMAT_DEB + | PACKAGE_FORMAT_EBUILD + | PACKAGE_FORMAT_PACMAN + | PACKAGE_FORMAT_PISI + | PACKAGE_FORMAT_PKGSRC + | PACKAGE_FORMAT_RPM + | PACKAGE_FORMAT_XBPS +and package_management = + | PACKAGE_MANAGEMENT_APK + | PACKAGE_MANAGEMENT_APT + | PACKAGE_MANAGEMENT_DNF + | PACKAGE_MANAGEMENT_PACMAN + | PACKAGE_MANAGEMENT_PISI + | PACKAGE_MANAGEMENT_PORTAGE + | PACKAGE_MANAGEMENT_UP2DATE + | PACKAGE_MANAGEMENT_URPMI + | PACKAGE_MANAGEMENT_XBPS + | PACKAGE_MANAGEMENT_YUM + | PACKAGE_MANAGEMENT_ZYPPER +and version = int * int +and fstab_entry = Mountable.t * string (* mountable, mountpoint *) +and drive_mapping = string * string (* drive name, device *) + +let rec string_of_fs { fs_location = location; role = role } = + sprintf "fs: %s role: %s\n" + (string_of_location location) + (match role with + | RoleRoot data -> "root\n" ^ string_of_inspection_data data + | RoleUsr data -> "usr\n" ^ string_of_inspection_data data + | RoleSwap -> "swap" + | RoleOther -> "other") + +and string_of_location { mountable = mountable; vfs_type = vfs_type } = + sprintf "%s (%s)" (Mountable.to_string mountable) vfs_type + +and string_of_root { root_location = location; + inspection_data = inspection_data } = + sprintf "%s:\n%s" + (string_of_location location) + (string_of_inspection_data inspection_data) + +and string_of_inspection_data data = + let b = Buffer.create 1024 in + let bpf fs = bprintf b fs in + may (fun v -> bpf " type: %s\n" (string_of_os_type v)) + data.os_type; + may (fun v -> bpf " distro: %s\n" (string_of_distro v)) + data.distro; + may (fun v -> bpf " package_format: %s\n" (string_of_package_format v)) + data.package_format; + may (fun v -> bpf " package_management: %s\n" (string_of_package_management v)) + data.package_management; + may (fun v -> bpf " product_name: %s\n" v) + data.product_name; + may (fun v -> bpf " product_variant: %s\n" v) + data.product_variant; + may (fun (major, minor) -> bpf " version: %d.%d\n" major minor) + data.version; + may (fun v -> bpf " arch: %s\n" v) + data.arch; + may (fun v -> bpf " hostname: %s\n" v) + data.hostname; + if data.fstab <> [] then ( + let v = List.map ( + fun (a, b) -> sprintf "(%s, %s)" (Mountable.to_string a) b + ) data.fstab in + bpf " fstab: [%s]\n" (String.concat ", " v) + ); + may (fun v -> bpf " windows_systemroot: %s\n" v) + data.windows_systemroot; + may (fun v -> bpf " windows_software_hive: %s\n" v) + data.windows_software_hive; + may (fun v -> bpf " windows_system_hive: %s\n" v) + data.windows_system_hive; + may (fun v -> bpf " windows_current_control_set: %s\n" v) + data.windows_current_control_set; + if data.drive_mappings <> [] then ( + let v = + List.map (fun (a, b) -> sprintf "(%s, %s)" a b) data.drive_mappings in + bpf " drive_mappings: [%s]\n" (String.concat ", " v) + ); + Buffer.contents b + +and string_of_os_type = function + | OS_TYPE_DOS -> "dos" + | OS_TYPE_FREEBSD -> "freebsd" + | OS_TYPE_HURD -> "hurd" + | OS_TYPE_LINUX -> "linux" + | OS_TYPE_MINIX -> "minix" + | OS_TYPE_NETBSD -> "netbsd" + | OS_TYPE_OPENBSD -> "openbsd" + | OS_TYPE_WINDOWS -> "windows" + +and string_of_distro = function + | DISTRO_ALPINE_LINUX -> "alpinelinux" + | DISTRO_ALTLINUX -> "altlinux" + | DISTRO_ARCHLINUX -> "archlinux" + | DISTRO_BUILDROOT -> "buildroot" + | DISTRO_CENTOS -> "centos" + | DISTRO_CIRROS -> "cirros" + | DISTRO_COREOS -> "coreos" + | DISTRO_DEBIAN -> "debian" + | DISTRO_FEDORA -> "fedora" + | DISTRO_FREEBSD -> "freebsd" + | DISTRO_FREEDOS -> "freedos" + | DISTRO_FRUGALWARE -> "frugalware" + | DISTRO_GENTOO -> "gentoo" + | DISTRO_LINUX_MINT -> "linuxmint" + | DISTRO_MAGEIA -> "mageia" + | DISTRO_MANDRIVA -> "mandriva" + | DISTRO_MEEGO -> "meego" + | DISTRO_NETBSD -> "netbsd" + | DISTRO_OPENBSD -> "openbsd" + | DISTRO_OPENSUSE -> "opensuse" + | DISTRO_ORACLE_LINUX -> "oraclelinux" + | DISTRO_PARDUS -> "pardus" + | DISTRO_PLD_LINUX -> "pldlinux" + | DISTRO_REDHAT_BASED -> "redhat-based" + | DISTRO_RHEL -> "rhel" + | DISTRO_SCIENTIFIC_LINUX -> "scientificlinux" + | DISTRO_SLACKWARE -> "slackware" + | DISTRO_SLES -> "sles" + | DISTRO_SUSE_BASED -> "suse-based" + | DISTRO_TTYLINUX -> "ttylinux" + | DISTRO_UBUNTU -> "ubuntu" + | DISTRO_VOID_LINUX -> "voidlinux" + | DISTRO_WINDOWS -> "windows" + +and string_of_package_format = function + | PACKAGE_FORMAT_APK -> "apk" + | PACKAGE_FORMAT_DEB -> "deb" + | PACKAGE_FORMAT_EBUILD -> "ebuild" + | PACKAGE_FORMAT_PACMAN -> "pacman" + | PACKAGE_FORMAT_PISI -> "pisi" + | PACKAGE_FORMAT_PKGSRC -> "pkgsrc" + | PACKAGE_FORMAT_RPM -> "rpm" + | PACKAGE_FORMAT_XBPS -> "xbps" + +and string_of_package_management = function + | PACKAGE_MANAGEMENT_APK -> "apk" + | PACKAGE_MANAGEMENT_APT -> "apt" + | PACKAGE_MANAGEMENT_DNF -> "dnf" + | PACKAGE_MANAGEMENT_PACMAN -> "pacman" + | PACKAGE_MANAGEMENT_PISI -> "pisi" + | PACKAGE_MANAGEMENT_PORTAGE -> "portage" + | PACKAGE_MANAGEMENT_UP2DATE -> "up2date" + | PACKAGE_MANAGEMENT_URPMI -> "urpmi" + | PACKAGE_MANAGEMENT_XBPS -> "xbps" + | PACKAGE_MANAGEMENT_YUM -> "yum" + | PACKAGE_MANAGEMENT_ZYPPER -> "zypper" + +let null_inspection_data = { + os_type = None; + distro = None; + package_format = None; + package_management = None; + product_name = None; + product_variant = None; + version = None; + arch = None; + hostname = None; + fstab = []; + windows_systemroot = None; + windows_software_hive = None; + windows_system_hive = None; + windows_current_control_set = None; + drive_mappings = []; +} +let null_inspection_data () = { null_inspection_data with os_type = None } + +let merge_inspection_data child parent = + let merge child parent = if parent = None then child else parent in + + parent.os_type <- merge child.os_type parent.os_type; + parent.distro <- merge child.distro parent.distro; + parent.package_format <- merge child.package_format parent.package_format; + parent.package_management <- + merge child.package_management parent.package_management; + parent.product_name <- merge child.product_name parent.product_name; + parent.product_variant <- merge child.product_variant parent.product_variant; + parent.version <- merge child.version parent.version; + parent.arch <- merge child.arch parent.arch; + parent.hostname <- merge child.hostname parent.hostname; + parent.fstab <- child.fstab @ parent.fstab; + parent.windows_systemroot <- + merge child.windows_systemroot parent.windows_systemroot; + parent.windows_software_hive <- + merge child.windows_software_hive parent.windows_software_hive; + parent.windows_system_hive <- + merge child.windows_system_hive parent.windows_system_hive; + parent.windows_current_control_set <- + merge child.windows_current_control_set parent.windows_current_control_set; + + (* This is what the old C code did, but I doubt that it's correct. *) + parent.drive_mappings <- child.drive_mappings @ parent.drive_mappings + +let merge child_fs parent_fs = + let inspection_data_of_fs = function + | { role = RoleRoot data } + | { role = RoleUsr data } -> data + | { role = (RoleSwap|RoleOther) } -> null_inspection_data () + in + + match parent_fs with + | { role = RoleRoot parent_data } -> + merge_inspection_data (inspection_data_of_fs child_fs) parent_data + | { role = RoleUsr parent_data } -> + merge_inspection_data (inspection_data_of_fs child_fs) parent_data + | { role = (RoleSwap|RoleOther) } -> + () + +let inspect_fses = ref [] diff --git a/daemon/inspect_types.mli b/daemon/inspect_types.mli new file mode 100644 index 000000000..5c2151e14 --- /dev/null +++ b/daemon/inspect_types.mli @@ -0,0 +1,182 @@ +(* 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. + *) + +type fs = { + fs_location : location; + role : role; (** Special cases: root filesystem or /usr *) +} +(** A single filesystem. *) + +and root = { + root_location : location; + inspection_data : inspection_data; +} +(** A root (as in "inspect_get_roots"). *) + +and location = { + mountable : Mountable.t; (** The device name or other mountable object.*) + vfs_type : string; (** Returned from [vfs_type] API. *) +} + +and role = + | RoleRoot of inspection_data + | RoleUsr of inspection_data + | RoleSwap + | RoleOther +(** During inspection, single filesystems are assigned a role which is + one of root, /usr, swap or other. *) + +and inspection_data = { + mutable os_type : os_type option; + mutable distro : distro option; + mutable package_format : package_format option; + mutable package_management : package_management option; + mutable product_name : string option; + mutable product_variant : string option; + mutable version : version option; + mutable arch : string option; + mutable hostname : string option; + mutable fstab : fstab_entry list; + mutable windows_systemroot : string option; + mutable windows_software_hive : string option; + mutable windows_system_hive : string option; + mutable windows_current_control_set : string option; + mutable drive_mappings : drive_mapping list; +} +(** During inspection, this data is collected incrementally for each + filesystem. At the end of inspection, inspection data is merged + into the root. *) + +and os_type = + | OS_TYPE_DOS + | OS_TYPE_FREEBSD + | OS_TYPE_HURD + | OS_TYPE_LINUX + | OS_TYPE_MINIX + | OS_TYPE_NETBSD + | OS_TYPE_OPENBSD + | OS_TYPE_WINDOWS +and distro = + | DISTRO_ALPINE_LINUX + | DISTRO_ALTLINUX + | DISTRO_ARCHLINUX + | DISTRO_BUILDROOT + | DISTRO_CENTOS + | DISTRO_CIRROS + | DISTRO_COREOS + | DISTRO_DEBIAN + | DISTRO_FEDORA + | DISTRO_FREEBSD + | DISTRO_FREEDOS + | DISTRO_FRUGALWARE + | DISTRO_GENTOO + | DISTRO_LINUX_MINT + | DISTRO_MAGEIA + | DISTRO_MANDRIVA + | DISTRO_MEEGO + | DISTRO_NETBSD + | DISTRO_OPENBSD + | DISTRO_OPENSUSE + | DISTRO_ORACLE_LINUX + | DISTRO_PARDUS + | DISTRO_PLD_LINUX + | DISTRO_REDHAT_BASED + | DISTRO_RHEL + | DISTRO_SCIENTIFIC_LINUX + | DISTRO_SLACKWARE + | DISTRO_SLES + | DISTRO_SUSE_BASED + | DISTRO_TTYLINUX + | DISTRO_UBUNTU + | DISTRO_VOID_LINUX + | DISTRO_WINDOWS +and package_format = + | PACKAGE_FORMAT_APK + | PACKAGE_FORMAT_DEB + | PACKAGE_FORMAT_EBUILD + | PACKAGE_FORMAT_PACMAN + | PACKAGE_FORMAT_PISI + | PACKAGE_FORMAT_PKGSRC + | PACKAGE_FORMAT_RPM + | PACKAGE_FORMAT_XBPS +and package_management = + | PACKAGE_MANAGEMENT_APK + | PACKAGE_MANAGEMENT_APT + | PACKAGE_MANAGEMENT_DNF + | PACKAGE_MANAGEMENT_PACMAN + | PACKAGE_MANAGEMENT_PISI + | PACKAGE_MANAGEMENT_PORTAGE + | PACKAGE_MANAGEMENT_UP2DATE + | PACKAGE_MANAGEMENT_URPMI + | PACKAGE_MANAGEMENT_XBPS + | PACKAGE_MANAGEMENT_YUM + | PACKAGE_MANAGEMENT_ZYPPER +and version = int * int +and fstab_entry = Mountable.t * string (* mountable, mountpoint *) +and drive_mapping = string * string (* drive name, device *) + +val merge_inspection_data : inspection_data -> inspection_data -> unit +(** [merge_inspection_data child parent] merges two sets of inspection + data into the parent. The parent inspection data fields, if + present, take precedence over the child inspection data fields. + + It's intended that you merge upwards, ie. + [merge_inspection_data usr root] *) + +val merge : fs -> fs -> unit +(** [merge child_fs parent_fs] merges two filesystems, + using [merge_inspection_data] to merge the inspection data of + the child into the parent. (Nothing else is merged, only + the inspection data). *) + +val string_of_fs : fs -> string +(** Convert [fs] into a multi-line string, for debugging only. *) + +val string_of_root : root -> string +(** Convert [root] into a multi-line string, for debugging only. *) + +val string_of_location : location -> string +(** Convert [location] into a string, for debugging only. *) + +val string_of_inspection_data : inspection_data -> string +(** Convert [inspection_data] into a multi-line string, for debugging only. *) + +val string_of_os_type : os_type -> string +(** Convert [os_type] to a string. + The string is part of the public API. *) + +val string_of_distro : distro -> string +(** Convert [distro] to a string. + The string is part of the public API. *) + +val string_of_package_format : package_format -> string +(** Convert [package_format] to a string. + The string is part of the public API. *) + +val string_of_package_management : package_management -> string +(** Convert [package_management] to a string. + The string is part of the public API. *) + +val null_inspection_data : unit -> inspection_data +(** {!inspection_data} structure with all fields set to [None]. + This is a function: since we mutate this structure, we want + a fresh structure each time (so we're not mutating a common copy). *) + +val inspect_fses : fs list ref +(** The global list of filesystems found by the previous call to + inspect_os. *) diff --git a/daemon/inspect_utils.ml b/daemon/inspect_utils.ml new file mode 100644 index 000000000..ce9c7b441 --- /dev/null +++ b/daemon/inspect_utils.ml @@ -0,0 +1,187 @@ +(* 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 Unix +open Printf + +open Std_utils + +open Utils +open Inspect_types + +let max_augeas_file_size = 100 * 1000 + +let rec with_augeas ?name configfiles f = + let name = + match name with + | None -> sprintf "with_augeas: %s" (String.concat " " configfiles) + | Some name -> name in + let chroot = Chroot.create ~name () in + + (* Security: + * + * The old C code had a few problems: It ignored non-regular-file + * objects (eg. devices), passing them to Augeas, so relying on + * Augeas to do the right thing. Also too-large regular files + * caused the whole inspection operation to fail. + * + * I have tried to improve this so that non-regular files and + * too large files are ignored (dropped from the configfiles list), + * so that Augeas won't touch them, but they also won't stop + * inspection. + *) + let safe_file file = + Is.is_file ~followsymlinks:true file && ( + let size = (Chroot.f chroot Unix.stat file).Unix.st_size in + size <= max_augeas_file_size + ) + in + let configfiles = List.filter safe_file configfiles in + + let aug = + Augeas.create (Sysroot.sysroot ()) None + [Augeas.AugSaveNoop; Augeas.AugNoLoad] in + + protect + ~f:(fun () -> + (* 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. + *) + let pathexpr = make_augeas_path_expression configfiles in + ignore (aug_rm_noerrors aug pathexpr); + Augeas.load aug; + + (* Check that augeas did not get a parse error for any of the + * configfiles, otherwise we are silently missing information. + *) + let matches = aug_matches_noerrors aug "/augeas/files//error" in + List.iter ( + fun match_ -> + List.iter ( + fun file -> + let errorpath = sprintf "/augeas/files%s/error" file in + if match_ = errorpath then ( + (* There's been an error - get the error details. *) + let get path = + match aug_get_noerrors aug (errorpath ^ path) with + | None -> "<missing>" + | Some v -> v + in + let message = get "message" in + let line = get "line" in + let charp = get "char" in + failwithf "%s:%s:%s: augeas parse failure: %s" + file line charp message + ) + ) configfiles + ) matches; + + f aug + ) + ~finally:( + fun () -> Augeas.close aug + ) + +(* Explained here: https://bugzilla.redhat.com/show_bug.cgi?id=975412#c0 *) +and make_augeas_path_expression files = + let subexprs = + List.map ( + fun file -> + (* v NB trailing '/' after filename *) + sprintf "\"%s/\" !~ regexp('^') + glob(incl) + regexp('/.*')" file + ) files in + let subexprs = String.concat " and " subexprs in + + let ret = sprintf "/augeas/load/*[ %s ]" subexprs in + if verbose () then + eprintf "augeas pathexpr = %s\n%!" ret; + + ret + +and aug_get_noerrors aug path = + try Augeas.get aug path + with Augeas.Error _ -> None + +and aug_matches_noerrors aug path = + try Augeas.matches aug path + with Augeas.Error _ -> [] + +and aug_rm_noerrors aug path = + try Augeas.rm aug path + with Augeas.Error _ -> 0 + +let is_file_nocase path = + let path = + try Some (Realpath.case_sensitive_path path) + with _ -> None in + match path with + | None -> false + | Some path -> Is.is_file path + +and is_dir_nocase path = + let path = + try Some (Realpath.case_sensitive_path path) + with _ -> None in + match path with + | None -> false + | Some path -> Is.is_dir path + +(* Rather hairy test for "is a partition", taken directly from + * the old C inspection code. XXX fix function and callers + *) +let is_partition partition = + try + let device = Devsparts.part_to_dev partition in + ignore (Devsparts.device_index device); + true + with _ -> false + +let re_major_minor = PCRE.compile "(\\d+)\\.(\\d+)" +let re_major_no_minor = PCRE.compile "(\\d+)" + +let parse_version_from_major_minor str data = + if verbose () then + eprintf "parse_version_from_major_minor: parsing '%s'\n%!" str; + + if PCRE.matches re_major_minor str || + PCRE.matches re_major_no_minor str then ( + let major = + try Some (int_of_string (PCRE.sub 1)) + with Not_found | Invalid_argument _ | Failure _ -> None in + let minor = + try Some (int_of_string (PCRE.sub 2)) + with Not_found | Invalid_argument _ | Failure _ -> None in + match major, minor with + | None, None + | None, Some _ -> () + | Some major, None -> data.version <- Some (major, 0) + | Some major, Some minor -> data.version <- Some (major, minor) + ) + else ( + eprintf "parse_version_from_major_minor: cannot parse version from '%s'\n" + str + ) + +let with_hive hive_filename f = + let flags = [ Hivex.OPEN_UNSAFE ] in + let flags = if verbose () then Hivex.OPEN_VERBOSE :: flags else flags in + let h = Hivex.open_file hive_filename flags in + protect ~f:(fun () -> f h (Hivex.root h)) ~finally:(fun () -> Hivex.close h) diff --git a/daemon/inspect_utils.mli b/daemon/inspect_utils.mli new file mode 100644 index 000000000..93e4c4b33 --- /dev/null +++ b/daemon/inspect_utils.mli @@ -0,0 +1,53 @@ +(* 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. + *) + +val with_augeas : ?name:string -> string list -> (Augeas.t -> 'a) -> 'a +(** Open an Augeas handle, parse only 'configfiles' (these + files must exist), and then call 'f' with the Augeas handle. + + 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. *) + +val aug_get_noerrors : Augeas.t -> string -> string option +val aug_matches_noerrors : Augeas.t -> string -> string list +val aug_rm_noerrors : Augeas.t -> string -> int +(** When inspecting a guest, we don't particularly care if Augeas + calls fail. These functions wrap {!Augeas.get}, {!Augeas.matches} + and {!Augeas.rm} returning null content if there is an error. *) + +val is_file_nocase : string -> bool +val is_dir_nocase : string -> bool +(** With a filesystem mounted under sysroot, check if [path] is + a file or directory under that sysroot. The [path] is + checked case-insensitively. *) + +val is_partition : string -> bool +(** Return true if the device is a partition. *) + +val parse_version_from_major_minor : string -> Inspect_types.inspection_data -> unit +(** Make a best effort attempt to parse either X or X.Y from a string, + usually the product_name string. *) + +val with_hive : string -> (Hivex.t -> Hivex.node -> 'a) -> 'a +(** Open a Windows registry "hive", and call the function on the + handle and root node. + + After the call to the function, the hive is always closed. + + The hive is opened readonly. *) -- 2.13.2 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs