Add "transient" unlock
I was thinking a bit more recently about the "live" changes stuff https://github.com/coreos/rpm-ostree/issues/639 (particularly since https://github.com/coreos/rpm-ostree/pull/2060 ) and I realized reading the last debates in that issue that there's really a much simpler solution; do exactly the same thing we do for `ostree admin unlock`, except mount it read-only by default. Then, anything that wants to modify it does the same thing libostree does for `/sysroot` and `/boot` as of recently; create a new mount namespace and do the modifications there. The advantages of this are numerous. First, we already have all of the code, it's basically just plumbing through a new entry in the state enumeration and passing `MS_RDONLY` into the `mount()` system call. "live" changes here also naturally don't persist, unlike what we are currently doing in rpm-ostree.
This commit is contained in:
1 parent
621e1d7394
commit
f2773c1b55
6 files changed
+77
-9
No files matched your search
@@ -318,6 +318,8 @@ ostree_deployment_unlocked_state_to_string (OstreeDeploymentUnlockedState state)
|
||||
return "hotfix";
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
|
||||
return "development";
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT:
|
||||
return "transient";
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ char *ostree_deployment_get_origin_relpath (OstreeDeployment *self);
|
||||
typedef enum {
|
||||
OSTREE_DEPLOYMENT_UNLOCKED_NONE,
|
||||
OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT,
|
||||
OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX
|
||||
OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX,
|
||||
OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT,
|
||||
} OstreeDeploymentUnlockedState;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
|
||||
@@ -85,6 +85,7 @@ struct OstreeSysroot {
|
||||
#define _OSTREE_SYSROOT_RUNSTATE_STAGED_LOCKED "/run/ostree/staged-deployment-locked"
|
||||
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/"
|
||||
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development"
|
||||
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_TRANSIENT "unlocked-transient"
|
||||
|
||||
gboolean
|
||||
_ostree_sysroot_ensure_writable (OstreeSysroot *self,
|
||||
|
||||
@@ -747,9 +747,13 @@ parse_deployment (OstreeSysroot *self,
|
||||
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE;
|
||||
g_autofree char *unlocked_development_path =
|
||||
_ostree_sysroot_get_runstate_path (ret_deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
|
||||
g_autofree char *unlocked_transient_path =
|
||||
_ostree_sysroot_get_runstate_path (ret_deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_TRANSIENT);
|
||||
struct stat stbuf;
|
||||
if (lstat (unlocked_development_path, &stbuf) == 0)
|
||||
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
|
||||
else if (lstat (unlocked_transient_path, &stbuf) == 0)
|
||||
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT;
|
||||
else
|
||||
{
|
||||
GKeyFile *origin = ostree_deployment_get_origin (ret_deployment);
|
||||
@@ -1932,6 +1936,8 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
|
||||
const char *ovl_options = NULL;
|
||||
static const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
|
||||
g_autofree char *unlock_ovldir = NULL;
|
||||
|
||||
switch (unlocked_state)
|
||||
{
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
|
||||
@@ -1951,11 +1957,12 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
}
|
||||
break;
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT:
|
||||
{
|
||||
unlock_ovldir = g_strdup ("/var/tmp/ostree-unlock-ovl.XXXXXX");
|
||||
/* We're just doing transient development/hacking? Okay,
|
||||
* stick the overlayfs bits in /var/tmp.
|
||||
*/
|
||||
char *development_ovldir = strdupa ("/var/tmp/ostree-unlock-ovl.XXXXXX");
|
||||
const char *development_ovl_upper;
|
||||
const char *development_ovl_work;
|
||||
|
||||
@@ -1966,14 +1973,14 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
"/usr", usr_mode, error))
|
||||
return FALSE;
|
||||
|
||||
if (g_mkdtemp_full (development_ovldir, 0755) == NULL)
|
||||
if (g_mkdtemp_full (unlock_ovldir, 0755) == NULL)
|
||||
return glnx_throw_errno_prefix (error, "mkdtemp");
|
||||
}
|
||||
|
||||
development_ovl_upper = glnx_strjoina (development_ovldir, "/upper");
|
||||
development_ovl_upper = glnx_strjoina (unlock_ovldir, "/upper");
|
||||
if (!mkdir_unmasked (AT_FDCWD, development_ovl_upper, usr_mode, cancellable, error))
|
||||
return FALSE;
|
||||
development_ovl_work = glnx_strjoina (development_ovldir, "/work");
|
||||
development_ovl_work = glnx_strjoina (unlock_ovldir, "/work");
|
||||
if (!mkdir_unmasked (AT_FDCWD, development_ovl_work, usr_mode, cancellable, error))
|
||||
return FALSE;
|
||||
ovl_options = glnx_strjoina ("lowerdir=usr,upperdir=", development_ovl_upper,
|
||||
@@ -1996,6 +2003,9 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
return glnx_throw_errno_prefix (error, "fork");
|
||||
else if (mount_child == 0)
|
||||
{
|
||||
int mountflags = 0;
|
||||
if (unlocked_state == OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT)
|
||||
mountflags |= MS_RDONLY;
|
||||
/* Child process. Do NOT use any GLib API here; it's not generally fork() safe.
|
||||
*
|
||||
* TODO: report errors across a pipe (or use the journal?) rather than
|
||||
@@ -2003,7 +2013,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
*/
|
||||
if (fchdir (deployment_dfd) < 0)
|
||||
err (1, "fchdir");
|
||||
if (mount ("overlay", "/usr", "overlay", 0, ovl_options) < 0)
|
||||
if (mount ("overlay", "/usr", "overlay", mountflags, ovl_options) < 0)
|
||||
err (1, "mount");
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
@@ -2036,15 +2046,19 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT:
|
||||
{
|
||||
g_autofree char *devpath =
|
||||
_ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
|
||||
unlocked_state == OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT ?
|
||||
_ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT)
|
||||
:
|
||||
_ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_TRANSIENT);
|
||||
g_autofree char *devpath_parent = dirname (g_strdup (devpath));
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!g_file_set_contents (devpath, "", 0, error))
|
||||
if (!g_file_set_contents (devpath, unlock_ovldir, -1, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user