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

lib/deploy: Add support for overlay initrds #2155

Merged
merged 3 commits into from
Oct 2, 2020
Merged
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions apidoc/ostree-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ ostree_bootconfig_parser_write
ostree_bootconfig_parser_write_at
ostree_bootconfig_parser_set
ostree_bootconfig_parser_get
ostree_bootconfig_parser_set_overlay_initrds
ostree_bootconfig_parser_get_overlay_initrds
<SUBSECTION Standard>
OSTREE_BOOTCONFIG_PARSER
OSTREE_IS_BOOTCONFIG_PARSER
Expand Down Expand Up @@ -545,7 +547,10 @@ ostree_sysroot_write_deployments
ostree_sysroot_write_deployments_with_options
ostree_sysroot_write_origin_file
ostree_sysroot_stage_tree
ostree_sysroot_stage_tree_with_options
ostree_sysroot_stage_overlay_initrd
ostree_sysroot_deploy_tree
ostree_sysroot_deploy_tree_with_options
ostree_sysroot_get_merge_deployment
ostree_sysroot_query_deployments_for
ostree_sysroot_origin_new_from_refspec
Expand Down
5 changes: 5 additions & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ global:
*/
ostree_repo_static_delta_execute_offline_with_signature;
ostree_repo_static_delta_verify_signature;
ostree_bootconfig_parser_get_overlay_initrds;
ostree_bootconfig_parser_set_overlay_initrds;
ostree_sysroot_deploy_tree_with_options;
ostree_sysroot_stage_tree_with_options;
ostree_sysroot_stage_overlay_initrd;
} LIBOSTREE_2020.4;

/* Stub section for the stable release *after* this development one; don't
Expand Down
73 changes: 71 additions & 2 deletions src/libostree/ostree-bootconfig-parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ struct _OstreeBootconfigParser
const char *separators;

GHashTable *options;

/* Additional initrds; the primary initrd is in options. */
char **overlay_initrds;
};

typedef GObjectClass OstreeBootconfigParserClass;
Expand All @@ -50,6 +53,8 @@ ostree_bootconfig_parser_clone (OstreeBootconfigParser *self)
GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v)
g_hash_table_replace (parser->options, g_strdup (k), g_strdup (v));

parser->overlay_initrds = g_strdupv (self->overlay_initrds);

return parser;
}

Expand All @@ -76,6 +81,8 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
if (!contents)
return FALSE;

g_autoptr(GPtrArray) overlay_initrds = NULL;

g_auto(GStrv) lines = g_strsplit (contents, "\n", -1);
for (char **iter = lines; *iter; iter++)
{
Expand All @@ -87,8 +94,19 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
items = g_strsplit_set (line, self->separators, 2);
if (g_strv_length (items) == 2 && items[0][0] != '\0')
{
g_hash_table_insert (self->options, items[0], items[1]);
g_free (items); /* Transfer ownership */
if (g_str_equal (items[0], "initrd") &&
g_hash_table_contains (self->options, "initrd"))
{
if (!overlay_initrds)
overlay_initrds = g_ptr_array_new_with_free_func (g_free);
g_ptr_array_add (overlay_initrds, items[1]);
g_free (items[0]);
}
else
{
g_hash_table_insert (self->options, items[0], items[1]);
}
g_free (items); /* Free container; we stole the elements */
}
else
{
Expand All @@ -97,6 +115,12 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
}
}

if (overlay_initrds)
{
g_ptr_array_add (overlay_initrds, NULL);
self->overlay_initrds = (char**)g_ptr_array_free (g_steal_pointer (&overlay_initrds), FALSE);
}

self->parsed = TRUE;

return TRUE;
Expand Down Expand Up @@ -127,6 +151,41 @@ ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
return g_hash_table_lookup (self->options, key);
}

/**
* ostree_bootconfig_parser_set_overlay_initrds:
* @self: Parser
* @initrds: (array zero-terminated=1) (transfer none) (allow-none): Array of overlay
* initrds or %NULL to unset.
*
* These are rendered as additional `initrd` keys in the final bootloader configs. The
* base initrd is part of the primary keys.
*
* Since: 2020.7
*/
void
ostree_bootconfig_parser_set_overlay_initrds (OstreeBootconfigParser *self,
char **initrds)
{
g_assert (g_hash_table_contains (self->options, "initrd"));
g_strfreev (self->overlay_initrds);
self->overlay_initrds = g_strdupv (initrds);
}

/**
* ostree_bootconfig_parser_get_overlay_initrds:
* @self: Parser
*
* Returns: (array zero-terminated=1) (transfer none) (nullable): Array of initrds or %NULL
* if none are set.
*
* Since: 2020.7
*/
char**
ostree_bootconfig_parser_get_overlay_initrds (OstreeBootconfigParser *self)
{
return self->overlay_initrds;
}

static void
write_key (OstreeBootconfigParser *self,
GString *buf,
Expand Down Expand Up @@ -165,6 +224,15 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
}
}

/* Write overlay initrds */
if (self->overlay_initrds && (g_strv_length (self->overlay_initrds) > 0))
{
/* we should've written the primary initrd already */
g_assert (g_hash_table_contains (keys_written, "initrd"));
for (char **it = self->overlay_initrds; it && *it; it++)
write_key (self, buf, "initrd", *it);
}

/* Write unknown fields */
GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v)
{
Expand Down Expand Up @@ -197,6 +265,7 @@ ostree_bootconfig_parser_finalize (GObject *object)
{
OstreeBootconfigParser *self = OSTREE_BOOTCONFIG_PARSER (object);

g_strfreev (self->overlay_initrds);
g_hash_table_unref (self->options);

G_OBJECT_CLASS (ostree_bootconfig_parser_parent_class)->finalize (object);
Expand Down
6 changes: 6 additions & 0 deletions src/libostree/ostree-bootconfig-parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,11 @@ _OSTREE_PUBLIC
const char *ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
const char *key);

_OSTREE_PUBLIC
void ostree_bootconfig_parser_set_overlay_initrds (OstreeBootconfigParser *self,
char **initrds);

_OSTREE_PUBLIC
char** ostree_bootconfig_parser_get_overlay_initrds (OstreeBootconfigParser *self);

G_END_DECLS
9 changes: 9 additions & 0 deletions src/libostree/ostree-deployment-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ G_BEGIN_DECLS
* @origin: How to construct an upgraded version of this tree
* @unlocked: The unlocked state
* @staged: TRUE iff this deployment is staged
* @overlay_initrds: Checksums of staged additional initrds for this deployment
* @overlay_initrds_id: Unique ID generated from initrd checksums; used to compare deployments
*/
struct _OstreeDeployment
{
Expand All @@ -52,8 +54,15 @@ struct _OstreeDeployment
GKeyFile *origin;
OstreeDeploymentUnlockedState unlocked;
gboolean staged;
char **overlay_initrds;
char *overlay_initrds_id;
};

void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum);

void _ostree_deployment_set_overlay_initrds (OstreeDeployment *self,
char **overlay_initrds);

char** _ostree_deployment_get_overlay_initrds (OstreeDeployment *self);

G_END_DECLS
32 changes: 32 additions & 0 deletions src/libostree/ostree-deployment.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,34 @@ _ostree_deployment_set_bootcsum (OstreeDeployment *self,
self->bootcsum = g_strdup (bootcsum);
}

void
_ostree_deployment_set_overlay_initrds (OstreeDeployment *self,
char **overlay_initrds)
{
g_clear_pointer (&self->overlay_initrds, g_strfreev);
g_clear_pointer (&self->overlay_initrds_id, g_free);

if (!overlay_initrds || g_strv_length (overlay_initrds) == 0)
return;

/* Generate a unique ID representing this combination of overlay initrds. This is so that
* ostree_sysroot_write_deployments_with_options() can easily compare initrds when
* comparing deployments for whether a bootswap is necessary. We could be fancier here but
* meh... this works. */
g_autoptr(GString) id = g_string_new (NULL);
for (char **it = overlay_initrds; it && *it; it++)
g_string_append (id, *it);

self->overlay_initrds = g_strdupv (overlay_initrds);
self->overlay_initrds_id = g_string_free (g_steal_pointer (&id), FALSE);
}

char**
_ostree_deployment_get_overlay_initrds (OstreeDeployment *self)
{
return self->overlay_initrds;
}

/**
* ostree_deployment_clone:
* @self: Deployment
Expand All @@ -175,6 +203,8 @@ ostree_deployment_clone (OstreeDeployment *self)
new_bootconfig = ostree_bootconfig_parser_clone (self->bootconfig);
ostree_deployment_set_bootconfig (ret, new_bootconfig);

_ostree_deployment_set_overlay_initrds (ret, self->overlay_initrds);

if (self->origin)
{
g_autoptr(GKeyFile) new_origin = NULL;
Expand Down Expand Up @@ -238,6 +268,8 @@ ostree_deployment_finalize (GObject *object)
g_free (self->bootcsum);
g_clear_object (&self->bootconfig);
g_clear_pointer (&self->origin, g_key_file_unref);
g_strfreev (self->overlay_initrds);
g_free (self->overlay_initrds_id);

G_OBJECT_CLASS (ostree_deployment_parent_class)->finalize (object);
}
Expand Down
43 changes: 43 additions & 0 deletions src/libostree/ostree-sysroot-cleanup.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ cleanup_old_deployments (OstreeSysroot *self,
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autoptr(GHashTable) active_boot_checksums =
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autoptr(GHashTable) active_overlay_initrds =
g_hash_table_new (g_str_hash, g_str_equal); /* borrows from deployment's bootconfig */
for (guint i = 0; i < self->deployments->len; i++)
{
OstreeDeployment *deployment = self->deployments->pdata[i];
Expand All @@ -306,6 +308,11 @@ cleanup_old_deployments (OstreeSysroot *self,
/* Transfer ownership */
g_hash_table_replace (active_deployment_dirs, deployment_path, deployment_path);
g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum);

OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
char **initrds = ostree_bootconfig_parser_get_overlay_initrds (bootconfig);
for (char **it = initrds; it && *it; it++)
g_hash_table_add (active_overlay_initrds, (char*)glnx_basename (*it));
}

/* Find all deployment directories, both active and inactive */
Expand Down Expand Up @@ -349,6 +356,42 @@ cleanup_old_deployments (OstreeSysroot *self,
return FALSE;
}

/* Clean up overlay initrds */
glnx_autofd int overlays_dfd =
glnx_opendirat_with_errno (self->sysroot_fd, _OSTREE_SYSROOT_INITRAMFS_OVERLAYS, FALSE);
if (overlays_dfd < 0)
{
if (errno != ENOENT)
return glnx_throw_errno_prefix (error, "open(initrd_overlays)");
}
else
{
g_autoptr(GPtrArray) initrds_to_delete = g_ptr_array_new_with_free_func (g_free);
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
if (!glnx_dirfd_iterator_init_at (overlays_dfd, ".", TRUE, &dfd_iter, error))
return FALSE;
while (TRUE)
{
struct dirent *dent;
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
return FALSE;
if (dent == NULL)
break;

/* there shouldn't be other file types there, but let's be conservative */
if (dent->d_type != DT_REG)
continue;

if (!g_hash_table_lookup (active_overlay_initrds, dent->d_name))
g_ptr_array_add (initrds_to_delete, g_strdup (dent->d_name));
}
for (guint i = 0; i < initrds_to_delete->len; i++)
{
if (!ot_ensure_unlinked_at (overlays_dfd, initrds_to_delete->pdata[i], error))
return FALSE;
}
}

return TRUE;
}

Expand Down
Loading