From ba1ee149fe81cf4061e53eecb0ec0cc1aee63da7 Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Tue, 6 Dec 2016 16:08:12 +0100 Subject: [PATCH] inspect: gather info from /usr filesystems as well (RHBZ#1401474) Flag the filesystems for Linux /usr properly as USR role, and detect some data out of it, like the distro information from an os-release (if present), and the architecture (since the binaries used for our architecture check will be available there only). Later on, collect the results in a way similar to what is done for CoreOS: for each non-CoreOS root, try to find its /usr filesystem, and if found then merge what is missing from root; in the last case, also override the distro inspection data (version, product name) if available in /usr. (cherry picked from commit 1d86b3768956f818262a5189bb1ba996dedbf531) --- src/guestfs-internal.h | 1 + src/inspect-fs-unix.c | 26 ++++++++++++++++ src/inspect-fs.c | 6 ++-- src/inspect.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 109 insertions(+), 5 deletions(-) diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index eb201aa..0f5f975 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -795,6 +795,7 @@ extern void guestfs_int_merge_fs_inspections (guestfs_h *g, struct inspect_fs *d /* 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); diff --git a/src/inspect-fs-unix.c b/src/inspect-fs-unix.c index 8b7a7ee..48c4fd2 100644 --- a/src/inspect-fs-unix.c +++ b/src/inspect-fs-unix.c @@ -813,6 +813,32 @@ guestfs_int_check_linux_root (guestfs_h *g, struct inspect_fs *fs) 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) diff --git a/src/inspect-fs.c b/src/inspect-fs.c index 58f08b8..f6c2656 100644 --- a/src/inspect-fs.c +++ b/src/inspect-fs.c @@ -247,8 +247,10 @@ check_filesystem (guestfs_h *g, const char *mountable, is_dir_bin && is_dir_share && guestfs_is_dir (g, "/local") > 0 && - guestfs_is_file (g, "/etc/fstab") == 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 && diff --git a/src/inspect.c b/src/inspect.c index e805291..db2a125 100644 --- a/src/inspect.c +++ b/src/inspect.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef HAVE_ENDIAN_H #include @@ -41,6 +42,8 @@ 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 code. */ char ** @@ -81,6 +84,12 @@ guestfs_impl_inspect_os (guestfs_h *g) */ 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. @@ -143,9 +152,75 @@ collect_coreos_inspection_info (guestfs_h *g) guestfs_int_merge_fs_inspections (g, root, usr); } -/* On *BSD systems, sometimes /dev/sda[1234] is a shadow of the real root - * filesystem that is probably /dev/sda5 - * (see: http://www.freebsd.org/doc/handbook/disk-organization.html) +/** + * Traverse through the filesystems and find the /usr filesystem for + * the specified C: 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 (!(usr->major_version == 0 && usr->minor_version == 0)) { + 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 filesystems of a Linux image (but not CoreOS, + * for which there is a separate C). + * 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 is a shadow of the + * real root filesystem that is probably F (see: + * L) */ static void check_for_duplicated_bsd_root (guestfs_h *g) -- 2.7.4