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

WIP: transient /etc #2970

Closed
Closed
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
83 changes: 76 additions & 7 deletions src/switchroot/ostree-prepare-root.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const char *config_roots[] = { "/usr/lib", "/etc" };

#define SYSROOT_KEY "sysroot"
#define READONLY_KEY "readonly"
#define ETC_KEY "etc" // Possible values = "persistent" "transient"

// The kernel argument we support to configure composefs.
#define OT_COMPOSEFS_KARG "ot-composefs"
Expand Down Expand Up @@ -326,6 +327,34 @@ load_composefs_config (GError **error)
return g_steal_pointer (&ret);
}

static gboolean
find_etc (const char **out_path, GError **error)
{
// Look for /etc
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Look for /etc
struct stat stbuf;
// Look for /etc

if (fstatat (AT_FDCWD, "etc") == 0)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (fstatat (AT_FDCWD, "etc") == 0)
if (!glnx_fstatat (AT_FDCWD, "etc", &stbuf, AT_SYMLINK_NOFOLLOW, error))

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not entirely sure if I used the correct flag here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If using plain glnx_fstatat you need to use g_error_matches(error, ...), not errno. Easiest fix is to use
glnx_fstatat_allow_noent() which keeps errno for ENOENT.

{
*out_path = "etc";
return TRUE;
}
else if (errno != ENOENT)
{
return glnx_throw_errno_prefix (error, "failed to stat etc");
}

// Look for /usr/etc
if (fstatat (AT_FDCWD, "usr/etc") == 0)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (fstatat (AT_FDCWD, "usr/etc") == 0)
if (!glnx_fstatat (AT_FDCWD, "usr/etc", &stbuf, AT_SYMLINK_NOFOLLOW, error))

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not entirely sure if I used the correct flag here.

{
*out_path = "usr/etc";
return TRUE;
}
else if (errno != ENOENT)
{
return glnx_throw_errno_prefix (error, "failed to stat etc");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return glnx_throw_errno_prefix (error, "failed to stat etc");
return glnx_throw_errno_prefix (error, "failed to stat usr/etc");

}
*out_path = NULL;
return TRUE;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return TRUE;
return FALSE;

If there is no lower etc dir, shouldnt this function return false so that https://github.com/cgwalters/ostree/blob/c9a38dfb7fcebeb0b678d27ded78e92580be79a5/src/switchroot/ostree-prepare-root.c#L633-L637 evaluates to false?

      if (!find_etc (&etc_lower, &error))

}

int
main (int argc, char *argv[])
{
Expand Down Expand Up @@ -569,18 +598,58 @@ main (int argc, char *argv[])
}
}

g_autofree char *etc_config = NULL;
if (!ot_keyfile_get_value_with_default (config, SYSROOT_KEY, ETC_KEY, "persistent", &etc_config,
error))
Comment on lines +602 to +603
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (!ot_keyfile_get_value_with_default (config, SYSROOT_KEY, ETC_KEY, "persistent", &etc_config,
error))
if (!ot_keyfile_get_value_with_default (config, SYSROOT_KEY, ETC_KEY, "persistent", &etc_config,
&error))

errx (EXIT_FAILURE, "failed to parse %s.%s: %s", SYSROOT_KEY, ETC_KEY, error->message);
bool etc_transient = FALSE;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird mix of FALSE and false/true.

if (g_str_equal (etc_config, "persistent"))
etc_transient = false;
else if (g_str_equal (etc_config, "transient"))
etc_transient = true;
else
errx (EXIT_FAILURE, "Invalid %s.%s: %s", SYSROOT_KEY, ETC_KEY, etc_config);

// In theory these could be distinct, but no reason to try to support it.
if (etc_transient && !sysroot_readonly)
errx (EXIT_FAILURE, "Must specify %s.%s for %s.%s=transient", SYSROOT_KEY, READONLY_KEY,
SYSROOT_KEY, ETC_KEY);

/* Prepare /etc.
* No action required if sysroot is writable. Otherwise, a bind-mount for
* the deployment needs to be created and remounted as read/write. */
if (sysroot_readonly || using_composefs)
{
/* Bind-mount /etc (at deploy path), and remount as writable. */
if (mount ("etc", TMP_SYSROOT "/etc", NULL, MS_BIND | MS_SILENT, NULL) < 0)
err (EXIT_FAILURE, "failed to prepare /etc bind-mount at /sysroot.tmp/etc");
if (mount (TMP_SYSROOT "/etc", TMP_SYSROOT "/etc", NULL, MS_BIND | MS_REMOUNT | MS_SILENT,
NULL)
< 0)
err (EXIT_FAILURE, "failed to make writable /etc bind-mount at /sysroot.tmp/etc");
if (etc_transient)
{
/* Do we have a persistent overlayfs for /usr? If so, mount it now. */
g_autofree char *etc_ovldir
= g_build_filename (OTCORE_RUN_OSTREE_PRIVATE, "etc-transient", NULL);
if (mkdirat (AT_FDCWD, etc_ovldir, 0700) < 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you boot test this? Because when I tried something like this the selinux context on the initramfs at this point was uninitialized, which was carried over into boot for the overlayfs lowerdir, and without etc_t selinux context on /tmp a bunch of stuff broke at boot.

err (EXIT_FAILURE, "Failed to create %s", etc_ovldir);
g_autofree char *upper = g_build_filename (etc_ovldir, "upper", NULL);
g_autofree char *work = g_build_filename (etc_ovldir, "work", NULL);

const char *etc_lower = NULL;
if (!find_etc (&etc_lower, &error))
alexlarsson marked this conversation as resolved.
Show resolved Hide resolved
errx (EXIT_FAILURE, "Failed to find etc: %s", error->message);

if (etc_lower)
{
g_autofree char etc_ovl_options
= g_strdup_printf ("lowerdir=%s,upperdir=%s,workdir=%s", etc_lower, upper, work);
if (g_str_equal (""))
Comment on lines +637 to +641
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (etc_lower)
{
g_autofree char etc_ovl_options
= g_strdup_printf ("lowerdir=%s,upperdir=%s,workdir=%s", etc_lower, upper, work);
if (g_str_equal (""))
g_autofree char *etc_ovl_options
= g_strdup_printf ("lowerdir=%s,upperdir=%s,workdir=%s", etc_lower, upper, work);
if (mount ("overlay", TMP_SYSROOT "/etc", "overlay", MS_SILENT, etc_ovl_options) < 0)
err (EXIT_FAILURE, "failed to mount transient etc overlayfs");

}
else
{
/* Bind-mount /etc (at deploy path), and remount as writable. */
if (mount ("etc", TMP_SYSROOT "/etc", NULL, MS_BIND | MS_SILENT, NULL) < 0)
err (EXIT_FAILURE, "failed to prepare /etc bind-mount at /sysroot.tmp/etc");
if (mount (TMP_SYSROOT "/etc", TMP_SYSROOT "/etc", NULL, MS_BIND | MS_REMOUNT | MS_SILENT,
NULL)
< 0)
err (EXIT_FAILURE, "failed to make writable /etc bind-mount at /sysroot.tmp/etc");
}
}

/* Prepare /usr.
Expand Down
Loading