From 44d5f1cb8c1544b5df332a32149c61745fcfc43c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Fri, 21 Sep 2018 09:47:36 -0400 Subject: [PATCH] deploy: Fix removing /var/.updated with separate /var mount There's some subtlety to this, we don't handle all cases. But the 99% cases are using `--sysroot deploy` to create an initial deployment, and then doing upgrades from inside a booted deployment. It was only the latter case that didn't work with a separate `/var`. Fixing all of them would probably require libostree to learn how to e.g. look at `/etc/fstab` (or worse, systemd mount units?) and handle the mounting. I don't think we want to do anything like that right now, since there are no active drivers for the use case. Closes: https://github.com/ostreedev/ostree/issues/1729 Closes: #1730 Approved by: akiernan --- src/libostree/ostree-sysroot-deploy.c | 46 ++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 8198e191..246f1114 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -2509,6 +2509,47 @@ sysroot_initialize_deployment (OstreeSysroot *self, return TRUE; } +/* Get a directory fd for the /var of @deployment. + * Before we supported having /var be a separate mount point, + * this was easy. However, as https://github.com/ostreedev/ostree/issues/1729 + * raised, in the primary case where we're + * doing a new deployment for the booted stateroot, + * we need to use /var/. This code doesn't correctly + * handle the case of `ostree admin --sysroot upgrade`, + * nor (relatedly) the case of upgrading a separate stateroot. + */ +static gboolean +get_var_dfd (OstreeSysroot *self, + int osdeploy_dfd, + OstreeDeployment *deployment, + int *ret_fd, + GError **error) +{ + const char *booted_stateroot = + self->booted_deployment ? ostree_deployment_get_osname (self->booted_deployment) : NULL; + + int base_dfd; + const char *base_path; + /* The common case is when we're doing a new deployment for the same stateroot (osname). + * If we have a separate mounted /var, then we need to use it - the /var in the + * stateroot will probably just be an empty directory. + * + * If the stateroot doesn't match, just fall back to /var in the target's stateroot. + */ + if (g_strcmp0 (booted_stateroot, ostree_deployment_get_osname (deployment)) == 0) + { + base_dfd = AT_FDCWD; + base_path = "/var"; + } + else + { + base_dfd = osdeploy_dfd; + base_path = "var"; + } + + return glnx_opendirat (base_dfd, base_path, TRUE, ret_fd, error); +} + static gboolean sysroot_finalize_deployment (OstreeSysroot *self, OstreeDeployment *deployment, @@ -2547,6 +2588,9 @@ sysroot_finalize_deployment (OstreeSysroot *self, glnx_autofd int os_deploy_dfd = -1; if (!glnx_opendirat (self->sysroot_fd, osdeploypath, TRUE, &os_deploy_dfd, error)) return FALSE; + glnx_autofd int var_dfd = -1; + if (!get_var_dfd (self, os_deploy_dfd, deployment, &var_dfd, error)) + return FALSE; /* Ensure that the new deployment does not have /etc/.updated or * /var/.updated so that systemd ConditionNeedsUpdate=/etc|/var services run @@ -2554,7 +2598,7 @@ sysroot_finalize_deployment (OstreeSysroot *self, */ if (!ot_ensure_unlinked_at (deployment_dfd, "etc/.updated", error)) return FALSE; - if (!ot_ensure_unlinked_at (os_deploy_dfd, "var/.updated", error)) + if (!ot_ensure_unlinked_at (var_dfd, ".updated", error)) return FALSE; g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error);