* Implement coreos distro
* Detect CoreOS images
Signed-off-by: Nikos Skalkotos <skalkoto(a)grnet.gr>
---
generator/actions.ml | 4 +++
src/guestfs-internal.h | 3 +++
src/inspect-fs-unix.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++---
src/inspect-fs.c | 21 +++++++++++++++
src/inspect-icon.c | 1 +
src/inspect.c | 62 +++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 157 insertions(+), 3 deletions(-)
diff --git a/generator/actions.ml b/generator/actions.ml
index e9374a3..e1b14ca 100644
--- a/generator/actions.ml
+++ b/generator/actions.ml
@@ -1073,6 +1073,10 @@ Cirros.
=item \"debian\"
+CoreOS.
+
+=item \"coreos\"
+
Debian.
=item \"fedora\"
diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h
index 01cbca7..1462673 100644
--- a/src/guestfs-internal.h
+++ b/src/guestfs-internal.h
@@ -551,6 +551,7 @@ enum inspect_os_distro {
OS_DISTRO_ORACLE_LINUX,
OS_DISTRO_FREEBSD,
OS_DISTRO_NETBSD,
+ OS_DISTRO_COREOS,
};
enum inspect_os_package_format {
@@ -797,6 +798,8 @@ 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 *);
diff --git a/src/inspect-fs-unix.c b/src/inspect-fs-unix.c
index 2abbf24..ff50b2a 100644
--- a/src/inspect-fs-unix.c
+++ b/src/inspect-fs-unix.c
@@ -160,11 +160,16 @@ parse_release_file (guestfs_h *g, struct inspect_fs *fs,
* 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)
+parse_lsb_release (guestfs_h *g, struct inspect_fs *fs, const char *filename)
{
- const char *filename = "/etc/lsb-release";
int64_t size;
CLEANUP_FREE_STRING_LIST char **lines = NULL;
size_t i;
@@ -208,6 +213,11 @@ parse_lsb_release (guestfs_h *g, struct inspect_fs *fs)
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=")) {
char *major, *minor;
if (match2 (g, &lines[i][16], re_major_minor, &major, &minor)) {
@@ -338,7 +348,7 @@ guestfs_int_check_linux_root (guestfs_h *g, struct inspect_fs *fs)
if (guestfs_is_file_opts (g, "/etc/lsb-release",
GUESTFS_IS_FILE_OPTS_FOLLOWSYMLINKS, 1, -1) > 0) {
- r = parse_lsb_release (g, fs);
+ 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 */
@@ -795,6 +805,59 @@ guestfs_int_check_minix_root (guestfs_h *g, struct inspect_fs *fs)
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.
+ */
+ if (add_fstab_entry (g, fs, fs->mountable, "/") == -1)
+ return -1;
+
+ 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;
+ 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;
+ }
+
+ /* 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.
+ */
+ if (add_fstab_entry (g, fs, fs->mountable, "/usr") == -1)
+ return -1;
+
+ return 0;
+}
+
static void
check_architecture (guestfs_h *g, struct inspect_fs *fs)
{
diff --git a/src/inspect-fs.c b/src/inspect-fs.c
index 5f55f1d..64f904f 100644
--- a/src/inspect-fs.c
+++ b/src/inspect-fs.c
@@ -232,6 +232,17 @@ check_filesystem (guestfs_h *g, const char *mountable,
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->is_root = 1;
+ 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 &&
@@ -246,6 +257,14 @@ check_filesystem (guestfs_h *g, const char *mountable,
guestfs_is_dir (g, "/local") > 0 &&
guestfs_is_file (g, "/etc/fstab") == 0)
;
+ /* 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 &&
@@ -476,6 +495,7 @@ guestfs_int_check_package_format (guestfs_h *g, struct inspect_fs
*fs)
case OS_DISTRO_SLACKWARE:
case OS_DISTRO_TTYLINUX:
+ case OS_DISTRO_COREOS:
case OS_DISTRO_WINDOWS:
case OS_DISTRO_BUILDROOT:
case OS_DISTRO_CIRROS:
@@ -546,6 +566,7 @@ guestfs_int_check_package_management (guestfs_h *g, struct inspect_fs
*fs)
case OS_DISTRO_SLACKWARE:
case OS_DISTRO_TTYLINUX:
+ case OS_DISTRO_COREOS:
case OS_DISTRO_WINDOWS:
case OS_DISTRO_BUILDROOT:
case OS_DISTRO_CIRROS:
diff --git a/src/inspect-icon.c b/src/inspect-icon.c
index fb998c2..57b2ce3 100644
--- a/src/inspect-icon.c
+++ b/src/inspect-icon.c
@@ -169,6 +169,7 @@ guestfs_impl_inspect_get_icon (guestfs_h *g, const char *root, size_t
*size_r,
/* 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:
diff --git a/src/inspect.c b/src/inspect.c
index f528bf2..dd6a06f 100644
--- a/src/inspect.c
+++ b/src/inspect.c
@@ -42,6 +42,7 @@
COMPILE_REGEXP (re_primary_partition, "^/dev/(?:h|s|v)d.[1234]$", 0)
static void check_for_duplicated_bsd_root (guestfs_h *g);
+static int collect_coreos_inspection_info (guestfs_h *g);
/* The main inspection code. */
char **
@@ -70,6 +71,15 @@ guestfs_impl_inspect_os (guestfs_h *g)
}
}
+ /* 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.
+ */
+ if (collect_coreos_inspection_info (g)) {
+ guestfs_int_free_inspect_info (g);
+ return NULL;
+ }
+
/* 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
@@ -87,6 +97,57 @@ guestfs_impl_inspect_os (guestfs_h *g)
return ret;
}
+/* Traverse through the filesystem list and find out if it contains the
+ * "/" and "/usr" filesystems of a CoreOS image. If this is the
case,
+ * sum up all the collected information on the root fs.
+ */
+static int
+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->is_root)
+ root = fs;
+ }
+
+ if (root == NULL)
+ return 0;
+
+ for (i = 0; i < g->nr_fses; ++i) {
+ struct inspect_fs *fs = &g->fses[i];
+
+ if (fs->distro != OS_DISTRO_COREOS || fs->is_root != 0)
+ 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 &&
+ (usr->major_version > fs->major_version ||
+ (usr->major_version == fs->major_version &&
+ usr->minor_version > fs->minor_version)))
+ continue;
+
+ usr = fs;
+ }
+
+ if (usr == NULL)
+ return 0;
+
+ return 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)
@@ -201,6 +262,7 @@ guestfs_impl_inspect_get_distro (guestfs_h *g, const char *root)
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;
--
2.1.0