mirror of
https://github.com/ostreedev/ostree.git
synced 2025-03-25 18:50:44 +03:00
Merge 7e4fe416c2d21147038466b180b5e6209d03665d into ce4e49e1f44b21b3cdea6fa41e2b047d70a6d70b
This commit is contained in:
commit
a2c7ce1f3e
@ -416,6 +416,18 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>boot-counting-tries</varname></term>
|
||||
<listitem><para>Integer value controlling the number of maximum boot attempts. The boot
|
||||
counting data is stored in the name of the boot loader entry. A boot loader entry file name
|
||||
may contain a plus (+) followed by a number. This may optionally be followed by
|
||||
a minus (-) followed by a second number. The dot (.) and file name suffix (conf or efi) must
|
||||
immediately follow. More details in the
|
||||
<ulink url="https://uapi-group.org/specifications/specs/boot_loader_specification/#boot-counting">
|
||||
The Boot Loader Specification</ulink>
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>bls-append-except-default</varname></term>
|
||||
<listitem><para>A semicolon separated string list of key-value pairs. For example:
|
||||
|
@ -27,6 +27,9 @@ struct _OstreeBootconfigParser
|
||||
gboolean parsed;
|
||||
const char *separators;
|
||||
|
||||
guint64 tries_left;
|
||||
guint64 tries_done;
|
||||
|
||||
GHashTable *options;
|
||||
|
||||
/* Additional initrds; the primary initrd is in options. */
|
||||
@ -56,6 +59,94 @@ ostree_bootconfig_parser_clone (OstreeBootconfigParser *self)
|
||||
return parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_bootconfig_parser_parse_tries:
|
||||
* @self: Parser
|
||||
* @path: File path
|
||||
*
|
||||
* Parses a suffix of two counters in the form "+LEFT-DONE" from the end of the
|
||||
* filename (excluding file extension).
|
||||
*/
|
||||
static void
|
||||
ostree_bootconfig_parser_parse_tries (OstreeBootconfigParser *self, const char *filename)
|
||||
{
|
||||
gchar *counter = NULL;
|
||||
gchar *old_counter = NULL;
|
||||
self->tries_left = 0;
|
||||
self->tries_done = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char *plus = strchr (counter ?: filename, '+');
|
||||
if (plus)
|
||||
{
|
||||
/* Look for the last "+" symbol in the filename */
|
||||
counter = plus + 1;
|
||||
continue;
|
||||
}
|
||||
if (counter)
|
||||
break;
|
||||
|
||||
/* No boot counter found */
|
||||
return;
|
||||
}
|
||||
|
||||
guint64 tries_left, tries_done = 0;
|
||||
|
||||
old_counter = counter;
|
||||
tries_left = g_ascii_strtoull (old_counter, &counter, 10);
|
||||
if ((old_counter == counter) || (tries_left > INT_MAX))
|
||||
return;
|
||||
|
||||
/* Parse done counter only if present */
|
||||
if (*counter == '-')
|
||||
{
|
||||
old_counter = counter;
|
||||
tries_done = g_ascii_strtoull (counter + 1, &counter, 10);
|
||||
if ((old_counter == counter) || (tries_left > INT_MAX))
|
||||
return;
|
||||
}
|
||||
|
||||
self->tries_left = tries_left;
|
||||
self->tries_done = tries_done;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_bootconfig_parser_get_tries_left:
|
||||
* @self: Parser
|
||||
*
|
||||
* Returns: Amount of boot tries left
|
||||
*/
|
||||
guint64
|
||||
ostree_bootconfig_parser_get_tries_left (OstreeBootconfigParser *self)
|
||||
{
|
||||
return self->tries_left;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_bootconfig_parser_get_tries_done:
|
||||
* @self: Parser
|
||||
*
|
||||
* Returns: Amount of boot tries
|
||||
*/
|
||||
guint64
|
||||
ostree_bootconfig_parser_get_tries_done (OstreeBootconfigParser *self)
|
||||
{
|
||||
return self->tries_done;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_bootconfig_parser_get_tries_done:
|
||||
* @self: Parser
|
||||
*
|
||||
* Returns: TRUE if the boot config was parsed from existing boot config file
|
||||
*/
|
||||
gboolean
|
||||
ostree_bootconfig_parser_is_parsed (OstreeBootconfigParser *self)
|
||||
{
|
||||
return self->parsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_bootconfig_parser_parse_at:
|
||||
* @self: Parser
|
||||
@ -116,6 +207,8 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, int dfd, const
|
||||
self->overlay_initrds = (char **)g_ptr_array_free (g_steal_pointer (&overlay_initrds), FALSE);
|
||||
}
|
||||
|
||||
ostree_bootconfig_parser_parse_tries(self, glnx_basename(path));
|
||||
|
||||
self->parsed = TRUE;
|
||||
|
||||
return TRUE;
|
||||
|
@ -67,4 +67,13 @@ void ostree_bootconfig_parser_set_overlay_initrds (OstreeBootconfigParser *self,
|
||||
_OSTREE_PUBLIC
|
||||
char **ostree_bootconfig_parser_get_overlay_initrds (OstreeBootconfigParser *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
guint64 ostree_bootconfig_parser_get_tries_left (OstreeBootconfigParser *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
guint64 ostree_bootconfig_parser_get_tries_done (OstreeBootconfigParser *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_bootconfig_parser_is_parsed (OstreeBootconfigParser *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -247,6 +247,7 @@ struct OstreeRepo
|
||||
GHashTable
|
||||
*bls_append_values; /* Parsed key-values from bls-append-except-default key in config. */
|
||||
gboolean enable_bootprefix; /* If true, prepend bootloader entries with /boot */
|
||||
guint boot_counting;
|
||||
|
||||
OstreeRepo *parent_repo;
|
||||
};
|
||||
|
@ -3297,6 +3297,20 @@ reload_remote_config (OstreeRepo *self, GCancellable *cancellable, GError **erro
|
||||
static gboolean
|
||||
reload_sysroot_config (OstreeRepo *self, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
{
|
||||
g_autofree char *boot_counting_str = NULL;
|
||||
|
||||
(void)ot_keyfile_get_value_with_default_group_optional (self->config, "sysroot", "boot-counting-tries", "0",
|
||||
&boot_counting_str, NULL);
|
||||
|
||||
if (boot_counting_str)
|
||||
/* Ensure boot count value is in [0,5] */
|
||||
self->boot_counting
|
||||
= MAX (0, MIN (INT_MAX, g_ascii_strtoull (boot_counting_str, NULL, 10)));
|
||||
else
|
||||
self->boot_counting = 0;
|
||||
}
|
||||
|
||||
g_autofree char *bootloader = NULL;
|
||||
|
||||
if (!ot_keyfile_get_value_with_default_group_optional (self->config, "sysroot", "bootloader",
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <gio/gunixinputstream.h>
|
||||
#include <gio/gunixoutputstream.h>
|
||||
#include <glib-unix.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
@ -1806,14 +1807,36 @@ parse_os_release (const char *contents, const char *split)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static guint
|
||||
bootloader_get_max_boot_tries (OstreeSysroot *self, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
g_autoptr (OstreeRepo) repo = NULL;
|
||||
if (!ostree_sysroot_get_repo (self, &repo, cancellable, error))
|
||||
return 0;
|
||||
|
||||
return repo->boot_counting;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
bootloader_is_boot_count_enabled (OstreeSysroot *self, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
g_autoptr (OstreeRepo) repo = NULL;
|
||||
if (!ostree_sysroot_get_repo (self, &repo, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return (repo->boot_counting != 0 ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
/* Generate the filename 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,
|
||||
OstreeDeployment *deployment)
|
||||
OstreeDeployment *deployment, GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *bootconf_name;
|
||||
guint index = n_deployments - ostree_deployment_get_index (deployment);
|
||||
// Allow opt-out to dropping the stateroot in case of compatibility issues.
|
||||
// As of 2024.5, we have a new naming scheme because grub2 parses the *filename* and ignores
|
||||
@ -1822,12 +1845,28 @@ 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);
|
||||
bootconf_name = g_strdup_printf ("ostree-%d-%s", index, stateroot);
|
||||
}
|
||||
else
|
||||
{
|
||||
return g_strdup_printf ("ostree-%d.conf", index);
|
||||
bootconf_name = g_strdup_printf ("ostree-%d", index);
|
||||
}
|
||||
|
||||
if (!bootloader_is_boot_count_enabled(sysroot, cancellable, error))
|
||||
return g_strdup_printf ("%s.conf", bootconf_name);
|
||||
|
||||
guint max_tries = bootloader_get_max_boot_tries (sysroot, cancellable, error);
|
||||
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
|
||||
|
||||
if (!ostree_bootconfig_parser_is_parsed (bootconfig))
|
||||
return g_strdup_printf ("%s+%u.conf", bootconf_name, max_tries);
|
||||
else if (!ostree_bootconfig_parser_get_tries_left (bootconfig)
|
||||
&& !ostree_bootconfig_parser_get_tries_done (bootconfig))
|
||||
return g_strdup_printf ("%s.conf", bootconf_name);
|
||||
else
|
||||
return g_strdup_printf ("%s+%" PRIu64 "-%" PRIu64 ".conf", bootconf_name,
|
||||
ostree_bootconfig_parser_get_tries_left (bootconfig),
|
||||
ostree_bootconfig_parser_get_tries_done (bootconfig));
|
||||
}
|
||||
|
||||
/* Given @deployment, prepare it to be booted; basically copying its
|
||||
@ -1864,7 +1903,6 @@ 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);
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, bootcsumdir, 0775, cancellable, error))
|
||||
return FALSE;
|
||||
@ -2178,8 +2216,11 @@ 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 = bootloader_entry_filename (sysroot, n_deployments, deployment,
|
||||
cancellable, error);
|
||||
|
||||
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;
|
||||
@ -4217,15 +4258,15 @@ ostree_sysroot_deployment_set_kargs_in_place (OstreeSysroot *self, OstreeDeploym
|
||||
OstreeBootconfigParser *new_bootconfig = ostree_deployment_get_bootconfig (deployment);
|
||||
ostree_bootconfig_parser_set (new_bootconfig, "options", kargs_str);
|
||||
|
||||
g_autofree char *bootconf_name
|
||||
= bootloader_entry_filename (self, self->deployments->len, deployment);
|
||||
g_autofree char *bootconf_filename
|
||||
= bootloader_entry_filename (self, self->deployments->len, deployment, cancellable, error);
|
||||
|
||||
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,
|
||||
if (!ostree_bootconfig_parser_write_at (new_bootconfig, bootconf_dfd, bootconf_filename,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user