diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index d52eecf3de..1f6843d8e2 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -62,6 +62,8 @@ SD_ID128_MAKE (e8, 64, 6c, d6, 3d, ff, 46, 25, b7, 79, 09, a8, e7, a4, 09, 94) #endif +#define BOOT_COUNT_MAX_RETRIES 3 + /* How much additional space we require available on top of what we accounted * during the early prune fallocate space check. This accounts for anything not * captured directly by `get_kernel_layout_size()` like writing new BLS entries. @@ -1776,12 +1778,12 @@ parse_os_release (const char *contents, const char *split) return ret; } -/* Generate the filename we will use in /boot/loader/entries for this deployment. +/* Generate the entry name we will use in /boot/loader/entries for this deployment. * The provided n_deployments should be the total number of target deployments (which * might be different from the cached value in the sysroot). */ static char * -bootloader_entry_filename (OstreeSysroot *sysroot, guint n_deployments, +bootloader_entry_name (OstreeSysroot *sysroot, guint n_deployments, OstreeDeployment *deployment) { guint index = n_deployments - ostree_deployment_get_index (deployment); @@ -1792,12 +1794,50 @@ bootloader_entry_filename (OstreeSysroot *sysroot, guint n_deployments, if (use_old_naming) { const char *stateroot = ostree_deployment_get_osname (deployment); - return g_strdup_printf ("ostree-%d-%s.conf", index, stateroot); + return g_strdup_printf ("ostree-%d-%s", index, stateroot); } else { - return g_strdup_printf ("ostree-%d.conf", index); + return g_strdup_printf ("ostree-%d", index); + } +} + +/* Drop all temporary entries in /boot/loader/entries for this deployment, + * which were created during automatic boot assesment + * https://systemd.io/AUTOMATIC_BOOT_ASSESSMENT/ + */ +static gboolean +bootloader_remove_tmp_entries (int dfd, const char *entry_name, GCancellable *cancellable, + GError **error) +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + g_autofree char *entry_name_init = g_strdup_printf ("%s+%d", entry_name, BOOT_COUNT_MAX_RETRIES); + + if (!glnx_dirfd_iterator_init_at (dfd, ".", FALSE, &dfd_iter, error)) + return FALSE; + + while (TRUE) + { + struct dirent *dent = NULL; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + + /* Don't remove default boot entry (with +3 suffix) */ + if (g_str_has_prefix (dent->d_name, entry_name_init)) + continue; + + if (g_str_has_prefix (dent->d_name, entry_name)) + { + if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error)) + return FALSE; + } + } + + return TRUE; } /* Given @deployment, prepare it to be booted; basically copying its @@ -1834,7 +1874,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, int new_bootversion, const char *bootcsum = ostree_deployment_get_bootcsum (deployment); g_autofree char *bootcsumdir = g_strdup_printf ("ostree/%s-%s", osname, bootcsum); g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", new_bootversion); - g_autofree char *bootconf_name = bootloader_entry_filename (sysroot, n_deployments, deployment); + g_autofree char *bootconf_name = bootloader_entry_name (sysroot, n_deployments, deployment); if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, bootcsumdir, 0775, cancellable, error)) return FALSE; @@ -2146,8 +2186,13 @@ install_deployment_kernel (OstreeSysroot *sysroot, int new_bootversion, if (!glnx_opendirat (sysroot->boot_fd, bootconfdir, TRUE, &bootconf_dfd, error)) return FALSE; + g_autofree char *bootconf_filename = g_strdup_printf ("%s+%d.conf", bootconf_name, BOOT_COUNT_MAX_RETRIES); + + if (!bootloader_remove_tmp_entries(bootconf_dfd, bootconf_name, cancellable, error)) + return FALSE; + if (!ostree_bootconfig_parser_write_at (ostree_deployment_get_bootconfig (deployment), - bootconf_dfd, bootconf_name, cancellable, error)) + bootconf_dfd, bootconf_filename, cancellable, error)) return FALSE; return TRUE; @@ -4176,14 +4221,19 @@ ostree_sysroot_deployment_set_kargs_in_place (OstreeSysroot *self, OstreeDeploym ostree_bootconfig_parser_set (new_bootconfig, "options", kargs_str); g_autofree char *bootconf_name - = bootloader_entry_filename (self, self->deployments->len, deployment); + = bootloader_entry_name (self, self->deployments->len, deployment); g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", self->bootversion); glnx_autofd int bootconf_dfd = -1; if (!glnx_opendirat (self->boot_fd, bootconfdir, TRUE, &bootconf_dfd, error)) return FALSE; - if (!ostree_bootconfig_parser_write_at (new_bootconfig, bootconf_dfd, bootconf_name, + g_autofree char *bootconf_filename = g_strdup_printf ("%s+%d.conf", bootconf_name, BOOT_COUNT_MAX_RETRIES); + + if (!bootloader_remove_tmp_entries(bootconf_dfd, bootconf_name, cancellable, error)) + return FALSE; + + if (!ostree_bootconfig_parser_write_at (new_bootconfig, bootconf_dfd, bootconf_filename, cancellable, error)) return FALSE; }