New upstream version 2021.1

This commit is contained in:
Simon McVittie committed 2021-04-14 12:52:43 +01:00
commit 1c67002e63
82 files changed
+4382 -4088

No files matched your search

+6
View File
@@ -638,6 +638,12 @@ global:
ostree_repo_gpg_sign_data;
} LIBOSTREE_2020.7;
LIBOSTREE_2021.1 {
global:
ostree_commit_metadata_for_bootable;
ostree_sysroot_require_booted_deployment;
} LIBOSTREE_2020.8;
/* NOTE: Only add more content here in release commits! See the
* comments at the top of this file.
*/
+14 -13
View File
@@ -28,25 +28,26 @@
#include <string.h>
/* I only did some cursory research here, but it appears
* that we only want to use "linux16" for x86 platforms.
* At least, I got a report that "linux16" is definitely wrong
* for ppc64. See
* http://pkgs.fedoraproject.org/cgit/rpms/grub2.git/tree/0036-Use-linux16-when-appropriate-880840.patch?h=f25
* https://bugzilla.redhat.com/show_bug.cgi?id=1108296
* among others.
/* Maintain backwards compatibility with legacy GRUB
* installations that might rely on the -16 suffix
* for real-mode booting.
* Allow us to override this at build time if we're
* using a modern GRUB installation.
*/
#if defined(__i386__) || defined(__x86_64__)
#if !defined(WITH_MODERN_GRUB) && ( defined(__i386__) || defined(__x86_64__) )
#define GRUB2_SUFFIX "16"
#else
#define GRUB2_SUFFIX ""
#endif
/* https://github.com/projectatomic/rpm-ostree-toolbox/issues/102#issuecomment-316483554
* https://github.com/rhboot/grubby/blob/34b1436ccbd56eab8024314cab48f2fc880eef08/grubby.c#L63
*
* This is true at least on Fedora/Red Hat Enterprise Linux for aarch64.
/* Maintain backwards compatibility with legacy GRUB
* installations that might rely on the -efi suffix
* for RHEL/fedora-based distros.
* Allow us to override this at build time if we're
* using a modern GRUB installation that makes the
* suffix-less linux/initrd commands synonymous for
* both EFI and BIOS booting.
*/
#if defined(__aarch64__)
#if defined(WITH_MODERN_GRUB) || defined(__aarch64__)
#define GRUB2_EFI_SUFFIX ""
#else
#define GRUB2_EFI_SUFFIX "efi"
-110
View File
@@ -33,9 +33,6 @@
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <ext2fs/ext2_fs.h>
#ifdef HAVE_LINUX_FSVERITY_H
#include <linux/fsverity.h>
#endif
#include "otutil.h"
#include "ostree.h"
@@ -190,113 +187,6 @@ ot_security_smack_reset_fd (int fd)
#endif
}
/* Wrapper around the fsverity ioctl, compressing the result to
* "success, unsupported or error". This is used for /boot where
* we enable verity if supported.
* */
gboolean
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
_OstreeFeatureSupport fsverity_requested,
gboolean *supported,
GError **error)
{
/* Set this by default to simplify the code below */
if (supported)
*supported = FALSE;
if (fsverity_requested == _OSTREE_FEATURE_NO)
return TRUE;
#ifdef HAVE_LINUX_FSVERITY_H
GLNX_AUTO_PREFIX_ERROR ("fsverity", error);
/* fs-verity requires a read-only file descriptor */
if (!glnx_tmpfile_reopen_rdonly (tmpf, error))
return FALSE;
struct fsverity_enable_arg arg = { 0, };
arg.version = 1;
arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; /* TODO configurable? */
arg.block_size = 4096; /* FIXME query */
arg.salt_size = 0; /* TODO store salt in ostree repo config */
arg.salt_ptr = 0;
arg.sig_size = 0; /* We don't currently expect use of in-kernel signature verification */
arg.sig_ptr = 0;
if (ioctl (tmpf->fd, FS_IOC_ENABLE_VERITY, &arg) < 0)
{
switch (errno)
{
case ENOTTY:
case EOPNOTSUPP:
return TRUE;
default:
return glnx_throw_errno_prefix (error, "ioctl(FS_IOC_ENABLE_VERITY)");
}
}
if (supported)
*supported = TRUE;
#endif
return TRUE;
}
/* Enable verity on a file, respecting the "wanted" and "supported" states.
* The main idea here is to optimize out pointlessly calling the ioctl()
* over and over in cases where it's not supported for the repo's filesystem,
* as well as to support "opportunistic" use (requested and if filesystem supports).
* */
gboolean
_ostree_tmpf_fsverity (OstreeRepo *self,
GLnxTmpfile *tmpf,
GError **error)
{
#ifdef HAVE_LINUX_FSVERITY_H
g_mutex_lock (&self->txn_lock);
_OstreeFeatureSupport fsverity_wanted = self->fs_verity_wanted;
_OstreeFeatureSupport fsverity_supported = self->fs_verity_supported;
g_mutex_unlock (&self->txn_lock);
switch (fsverity_wanted)
{
case _OSTREE_FEATURE_YES:
{
if (fsverity_supported == _OSTREE_FEATURE_NO)
return glnx_throw (error, "fsverity required but filesystem does not support it");
}
break;
case _OSTREE_FEATURE_MAYBE:
break;
case _OSTREE_FEATURE_NO:
return TRUE;
}
gboolean supported = FALSE;
if (!_ostree_tmpf_fsverity_core (tmpf, fsverity_wanted, &supported, error))
return FALSE;
if (!supported)
{
if (G_UNLIKELY (fsverity_wanted == _OSTREE_FEATURE_YES))
return glnx_throw (error, "fsverity required but filesystem does not support it");
/* If we got here, we must be trying "opportunistic" use of fs-verity */
g_assert_cmpint (fsverity_wanted, ==, _OSTREE_FEATURE_MAYBE);
g_mutex_lock (&self->txn_lock);
self->fs_verity_supported = _OSTREE_FEATURE_NO;
g_mutex_unlock (&self->txn_lock);
return TRUE;
}
g_mutex_lock (&self->txn_lock);
self->fs_verity_supported = _OSTREE_FEATURE_YES;
g_mutex_unlock (&self->txn_lock);
#else
g_assert_cmpint (self->fs_verity_wanted, !=, _OSTREE_FEATURE_YES);
#endif
return TRUE;
}
/* Given an O_TMPFILE regular file, link it into place. */
gboolean
_ostree_repo_commit_tmpf_final (OstreeRepo *self,
+33 -2
View File
@@ -458,12 +458,43 @@ aic_get_xattrs (OstreeRepoArchiveImportContext *ctx,
g_autoptr(GVariant) xattrs = NULL;
const char *cb_path = abspath;
gboolean no_xattrs = ctx->modifier &&
ctx->modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_SKIP_XATTRS;
if (!no_xattrs && archive_entry_xattr_count (ctx->entry) > 0)
{
const char *name;
const void *value;
size_t size;
g_autoptr(GVariantBuilder) builder =
ot_util_variant_builder_from_variant (xattrs,
G_VARIANT_TYPE ("a(ayay)"));
archive_entry_xattr_reset (ctx->entry);
while (archive_entry_xattr_next (
ctx->entry, &name, &value, &size) == ARCHIVE_OK)
{
g_variant_builder_add (builder, "(@ay@ay)",
g_variant_new_bytestring (name),
g_variant_new_fixed_array (G_VARIANT_TYPE("y"),
value, size, 1));
}
xattrs = g_variant_builder_end (builder);
g_variant_ref_sink (xattrs);
}
if (ctx->opts->callback_with_entry_pathname)
cb_path = archive_entry_pathname (ctx->entry);
if (ctx->modifier && ctx->modifier->xattr_callback)
xattrs = ctx->modifier->xattr_callback (ctx->repo, cb_path, file_info,
ctx->modifier->xattr_user_data);
{
if (xattrs)
g_variant_unref (xattrs);
xattrs = ctx->modifier->xattr_callback (ctx->repo, cb_path, file_info,
ctx->modifier->xattr_user_data);
}
if (ctx->modifier && ctx->modifier->sepolicy)
{
+83
View File
@@ -0,0 +1,83 @@
/*
* SPDX-License-Identifier: LGPL-2.0+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <gio/gfiledescriptorbased.h>
#include <gio/gunixinputstream.h>
#include "libglnx.h"
#include "ostree.h"
#include "ostree-core-private.h"
#include "ostree-repo-os.h"
#include "otutil.h"
/**
* ostree_commit_metadata_for_bootable:
* @root: Root filesystem to be committed
* @dict: Dictionary to update
*
* Update provided @dict with standard metadata for bootable OSTree commits.
* Since: 2021.1
*/
_OSTREE_PUBLIC
gboolean
ostree_commit_metadata_for_bootable (GFile *root, GVariantDict *dict, GCancellable *cancellable, GError **error)
{
g_autoptr(GFile) modules = g_file_resolve_relative_path (root, "usr/lib/modules");
g_autoptr(GFileEnumerator) dir_enum
= g_file_enumerate_children (modules, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
if (!dir_enum)
return glnx_prefix_error (error, "Opening usr/lib/modules");
g_autofree char *linux_release = NULL;
while (TRUE)
{
GFileInfo *child_info;
GFile *child_path;
if (!g_file_enumerator_iterate (dir_enum, &child_info, &child_path,
cancellable, error))
return FALSE;
if (child_info == NULL)
break;
if (g_file_info_get_file_type (child_info) != G_FILE_TYPE_DIRECTORY)
continue;
g_autoptr(GFile) kernel_path = g_file_resolve_relative_path (child_path, "vmlinuz");
if (!g_file_query_exists (kernel_path, NULL))
continue;
if (linux_release != NULL)
return glnx_throw (error, "Multiple kernels found in /usr/lib/modules");
linux_release = g_strdup (g_file_info_get_name (child_info));
}
if (linux_release)
{
g_variant_dict_insert (dict, OSTREE_METADATA_KEY_BOOTABLE, "b", TRUE);
g_variant_dict_insert (dict, OSTREE_METADATA_KEY_LINUX, "s", linux_release);
return TRUE;
}
return glnx_throw (error, "No kernel found in /usr/lib/modules");
}
+47
View File
@@ -0,0 +1,47 @@
/*
* SPDX-License-Identifier: LGPL-2.0+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#pragma once
#include <sys/stat.h>
#include <gio/gio.h>
#include <ostree-types.h>
G_BEGIN_DECLS
/**
* OSTREE_METADATA_KEY_BOOTABLE:
*
* GVariant type `b`: Set if this commit is intended to be bootable
* Since: 2021.1
*/
#define OSTREE_METADATA_KEY_BOOTABLE "ostree.bootable"
/**
* OSTREE_METADATA_KEY_LINUX:
*
* GVariant type `s`: Contains the Linux kernel release (i.e. `uname -r`)
* Since: 2021.1
*/
#define OSTREE_METADATA_KEY_LINUX "ostree.linux"
_OSTREE_PUBLIC
gboolean
ostree_commit_metadata_for_bootable (GFile *root, GVariantDict *dict, GCancellable *cancellable, GError **error);
G_END_DECLS
+2
View File
@@ -521,6 +521,8 @@ OstreeRepoAutoLock * _ostree_repo_auto_lock_push (OstreeRepo *self,
void _ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, _ostree_repo_auto_lock_cleanup)
gboolean _ostree_repo_parse_fsverity_config (OstreeRepo *self, GError **error);
gboolean
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
_OstreeFeatureSupport fsverity_requested,
+2 -1
View File
@@ -70,6 +70,7 @@ typedef struct {
gboolean require_static_deltas;
gboolean disable_static_deltas;
gboolean has_tombstone_commits;
gboolean disable_verify_bindings;
GBytes *summary_data;
char *summary_etag;
@@ -87,7 +88,7 @@ typedef struct {
GHashTable *ref_keyring_map; /* Maps OstreeCollectionRef to keyring remote name */
GPtrArray *static_delta_superblocks;
GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */
GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */
GHashTable *commit_to_depth; /* Maps parent commit checksum maximum depth */
GHashTable *scanned_metadata; /* Maps object name to itself */
GHashTable *fetched_detached_metadata; /* Map<checksum,GVariant> */
GHashTable *requested_metadata; /* Maps object name to itself */
+102 -66
View File
@@ -706,7 +706,7 @@ scan_dirtree_object (OtPullData *pull_data,
* before libostree's validation was strengthened.
*/
if (!ot_util_filename_validate (filename, error))
return FALSE;
return glnx_prefix_error (error, "File %u in dirtree", i);
/* Skip files if we're traversing a request only directory, unless it exactly
* matches the path */
@@ -781,7 +781,7 @@ scan_dirtree_object (OtPullData *pull_data,
/* See comment above for files */
if (!ot_util_filename_validate (dirname, error))
return FALSE;
return glnx_prefix_error (error, "Dir %u in dirtree", i);
if (!pull_matches_subdir (pull_data, path, dirname, TRUE))
continue;
@@ -1113,6 +1113,18 @@ on_metadata_written (GObject *object,
check_outstanding_requests_handle_error (pull_data, &local_error);
}
static gboolean
is_parent_commit (OtPullData *pull_data,
const char *checksum)
{
/* FIXME: Only parent commits are added to the commit_to_depth table,
* so if the checksum isn't in the table then a new commit chain is
* being started. However, if the desired commit was a parent in a
* previously followed chain, then this will be wrong.
*/
return g_hash_table_contains (pull_data->commit_to_depth, checksum);
}
static void
meta_fetch_on_complete (GObject *object,
GAsyncResult *result,
@@ -1155,10 +1167,13 @@ meta_fetch_on_complete (GObject *object,
}
/* When traversing parents, do not fail on a missing commit.
* We may be pulling from a partial repository that ends in
* a dangling parent reference. */
* We may be pulling from a partial repository that ends in a
* dangling parent reference. This logic should match the
* local case in scan_one_metadata_object.
*/
else if (objtype == OSTREE_OBJECT_TYPE_COMMIT &&
pull_data->maxdepth != 0)
pull_data->maxdepth != 0 &&
is_parent_commit (pull_data, checksum))
{
g_clear_error (&local_error);
/* If the remote repo supports tombstone commits, check if the commit was intentionally
@@ -1542,8 +1557,6 @@ scan_commit_object (OtPullData *pull_data,
else
{
depth = pull_data->maxdepth;
g_hash_table_insert (pull_data->commit_to_depth, g_strdup (checksum),
GINT_TO_POINTER (depth));
}
#ifndef OSTREE_DISABLE_GPGME
@@ -1620,15 +1633,19 @@ scan_commit_object (OtPullData *pull_data,
if (!ostree_repo_load_commit (pull_data->repo, checksum, &commit, &commitstate, error))
return FALSE;
/* If ref is non-NULL then the commit we fetched was requested through the
* branch, otherwise we requested a commit checksum without specifying a branch.
*/
g_autofree char *remote_collection_id = NULL;
remote_collection_id = get_remote_repo_collection_id (pull_data);
if (!_ostree_repo_verify_bindings (remote_collection_id,
(ref != NULL) ? ref->ref_name : NULL,
commit, error))
return glnx_prefix_error (error, "Commit %s", checksum);
if (!pull_data->disable_verify_bindings)
{
/* If ref is non-NULL then the commit we fetched was requested through
* the branch, otherwise we requested a commit checksum without
* specifying a branch.
*/
g_autofree char *remote_collection_id = NULL;
remote_collection_id = get_remote_repo_collection_id (pull_data);
if (!_ostree_repo_verify_bindings (remote_collection_id,
(ref != NULL) ? ref->ref_name : NULL,
commit, error))
return glnx_prefix_error (error, "Commit %s", checksum);
}
guint64 new_ts = ostree_commit_get_timestamp (commit);
if (pull_data->timestamp_check)
@@ -1680,40 +1697,19 @@ scan_commit_object (OtPullData *pull_data,
return FALSE;
}
if (parent_csum_bytes != NULL && pull_data->maxdepth == -1)
{
queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes,
OSTREE_OBJECT_TYPE_COMMIT, NULL,
recursion_depth + 1, NULL);
}
else if (parent_csum_bytes != NULL && depth > 0)
if (parent_csum_bytes != NULL && (pull_data->maxdepth == -1 || depth > 0))
{
char parent_checksum[OSTREE_SHA256_STRING_LEN+1];
gpointer parent_depthp;
int parent_depth;
ostree_checksum_inplace_from_bytes (parent_csum_bytes, parent_checksum);
if (g_hash_table_lookup_extended (pull_data->commit_to_depth, parent_checksum,
NULL, &parent_depthp))
{
parent_depth = GPOINTER_TO_INT (parent_depthp);
}
else
{
parent_depth = depth - 1;
}
if (parent_depth >= 0)
{
g_hash_table_insert (pull_data->commit_to_depth, g_strdup (parent_checksum),
GINT_TO_POINTER (parent_depth));
queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes,
OSTREE_OBJECT_TYPE_COMMIT,
NULL,
recursion_depth + 1,
NULL);
}
int parent_depth = (depth > 0) ? depth - 1 : -1;
g_hash_table_insert (pull_data->commit_to_depth, g_strdup (parent_checksum),
GINT_TO_POINTER (parent_depth));
queue_scan_one_metadata_object_c (pull_data, parent_csum_bytes,
OSTREE_OBJECT_TYPE_COMMIT,
NULL,
recursion_depth + 1,
NULL);
}
/* We only recurse to looking whether we need dirtree/dirmeta
@@ -1826,10 +1822,46 @@ scan_one_metadata_object (OtPullData *pull_data,
return FALSE;
}
g_autoptr(GError) local_error = NULL;
if (!_ostree_repo_import_object (pull_data->repo, pull_data->remote_repo_local,
objtype, checksum, pull_data->importflags,
cancellable, error))
return FALSE;
cancellable, &local_error))
{
/* When traversing parents, do not fail on a missing commit.
* We may be pulling from a partial repository that ends in a
* dangling parent reference. This logic should match the
* remote case in meta_fetch_on_complete.
*
* Note early return.
*/
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND) &&
objtype == OSTREE_OBJECT_TYPE_COMMIT &&
pull_data->maxdepth != 0 &&
is_parent_commit (pull_data, checksum))
{
g_clear_error (&local_error);
/* If the remote repo supports tombstone commits, check if
* the commit was intentionally deleted.
*/
if (pull_data->has_tombstone_commits)
{
if (!_ostree_repo_import_object (pull_data->repo, pull_data->remote_repo_local,
OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT,
checksum, pull_data->importflags,
cancellable, error))
return FALSE;
}
return TRUE;
}
else
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
}
/* The import API will fetch both the commit and detached metadata, so
* add it to the hash to avoid re-fetching it below.
*/
@@ -1902,7 +1934,7 @@ scan_one_metadata_object (OtPullData *pull_data,
{
if (!scan_dirtree_object (pull_data, checksum, path, recursion_depth,
pull_data->cancellable, error))
return FALSE;
return glnx_prefix_error (error, "Validating dirtree %s (%s)", checksum, path);
g_hash_table_add (pull_data->scanned_metadata, g_variant_ref (object));
pull_data->n_scanned_metadata++;
@@ -3670,6 +3702,8 @@ all_requested_refs_have_commit (GHashTable *requested_refs /* (element-type Ostr
* specified, the `summary` will be downloaded from the remote. Since: 2020.5
* * `summary-sig-bytes` (`ay`): Contents of the `summary.sig` file. If this
* is specified, `summary-bytes` must also be specified. Since: 2020.5
* * `disable-verify-bindings` (`b`): Disable verification of commit bindings.
* Since: 2020.9
*/
gboolean
ostree_repo_pull_with_options (OstreeRepo *self,
@@ -3771,6 +3805,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_variant_lookup (options, "ref-keyring-map", "a(sss)", &ref_keyring_map_iter);
(void) g_variant_lookup (options, "summary-bytes", "@ay", &summary_bytes_v);
(void) g_variant_lookup (options, "summary-sig-bytes", "@ay", &summary_sig_bytes_v);
(void) g_variant_lookup (options, "disable-verify-bindings", "b", &pull_data->disable_verify_bindings);
if (pull_data->remote_refspec_name != NULL)
pull_data->remote_name = g_strdup (pull_data->remote_refspec_name);
@@ -4069,24 +4104,25 @@ ostree_repo_pull_with_options (OstreeRepo *self,
&configured_branches, error))
goto out;
/* TODO reindent later */
{ OstreeFetcherURI *first_uri = pull_data->meta_mirrorlist->pdata[0];
/* Handle file:// URIs */
{
OstreeFetcherURI *first_uri = pull_data->meta_mirrorlist->pdata[0];
g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri);
/* NB: we don't support local mirrors in mirrorlists, so if this passes, it
* means that we're not using mirrorlists (see also fetch_mirrorlist())
* Also, we explicitly disable the "local repo" path if static deltas
* were explicitly requested to be required; this is going to happen
* most often for testing deltas without setting up a HTTP server.
*/
if (g_str_equal (first_scheme, "file") && !pull_data->require_static_deltas)
{
g_autofree char *path = _ostree_fetcher_uri_get_path (first_uri);
g_autoptr(GFile) remote_repo_path = g_file_new_for_path (path);
pull_data->remote_repo_local = ostree_repo_new (remote_repo_path);
if (!ostree_repo_open (pull_data->remote_repo_local, cancellable, error))
goto out;
}
/* NB: we don't support local mirrors in mirrorlists, so if this passes, it
* means that we're not using mirrorlists (see also fetch_mirrorlist())
* Also, we explicitly disable the "local repo" path if static deltas
* were explicitly requested to be required; this is going to happen
* most often for testing deltas without setting up a HTTP server.
*/
if (g_str_equal (first_scheme, "file") && !pull_data->require_static_deltas)
{
g_autofree char *uri = _ostree_fetcher_uri_to_string (first_uri);
g_autoptr(GFile) remote_repo_path = g_file_new_for_uri (uri);
pull_data->remote_repo_local = ostree_repo_new (remote_repo_path);
if (!ostree_repo_open (pull_data->remote_repo_local, cancellable, error))
goto out;
}
}
/* Change some option defaults if we're actually pulling from a local
@@ -6639,7 +6675,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
return FALSE;
}
if (signatures)
if (signatures && !summary)
{
if (!_ostree_repo_load_cache_summary_if_same_sig (self,
name,
+2 -2
View File
@@ -449,7 +449,7 @@ _ostree_repo_resolve_rev_internal (OstreeRepo *self,
* @self: Repo
* @refspec: A refspec
* @allow_noent: Do not throw an error if refspec does not exist
* @out_rev: (out) (transfer full): A checksum,or %NULL if @allow_noent is true and it does not exist
* @out_rev: (out) (nullable) (transfer full): A checksum,or %NULL if @allow_noent is true and it does not exist
* @error: Error
*
* Look up the given refspec, returning the checksum it references in
@@ -472,7 +472,7 @@ ostree_repo_resolve_rev (OstreeRepo *self,
* @refspec: A refspec
* @allow_noent: Do not throw an error if refspec does not exist
* @flags: Options controlling behavior
* @out_rev: (out) (transfer full): A checksum,or %NULL if @allow_noent is true and it does not exist
* @out_rev: (out) (nullable) (transfer full): A checksum,or %NULL if @allow_noent is true and it does not exist
* @error: Error
*
* Look up the given refspec, returning the checksum it references in
@@ -636,7 +636,7 @@ try_content_rollsum (OstreeRepo *repo,
if (!get_unpacked_unlinked_content (repo, to, &tmp_to, cancellable, error))
return FALSE;
OstreeRollsumMatches *matches = _ostree_compute_rollsum_matches (tmp_from, tmp_to);
g_autoptr(OstreeRollsumMatches) matches = _ostree_compute_rollsum_matches (tmp_from, tmp_to);
const guint match_ratio = (matches->bufmatches*100)/matches->total;
+174
View File
@@ -0,0 +1,174 @@
/*
* Copyright (C) Red Hat, Inc.
*
* SPDX-License-Identifier: LGPL-2.0+
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <sys/ioctl.h>
#include "ostree-core-private.h"
#include "ostree-repo-private.h"
#include "otutil.h"
#include "ot-fs-utils.h"
#ifdef HAVE_LINUX_FSVERITY_H
#include <linux/fsverity.h>
#endif
gboolean
_ostree_repo_parse_fsverity_config (OstreeRepo *self, GError **error)
{
/* Currently experimental */
static const char fsverity_key[] = "ex-fsverity";
self->fs_verity_wanted = _OSTREE_FEATURE_NO;
#ifdef HAVE_LINUX_FSVERITY_H
self->fs_verity_supported = _OSTREE_FEATURE_MAYBE;
#else
self->fs_verity_supported = _OSTREE_FEATURE_NO;
#endif
gboolean fsverity_required = FALSE;
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "required",
FALSE, &fsverity_required, error))
return FALSE;
if (fsverity_required)
{
self->fs_verity_wanted = _OSTREE_FEATURE_YES;
if (self->fs_verity_supported == _OSTREE_FEATURE_NO)
return glnx_throw (error, "fsverity required, but libostree compiled without support");
}
else
{
gboolean fsverity_opportunistic = FALSE;
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "opportunistic",
FALSE, &fsverity_opportunistic, error))
return FALSE;
if (fsverity_opportunistic)
self->fs_verity_wanted = _OSTREE_FEATURE_MAYBE;
}
return TRUE;
}
/* Wrapper around the fsverity ioctl, compressing the result to
* "success, unsupported or error". This is used for /boot where
* we enable verity if supported.
* */
gboolean
_ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf,
_OstreeFeatureSupport fsverity_requested,
gboolean *supported,
GError **error)
{
/* Set this by default to simplify the code below */
if (supported)
*supported = FALSE;
if (fsverity_requested == _OSTREE_FEATURE_NO)
return TRUE;
#ifdef HAVE_LINUX_FSVERITY_H
GLNX_AUTO_PREFIX_ERROR ("fsverity", error);
/* fs-verity requires a read-only file descriptor */
if (!glnx_tmpfile_reopen_rdonly (tmpf, error))
return FALSE;
struct fsverity_enable_arg arg = { 0, };
arg.version = 1;
arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; /* TODO configurable? */
arg.block_size = 4096; /* FIXME query */
arg.salt_size = 0; /* TODO store salt in ostree repo config */
arg.salt_ptr = 0;
arg.sig_size = 0; /* We don't currently expect use of in-kernel signature verification */
arg.sig_ptr = 0;
if (ioctl (tmpf->fd, FS_IOC_ENABLE_VERITY, &arg) < 0)
{
switch (errno)
{
case ENOTTY:
case EOPNOTSUPP:
return TRUE;
default:
return glnx_throw_errno_prefix (error, "ioctl(FS_IOC_ENABLE_VERITY)");
}
}
if (supported)
*supported = TRUE;
#endif
return TRUE;
}
/* Enable verity on a file, respecting the "wanted" and "supported" states.
* The main idea here is to optimize out pointlessly calling the ioctl()
* over and over in cases where it's not supported for the repo's filesystem,
* as well as to support "opportunistic" use (requested and if filesystem supports).
* */
gboolean
_ostree_tmpf_fsverity (OstreeRepo *self,
GLnxTmpfile *tmpf,
GError **error)
{
#ifdef HAVE_LINUX_FSVERITY_H
g_mutex_lock (&self->txn_lock);
_OstreeFeatureSupport fsverity_wanted = self->fs_verity_wanted;
_OstreeFeatureSupport fsverity_supported = self->fs_verity_supported;
g_mutex_unlock (&self->txn_lock);
switch (fsverity_wanted)
{
case _OSTREE_FEATURE_YES:
{
if (fsverity_supported == _OSTREE_FEATURE_NO)
return glnx_throw (error, "fsverity required but filesystem does not support it");
}
break;
case _OSTREE_FEATURE_MAYBE:
break;
case _OSTREE_FEATURE_NO:
return TRUE;
}
gboolean supported = FALSE;
if (!_ostree_tmpf_fsverity_core (tmpf, fsverity_wanted, &supported, error))
return FALSE;
if (!supported)
{
if (G_UNLIKELY (fsverity_wanted == _OSTREE_FEATURE_YES))
return glnx_throw (error, "fsverity required but filesystem does not support it");
/* If we got here, we must be trying "opportunistic" use of fs-verity */
g_assert_cmpint (fsverity_wanted, ==, _OSTREE_FEATURE_MAYBE);
g_mutex_lock (&self->txn_lock);
self->fs_verity_supported = _OSTREE_FEATURE_NO;
g_mutex_unlock (&self->txn_lock);
return TRUE;
}
g_mutex_lock (&self->txn_lock);
self->fs_verity_supported = _OSTREE_FEATURE_YES;
g_mutex_unlock (&self->txn_lock);
#else
g_assert_cmpint (self->fs_verity_wanted, !=, _OSTREE_FEATURE_YES);
#endif
return TRUE;
}
+2 -27
View File
@@ -2584,7 +2584,7 @@ ostree_repo_create (OstreeRepo *self,
* @dfd: Directory fd
* @path: Path
* @mode: The mode to store the repository in
* @options: a{sv}: See below for accepted keys
* @options: (nullable): a{sv}: See below for accepted keys
* @cancellable: Cancellable
* @error: Error
*
@@ -3017,33 +3017,8 @@ reload_core_config (OstreeRepo *self,
}
}
/* Currently experimental */
static const char fsverity_key[] = "ex-fsverity";
self->fs_verity_wanted = _OSTREE_FEATURE_NO;
#ifdef HAVE_LINUX_FSVERITY_H
self->fs_verity_supported = _OSTREE_FEATURE_MAYBE;
#else
self->fs_verity_supported = _OSTREE_FEATURE_NO;
#endif
gboolean fsverity_required = FALSE;
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "required",
FALSE, &fsverity_required, error))
if (!_ostree_repo_parse_fsverity_config (self, error))
return FALSE;
if (fsverity_required)
{
self->fs_verity_wanted = _OSTREE_FEATURE_YES;
if (self->fs_verity_supported == _OSTREE_FEATURE_NO)
return glnx_throw (error, "fsverity required, but libostree compiled without support");
}
else
{
gboolean fsverity_opportunistic = FALSE;
if (!ot_keyfile_get_boolean_with_default (self->config, fsverity_key, "opportunistic",
FALSE, &fsverity_opportunistic, error))
return FALSE;
if (fsverity_opportunistic)
self->fs_verity_wanted = _OSTREE_FEATURE_MAYBE;
}
{
g_clear_pointer (&self->collection_id, g_free);
+31 -108
View File
@@ -56,9 +56,6 @@
#define OSTREE_DEPLOYMENT_FINALIZING_ID SD_ID128_MAKE(e8,64,6c,d6,3d,ff,46,25,b7,79,09,a8,e7,a4,09,94)
#endif
static gboolean
is_ro_mount (const char *path);
/*
* Like symlinkat() but overwrites (atomically) an existing
* symlink.
@@ -1582,11 +1579,11 @@ full_system_sync (OstreeSysroot *self,
out_stats->root_syncfs_msec = (end_msec - start_msec);
start_msec = g_get_monotonic_time () / 1000;
glnx_autofd int boot_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, &boot_dfd, error))
if (!_ostree_sysroot_ensure_boot_fd (self, error))
return FALSE;
if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error))
start_msec = g_get_monotonic_time () / 1000;
if (!fsfreeze_thaw_cycle (self, self->boot_fd, cancellable, error))
return FALSE;
end_msec = g_get_monotonic_time () / 1000;
out_stats->boot_syncfs_msec = (end_msec - start_msec);
@@ -1678,6 +1675,7 @@ static gboolean
swap_bootlinks (OstreeSysroot *self,
int bootversion,
GPtrArray *new_deployments,
char **out_subbootdir,
GCancellable *cancellable,
GError **error)
{
@@ -1702,7 +1700,8 @@ swap_bootlinks (OstreeSysroot *self,
if (!symlink_at_replace (ostree_subbootdir_name, ostree_dfd, ostree_bootdir_name,
cancellable, error))
return FALSE;
if (out_subbootdir)
*out_subbootdir = g_steal_pointer (&ostree_subbootdir_name);
return TRUE;
}
@@ -1770,8 +1769,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
cancellable, error))
return FALSE;
glnx_autofd int boot_dfd = -1;
if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error))
if (!_ostree_sysroot_ensure_boot_fd (sysroot, error))
return FALSE;
const char *osname = ostree_deployment_get_osname (deployment);
@@ -1781,14 +1779,14 @@ install_deployment_kernel (OstreeSysroot *sysroot,
g_autofree char *bootconf_name = g_strdup_printf ("ostree-%d-%s.conf",
n_deployments - ostree_deployment_get_index (deployment),
osname);
if (!glnx_shutil_mkdir_p_at (boot_dfd, bootcsumdir, 0775, cancellable, error))
if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, bootcsumdir, 0775, cancellable, error))
return FALSE;
glnx_autofd int bootcsum_dfd = -1;
if (!glnx_opendirat (boot_dfd, bootcsumdir, TRUE, &bootcsum_dfd, error))
if (!glnx_opendirat (sysroot->boot_fd, bootcsumdir, TRUE, &bootcsum_dfd, error))
return FALSE;
if (!glnx_shutil_mkdir_p_at (boot_dfd, bootconfdir, 0775, cancellable, error))
if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, bootconfdir, 0775, cancellable, error))
return FALSE;
/* Install (hardlink/copy) the kernel into /boot/ostree/osname-${bootcsum} if
@@ -1879,18 +1877,18 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{
overlay_initrds = g_ptr_array_new_with_free_func (g_free);
if (!glnx_shutil_mkdir_p_at (boot_dfd, _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS,
if (!glnx_shutil_mkdir_p_at (sysroot->boot_fd, _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS,
0755, cancellable, error))
return FALSE;
}
if (!glnx_fstatat_allow_noent (boot_dfd, rel_destpath, NULL, 0, error))
if (!glnx_fstatat_allow_noent (sysroot->boot_fd, rel_destpath, NULL, 0, error))
return FALSE;
if (errno == ENOENT)
{
g_autofree char *srcpath =
g_strdup_printf (_OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR "/%s", checksum);
if (!install_into_boot (repo, sepolicy, AT_FDCWD, srcpath, boot_dfd, rel_destpath,
if (!install_into_boot (repo, sepolicy, AT_FDCWD, srcpath, sysroot->boot_fd, rel_destpath,
cancellable, error))
return FALSE;
}
@@ -2019,7 +2017,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
ostree_bootconfig_parser_set (bootconfig, "options", options_key);
glnx_autofd int bootconf_dfd = -1;
if (!glnx_opendirat (boot_dfd, bootconfdir, TRUE, &bootconf_dfd, error))
if (!glnx_opendirat (sysroot->boot_fd, bootconfdir, TRUE, &bootconf_dfd, error))
return FALSE;
if (!ostree_bootconfig_parser_write_at (ostree_deployment_get_bootconfig (deployment),
@@ -2076,15 +2074,14 @@ swap_bootloader (OstreeSysroot *sysroot,
g_assert ((current_bootversion == 0 && new_bootversion == 1) ||
(current_bootversion == 1 && new_bootversion == 0));
glnx_autofd int boot_dfd = -1;
if (!glnx_opendirat (sysroot->sysroot_fd, "boot", TRUE, &boot_dfd, error))
if (!_ostree_sysroot_ensure_boot_fd (sysroot, error))
return FALSE;
/* The symlink was already written, and we used syncfs() to ensure
* its data is in place. Renaming now should give us atomic semantics;
* see https://bugzilla.gnome.org/show_bug.cgi?id=755595
*/
if (!glnx_renameat (boot_dfd, "loader.tmp", boot_dfd, "loader", error))
if (!glnx_renameat (sysroot->boot_fd, "loader.tmp", sysroot->boot_fd, "loader", error))
return FALSE;
/* Now we explicitly fsync this directory, even though it
@@ -2096,7 +2093,7 @@ swap_bootloader (OstreeSysroot *sysroot,
* for whatever reason, and we wouldn't want to confuse the
* admin by going back to the previous session.
*/
if (fsync (boot_dfd) != 0)
if (fsync (sysroot->boot_fd) != 0)
return glnx_throw_errno_prefix (error, "fsync(boot)");
/* TODO: In the future also execute this automatically via a systemd unit
@@ -2227,57 +2224,6 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self,
return TRUE;
}
/* Detect whether or not @path refers to a read-only mountpoint. This is
* currently just used to handle a potentially read-only /boot by transiently
* remounting it read-write. In the future we might also do this for e.g.
* /sysroot.
*/
static gboolean
is_ro_mount (const char *path)
{
#ifdef HAVE_LIBMOUNT
/* Dragging in all of this crud is apparently necessary just to determine
* whether something is a mount point.
*
* Systemd has a totally different implementation in
* src/basic/mount-util.c.
*/
struct libmnt_table *tb = mnt_new_table_from_file ("/proc/self/mountinfo");
struct libmnt_fs *fs;
struct libmnt_cache *cache;
gboolean is_mount = FALSE;
struct statvfs stvfsbuf;
if (!tb)
return FALSE;
/* to canonicalize all necessary paths */
cache = mnt_new_cache ();
mnt_table_set_cache (tb, cache);
fs = mnt_table_find_target(tb, path, MNT_ITER_BACKWARD);
is_mount = fs && mnt_fs_get_target (fs);
#ifdef HAVE_MNT_UNREF_CACHE
mnt_unref_table (tb);
mnt_unref_cache (cache);
#else
mnt_free_table (tb);
mnt_free_cache (cache);
#endif
if (!is_mount)
return FALSE;
/* We *could* parse the options, but it seems more reliable to
* introspect the actual mount at runtime.
*/
if (statvfs (path, &stvfsbuf) == 0)
return (stvfsbuf.f_flag & ST_RDONLY) != 0;
#endif
return FALSE;
}
/**
* ostree_sysroot_write_deployments:
* @self: Sysroot
@@ -2309,6 +2255,7 @@ write_deployments_bootswap (OstreeSysroot *self,
OstreeSysrootWriteDeploymentsOpts *opts,
OstreeBootloader *bootloader,
SyncStats *out_syncstats,
char **out_subbootdir,
GCancellable *cancellable,
GError **error)
{
@@ -2356,7 +2303,8 @@ write_deployments_bootswap (OstreeSysroot *self,
new_deployments,
cancellable, error))
return FALSE;
if (!swap_bootlinks (self, new_bootversion, new_deployments,
g_autofree char *new_subbootdir = NULL;
if (!swap_bootlinks (self, new_bootversion, new_deployments, &new_subbootdir,
cancellable, error))
return FALSE;
@@ -2382,6 +2330,8 @@ write_deployments_bootswap (OstreeSysroot *self,
cancellable, error))
return FALSE;
if (out_subbootdir)
*out_subbootdir = g_steal_pointer (&new_subbootdir);
return TRUE;
}
@@ -2560,6 +2510,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
gboolean bootloader_is_atomic = FALSE;
SyncStats syncstats = { 0, };
g_autoptr(OstreeBootloader) bootloader = NULL;
g_autofree char *new_subbootdir = NULL;
if (!requires_new_bootversion)
{
if (!create_new_bootlinks (self, self->bootversion,
@@ -2571,7 +2522,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
return FALSE;
if (!swap_bootlinks (self, self->bootversion,
new_deployments,
new_deployments, &new_subbootdir,
cancellable, error))
return FALSE;
@@ -2579,49 +2530,21 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
}
else
{
gboolean boot_was_ro_mount = FALSE;
if (self->booted_deployment)
boot_was_ro_mount = is_ro_mount ("/boot");
g_debug ("boot is ro: %s", boot_was_ro_mount ? "yes" : "no");
if (boot_was_ro_mount)
{
if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
return glnx_throw_errno_prefix (error, "Remounting /boot read-write");
}
if (!_ostree_sysroot_query_bootloader (self, &bootloader, cancellable, error))
return FALSE;
bootloader_is_atomic = bootloader != NULL && _ostree_bootloader_is_atomic (bootloader);
/* Note equivalent of try/finally here */
gboolean success = write_deployments_bootswap (self, new_deployments, opts, bootloader,
&syncstats, cancellable, error);
/* Below here don't set GError until the if (!success) check.
* Note we only bother remounting if a mount namespace isn't in use.
* */
if (boot_was_ro_mount && !self->mount_namespace_in_use)
{
if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_RDONLY | MS_SILENT, NULL) < 0)
{
/* Only make this a warning because we don't want to
* completely bomb out if some other process happened to
* jump in and open a file there. See above TODO
* around doing this in a new mount namespace.
*/
g_printerr ("warning: Failed to remount /boot read-only: %s\n", strerror (errno));
}
}
if (!success)
if (!write_deployments_bootswap (self, new_deployments, opts, bootloader,
&syncstats, &new_subbootdir, cancellable, error))
return FALSE;
}
{ g_autofree char *msg =
g_strdup_printf ("%s; bootconfig swap: %s; deployment count change: %i",
g_strdup_printf ("%s; bootconfig swap: %s; bootversion: %s, deployment count change: %i",
(bootloader_is_atomic ? "Transaction complete" : "Bootloader updated"),
requires_new_bootversion ? "yes" : "no",
new_subbootdir,
new_deployments->len - self->deployments->len);
const gchar *bootloader_config = ostree_repo_get_bootloader (ostree_sysroot_repo (self));
ot_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_DEPLOYMENT_COMPLETE_ID),
@@ -3143,9 +3066,9 @@ ostree_sysroot_stage_tree_with_options (OstreeSysroot *self,
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;
OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (self);
OstreeDeployment *booted_deployment = ostree_sysroot_require_booted_deployment (self, error);
if (booted_deployment == NULL)
return glnx_throw (error, "Cannot stage a deployment when not currently booted into an OSTree system");
return glnx_prefix_error (error, "Cannot stage deployment");
/* This is used by the testsuite to exercise the path unit, until it becomes the default
* (which is pending on the preset making it everywhere). */
+4
View File
@@ -56,6 +56,7 @@ struct OstreeSysroot {
GFile *path;
int sysroot_fd;
int boot_fd;
GLnxLockFile lock;
OstreeSysrootLoadState loadstate;
@@ -160,6 +161,9 @@ char * _ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const ch
char *_ostree_sysroot_join_lines (GPtrArray *lines);
gboolean
_ostree_sysroot_ensure_boot_fd (OstreeSysroot *self, GError **error);
gboolean _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
OstreeBootloader **out_bootloader,
GCancellable *cancellable,
+83 -12
View File
@@ -198,6 +198,7 @@ ostree_sysroot_init (OstreeSysroot *self)
keys, G_N_ELEMENTS (keys));
self->sysroot_fd = -1;
self->boot_fd = -1;
}
/**
@@ -278,6 +279,44 @@ ensure_sysroot_fd (OstreeSysroot *self,
&self->sysroot_fd, error))
return FALSE;
}
return TRUE;
}
gboolean
_ostree_sysroot_ensure_boot_fd (OstreeSysroot *self, GError **error)
{
if (self->boot_fd == -1)
{
if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE,
&self->boot_fd, error))
return FALSE;
}
return TRUE;
}
static gboolean
remount_writable (const char *path, gboolean *did_remount, GError **error)
{
*did_remount = FALSE;
struct statvfs stvfsbuf;
if (statvfs (path, &stvfsbuf) < 0)
{
if (errno != ENOENT)
return glnx_throw_errno_prefix (error, "statvfs(%s)", path);
else
return TRUE;
}
if ((stvfsbuf.f_flag & ST_RDONLY) != 0)
{
/* OK, let's remount writable. */
if (mount (path, path, NULL, MS_REMOUNT | MS_RELATIME, "") < 0)
return glnx_throw_errno_prefix (error, "Remounting %s read-write", path);
*did_remount = TRUE;
g_debug ("remounted %s writable", path);
}
return TRUE;
}
@@ -300,19 +339,19 @@ _ostree_sysroot_ensure_writable (OstreeSysroot *self,
if (!self->root_is_ostree_booted)
return TRUE;
/* Check if /sysroot is a read-only mountpoint */
struct statvfs stvfsbuf;
if (statvfs ("/sysroot", &stvfsbuf) < 0)
return glnx_throw_errno_prefix (error, "fstatvfs(/sysroot)");
if ((stvfsbuf.f_flag & ST_RDONLY) == 0)
return TRUE;
/* In these cases we also require /boot */
if (!_ostree_sysroot_ensure_boot_fd (self, error))
return FALSE;
/* OK, let's remount writable. */
if (mount ("/sysroot", "/sysroot", NULL, MS_REMOUNT | MS_RELATIME, "") < 0)
return glnx_throw_errno_prefix (error, "Remounting /sysroot read-write");
gboolean did_remount_sysroot = FALSE;
if (!remount_writable ("/sysroot", &did_remount_sysroot, error))
return FALSE;
gboolean did_remount_boot = FALSE;
if (!remount_writable ("/boot", &did_remount_boot, error))
return FALSE;
/* Reopen our fd */
glnx_close_fd (&self->sysroot_fd);
/* Now close and reopen our file descriptors */
ostree_sysroot_unload (self);
if (!ensure_sysroot_fd (self, error))
return FALSE;
@@ -380,6 +419,7 @@ void
ostree_sysroot_unload (OstreeSysroot *self)
{
glnx_close_fd (&self->sysroot_fd);
glnx_close_fd (&self->boot_fd);
}
/**
@@ -449,6 +489,7 @@ _ostree_sysroot_parse_deploy_path_name (const char *name,
return TRUE;
}
/* For a given bootversion, get its subbootversion from `/ostree/boot.$bootversion`. */
gboolean
_ostree_sysroot_read_current_subbootversion (OstreeSysroot *self,
int bootversion,
@@ -465,6 +506,7 @@ _ostree_sysroot_read_current_subbootversion (OstreeSysroot *self,
return FALSE;
if (errno == ENOENT)
{
g_debug ("Didn't find $sysroot/ostree/boot.%d symlink; assuming subbootversion 0", bootversion);
*out_subbootversion = 0;
}
else
@@ -516,6 +558,7 @@ compare_loader_configs_for_sorting (gconstpointer a_pp,
return compare_boot_loader_configs (a, b);
}
/* Read all the bootconfigs from `/boot/loader/`. */
gboolean
_ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
int bootversion,
@@ -574,6 +617,7 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
return TRUE;
}
/* Get the bootversion from the `/boot/loader` symlink. */
static gboolean
read_current_bootversion (OstreeSysroot *self,
int *out_bootversion,
@@ -587,6 +631,7 @@ read_current_bootversion (OstreeSysroot *self,
return FALSE;
if (errno == ENOENT)
{
g_debug ("Didn't find $sysroot/boot/loader symlink; assuming bootversion 0");
ret_bootversion = 0;
}
else
@@ -698,7 +743,7 @@ parse_deployment (OstreeSysroot *self,
return FALSE;
g_autofree char *errprefix =
g_strdup_printf ("Parsing deployment %i in stateroot '%s'", treebootserial, osname);
g_strdup_printf ("Parsing deployment %s in stateroot '%s'", boot_link, osname);
GLNX_AUTO_PREFIX_ERROR(errprefix, error);
const char *relative_boot_link = boot_link;
@@ -799,6 +844,8 @@ get_ostree_kernel_arg_from_config (OstreeBootconfigParser *config)
return NULL;
}
/* From a BLS config, use its ostree= karg to find the deployment it points to and add it to
* the inout_deployments array. */
static gboolean
list_deployments_process_one_boot_entry (OstreeSysroot *self,
OstreeBootconfigParser *config,
@@ -1016,6 +1063,9 @@ _ostree_sysroot_reload_staged (OstreeSysroot *self,
return TRUE;
}
/* Loads the current bootversion, subbootversion, and deplyments, starting from the
* bootloader configs which are the source of truth.
*/
static gboolean
sysroot_load_from_bootloader_configs (OstreeSysroot *self,
GCancellable *cancellable,
@@ -1196,6 +1246,27 @@ ostree_sysroot_get_booted_deployment (OstreeSysroot *self)
return self->booted_deployment;
}
/**
* ostree_sysroot_require_booted_deployment:
* @self: Sysroot
*
* Find the booted deployment, or return an error if not booted via OSTree.
*
* Returns: (transfer none) (not nullable): The currently booted deployment, or an error
* Since: 2021.1
*/
OstreeDeployment *
ostree_sysroot_require_booted_deployment (OstreeSysroot *self, GError **error)
{
g_return_val_if_fail (self->loadstate == OSTREE_SYSROOT_LOAD_STATE_LOADED, NULL);
if (!self->booted_deployment)
return glnx_null_throw (error, "Not currently booted into an OSTree system");
return self->booted_deployment;
}
/**
* ostree_sysroot_get_staged_deployment:
* @self: Sysroot
+3
View File
@@ -85,6 +85,9 @@ GPtrArray *ostree_sysroot_get_deployments (OstreeSysroot *self);
_OSTREE_PUBLIC
OstreeDeployment *ostree_sysroot_get_booted_deployment (OstreeSysroot *self);
_OSTREE_PUBLIC
OstreeDeployment *
ostree_sysroot_require_booted_deployment (OstreeSysroot *self, GError **error);
_OSTREE_PUBLIC
OstreeDeployment *ostree_sysroot_get_staged_deployment (OstreeSysroot *self);
_OSTREE_PUBLIC
+5 -5
View File
@@ -34,7 +34,7 @@
*
* Since: 2017.4
*/
#define OSTREE_YEAR_VERSION (2020)
#define OSTREE_YEAR_VERSION (2021)
/**
* OSTREE_RELEASE_VERSION:
@@ -43,7 +43,7 @@
*
* Since: 2017.4
*/
#define OSTREE_RELEASE_VERSION (8)
#define OSTREE_RELEASE_VERSION (1)
/**
* OSTREE_VERSION
@@ -52,7 +52,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION (2020.8)
#define OSTREE_VERSION (2021.1)
/**
* OSTREE_VERSION_S:
@@ -62,7 +62,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION_S "2020.8"
#define OSTREE_VERSION_S "2021.1"
#define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release))
@@ -100,4 +100,4 @@
*
* Since: 2019.3
*/
#define OSTREE_BUILT_FEATURES "libsoup gpgme ex-fsverity libarchive selinux avahi libmount systemd release p2p"
#define OSTREE_BUILT_FEATURES "libsoup gpgme ex-fsverity libarchive selinux libmount systemd release p2p"
+1
View File
@@ -24,6 +24,7 @@
#include <ostree-async-progress.h>
#include <ostree-core.h>
#include <ostree-repo.h>
#include <ostree-repo-os.h>
#include <ostree-mutable-tree.h>
#include <ostree-remote.h>
#include <ostree-repo-file.h>