Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

apply: Don't use staged deployments when /boot is automounted #301

Merged
merged 2 commits into from
Mar 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Build-Depends:
libgsystem-dev,
libjson-glib-dev (>= 1.2.6-1endless2),
libmogwai-schedule-client-0-dev,
libmount-dev (>= 2.24),
libnm-dev (>= 1.2.0),
libostree-dev (>= 2017.12),
libsoup2.4-dev,
Expand Down
10 changes: 6 additions & 4 deletions eos-updater/apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,13 @@ apply_internal (ApplyData *apply_data,

origin = ostree_sysroot_origin_new_from_refspec (sysroot, update_refspec);

/* When booted into an OSTree system, stage the deployment so that the
* /etc merge happens during shutdown. Otherwise (primarily the test
* suite), deploy the finalized tree immediately.
/* When booted into an OSTree system without an automount /boot, stage the
* deployment so that the /etc merge happens during shutdown. Otherwise
* (primarily sd-boot and the test suite), deploy the finalized tree
* immediately.
*/
staged_deploy = ostree_sysroot_is_booted (sysroot);
staged_deploy = ostree_sysroot_is_booted (sysroot) &&
!eos_updater_sysroot_boot_is_automount (sysroot, NULL);
if (staged_deploy)
{
g_message ("Creating staged deployment for revision %s", update_id);
Expand Down
1 change: 1 addition & 0 deletions libeos-updater-util/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ libeos_updater_util_deps = [
dependency('gobject-2.0', version: '>= 2.62'),
dependency('json-glib-1.0', version: '>= 1.2.6'),
dependency('libsoup-2.4'),
dependency('mount', version: '>= 2.24'),
dependency('ostree-1', version: '>= 2018.6'),
]

Expand Down
77 changes: 77 additions & 0 deletions libeos-updater-util/ostree-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <glib.h>
#include <libeos-updater-util/ostree-util.h>
#include <libeos-updater-util/util.h>
#include <libmount.h>
#include <libsoup/soup.h>
#include <ostree.h>
#include <string.h>
Expand Down Expand Up @@ -311,3 +312,79 @@ eos_updater_get_ostree_path (OstreeRepo *repo,
*ostree_path = g_steal_pointer (&path);
return TRUE;
}

/**
* eos_updater_sysroot_boot_is_automount:
* @sysroot: loaded OSTree sysroot to use
* @mountinfo: (nullable): path to mountinfo file
*
* Find if the boot directory in @sysroot is an automount mount. The first
* mountpoint for the boot directory in @mountinfo is found. If the filesystem
* type for the mountpoint is autofs, then the boot directory is automounted.
*
* If @mountinfo is %NULL, /proc/self/mountinfo is used.
*
* Returns: %TRUE if boot is an automount
*/
gboolean
eos_updater_sysroot_boot_is_automount (OstreeSysroot *sysroot,
const gchar *mountinfo)
{
GFile *sysroot_file;
g_autoptr(GFile) boot_file = NULL;
g_autofree gchar *boot_path = NULL;
gboolean ret = FALSE;
struct libmnt_table *tb = NULL;
struct libmnt_cache *cache;
struct libmnt_fs *fs;

sysroot_file = ostree_sysroot_get_path (sysroot);
boot_file = g_file_get_child (sysroot_file, "boot");
boot_path = g_file_get_path (boot_file);
if (boot_path == NULL)
{
g_autofree gchar *sysroot_path = g_file_get_path (sysroot_file);
g_warning ("No boot directory in sysroot %s", sysroot_path);
goto out;
}

if (mountinfo == NULL)
mountinfo = "/proc/self/mountinfo";
tb = mnt_new_table_from_file (mountinfo);
if (tb == NULL)
{
g_warning ("Failed to parse %s: %s", mountinfo, g_strerror (errno));
goto out;
}

cache = mnt_new_cache ();
if (cache == NULL)
{
g_warning ("Failed to create libmount cache: %s", g_strerror (errno));
goto out;
}
mnt_table_set_cache (tb, cache);
mnt_unref_cache (cache);

/* Find the /boot mountpoint iterating forward so that the autofs mount is
* found and not the automount target filesystem, as the autofs mount is
* listed first in mountinfo.
*/
fs = mnt_table_find_mountpoint (tb, boot_path, MNT_ITER_FORWARD);
if (fs == NULL)
{
g_warning ("Failed to find mountpoint for %s: %s", boot_path,
g_strerror (errno));
goto out;
}

ret = g_strcmp0 (mnt_fs_get_fstype (fs), "autofs") == 0;
g_debug ("Boot directory %s is%s on an autofs filesystem",
boot_path, ret ? "" : " not");

out:
if (tb != NULL)
mnt_unref_table (tb);

return ret;
}
3 changes: 3 additions & 0 deletions libeos-updater-util/ostree-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,7 @@ gboolean eos_updater_get_ostree_path (OstreeRepo *repo,
gchar **ostree_path,
GError **error);

gboolean eos_updater_sysroot_boot_is_automount (OstreeSysroot *sysroot,
const gchar *mountinfo);

G_END_DECLS
81 changes: 81 additions & 0 deletions libeos-updater-util/tests/ostree-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,85 @@ test_ostree_no_deployments (Fixture *fixture,
g_assert_cmpuint (commit_timestamp, ==, 0);
}

static void
test_ostree_sysroot_boot_automount (Fixture *fixture,
gconstpointer user_data G_GNUC_UNUSED)
{
g_autoptr(GError) error = NULL;
gboolean retval;
GFile *sysroot_file = ostree_sysroot_get_path (fixture->sysroot);
g_autofree gchar *sysroot_path = g_file_get_path (sysroot_file);
g_autoptr(GFile) boot_file = g_file_get_child (sysroot_file, "boot");
g_autofree gchar *boot_path = g_file_get_path (boot_file);
g_autoptr(GFile) mountinfo_file = g_file_get_child (fixture->tmp_dir,
"mountinfo");
g_autofree gchar *mountinfo_path = g_file_get_path (mountinfo_file);
g_autofree gchar *mountinfo_contents = NULL;

retval = g_file_make_directory (boot_file, NULL, &error);
g_assert_no_error (error);
g_assert_true (retval);

/* No separate /boot mount */
g_clear_pointer (&mountinfo_contents, g_free);
mountinfo_contents =
g_strdup_printf ("1 1 1:1 / %s rw - ext4 /dev/sda1 rw\n", sysroot_path);
g_test_message ("boot %s, mountinfo:\n%s", boot_path, mountinfo_contents);
retval = g_file_replace_contents (mountinfo_file, mountinfo_contents,
strlen (mountinfo_contents), NULL, FALSE,
G_FILE_CREATE_NONE, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (retval);
retval = eos_updater_sysroot_boot_is_automount (fixture->sysroot, mountinfo_path);
g_assert_false (retval);

/* Non-automount /boot */
g_clear_pointer (&mountinfo_contents, g_free);
mountinfo_contents =
g_strdup_printf ("1 1 1:2 / %s rw - ext4 /dev/sda2 rw\n"
"2 1 1:1 / %s rw - ext4 /dev/sda1 rw\n",
sysroot_path, boot_path);
g_test_message ("boot %s, mountinfo:\n%s", boot_path, mountinfo_contents);
retval = g_file_replace_contents (mountinfo_file, mountinfo_contents,
strlen (mountinfo_contents), NULL, FALSE,
G_FILE_CREATE_NONE, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (retval);
retval = eos_updater_sysroot_boot_is_automount (fixture->sysroot, mountinfo_path);
g_assert_false (retval);

/* Automount /boot without target mount */
g_clear_pointer (&mountinfo_contents, g_free);
mountinfo_contents =
g_strdup_printf ("1 1 1:2 / %s rw - ext4 /dev/sda2 rw\n"
"2 1 0:1 / %s rw - autofs systemd-1 rw\n",
sysroot_path, boot_path);
g_test_message ("boot %s, mountinfo:\n%s", boot_path, mountinfo_contents);
retval = g_file_replace_contents (mountinfo_file, mountinfo_contents,
strlen (mountinfo_contents), NULL, FALSE,
G_FILE_CREATE_NONE, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (retval);
retval = eos_updater_sysroot_boot_is_automount (fixture->sysroot, mountinfo_path);
g_assert_true (retval);

/* Automount /boot with target mount */
g_clear_pointer (&mountinfo_contents, g_free);
mountinfo_contents =
g_strdup_printf ("1 1 1:2 / %s rw - ext4 /dev/sda2 rw\n"
"2 1 0:1 / %s rw - autofs systemd-1 rw\n"
"3 2 1:1 / %s rw - vfat /dev/sda1 rw\n",
sysroot_path, boot_path, boot_path);
g_test_message ("boot %s, mountinfo:\n%s", boot_path, mountinfo_contents);
retval = g_file_replace_contents (mountinfo_file, mountinfo_contents,
strlen (mountinfo_contents), NULL, FALSE,
G_FILE_CREATE_NONE, NULL, NULL, &error);
g_assert_no_error (error);
g_assert_true (retval);
retval = eos_updater_sysroot_boot_is_automount (fixture->sysroot, mountinfo_path);
g_assert_true (retval);
}

int
main (int argc,
char *argv[])
Expand All @@ -157,6 +236,8 @@ main (int argc,

g_test_add ("/ostree/no-deployments", Fixture, NULL, setup,
test_ostree_no_deployments, teardown);
g_test_add ("/ostree/sysroot-boot-automount", Fixture, NULL, setup,
test_ostree_sysroot_boot_automount, teardown);
/* TODO: More */

return g_test_run ();
Expand Down