New upstream version 2018.5

This commit is contained in:
Simon McVittie committed 2018-05-15 11:05:08 +01:00
commit 144d8ab093
74 files changed
+2347 -4165

No files matched your search

+36
View File
@@ -0,0 +1,36 @@
# Copyright (C) 2018 Red Hat, Inc.
#
# 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.
# For some implementation discussion, see:
# https://lists.freedesktop.org/archives/systemd-devel/2018-March/040557.html
[Unit]
Description=OSTree Finalize Staged Deployment
ConditionPathExists=/run/ostree-booted
DefaultDependencies=no
RequiresMountsFor=/sysroot
After=basic.target
Before=multi-user.target final.target
Conflicts=final.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStop=/usr/bin/ostree admin finalize-staged
[Install]
WantedBy=multi-user.target
-2
View File
@@ -18,8 +18,6 @@
***/
/* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2018.5 {
} LIBOSTREE_2018.3;
/* Stub section for the stable release *after* this development one; don't
* edit this other than to update the last number. This is just a copy/paste
-4
View File
@@ -94,8 +94,4 @@ LIBOSTREE_2017.14_EXPERIMENTAL {
global:
ostree_remote_get_type;
ostree_remote_get_url;
ostree_repo_auto_lock_cleanup;
ostree_repo_auto_lock_push;
ostree_repo_lock_pop;
ostree_repo_lock_push;
} LIBOSTREE_2017.13_EXPERIMENTAL;
+9
View File
@@ -464,6 +464,15 @@ LIBOSTREE_2018.3 {
ostree_deployment_is_pinned;
} LIBOSTREE_2018.2;
LIBOSTREE_2018.5 {
ostree_sysroot_stage_tree;
ostree_sysroot_get_staged_deployment;
ostree_deployment_is_staged;
ostree_repo_traverse_new_parents;
ostree_repo_traverse_parents_get_commits;
ostree_repo_traverse_commit_union_with_parents;
} LIBOSTREE_2018.3;
/* NOTE: Only add more content here in release commits! See the
* comments at the top of this file.
*/
-1
View File
@@ -61,7 +61,6 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysrootUpgrader, g_object_unref)
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (OstreeRepoCommitTraverseIter, ostree_repo_commit_traverse_iter_clear)
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, ostree_repo_auto_lock_cleanup)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeCollectionRef, ostree_collection_ref_free)
G_DEFINE_AUTO_CLEANUP_FREE_FUNC (OstreeCollectionRefv, ostree_collection_ref_freev, NULL)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRemote, ostree_remote_unref)
+3 -2
View File
@@ -26,7 +26,7 @@
#include "ostree-core-private.h"
#include "ostree-repo-pull-private.h"
#include "ostree-repo-static-delta-private.h"
#include "ostree-sysroot.h"
#include "ostree-sysroot-private.h"
#include "ostree-bootloader-grub2.h"
#include "otutil.h"
@@ -52,7 +52,8 @@ ostree_cmd__private__ (void)
_ostree_repo_static_delta_dump,
_ostree_repo_static_delta_query_exists,
_ostree_repo_static_delta_delete,
_ostree_repo_verify_bindings
_ostree_repo_verify_bindings,
_ostree_sysroot_finalize_staged,
};
return &table;
+1
View File
@@ -34,6 +34,7 @@ typedef struct {
gboolean (* ostree_static_delta_query_exists) (OstreeRepo *repo, const char *delta_id, gboolean *out_exists, GCancellable *cancellable, GError **error);
gboolean (* ostree_static_delta_delete) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error);
gboolean (* ostree_repo_verify_bindings) (const char *collection_id, const char *ref_name, GVariant *commit, GError **error);
gboolean (* ostree_finalize_staged) (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
} OstreeCmdPrivateVTable;
/* Note this not really "public", we just export the symbol, but not the header */
@@ -36,6 +36,7 @@ G_BEGIN_DECLS
* @bootconfig: Bootloader configuration
* @origin: How to construct an upgraded version of this tree
* @unlocked: The unlocked state
* @staged: TRUE iff this deployment is staged
*/
struct _OstreeDeployment
{
@@ -50,6 +51,7 @@ struct _OstreeDeployment
OstreeBootconfigParser *bootconfig;
GKeyFile *origin;
OstreeDeploymentUnlockedState unlocked;
gboolean staged;
};
void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum);
+13
View File
@@ -339,3 +339,16 @@ ostree_deployment_is_pinned (OstreeDeployment *self)
return FALSE;
return g_key_file_get_boolean (self->origin, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL);
}
/**
* ostree_deployment_is_staged:
* @self: Deployment
*
* Returns: `TRUE` if deployment should be "finalized" at shutdown time
* Since: 2018.3
*/
gboolean
ostree_deployment_is_staged (OstreeDeployment *self)
{
return self->staged;
}
+2 -1
View File
@@ -73,7 +73,8 @@ OstreeBootconfigParser *ostree_deployment_get_bootconfig (OstreeDeployment *self
_OSTREE_PUBLIC
GKeyFile *ostree_deployment_get_origin (OstreeDeployment *self);
_OSTREE_PUBLIC
gboolean ostree_deployment_is_staged (OstreeDeployment *self);
_OSTREE_PUBLIC
gboolean ostree_deployment_is_pinned (OstreeDeployment *self);
+41 -31
View File
@@ -598,27 +598,26 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
}
static gboolean
_check_support_reflink (OstreeRepo *self, gboolean *supported, GError **error)
_check_support_reflink (OstreeRepo *dest, gboolean *supported, GError **error)
{
/* We have not checked yet if the file system supports reflinks, do it here */
if (g_atomic_int_get (&self->fs_support_reflink) == 0)
/* We have not checked yet if the destination file system supports reflinks, do it here */
if (g_atomic_int_get (&dest->fs_support_reflink) == 0)
{
g_auto(GLnxTmpfile) src_tmpf = { 0, };
glnx_autofd int src_fd = -1;
g_auto(GLnxTmpfile) dest_tmpf = { 0, };
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_RDWR|O_CLOEXEC,
&src_tmpf, error))
if (!glnx_openat_rdonly (dest->repo_dir_fd, "config", TRUE, &src_fd, error))
return FALSE;
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_WRONLY|O_CLOEXEC,
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (dest), ".", O_WRONLY|O_CLOEXEC,
&dest_tmpf, error))
return FALSE;
if (ioctl (dest_tmpf.fd, FICLONE, src_tmpf.fd) == 0)
g_atomic_int_set (&self->fs_support_reflink, 1);
if (ioctl (dest_tmpf.fd, FICLONE, src_fd) == 0)
g_atomic_int_set (&dest->fs_support_reflink, 1);
else if (errno == EOPNOTSUPP) /* Ignore other kind of errors as they might be temporary failures */
g_atomic_int_set (&self->fs_support_reflink, -1);
g_atomic_int_set (&dest->fs_support_reflink, -1);
}
*supported = g_atomic_int_get (&self->fs_support_reflink) >= 0;
*supported = g_atomic_int_get (&dest->fs_support_reflink) >= 0;
return TRUE;
}
@@ -631,6 +630,7 @@ _create_payload_link (OstreeRepo *self,
GError **error)
{
gboolean reflinks_supported = FALSE;
if (!_check_support_reflink (self, &reflinks_supported, error))
return FALSE;
@@ -664,8 +664,8 @@ _create_payload_link (OstreeRepo *self,
}
static gboolean
_import_payload_link (OstreeRepo *self,
OstreeRepo *source,
_import_payload_link (OstreeRepo *dest_repo,
OstreeRepo *src_repo,
const char *checksum,
GCancellable *cancellable,
GError **error)
@@ -676,20 +676,24 @@ _import_payload_link (OstreeRepo *self,
glnx_unref_object OtChecksumInstream *checksum_payload = NULL;
g_autoptr(GFileInfo) file_info = NULL;
if (!_check_support_reflink (self, &reflinks_supported, error))
/* The two repositories are on different devices */
if (src_repo->device != dest_repo->device)
return TRUE;
if (!_check_support_reflink (dest_repo, &reflinks_supported, error))
return FALSE;
if (!reflinks_supported)
return TRUE;
if (!G_IN_SET(self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY))
if (!G_IN_SET(dest_repo->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY))
return TRUE;
if (!ostree_repo_load_file (source, checksum, &is, &file_info, NULL, cancellable, error))
if (!ostree_repo_load_file (src_repo, checksum, &is, &file_info, NULL, cancellable, error))
return FALSE;
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR
|| g_file_info_get_size (file_info) < self->payload_link_threshold)
|| g_file_info_get_size (file_info) < dest_repo->payload_link_threshold)
return TRUE;
checksum_payload = ot_checksum_instream_new (is, G_CHECKSUM_SHA256);
@@ -706,11 +710,12 @@ _import_payload_link (OstreeRepo *self,
}
payload_checksum = ot_checksum_instream_get_string (checksum_payload);
return _create_payload_link (self, checksum, payload_checksum, file_info, cancellable, error);
return _create_payload_link (dest_repo, checksum, payload_checksum, file_info, cancellable, error);
}
static gboolean
_try_clone_from_payload_link (OstreeRepo *self,
OstreeRepo *dest_repo,
const char *payload_checksum,
GFileInfo *file_info,
GLnxTmpfile *tmpf,
@@ -722,7 +727,11 @@ _try_clone_from_payload_link (OstreeRepo *self,
if (self->commit_stagedir.initialized)
dfd_searches[0] = self->commit_stagedir.fd;
if (!_check_support_reflink (self, &reflinks_supported, error))
/* The two repositories are on different devices */
if (self->device != dest_repo->device)
return TRUE;
if (!_check_support_reflink (dest_repo, &reflinks_supported, error))
return FALSE;
if (!reflinks_supported)
@@ -778,7 +787,7 @@ _try_clone_from_payload_link (OstreeRepo *self,
}
}
if (self->parent_repo)
return _try_clone_from_payload_link (self->parent_repo, payload_checksum, file_info, tmpf, cancellable, error);
return _try_clone_from_payload_link (self->parent_repo, dest_repo, payload_checksum, file_info, tmpf, cancellable, error);
return TRUE;
}
@@ -1073,7 +1082,7 @@ write_content_object (OstreeRepo *self,
/* Check if a file with the same payload is present in the repository,
and in case try to reflink it */
if (actual_payload_checksum && !_try_clone_from_payload_link (self, actual_payload_checksum, file_info, &tmpf, cancellable, error))
if (actual_payload_checksum && !_try_clone_from_payload_link (self, self, actual_payload_checksum, file_info, &tmpf, cancellable, error))
return FALSE;
/* This path is for regular files */
@@ -1246,7 +1255,7 @@ write_metadata_object (OstreeRepo *self,
}
else
{
OtChecksum checksum = { 0, };
g_auto(OtChecksum) checksum = { 0, };
ot_checksum_init (&checksum);
gsize len;
const guint8*bufdata = g_bytes_get_data (buf, &len);
@@ -1440,7 +1449,8 @@ scan_loose_devino (OstreeRepo *self,
return FALSE;
}
if (self->mode == OSTREE_REPO_MODE_ARCHIVE)
if (self->mode == OSTREE_REPO_MODE_ARCHIVE &&
self->uncompressed_objects_dir_fd != -1)
{
if (!scan_one_loose_devino (self, self->uncompressed_objects_dir_fd, devino_cache,
cancellable, error))
@@ -1500,7 +1510,7 @@ devino_cache_lookup (OstreeRepo *self,
* There is an upfront cost to creating this mapping, as this will scan the
* entire objects directory. If your commit is composed of mostly hardlinks to
* existing ostree objects, then this will speed up considerably, so call it
* before you call ostree_write_directory_to_mtree() or similar. However,
* before you call ostree_repo_write_directory_to_mtree() or similar. However,
* ostree_repo_devino_cache_new() is better as it avoids scanning all objects.
*
* Multithreading: This function is *not* MT safe.
@@ -1541,10 +1551,9 @@ ostree_repo_scan_hardlinks (OstreeRepo *self,
* on a single `OstreeRepo` instance as long as their lifetime is bounded by the
* transaction.
*
* Locking: Acquires a `shared` lock; release via commit or abort
* Multithreading: This function is *not* MT safe; only one transaction can be
* active at a time.
*
* This function takes a shared lock on the @self repository.
*/
gboolean
ostree_repo_prepare_transaction (OstreeRepo *self,
@@ -1557,8 +1566,8 @@ ostree_repo_prepare_transaction (OstreeRepo *self,
memset (&self->txn.stats, 0, sizeof (OstreeRepoTransactionStats));
self->txn_locked = ostree_repo_lock_push (self, OSTREE_REPO_LOCK_SHARED,
cancellable, error);
self->txn_locked = _ostree_repo_lock_push (self, OSTREE_REPO_LOCK_SHARED,
cancellable, error);
if (!self->txn_locked)
return FALSE;
@@ -2070,6 +2079,7 @@ ostree_repo_set_collection_ref_immediate (OstreeRepo *self,
* Note that if multiple threads are performing writes, all such threads must
* have terminated before this function is invoked.
*
* Locking: Releases `shared` lock acquired by `ostree_repo_prepare_transaction()`
* Multithreading: This function is *not* MT safe; only one transaction can be
* active at a time.
*/
@@ -2126,7 +2136,7 @@ ostree_repo_commit_transaction (OstreeRepo *self,
if (self->txn_locked)
{
if (!ostree_repo_lock_pop (self, cancellable, error))
if (!_ostree_repo_lock_pop (self, cancellable, error))
return FALSE;
self->txn_locked = FALSE;
}
@@ -2179,7 +2189,7 @@ ostree_repo_abort_transaction (OstreeRepo *self,
if (self->txn_locked)
{
if (!ostree_repo_lock_pop (self, cancellable, error))
if (!_ostree_repo_lock_pop (self, cancellable, error))
return FALSE;
self->txn_locked = FALSE;
}
@@ -2216,7 +2226,7 @@ metadata_size_valid (OstreeObjectType objtype,
* @cancellable: Cancellable
* @error: Error
*
* Store the metadata object @variant. Return the checksum
* Store the metadata object @object. Return the checksum
* as @out_csum.
*
* If @expected_checksum is not %NULL, verify it against the
+10 -4
View File
@@ -844,7 +844,7 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService
}
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, OSTREE_REPO_FINDER (finder),
priority, supported_ref_to_checksum,
priority, supported_ref_to_checksum, NULL,
GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp))));
}
}
@@ -1437,9 +1437,15 @@ ostree_repo_finder_avahi_start (OstreeRepoFinderAvahi *self,
if (client == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create finder client: %s",
avahi_strerror (failure));
if (failure == AVAHI_ERR_NO_DAEMON)
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Avahi daemon is not running: %s",
avahi_strerror (failure));
else
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to create finder client: %s",
avahi_strerror (failure));
return;
}
+1 -1
View File
@@ -192,7 +192,7 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
continue;
}
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
}
g_ptr_array_sort (results, results_compare_cb);
+3 -2
View File
@@ -434,7 +434,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
g_array_sort (repos_refs, repo_and_refs_compare);
/* Also check the well-known special-case directories in the mount.
* Add them after sorting, so they’re always last. */
* Add them after sorting, so they’re always last.
* NOTE: If you change these, update the man page. */
const gchar * const well_known_repos[] =
{
".ostree/repo",
@@ -545,7 +546,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
* the code in ostree_repo_pull_from_remotes_async() will be able to
* check it just as quickly as we can here; so don’t duplicate the
* code. */
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
}
}
+1 -1
View File
@@ -243,7 +243,7 @@ ostree_repo_finder_override_resolve_async (OstreeRepoFinder *fi
g_hash_table_iter_init (&iter, repo_remote_to_refs);
while (g_hash_table_iter_next (&iter, (gpointer *) &remote, (gpointer *) &supported_ref_to_checksum))
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, 0));
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
g_ptr_array_sort (results, results_compare_cb);
+9 -3
View File
@@ -132,8 +132,8 @@ static void resolve_cb (GObject *obj,
* which the result provides. If the result provides the latest commit for a ref
* across all of the results, the checksum will be set. Otherwise, if the
* result provides an outdated commit, or doesn’t provide a given ref at all,
* the ref will not be set. Results which provide none of the requested @refs
* may be listed with an empty refs map.
* the checksum will not be set. Results which provide none of the requested
* @refs may be listed with an empty refs map.
*
* Pass the results to ostree_repo_pull_from_remotes_async() to pull the given
* @refs from those remotes.
@@ -436,6 +436,9 @@ G_DEFINE_BOXED_TYPE (OstreeRepoFinderResult, ostree_repo_finder_result,
* priority
* @ref_to_checksum: (element-type OstreeCollectionRef utf8) (transfer none):
* map of collection–ref pairs to checksums provided by this result
* @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable)
* (transfer none): map of collection–ref pairs to timestamps provided by this
* result
* @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when
* the summary file for the result was last modified, or `0` if this is unknown
*
@@ -450,6 +453,7 @@ ostree_repo_finder_result_new (OstreeRemote *remote,
OstreeRepoFinder *finder,
gint priority,
GHashTable *ref_to_checksum,
GHashTable *ref_to_timestamp,
guint64 summary_last_modified)
{
g_autoptr(OstreeRepoFinderResult) result = NULL;
@@ -463,6 +467,7 @@ ostree_repo_finder_result_new (OstreeRemote *remote,
result->finder = g_object_ref (finder);
result->priority = priority;
result->ref_to_checksum = g_hash_table_ref (ref_to_checksum);
result->ref_to_timestamp = ref_to_timestamp != NULL ? g_hash_table_ref (ref_to_timestamp) : NULL;
result->summary_last_modified = summary_last_modified;
return g_steal_pointer (&result);
@@ -484,7 +489,7 @@ ostree_repo_finder_result_dup (OstreeRepoFinderResult *result)
return ostree_repo_finder_result_new (result->remote, result->finder,
result->priority, result->ref_to_checksum,
result->summary_last_modified);
result->ref_to_timestamp, result->summary_last_modified);
}
/**
@@ -554,6 +559,7 @@ ostree_repo_finder_result_free (OstreeRepoFinderResult *result)
/* This may be NULL iff the result is freed half-way through find_remotes_cb()
* in ostree-repo-pull.c, and at no other time. */
g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref);
g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref);
g_object_unref (result->finder);
ostree_remote_unref (result->remote);
g_free (result);
+14 -1
View File
@@ -99,6 +99,8 @@ GPtrArray *ostree_repo_finder_resolve_all_finish (GAsyncResult *result,
* @ref_to_checksum: (element-type OstreeCollectionRef utf8): map of collection–ref
* pairs to checksums provided by this remote; values may be %NULL to
* indicate this remote doesn’t provide that ref
* @ref_to_timestamp: (element-type OstreeCollectionRef guint64) (nullable): map of
* collection–ref pairs to timestamps; values may be 0 for various reasons
* @summary_last_modified: Unix timestamp (seconds since the epoch, UTC) when
* the summary file on the remote was last modified, or `0` if unknown
*
@@ -122,6 +124,15 @@ GPtrArray *ostree_repo_finder_resolve_all_finish (GAsyncResult *result,
* should be available locally, so the details for each checksum can be looked
* up using ostree_repo_load_commit().
*
* @ref_to_timestamp provides timestamps for the set of refs in
* @ref_to_checksum. The refs are keys (of type #OstreeCollectionRef) and the
* values are guint64 pointers with the timestamp associated with the checksum
* provided in @ref_to_checksum. @ref_to_timestamp can be %NULL, and when it's
* not, the timestamps are zero when any of the following conditions are met:
* (1) the override-commit-ids option was used on
* ostree_repo_find_remotes_async (2) there was an error in trying to get the
* commit metadata (3) the checksum for this ref is %NULL in @ref_to_checksum.
*
* Since: 2017.8
*/
typedef struct
@@ -131,9 +142,10 @@ typedef struct
gint priority;
GHashTable *ref_to_checksum;
guint64 summary_last_modified;
GHashTable *ref_to_timestamp;
/*< private >*/
gpointer padding[4];
gpointer padding[3];
} OstreeRepoFinderResult;
_OSTREE_PUBLIC
@@ -144,6 +156,7 @@ OstreeRepoFinderResult *ostree_repo_finder_result_new (OstreeRemote *remote,
OstreeRepoFinder *finder,
gint priority,
GHashTable *ref_to_checksum,
GHashTable *ref_to_timestamp,
guint64 summary_last_modified);
_OSTREE_PUBLIC
OstreeRepoFinderResult *ostree_repo_finder_result_dup (OstreeRepoFinderResult *result);
+17 -15
View File
@@ -435,34 +435,36 @@ _ostree_repo_get_remote_inherited (OstreeRepo *self,
const char *name,
GError **error);
#ifndef OSTREE_ENABLE_EXPERIMENTAL_API
/* All the locking APIs below are duplicated in ostree-repo.h. Remove the ones
* here once it's no longer experimental.
/* Locking APIs are currently private.
* See https://github.com/ostreedev/ostree/pull/1555
*/
typedef enum {
OSTREE_REPO_LOCK_SHARED,
OSTREE_REPO_LOCK_EXCLUSIVE
} OstreeRepoLockType;
gboolean ostree_repo_lock_push (OstreeRepo *self,
gboolean _ostree_repo_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error);
gboolean ostree_repo_lock_pop (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
gboolean _ostree_repo_lock_pop (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
typedef OstreeRepo OstreeRepoAutoLock;
OstreeRepoAutoLock * ostree_repo_auto_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error);
void ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, ostree_repo_auto_lock_cleanup)
OstreeRepoAutoLock * _ostree_repo_auto_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error);
void _ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, _ostree_repo_auto_lock_cleanup)
#ifndef OSTREE_ENABLE_EXPERIMENTAL_API
/* These APIs are duplicated in the public headers when doing an
* experimental-API build.
*/
const gchar * ostree_repo_get_collection_id (OstreeRepo *self);
gboolean ostree_repo_set_collection_id (OstreeRepo *self,
const gchar *collection_id,
+6 -9
View File
@@ -193,7 +193,7 @@ _ostree_repo_prune_tmp (OstreeRepo *self,
* targeting that commit; otherwise any static delta of non existing commits are
* deleted.
*
* This function takes an exclusive lock on the @self repository.
* Locking: exclusive
*/
gboolean
ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
@@ -201,8 +201,7 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
GError **error)
{
g_autoptr(OstreeRepoAutoLock) lock =
ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable,
error);
_ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
if (!lock)
return FALSE;
@@ -327,7 +326,7 @@ repo_prune_internal (OstreeRepo *self,
* statistics on objects that would be deleted, without actually
* deleting them.
*
* This function takes an exclusive lock on the @self repository.
* Locking: exclusive
*/
gboolean
ostree_repo_prune (OstreeRepo *self,
@@ -340,8 +339,7 @@ ostree_repo_prune (OstreeRepo *self,
GError **error)
{
g_autoptr(OstreeRepoAutoLock) lock =
ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable,
error);
_ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
if (!lock)
return FALSE;
@@ -440,7 +438,7 @@ ostree_repo_prune (OstreeRepo *self,
* The %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE flag may be specified to just determine
* statistics on objects that would be deleted, without actually deleting them.
*
* This function takes an exclusive lock on the @self repository.
* Locking: exclusive
*/
gboolean
ostree_repo_prune_from_reachable (OstreeRepo *self,
@@ -452,8 +450,7 @@ ostree_repo_prune_from_reachable (OstreeRepo *self,
GError **error)
{
g_autoptr(OstreeRepoAutoLock) lock =
ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable,
error);
_ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
if (!lock)
return FALSE;
+98 -31
View File
@@ -2913,6 +2913,7 @@ repo_remote_fetch_summary (OstreeRepo *self,
GVariant *options,
GBytes **out_summary,
GBytes **out_signatures,
gboolean *out_from_cache,
GCancellable *cancellable,
GError **error)
{
@@ -3015,32 +3016,13 @@ repo_remote_fetch_summary (OstreeRepo *self,
goto out;
}
if (!from_cache && *out_summary && *out_signatures)
{
g_autoptr(GError) temp_error = NULL;
if (!_ostree_repo_cache_summary (self,
name,
*out_summary,
*out_signatures,
cancellable,
&temp_error))
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
g_debug ("No permissions to save summary cache");
else
{
g_propagate_error (error, g_steal_pointer (&temp_error));
goto out;
}
}
}
ret = TRUE;
out:
if (mainctx)
g_main_context_pop_thread_default (mainctx);
*out_from_cache = from_cache;
return ret;
}
@@ -4704,7 +4686,20 @@ ostree_repo_find_remotes_async (OstreeRepo *self,
if (local_error != NULL)
{
g_warning ("Avahi finder failed; removing it: %s", local_error->message);
/* See ostree-repo-finder-avahi.c:ostree_repo_finder_avahi_start, we
* intentionally throw this so as to distinguish between the Avahi
* finder failing because the Avahi daemon wasn't running and
* the Avahi finder failing because of some actual error.
*
* We need to distinguish between g_debug and g_warning here because
* unit tests that use this code may set G_DEBUG=fatal-warnings which
* would cause client code to abort if a warning were emitted.
*/
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
g_debug ("Avahi finder failed under normal operation; removing it: %s", local_error->message);
else
g_warning ("Avahi finder failed abnormally; removing it: %s", local_error->message);
default_finders[2] = NULL;
g_clear_object (&finder_avahi);
}
@@ -4764,7 +4759,7 @@ find_remotes_process_refs (OstreeRepo *self,
for (j = 0, n = g_variant_n_children (summary_refs); j < n; j++)
{
const guchar *csum_bytes;
g_autoptr(GVariant) ref_v = NULL, csum_v = NULL, commit_metadata_v = NULL, stored_commit_metadata_v = NULL;
g_autoptr(GVariant) ref_v = NULL, csum_v = NULL, commit_metadata_v = NULL, stored_commit_v = NULL;
guint64 commit_size, commit_timestamp;
gchar tmp_checksum[OSTREE_SHA256_STRING_LEN + 1];
gsize ref_index;
@@ -4801,9 +4796,9 @@ find_remotes_process_refs (OstreeRepo *self,
if (!collection_refv_contains (refs, summary_collection_id, ref_name, &ref_index))
continue;
/* Load the commit metadata from disk if possible, for verification. */
if (!ostree_repo_load_commit (self, tmp_checksum, &stored_commit_metadata_v, NULL, NULL))
stored_commit_metadata_v = NULL;
/* Load the commit from disk if possible, for verification. */
if (!ostree_repo_load_commit (self, tmp_checksum, &stored_commit_v, NULL, NULL))
stored_commit_v = NULL;
/* Check the additional metadata. */
if (!g_variant_lookup (commit_metadata_v, OSTREE_COMMIT_TIMESTAMP, "t", &commit_timestamp))
@@ -4826,7 +4821,7 @@ find_remotes_process_refs (OstreeRepo *self,
if (commit_metadata == NULL)
{
commit_metadata = commit_metadata_new (tmp_checksum, commit_size,
(stored_commit_metadata_v != NULL) ? ostree_commit_get_timestamp (stored_commit_metadata_v) : 0,
(stored_commit_v != NULL) ? ostree_commit_get_timestamp (stored_commit_v) : 0,
NULL);
g_hash_table_insert (commit_metadatas, commit_metadata->checksum,
commit_metadata /* transfer */);
@@ -4880,6 +4875,7 @@ find_remotes_cb (GObject *obj,
g_autoptr(GHashTable) commit_metadatas = NULL; /* (element-type commit-checksum CommitMetadata) */
g_autoptr(OstreeFetcher) fetcher = NULL;
g_autofree const gchar **ref_to_latest_commit = NULL; /* indexed as @refs; (element-type commit-checksum) */
g_autofree guint64 *ref_to_latest_timestamp = NULL; /* indexed as @refs; (element-type commit-timestamp) */
gsize n_refs;
g_autofree char **override_commit_ids = NULL;
g_autoptr(GPtrArray) remotes_to_remove = NULL; /* (element-type OstreeRemote) */
@@ -5035,6 +5031,7 @@ find_remotes_cb (GObject *obj,
* it’s been moved to @refs_and_remotes_table and is now potentially out
* of date. */
g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref);
g_clear_pointer (&result->ref_to_timestamp, g_hash_table_unref);
result->summary_last_modified = summary_last_modified;
}
@@ -5171,8 +5168,12 @@ find_remotes_cb (GObject *obj,
*
* @ref_to_latest_commit is indexed by @ref_index, and its values are the
* latest checksum for each ref. If override-commit-ids was used,
* @ref_to_latest_commit won't be initialized or used.*/
* @ref_to_latest_commit won't be initialized or used.
*
* @ref_to_latest_timestamp is also indexed by @ref_index, and its values are
* the latest timestamp for each ref, when available.*/
ref_to_latest_commit = g_new0 (const gchar *, n_refs);
ref_to_latest_timestamp = g_new0 (guint64, n_refs);
for (i = 0; i < n_refs; i++)
{
@@ -5213,6 +5214,11 @@ find_remotes_cb (GObject *obj,
* the summary or commit metadata files above. */
ref_to_latest_commit[i] = latest_checksum;
if (latest_checksum != NULL && latest_commit_metadata != NULL)
ref_to_latest_timestamp[i] = latest_commit_metadata->timestamp;
else
ref_to_latest_timestamp[i] = 0;
if (latest_commit_metadata != NULL)
{
latest_commit_timestamp_str = uint64_secs_to_iso8601 (latest_commit_metadata->timestamp);
@@ -5235,7 +5241,8 @@ find_remotes_cb (GObject *obj,
for (i = 0; i < results->len; i++)
{
OstreeRepoFinderResult *result = g_ptr_array_index (results, i);
g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type utf8 utf8) */
g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type OstreeCollectionRef utf8) */
g_autoptr(GHashTable) validated_ref_to_timestamp = NULL; /* (element-type OstreeCollectionRef guint64) */
gsize j, n_latest_refs;
/* Previous error processing this result? */
@@ -5249,11 +5256,24 @@ find_remotes_cb (GObject *obj,
(GDestroyNotify) ostree_collection_ref_free,
g_free);
validated_ref_to_timestamp = g_hash_table_new_full (ostree_collection_ref_hash,
ostree_collection_ref_equal,
(GDestroyNotify) ostree_collection_ref_free,
g_free);
if (override_commit_ids)
{
for (j = 0; refs[j] != NULL; j++)
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
g_strdup (override_commit_ids[j]));
{
guint64 *timestamp_ptr;
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
g_strdup (override_commit_ids[j]));
timestamp_ptr = g_malloc (sizeof (guint64));
*timestamp_ptr = 0;
g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]),
timestamp_ptr);
}
}
else
{
@@ -5262,6 +5282,7 @@ find_remotes_cb (GObject *obj,
for (j = 0; refs[j] != NULL; j++)
{
const gchar *latest_commit_for_ref = ref_to_latest_commit[j];
guint64 *timestamp_ptr;
if (pointer_table_get (refs_and_remotes_table, j, i) != latest_commit_for_ref)
latest_commit_for_ref = NULL;
@@ -5270,6 +5291,14 @@ find_remotes_cb (GObject *obj,
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]),
g_strdup (latest_commit_for_ref));
timestamp_ptr = g_malloc (sizeof (guint64));
if (latest_commit_for_ref != NULL)
*timestamp_ptr = GUINT64_TO_BE (ref_to_latest_timestamp[j]);
else
*timestamp_ptr = 0;
g_hash_table_insert (validated_ref_to_timestamp, ostree_collection_ref_dup (refs[j]),
timestamp_ptr);
}
if (n_latest_refs == 0)
@@ -5282,6 +5311,7 @@ find_remotes_cb (GObject *obj,
}
result->ref_to_checksum = g_steal_pointer (&validated_ref_to_checksum);
result->ref_to_timestamp = g_steal_pointer (&validated_ref_to_timestamp);
g_ptr_array_add (final_results, g_steal_pointer (&g_ptr_array_index (results, i)));
}
@@ -5396,6 +5426,13 @@ copy_option (GVariantDict *master_options,
* * `flags` (`i`): #OstreeRepoPullFlags to apply to the pull operation
* * `inherit-transaction` (`b`): %TRUE to inherit an ongoing transaction on
* the #OstreeRepo, rather than encapsulating the pull in a new one
* * `depth` (`i`): How far in the history to traverse; default is 0, -1 means infinite
* * `disable-static-deltas` (`b`): Do not use static deltas
* * `http-headers` (`a(ss)`): Additional headers to add to all HTTP requests
* * `subdirs` (`as`): Pull just these subdirectories
* * `update-frequency` (`u`): Frequency to call the async progress callback in
* milliseconds, if any; only values higher than 0 are valid
* * `append-user-agent` (`s`): Additional string to append to the user agent
*
* Since: 2017.8
*/
@@ -5756,6 +5793,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
g_autoptr(GBytes) signatures = NULL;
gboolean ret = FALSE;
gboolean gpg_verify_summary;
gboolean summary_is_from_cache;
g_return_val_if_fail (OSTREE_REPO (self), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
@@ -5770,6 +5808,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
options,
&summary,
&signatures,
&summary_is_from_cache,
cancellable,
error))
goto out;
@@ -5777,6 +5816,13 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
if (!ostree_repo_remote_get_gpg_verify_summary (self, name, &gpg_verify_summary, error))
goto out;
if (gpg_verify_summary && summary == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"GPG verification enabled, but no summary found (check that the configured URL in remote config is correct)");
goto out;
}
if (gpg_verify_summary && signatures == NULL)
{
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
@@ -5799,6 +5845,27 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
goto out;
}
if (!summary_is_from_cache && summary && signatures)
{
g_autoptr(GError) temp_error = NULL;
if (!_ostree_repo_cache_summary (self,
name,
summary,
signatures,
cancellable,
&temp_error))
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
g_debug ("No permissions to save summary cache");
else
{
g_propagate_error (error, g_steal_pointer (&temp_error));
goto out;
}
}
}
if (out_summary != NULL)
*out_summary = g_steal_pointer (&summary);
+50 -80
View File
@@ -104,11 +104,6 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
while (TRUE)
{
struct dirent *sub_dent;
const char *name1;
const char *name2;
g_autofree char *superblock_subpath = NULL;
struct stat stbuf;
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent,
cancellable, error))
return FALSE;
@@ -117,39 +112,33 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
if (dent->d_type != DT_DIR)
continue;
name1 = dent->d_name;
name2 = sub_dent->d_name;
const char *name1 = dent->d_name;
const char *name2 = sub_dent->d_name;
superblock_subpath = g_strconcat (name2, "/superblock", NULL);
if (fstatat (sub_dfd_iter.fd, superblock_subpath, &stbuf, 0) < 0)
{
if (errno != ENOENT)
{
glnx_set_error_from_errno (error);
return FALSE;
}
}
else
{
g_autofree char *buf = g_strconcat (name1, name2, NULL);
GString *out = g_string_new ("");
char checksum[OSTREE_SHA256_STRING_LEN+1];
guchar csum[OSTREE_SHA256_DIGEST_LEN];
const char *dash = strchr (buf, '-');
g_autofree char *superblock_subpath = g_strconcat (name2, "/superblock", NULL);
if (!glnx_fstatat_allow_noent (sub_dfd_iter.fd, superblock_subpath, NULL, 0, error))
return FALSE;
if (errno == ENOENT)
continue;
ostree_checksum_b64_inplace_to_bytes (buf, csum);
g_autofree char *buf = g_strconcat (name1, name2, NULL);
GString *out = g_string_new ("");
char checksum[OSTREE_SHA256_STRING_LEN+1];
guchar csum[OSTREE_SHA256_DIGEST_LEN];
const char *dash = strchr (buf, '-');
ostree_checksum_b64_inplace_to_bytes (buf, csum);
ostree_checksum_inplace_from_bytes (csum, checksum);
g_string_append (out, checksum);
if (dash)
{
g_string_append_c (out, '-');
ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
ostree_checksum_inplace_from_bytes (csum, checksum);
g_string_append (out, checksum);
if (dash)
{
g_string_append_c (out, '-');
ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
ostree_checksum_inplace_from_bytes (csum, checksum);
g_string_append (out, checksum);
}
g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
}
g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
}
}
@@ -320,13 +309,10 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
guint32 version;
guint64 size;
guint64 usize;
const guchar *csum;
char checksum[OSTREE_SHA256_STRING_LEN+1];
gboolean have_all;
g_autoptr(GVariant) csum_v = NULL;
g_autoptr(GVariant) objects = NULL;
g_autoptr(GVariant) part = NULL;
g_autofree char *deltapart_path = NULL;
OstreeStaticDeltaOpenFlags delta_open_flags =
skip_validation ? OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM : 0;
g_autoptr(GVariant) header = g_variant_get_child_value (headers, i);
@@ -335,6 +321,7 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
if (version > OSTREE_DELTAPART_VERSION)
return glnx_throw (error, "Delta part has too new version %u", version);
gboolean have_all;
if (!_ostree_repo_static_delta_part_have_all_objects (self, objects, &have_all,
cancellable, error))
return FALSE;
@@ -345,12 +332,12 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
if (have_all)
continue;
csum = ostree_checksum_bytes_peek_validate (csum_v, error);
const guchar *csum = ostree_checksum_bytes_peek_validate (csum_v, error);
if (!csum)
return FALSE;
ostree_checksum_inplace_from_bytes (csum, checksum);
deltapart_path =
g_autofree char *deltapart_path =
_ostree_get_relative_static_delta_part_path (from_checksum, to_checksum, i);
g_autoptr(GInputStream) part_in = NULL;
@@ -410,16 +397,14 @@ _ostree_static_delta_part_open (GInputStream *part_in,
{
const gboolean trusted = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_VARIANT_TRUSTED) > 0;
const gboolean skip_checksum = (flags & OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM) > 0;
gsize bytes_read;
guint8 comptype;
g_autoptr(GChecksum) checksum = NULL;
g_autoptr(GInputStream) checksum_in = NULL;
GInputStream *source_in;
/* We either take a fd or a GBytes reference */
g_return_val_if_fail (G_IS_FILE_DESCRIPTOR_BASED (part_in) || inline_part_bytes != NULL, FALSE);
g_return_val_if_fail (skip_checksum || expected_checksum != NULL, FALSE);
g_autoptr(GChecksum) checksum = NULL;
g_autoptr(GInputStream) checksum_in = NULL;
GInputStream *source_in;
if (!skip_checksum)
{
checksum = g_checksum_new (G_CHECKSUM_SHA256);
@@ -431,7 +416,9 @@ _ostree_static_delta_part_open (GInputStream *part_in,
source_in = part_in;
}
guint8 comptype;
{ guint8 buf[1];
gsize bytes_read;
/* First byte is compression type */
if (!g_input_stream_read_all (source_in, buf, sizeof(buf), &bytes_read,
cancellable, error))
@@ -511,7 +498,6 @@ show_one_part (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GVariant) part = NULL;
g_autofree char *part_path = _ostree_get_relative_static_delta_part_path (from, to, i);
guint32 version;
@@ -530,6 +516,7 @@ show_one_part (OstreeRepo *self,
return glnx_throw_errno_prefix (error, "openat(%s)", part_path);
g_autoptr(GInputStream) part_in = g_unix_input_stream_new (part_fd, FALSE);
g_autoptr(GVariant) part = NULL;
if (!_ostree_static_delta_part_open (part_in, NULL,
OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM,
NULL,
@@ -576,19 +563,13 @@ OstreeDeltaEndianness
_ostree_delta_get_endianness (GVariant *superblock,
gboolean *out_was_heuristic)
{
guint8 endianness_char;
g_autoptr(GVariant) delta_meta = NULL;
g_autoptr(GVariantDict) delta_metadict = NULL;
guint64 total_size = 0;
guint64 total_usize = 0;
guint total_objects = 0;
delta_meta = g_variant_get_child_value (superblock, 0);
delta_metadict = g_variant_dict_new (delta_meta);
g_autoptr(GVariant) delta_meta = g_variant_get_child_value (superblock, 0);
g_autoptr(GVariantDict) delta_metadict = g_variant_dict_new (delta_meta);
if (out_was_heuristic)
*out_was_heuristic = FALSE;
guint8 endianness_char;
if (g_variant_dict_lookup (delta_metadict, "ostree.endianness", "y", &endianness_char))
{
switch (endianness_char)
@@ -605,15 +586,16 @@ _ostree_delta_get_endianness (GVariant *superblock,
if (out_was_heuristic)
*out_was_heuristic = TRUE;
guint64 total_size = 0;
guint64 total_usize = 0;
guint total_objects = 0;
{ g_autoptr(GVariant) meta_entries = NULL;
guint n_parts;
guint i;
gboolean is_byteswapped = FALSE;
g_variant_get_child (superblock, 6, "@a" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT, &meta_entries);
n_parts = g_variant_n_children (meta_entries);
const guint n_parts = g_variant_n_children (meta_entries);
for (i = 0; i < n_parts; i++)
for (guint i = 0; i < n_parts; i++)
{
g_autoptr(GVariant) objects = NULL;
guint64 size, usize;
@@ -631,7 +613,7 @@ _ostree_delta_get_endianness (GVariant *superblock,
double ratio = ((double)size)/((double)usize);
/* This should really never happen where compressing things makes it more than 50% bigger.
*/
*/
if (ratio > 1.2)
{
is_byteswapped = TRUE;
@@ -724,26 +706,16 @@ _ostree_repo_static_delta_query_exists (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
g_autofree char *from = NULL;
g_autofree char *from = NULL;
g_autofree char *to = NULL;
struct stat stbuf;
if (!_ostree_parse_delta_name (delta_id, &from, &to, error))
return FALSE;
g_autofree char *superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
if (!glnx_fstatat_allow_noent (self->repo_dir_fd, superblock_path, NULL, 0, error))
return FALSE;
if (fstatat (self->repo_dir_fd, superblock_path, &stbuf, 0) < 0)
{
if (errno == ENOENT)
{
*out_exists = FALSE;
return TRUE;
}
else
return glnx_throw_errno_prefix (error, "fstatat(%s)", superblock_path);
}
*out_exists = TRUE;
*out_exists = (errno == 0);
return TRUE;
}
@@ -755,21 +727,15 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
{
g_autofree char *from = NULL;
g_autofree char *to = NULL;
g_autofree char *superblock_path = NULL;
g_autoptr(GVariant) delta_superblock = NULL;
guint64 total_size = 0, total_usize = 0;
guint64 total_fallback_size = 0, total_fallback_usize = 0;
OstreeDeltaEndianness endianness;
gboolean swap_endian = FALSE;
if (!_ostree_parse_delta_name (delta_id, &from, &to, error))
return FALSE;
superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
g_autofree char *superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
glnx_autofd int superblock_fd = -1;
if (!glnx_openat_rdonly (self->repo_dir_fd, superblock_path, TRUE, &superblock_fd, error))
return FALSE;
g_autoptr(GVariant) delta_superblock = NULL;
if (!ot_variant_read_fd (superblock_fd, 0,
(GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
TRUE, &delta_superblock, error))
@@ -777,6 +743,8 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
g_print ("Delta: %s\n", delta_id);
gboolean swap_endian = FALSE;
OstreeDeltaEndianness endianness;
{ const char *endianness_description;
gboolean was_heuristic;
@@ -823,6 +791,8 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
g_print ("Number of fallback entries: %u\n", n_fallback);
guint64 total_size = 0, total_usize = 0;
guint64 total_fallback_size = 0, total_fallback_usize = 0;
for (guint i = 0; i < n_fallback; i++)
{
guint64 size, usize;
+175 -14
View File
@@ -294,18 +294,141 @@ ostree_repo_traverse_new_reachable (void)
NULL, (GDestroyNotify)g_variant_unref);
}
/**
* ostree_repo_traverse_new_parents:
*
* This hash table is a mapping from #GVariant which can be accessed
* via ostree_object_name_deserialize() to a #GVariant containing either
* a similar #GVariant or and array of them, listing the parents of the key.
*
* Returns: (transfer container) (element-type GVariant GVariant): A new hash table
*
* Since: 2018.5
*/
GHashTable *
ostree_repo_traverse_new_parents (void)
{
return g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
(GDestroyNotify)g_variant_unref, (GDestroyNotify)g_variant_unref);
}
static void
parents_get_commits (GHashTable *parents_ht, GVariant *object, GHashTable *res)
{
const char *checksum;
OstreeObjectType type;
if (object == NULL)
return;
ostree_object_name_deserialize (object, &checksum, &type);
if (type == OSTREE_OBJECT_TYPE_COMMIT)
g_hash_table_add (res, g_strdup (checksum));
else
{
GVariant *parents = g_hash_table_lookup (parents_ht, object);
if (parents == NULL)
g_debug ("Unexpected NULL parent");
else if (g_variant_is_of_type (parents, G_VARIANT_TYPE_ARRAY))
{
gsize i, len = g_variant_n_children (parents);
for (i = 0; i < len; i++)
{
g_autoptr(GVariant) parent = g_variant_get_child_value (parents, i);
parents_get_commits (parents_ht, parent, res);
}
}
else
parents_get_commits (parents_ht, parents, res);
}
}
/**
* ostree_repo_traverse_parents_get_commits:
*
* Gets all the commits that a certain object belongs to, as recorded
* by a parents table gotten from ostree_repo_traverse_commit_union_with_parents.
*
* Returns: (transfer full) (array zero-terminated=1): An array of checksums for
* the commits the key belongs to.
*
* Since: 2018.5
*/
char **
ostree_repo_traverse_parents_get_commits (GHashTable *parents, GVariant *object)
{
g_autoptr(GHashTable) res = g_hash_table_new (g_str_hash, g_str_equal);
parents_get_commits (parents, object, res);
return (char **)g_hash_table_get_keys_as_array (res, NULL);
}
static gboolean
traverse_dirtree (OstreeRepo *repo,
const char *checksum,
GVariant *parent_key,
GHashTable *inout_reachable,
GHashTable *inout_parents,
gboolean ignore_missing_dirs,
GCancellable *cancellable,
GError **error);
static void
add_parent_ref (GHashTable *inout_parents,
GVariant *key,
GVariant *parent_key)
{
GVariant *old_parents;
if (inout_parents == NULL)
return;
old_parents = g_hash_table_lookup (inout_parents, key);
if (old_parents == NULL)
{
/* For the common case of a single pointer we skip using an array to save memory. */
g_hash_table_insert (inout_parents, g_variant_ref (key), g_variant_ref (parent_key));
}
else
{
g_autofree GVariant **new_parents = NULL;
gsize i, len = 0;
if (g_variant_is_of_type (old_parents, G_VARIANT_TYPE_ARRAY))
{
gsize old_parents_len = g_variant_n_children (old_parents);
new_parents = g_new (GVariant *, old_parents_len + 1);
for (i = 0; i < old_parents_len ; i++)
{
g_autoptr(GVariant) old_parent = g_variant_get_child_value (old_parents, i);
if (!g_variant_equal (old_parent, parent_key))
new_parents[len++] = g_steal_pointer (&old_parent);
}
}
else
{
new_parents = g_new (GVariant *, 2);
if (!g_variant_equal (old_parents, parent_key))
new_parents[len++] = g_variant_ref (old_parents);
}
new_parents[len++] = g_variant_ref (parent_key);
g_hash_table_insert (inout_parents, g_variant_ref (key),
g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(su)"), new_parents , len)));
for (i = 0; i < len; i++)
g_variant_unref (new_parents[i]);
}
}
static gboolean
traverse_iter (OstreeRepo *repo,
OstreeRepoCommitTraverseIter *iter,
GVariant *parent_key,
GHashTable *inout_reachable,
GHashTable *inout_parents,
gboolean ignore_missing_dirs,
GCancellable *cancellable,
GError **error)
@@ -343,6 +466,7 @@ traverse_iter (OstreeRepo *repo,
g_debug ("Found file object %s", checksum);
key = g_variant_ref_sink (ostree_object_name_serialize (checksum, OSTREE_OBJECT_TYPE_FILE));
add_parent_ref (inout_parents, key, parent_key);
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
}
else if (iterres == OSTREE_REPO_COMMIT_ITER_RESULT_DIR)
@@ -357,16 +481,18 @@ traverse_iter (OstreeRepo *repo,
g_debug ("Found dirtree object %s", content_checksum);
g_debug ("Found dirmeta object %s", meta_checksum);
key = g_variant_ref_sink (ostree_object_name_serialize (meta_checksum, OSTREE_OBJECT_TYPE_DIR_META));
add_parent_ref (inout_parents, key, parent_key);
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
key = g_variant_ref_sink (ostree_object_name_serialize (content_checksum, OSTREE_OBJECT_TYPE_DIR_TREE));
add_parent_ref (inout_parents, key, parent_key);
if (!g_hash_table_lookup (inout_reachable, key))
{
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
if (!traverse_dirtree (repo, content_checksum, inout_reachable,
if (!traverse_dirtree (repo, content_checksum, key, inout_reachable, inout_parents,
ignore_missing_dirs, cancellable, error))
return FALSE;
g_hash_table_add (inout_reachable, g_steal_pointer (&key));
}
}
else
@@ -379,7 +505,9 @@ traverse_iter (OstreeRepo *repo,
static gboolean
traverse_dirtree (OstreeRepo *repo,
const char *checksum,
GVariant *parent_key,
GHashTable *inout_reachable,
GHashTable *inout_parents,
gboolean ignore_missing_dirs,
GCancellable *cancellable,
GError **error)
@@ -409,31 +537,39 @@ traverse_dirtree (OstreeRepo *repo,
error))
return FALSE;
if (!traverse_iter (repo, &iter, inout_reachable, ignore_missing_dirs, cancellable, error))
if (!traverse_iter (repo, &iter, parent_key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error))
return FALSE;
return TRUE;
}
/**
* ostree_repo_traverse_commit_union: (skip)
* ostree_repo_traverse_commit_union_with_parents: (skip)
* @repo: Repo
* @commit_checksum: ASCII SHA256 checksum
* @maxdepth: Traverse this many parent commits, -1 for unlimited
* @inout_reachable: Set of reachable objects
* @inout_parents: Map from object to parent object
* @cancellable: Cancellable
* @error: Error
*
* Update the set @inout_reachable containing all objects reachable
* from @commit_checksum, traversing @maxdepth parent commits.
*
* Additionally this constructs a mapping from each object to the parents
* of the object, which can be used to track which commits an object
* belongs to.
*
* Since: 2018.5
*/
gboolean
ostree_repo_traverse_commit_union (OstreeRepo *repo,
const char *commit_checksum,
int maxdepth,
GHashTable *inout_reachable,
GCancellable *cancellable,
GError **error)
ostree_repo_traverse_commit_union_with_parents (OstreeRepo *repo,
const char *commit_checksum,
int maxdepth,
GHashTable *inout_reachable,
GHashTable *inout_parents,
GCancellable *cancellable,
GError **error)
{
g_autofree char *tmp_checksum = NULL;
@@ -467,8 +603,7 @@ ostree_repo_traverse_commit_union (OstreeRepo *repo,
if ((commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) != 0)
ignore_missing_dirs = TRUE;
g_hash_table_add (inout_reachable, key);
key = NULL;
g_hash_table_add (inout_reachable, g_variant_ref (key));
g_debug ("Traversing commit %s", commit_checksum);
ostree_cleanup_repo_commit_traverse_iter
@@ -478,7 +613,7 @@ ostree_repo_traverse_commit_union (OstreeRepo *repo,
error))
return FALSE;
if (!traverse_iter (repo, &iter, inout_reachable, ignore_missing_dirs, cancellable, error))
if (!traverse_iter (repo, &iter, key, inout_reachable, inout_parents, ignore_missing_dirs, cancellable, error))
return FALSE;
gboolean recurse = FALSE;
@@ -501,6 +636,32 @@ ostree_repo_traverse_commit_union (OstreeRepo *repo,
return TRUE;
}
/**
* ostree_repo_traverse_commit_union: (skip)
* @repo: Repo
* @commit_checksum: ASCII SHA256 checksum
* @maxdepth: Traverse this many parent commits, -1 for unlimited
* @inout_reachable: Set of reachable objects
* @cancellable: Cancellable
* @error: Error
*
* Update the set @inout_reachable containing all objects reachable
* from @commit_checksum, traversing @maxdepth parent commits.
*/
gboolean
ostree_repo_traverse_commit_union (OstreeRepo *repo,
const char *commit_checksum,
int maxdepth,
GHashTable *inout_reachable,
GCancellable *cancellable,
GError **error)
{
return
ostree_repo_traverse_commit_union_with_parents (repo, commit_checksum, maxdepth,
inout_reachable, NULL,
cancellable, error);
}
/**
* ostree_repo_traverse_commit:
* @repo: Repo
+37 -35
View File
@@ -436,7 +436,7 @@ pop_repo_lock (OstreeRepo *self,
return TRUE;
}
/**
/*
* ostree_repo_lock_push:
* @self: a #OstreeRepo
* @lock_type: the type of lock to acquire
@@ -462,13 +462,12 @@ pop_repo_lock (OstreeRepo *self,
* %TRUE is returned.
*
* Returns: %TRUE on success, otherwise %FALSE with @error set
* Since: 2017.14
*/
gboolean
ostree_repo_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error)
_ostree_repo_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
@@ -531,8 +530,8 @@ ostree_repo_lock_push (OstreeRepo *self,
}
}
/**
* ostree_repo_lock_pop:
/*
* _ostree_repo_lock_pop:
* @self: a #OstreeRepo
* @cancellable: a #GCancellable
* @error: a #GError
@@ -553,12 +552,11 @@ ostree_repo_lock_push (OstreeRepo *self,
* %TRUE is returned.
*
* Returns: %TRUE on success, otherwise %FALSE with @error set
* Since: 2017.14
*/
gboolean
ostree_repo_lock_pop (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
_ostree_repo_lock_pop (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
@@ -621,8 +619,8 @@ ostree_repo_lock_pop (OstreeRepo *self,
}
}
/**
* ostree_repo_auto_lock_push: (skip)
/*
* _ostree_repo_auto_lock_push: (skip)
* @self: a #OstreeRepo
* @lock_type: the type of lock to acquire
* @cancellable: a #GCancellable
@@ -636,37 +634,34 @@ ostree_repo_lock_pop (OstreeRepo *self,
*
* |[<!-- language="C" -->
* g_autoptr(OstreeRepoAutoLock) lock = NULL;
* lock = ostree_repo_auto_lock_push (repo, lock_type, cancellable, error);
* lock = _ostree_repo_auto_lock_push (repo, lock_type, cancellable, error);
* if (!lock)
* return FALSE;
* ]|
*
* Returns: @self on success, otherwise %NULL with @error set
* Since: 2017.14
*/
OstreeRepoAutoLock *
ostree_repo_auto_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error)
_ostree_repo_auto_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error)
{
if (!ostree_repo_lock_push (self, lock_type, cancellable, error))
if (!_ostree_repo_lock_push (self, lock_type, cancellable, error))
return NULL;
return (OstreeRepoAutoLock *)self;
}
/**
* ostree_repo_auto_lock_cleanup: (skip)
/*
* _ostree_repo_auto_lock_cleanup: (skip)
* @lock: a #OstreeRepoAutoLock
*
* A cleanup handler for use with ostree_repo_auto_lock_push(). If @lock is
* not %NULL, ostree_repo_lock_pop() will be called on it. If
* ostree_repo_lock_pop() fails, a critical warning will be emitted.
*
* Since: 2017.14
*/
void
ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock)
_ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock)
{
OstreeRepo *repo = lock;
if (repo)
@@ -674,7 +669,7 @@ ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock)
g_autoptr(GError) error = NULL;
int errsv = errno;
if (!ostree_repo_lock_pop (repo, NULL, &error))
if (!_ostree_repo_lock_pop (repo, NULL, &error))
g_critical ("Cleanup repo lock failed: %s", error->message);
errno = errsv;
@@ -2742,10 +2737,10 @@ reload_core_config (OstreeRepo *self,
self->tmp_expiry_seconds = g_ascii_strtoull (tmp_expiry_seconds, NULL, 10);
}
/* Disable locking by default for now */
{ gboolean locking;
/* Enabled by default in 2018.05 */
if (!ot_keyfile_get_boolean_with_default (self->config, "core", "locking",
FALSE, &locking, error))
TRUE, &locking, error))
return FALSE;
if (!locking)
{
@@ -3550,6 +3545,9 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
return FALSE;
}
const char *errprefix = glnx_strjoina ("Opening content object ", checksum);
GLNX_AUTO_PREFIX_ERROR (errprefix, error);
struct stat stbuf;
glnx_autofd int fd = -1;
g_autofree char *ret_symlink = NULL;
@@ -3590,7 +3588,7 @@ _ostree_repo_load_file_bare (OstreeRepo *self,
}
if (!(S_ISREG (stbuf.st_mode) || S_ISLNK (stbuf.st_mode)))
return glnx_throw (error, "Not a regular file or symlink: %s", loose_path_buf);
return glnx_throw (error, "Not a regular file or symlink");
/* In the non-bare-user case, gather symlink info if requested */
if (self->mode != OSTREE_REPO_MODE_BARE_USER
@@ -4642,6 +4640,10 @@ sign_data (OstreeRepo *self,
if (gpgme_err_code (err) == GPG_ERR_EOF)
return glnx_throw (error, "No gpg key found with ID %s (homedir: %s)", key_id,
homedir ? homedir : "<default>");
else if (gpgme_err_code (err) == GPG_ERR_AMBIGUOUS_NAME) {
return glnx_throw (error, "gpg key id %s ambiguous (homedir: %s). Try the fingerprint instead", key_id,
homedir ? homedir : "<default>");
}
else if (err != GPG_ERR_NO_ERROR)
return ot_gpgme_throw (err, error, "Unable to lookup key ID %s", key_id);
@@ -5311,11 +5313,11 @@ summary_add_ref_entry (OstreeRepo *self,
* `core/commit-update-summary` is set.
*
* If the `core/collection-id` key is set in the configuration, it will be
* included as %OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs from the
* `refs/mirrors` directory will be included in the generated summary file,
* listed under the %OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs and refs
* in %OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in lexicographic
* order.
* included as %OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs that
* have associated collection IDs will be included in the generated summary
* file, listed under the %OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs
* and refs in %OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in
* lexicographic order.
*/
gboolean
ostree_repo_regenerate_summary (OstreeRepo *self,
+14 -42
View File
@@ -109,48 +109,6 @@ OstreeRepo * ostree_repo_create_at (int dfd,
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
/**
* OstreeRepoLockType:
* @OSTREE_REPO_LOCK_SHARED: A shared lock
* @OSTREE_REPO_LOCK_EXCLUSIVE: An exclusive lock
*
* The type of repository lock to acquire.
*
* Since: 2017.14
*/
typedef enum {
OSTREE_REPO_LOCK_SHARED,
OSTREE_REPO_LOCK_EXCLUSIVE
} OstreeRepoLockType;
_OSTREE_PUBLIC
gboolean ostree_repo_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_lock_pop (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
/**
* OstreeRepoAutoLock: (skip)
*
* This is simply an alias to #OstreeRepo used for automatic lock cleanup.
* See ostree_repo_auto_lock_push() for its intended usage.
*
* Since: 2017.14
*/
typedef OstreeRepo OstreeRepoAutoLock;
_OSTREE_PUBLIC
OstreeRepoAutoLock * ostree_repo_auto_lock_push (OstreeRepo *self,
OstreeRepoLockType lock_type,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock);
_OSTREE_PUBLIC
const gchar * ostree_repo_get_collection_id (OstreeRepo *self);
_OSTREE_PUBLIC
@@ -1112,6 +1070,12 @@ gboolean ostree_repo_static_delta_execute_offline (OstreeRepo
_OSTREE_PUBLIC
GHashTable *ostree_repo_traverse_new_reachable (void);
_OSTREE_PUBLIC
GHashTable *ostree_repo_traverse_new_parents (void);
_OSTREE_PUBLIC
char ** ostree_repo_traverse_parents_get_commits (GHashTable *parents, GVariant *object);
_OSTREE_PUBLIC
gboolean ostree_repo_traverse_commit (OstreeRepo *repo,
const char *commit_checksum,
@@ -1127,6 +1091,14 @@ gboolean ostree_repo_traverse_commit_union (OstreeRepo *repo,
GHashTable *inout_reachable,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_traverse_commit_union_with_parents (OstreeRepo *repo,
const char *commit_checksum,
int maxdepth,
GHashTable *inout_reachable,
GHashTable *inout_parents,
GCancellable *cancellable,
GError **error);
struct _OstreeRepoCommitTraverseIter {
gboolean initialized;
+42 -28
View File
@@ -239,6 +239,44 @@ cleanup_other_bootversions (OstreeSysroot *self,
return TRUE;
}
/* Delete a deployment directory */
gboolean
_ostree_sysroot_rmrf_deployment (OstreeSysroot *self,
OstreeDeployment *deployment,
GCancellable *cancellable,
GError **error)
{
g_autofree char *origin_relpath = ostree_deployment_get_origin_relpath (deployment);
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
struct stat stbuf;
glnx_autofd int deployment_fd = -1;
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE,
&deployment_fd, error))
return FALSE;
if (!glnx_fstat (deployment_fd, &stbuf, error))
return FALSE;
/* This shouldn't happen, because higher levels should
* disallow having the booted deployment not in the active
* deployment list, but let's be extra safe. */
if (stbuf.st_dev == self->root_device &&
stbuf.st_ino == self->root_inode)
return TRUE;
/* This deployment wasn't referenced, so delete it */
if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE,
cancellable, error))
return FALSE;
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error))
return FALSE;
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error))
return FALSE;
return TRUE;
}
/* As the bootloader configuration changes, we will have leftover deployments
* on disk. This function deletes all deployments which aren't actively
* referenced.
@@ -279,36 +317,12 @@ cleanup_old_deployments (OstreeSysroot *self,
{
OstreeDeployment *deployment = all_deployment_dirs->pdata[i];
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
g_autofree char *origin_relpath = ostree_deployment_get_origin_relpath (deployment);
if (!g_hash_table_lookup (active_deployment_dirs, deployment_path))
{
struct stat stbuf;
glnx_autofd int deployment_fd = -1;
if (g_hash_table_lookup (active_deployment_dirs, deployment_path))
continue;
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE,
&deployment_fd, error))
return FALSE;
if (!glnx_fstat (deployment_fd, &stbuf, error))
return FALSE;
/* This shouldn't happen, because higher levels should
* disallow having the booted deployment not in the active
* deployment list, but let's be extra safe. */
if (stbuf.st_dev == root_stbuf.st_dev &&
stbuf.st_ino == root_stbuf.st_ino)
continue;
/* This deployment wasn't referenced, so delete it */
if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE,
cancellable, error))
return FALSE;
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error))
return FALSE;
if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error))
return FALSE;
}
if (!_ostree_sysroot_rmrf_deployment (self, deployment, cancellable, error))
return FALSE;
}
/* Clean up boot directories */
File diff suppressed because it is too large. Load diff
+28 -2
View File
@@ -50,8 +50,7 @@ struct OstreeSysroot {
GLnxLockFile lock;
gboolean loaded;
gboolean ostree_booted;
gboolean root_is_sysroot; /* TRUE if sysroot_fd is pointed to rootfs "/" */
gboolean root_is_ostree_booted; /* TRUE if sysroot is / and we are booted via ostree */
/* The device/inode for /, used to detect booted deployment */
dev_t root_device;
ino_t root_inode;
@@ -61,6 +60,8 @@ struct OstreeSysroot {
int bootversion;
int subbootversion;
OstreeDeployment *booted_deployment;
OstreeDeployment *staged_deployment;
GVariant *staged_deployment_data;
struct timespec loaded_ts;
/* Only access through ostree_sysroot_[_get]repo() */
@@ -71,6 +72,7 @@ struct OstreeSysroot {
#define OSTREE_SYSROOT_LOCKFILE "ostree/lock"
/* We keep some transient state in /run */
#define _OSTREE_SYSROOT_RUNSTATE_STAGED "/run/ostree/staged-deployment"
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/"
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development"
@@ -105,6 +107,22 @@ _ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd,
GCancellable *cancellable,
GError **error);
void
_ostree_deployment_set_bootconfig_from_kargs (OstreeDeployment *deployment,
char **override_kernel_argv);
gboolean
_ostree_sysroot_reload_staged (OstreeSysroot *self, GError **error);
gboolean
_ostree_sysroot_finalize_staged (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
OstreeDeployment *
_ostree_sysroot_deserialize_deployment_from_variant (GVariant *v,
GError **error);
char *
_ostree_sysroot_get_origin_relpath (GFile *path,
guint32 *out_device,
@@ -112,6 +130,14 @@ _ostree_sysroot_get_origin_relpath (GFile *path,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_sysroot_rmrf_deployment (OstreeSysroot *sysroot,
OstreeDeployment *deployment,
GCancellable *cancellable,
GError **error);
char * _ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const char *key);
char *_ostree_sysroot_join_lines (GPtrArray *lines);
gboolean _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
+30 -14
View File
@@ -644,21 +644,37 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
GError **error)
{
g_autoptr(OstreeDeployment) new_deployment = NULL;
if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
self->new_revision,
self->origin,
self->merge_deployment,
NULL,
&new_deployment,
cancellable, error))
return FALSE;
if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname,
new_deployment,
self->merge_deployment,
0,
cancellable, error))
return FALSE;
/* Experimental flag to enable staging */
if (getenv ("OSTREE_EX_STAGE_DEPLOYMENTS"))
{
if (!ostree_sysroot_stage_tree (self->sysroot, self->osname,
self->new_revision,
self->origin,
self->merge_deployment,
NULL,
&new_deployment,
cancellable, error))
return FALSE;
}
else
{
if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
self->new_revision,
self->origin,
self->merge_deployment,
NULL,
&new_deployment,
cancellable, error))
return FALSE;
if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname,
new_deployment,
self->merge_deployment,
0,
cancellable, error))
return FALSE;
}
return TRUE;
}
+124 -35
View File
@@ -82,6 +82,8 @@ ostree_sysroot_finalize (GObject *object)
g_clear_object (&self->repo);
g_clear_pointer (&self->deployments, g_ptr_array_unref);
g_clear_object (&self->booted_deployment);
g_clear_object (&self->staged_deployment);
g_clear_pointer (&self->staged_deployment_data, (GDestroyNotify)g_variant_unref);
glnx_release_lock_file (&self->lock);
@@ -525,32 +527,30 @@ read_current_bootversion (OstreeSysroot *self,
}
static gboolean
parse_origin (OstreeSysroot *self,
int deployment_dfd,
const char *deployment_name,
GKeyFile **out_origin,
GCancellable *cancellable,
GError **error)
load_origin (OstreeSysroot *self,
OstreeDeployment *deployment,
GCancellable *cancellable,
GError **error)
{
g_autofree char *origin_path = g_strconcat ("../", deployment_name, ".origin", NULL);
g_autoptr(GKeyFile) ret_origin = g_key_file_new ();
g_autofree char *origin_path = ostree_deployment_get_origin_relpath (deployment);
struct stat stbuf;
if (!glnx_fstatat_allow_noent (deployment_dfd, origin_path, &stbuf, 0, error))
glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (self->sysroot_fd, origin_path, &fd, error))
return FALSE;
if (errno == 0)
if (fd >= 0)
{
g_autofree char *origin_contents =
glnx_file_get_contents_utf8_at (deployment_dfd, origin_path,
NULL, cancellable, error);
glnx_fd_readall_utf8 (fd, NULL, cancellable, error);
if (!origin_contents)
return FALSE;
if (!g_key_file_load_from_data (ret_origin, origin_contents, -1, 0, error))
g_autoptr(GKeyFile) origin = g_key_file_new ();
if (!g_key_file_load_from_data (origin, origin_contents, -1, 0, error))
return glnx_prefix_error (error, "Parsing %s", origin_path);
ostree_deployment_set_origin (deployment, origin);
}
ot_transfer_out_value(out_origin, &ret_origin);
return TRUE;
}
@@ -584,14 +584,14 @@ parse_bootlink (const char *bootlink,
return TRUE;
}
static char *
get_unlocked_development_path (OstreeDeployment *deployment)
char *
_ostree_sysroot_get_runstate_path (OstreeDeployment *deployment, const char *key)
{
return g_strdup_printf ("%s%s.%d/%s",
_OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR,
ostree_deployment_get_csum (deployment),
ostree_deployment_get_deployserial (deployment),
_OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
key);
}
static gboolean
@@ -637,8 +637,7 @@ parse_deployment (OstreeSysroot *self,
/* See if this is the booted deployment */
const gboolean looking_for_booted_deployment =
(self->ostree_booted && self->root_is_sysroot &&
!self->booted_deployment);
(self->root_is_ostree_booted && !self->booted_deployment);
gboolean is_booted_deployment = FALSE;
if (looking_for_booted_deployment)
{
@@ -653,26 +652,23 @@ parse_deployment (OstreeSysroot *self,
stbuf.st_ino == self->root_inode);
}
g_autoptr(GKeyFile) origin = NULL;
if (!parse_origin (self, deployment_dfd, deploy_basename, &origin,
cancellable, error))
return FALSE;
g_autoptr(OstreeDeployment) ret_deployment
= ostree_deployment_new (-1, osname, treecsum, deployserial,
bootcsum, treebootserial);
if (origin)
ostree_deployment_set_origin (ret_deployment, origin);
if (!load_origin (self, ret_deployment, cancellable, error))
return FALSE;
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE;
g_autofree char *unlocked_development_path = get_unlocked_development_path (ret_deployment);
g_autofree char *unlocked_development_path =
_ostree_sysroot_get_runstate_path (ret_deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
struct stat stbuf;
if (lstat (unlocked_development_path, &stbuf) == 0)
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
else
{
g_autofree char *existing_unlocked_state =
g_key_file_get_string (origin, "origin", "unlocked", NULL);
GKeyFile *origin = ostree_deployment_get_origin (ret_deployment);
g_autofree char *existing_unlocked_state = origin ?
g_key_file_get_string (origin, "origin", "unlocked", NULL) : NULL;
if (g_strcmp0 (existing_unlocked_state, "hotfix") == 0)
{
@@ -742,6 +738,15 @@ compare_deployments_by_boot_loader_version_reversed (gconstpointer a_pp,
OstreeBootconfigParser *a_bootconfig = ostree_deployment_get_bootconfig (a);
OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b);
/* Staged deployments are always first */
if (ostree_deployment_is_staged (a))
{
g_assert (!ostree_deployment_is_staged (b));
return -1;
}
else if (ostree_deployment_is_staged (b))
return 1;
return compare_boot_loader_configs (a_bootconfig, b_bootconfig);
}
@@ -789,6 +794,63 @@ ensure_repo (OstreeSysroot *self,
return TRUE;
}
/* Reload the staged deployment from the file in /run */
gboolean
_ostree_sysroot_reload_staged (OstreeSysroot *self,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Loading staged deployment", error);
if (!self->root_is_ostree_booted)
return TRUE; /* Note early return */
g_assert (self->booted_deployment);
g_clear_object (&self->staged_deployment);
g_clear_pointer (&self->staged_deployment_data, (GDestroyNotify)g_variant_unref);
/* Read the staged state from disk */
glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, &fd, error))
return FALSE;
if (fd != -1)
{
g_autoptr(GBytes) contents = ot_fd_readall_or_mmap (fd, 0, error);
if (!contents)
return FALSE;
g_autoptr(GVariant) staged_deployment_data =
g_variant_new_from_bytes ((GVariantType*)"a{sv}", contents, TRUE);
g_autoptr(GVariantDict) staged_deployment_dict =
g_variant_dict_new (staged_deployment_data);
/* Parse it */
g_autoptr(GVariant) target = NULL;
g_autofree char **kargs = NULL;
g_variant_dict_lookup (staged_deployment_dict, "target", "@a{sv}", &target);
g_variant_dict_lookup (staged_deployment_dict, "kargs", "^a&s", &kargs);
if (target)
{
g_autoptr(OstreeDeployment) staged =
_ostree_sysroot_deserialize_deployment_from_variant (target, error);
if (!staged)
return FALSE;
_ostree_deployment_set_bootconfig_from_kargs (staged, kargs);
if (!load_origin (self, staged, NULL, error))
return FALSE;
self->staged_deployment = g_steal_pointer (&staged);
self->staged_deployment_data = g_steal_pointer (&staged_deployment_data);
/* We set this flag for ostree_deployment_is_staged() because that API
* doesn't have access to the sysroot, which currently has the
* canonical "staged_deployment" reference.
*/
self->staged_deployment->staged = TRUE;
}
}
return TRUE;
}
gboolean
ostree_sysroot_load_if_changed (OstreeSysroot *self,
gboolean *out_changed,
@@ -813,7 +875,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
{
if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error))
return FALSE;
self->ostree_booted = (errno == 0);
const gboolean ostree_booted = (errno == 0);
{ struct stat root_stbuf;
if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error))
@@ -826,9 +888,11 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
if (!glnx_fstat (self->sysroot_fd, &self_stbuf, error))
return FALSE;
self->root_is_sysroot =
const gboolean root_is_sysroot =
(self->root_device == self_stbuf.st_dev &&
self->root_inode == self_stbuf.st_ino);
self->root_is_ostree_booted = (ostree_booted && root_is_sysroot);
}
int bootversion = 0;
@@ -857,6 +921,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
g_clear_pointer (&self->deployments, g_ptr_array_unref);
g_clear_object (&self->booted_deployment);
g_clear_object (&self->staged_deployment);
self->bootversion = -1;
self->subbootversion = -1;
@@ -880,11 +945,20 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
}
}
if (self->ostree_booted && self->root_is_sysroot
&& !self->booted_deployment)
if (self->root_is_ostree_booted && !self->booted_deployment)
return glnx_throw (error, "Unexpected state: /run/ostree-booted found and in / sysroot but not in a booted deployment");
if (!_ostree_sysroot_reload_staged (self, error))
return FALSE;
/* Ensure the entires are sorted */
g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed);
/* Staged shows up first */
if (self->staged_deployment)
g_ptr_array_insert (deployments, 0, g_object_ref (self->staged_deployment));
/* And then set their index variables */
for (guint i = 0; i < deployments->len; i++)
{
OstreeDeployment *deployment = deployments->pdata[i];
@@ -949,6 +1023,20 @@ ostree_sysroot_get_booted_deployment (OstreeSysroot *self)
return self->booted_deployment;
}
/**
* ostree_sysroot_get_staged_deployment:
* @self: Sysroot
*
* Returns: (transfer none): The currently staged deployment, or %NULL if none
*/
OstreeDeployment *
ostree_sysroot_get_staged_deployment (OstreeSysroot *self)
{
g_return_val_if_fail (self->loaded, NULL);
return self->staged_deployment;
}
/**
* ostree_sysroot_get_deployments:
* @self: Sysroot
@@ -1769,7 +1857,8 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
break;
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
{
g_autofree char *devpath = get_unlocked_development_path (deployment);
g_autofree char *devpath =
_ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
g_autofree char *devpath_parent = dirname (g_strdup (devpath));
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error))
+13
View File
@@ -74,6 +74,8 @@ _OSTREE_PUBLIC
GPtrArray *ostree_sysroot_get_deployments (OstreeSysroot *self);
_OSTREE_PUBLIC
OstreeDeployment *ostree_sysroot_get_booted_deployment (OstreeSysroot *self);
_OSTREE_PUBLIC
OstreeDeployment *ostree_sysroot_get_staged_deployment (OstreeSysroot *self);
_OSTREE_PUBLIC
GFile *ostree_sysroot_get_deployment_directory (OstreeSysroot *self,
@@ -174,6 +176,17 @@ gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_stage_tree (OstreeSysroot *self,
const char *osname,
const char *revision,
GKeyFile *origin,
OstreeDeployment *merge_deployment,
char **override_kernel_argv,
OstreeDeployment **out_new_deployment,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
OstreeDeployment *deployment,
+3 -3
View File
@@ -43,7 +43,7 @@
*
* Since: 2017.4
*/
#define OSTREE_RELEASE_VERSION (4)
#define OSTREE_RELEASE_VERSION (5)
/**
* OSTREE_VERSION
@@ -52,7 +52,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION (2018.4)
#define OSTREE_VERSION (2018.5)
/**
* OSTREE_VERSION_S:
@@ -62,7 +62,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION_S "2018.4"
#define OSTREE_VERSION_S "2018.5"
#define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release))
+4 -2
View File
@@ -54,6 +54,7 @@ ot_bin2hex (char *out_buf, const guint8 *inbuf, gsize len)
*/
typedef struct {
gboolean initialized;
gboolean closed;
#if defined(HAVE_OPENSSL)
EVP_MD_CTX *checksum;
#elif defined(HAVE_GNUTLS)
@@ -84,6 +85,7 @@ ot_checksum_init (OtChecksum *checksum)
real->digest_len = g_checksum_type_get_length (G_CHECKSUM_SHA256);
#endif
g_assert_cmpint (real->digest_len, ==, _OSTREE_SHA256_DIGEST_LEN);
real->closed = FALSE;
real->initialized = TRUE;
}
@@ -94,6 +96,7 @@ ot_checksum_update (OtChecksum *checksum,
{
OtRealChecksum *real = (OtRealChecksum*)checksum;
g_return_if_fail (real->initialized);
g_return_if_fail (!real->closed);
#if defined(HAVE_OPENSSL)
g_assert (EVP_DigestUpdate (real->checksum, buf, len));
#elif defined(HAVE_GNUTLS)
@@ -130,7 +133,7 @@ ot_checksum_get_digest (OtChecksum *checksum,
{
OtRealChecksum *real = (OtRealChecksum*)checksum;
ot_checksum_get_digest_internal (real, buf, buflen);
real->initialized = FALSE;
real->closed = TRUE;
}
void
@@ -143,7 +146,6 @@ ot_checksum_get_hexdigest (OtChecksum *checksum,
guint8 digest_buf[digest_len];
ot_checksum_get_digest (checksum, digest_buf, digest_len);
ot_bin2hex (buf, (guint8*)digest_buf, digest_len);
real->initialized = FALSE;
}
void
+5 -10
View File
@@ -37,21 +37,16 @@ static GOptionEntry options[] = {
gboolean
ot_admin_builtin_cleanup (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(GOptionContext) context = g_option_context_new ("");
g_autoptr(OstreeSysroot) sysroot = NULL;
gboolean ret = FALSE;
context = g_option_context_new ("");
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
invocation, &sysroot, cancellable, error))
goto out;
return FALSE;
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
goto out;
return FALSE;
ret = TRUE;
out:
return ret;
return TRUE;
}
+58 -30
View File
@@ -34,6 +34,7 @@
#include <glib/gi18n.h>
static gboolean opt_retain;
static gboolean opt_stage;
static gboolean opt_retain_pending;
static gboolean opt_retain_rollback;
static gboolean opt_not_as_default;
@@ -50,6 +51,7 @@ static GOptionEntry options[] = {
{ "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" },
{ "no-prune", 0, 0, G_OPTION_ARG_NONE, &opt_no_prune, "Don't prune the repo when done", NULL},
{ "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployments", NULL },
{ "stage", 0, 0, G_OPTION_ARG_NONE, &opt_stage, "Complete deployment at OS shutdown", NULL },
{ "retain-pending", 0, 0, G_OPTION_ARG_NONE, &opt_retain_pending, "Do not delete pending deployments", NULL },
{ "retain-rollback", 0, 0, G_OPTION_ARG_NONE, &opt_retain_rollback, "Do not delete rollback deployments", NULL },
{ "not-as-default", 0, 0, G_OPTION_ARG_NONE, &opt_not_as_default, "Append rather than prepend new deployment", NULL },
@@ -63,8 +65,6 @@ static GOptionEntry options[] = {
gboolean
ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
g_autoptr(OstreeKernelArgs) kargs = NULL;
g_autoptr(GOptionContext) context =
g_option_context_new ("REFSPEC");
@@ -127,61 +127,89 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocat
if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error))
return glnx_prefix_error (error, "Performing initial cleanup");
kargs = _ostree_kernel_args_new ();
/* If they want the current kernel's args, they very likely don't
* want the ones from the merge.
/* Initial set of kernel arguments; the default is to use the merge
* deployment, unless --karg-none or --karg-proc-cmdline are specified.
*/
if (opt_kernel_proc_cmdline)
g_autoptr(OstreeKernelArgs) kargs = NULL;
if (opt_kernel_arg_none)
{
kargs = _ostree_kernel_args_new ();
}
else if (opt_kernel_proc_cmdline)
{
kargs = _ostree_kernel_args_new ();
if (!_ostree_kernel_args_append_proc_cmdline (kargs, cancellable, error))
return FALSE;
}
else if (merge_deployment && !opt_kernel_arg_none)
else if (merge_deployment && (opt_kernel_argv || opt_kernel_argv_append))
{
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);
kargs = _ostree_kernel_args_new ();
_ostree_kernel_args_append_argv (kargs, previous_args);
}
/* Now replace/extend the above set. Note that if no options are specified,
* we should end up passing NULL as override_kernel_argv for
* ostree_sysroot_deploy_tree() so we get the defaults.
*/
if (opt_kernel_argv)
{
if (!kargs)
kargs = _ostree_kernel_args_new ();
_ostree_kernel_args_replace_argv (kargs, opt_kernel_argv);
}
if (opt_kernel_argv_append)
{
if (!kargs)
kargs = _ostree_kernel_args_new ();
_ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append);
}
g_autoptr(OstreeDeployment) new_deployment = NULL;
g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs);
if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment,
kargs_strv, &new_deployment, cancellable, error))
return FALSE;
OstreeSysrootSimpleWriteDeploymentFlags flags = OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN;
if (opt_retain)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN;
g_auto(GStrv) kargs_strv = kargs ? _ostree_kernel_args_to_strv (kargs) : NULL;
if (opt_stage)
{
if (opt_retain_pending || opt_retain_rollback)
return glnx_throw (error, "--stage cannot currently be combined with --retain arguments");
if (opt_not_as_default)
return glnx_throw (error, "--stage cannot currently be combined with --not-as-default");
if (!ostree_sysroot_stage_tree (sysroot, opt_osname, revision, origin, merge_deployment,
kargs_strv, &new_deployment, cancellable, error))
return FALSE;
g_assert (new_deployment);
}
else
{
if (opt_retain_pending)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING;
if (opt_retain_rollback)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK;
if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment,
kargs_strv, &new_deployment, cancellable, error))
return FALSE;
g_assert (new_deployment);
OstreeSysrootSimpleWriteDeploymentFlags flags = OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN;
if (opt_retain)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN;
else
{
if (opt_retain_pending)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING;
if (opt_retain_rollback)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK;
}
if (opt_not_as_default)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT;
if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment,
merge_deployment, flags, cancellable, error))
return FALSE;
}
if (opt_not_as_default)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT;
if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment,
merge_deployment, flags, cancellable, error))
return FALSE;
/* And finally, cleanup of any leftover data.
/* And finally, cleanup of any leftover data. In stage mode, we
* don't do a full cleanup as we didn't touch the bootloader.
*/
if (opt_no_prune)
if (opt_no_prune || opt_stage)
{
if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error))
return FALSE;
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2018 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 "config.h"
#include <stdlib.h>
#include "ot-main.h"
#include "ot-admin-builtins.h"
#include "ot-admin-functions.h"
#include "ostree.h"
#include "otutil.h"
#include "ostree-cmdprivate.h"
#include "ostree.h"
/* Called by ostree-finalize-staged.service, and in turn
* invokes a cmdprivate function inside the shared library.
*/
gboolean
ot_admin_builtin_finalize_staged (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
/* Just a sanity check; we shouldn't be called outside of the service though.
*/
struct stat stbuf;
if (fstatat (AT_FDCWD, "/run/ostree-booted", &stbuf, 0) < 0)
return TRUE;
g_autoptr(GFile) sysroot_file = g_file_new_for_path ("/");
g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (sysroot_file);
if (!ostree_sysroot_load (sysroot, cancellable, error))
return FALSE;
if (!ostree_cmd__private__()->ostree_finalize_staged (sysroot, cancellable, error))
return FALSE;
return TRUE;
}
+6 -3
View File
@@ -55,9 +55,12 @@ ostree_admin_instutil_option_context_new_with_commands (void)
while (command->name != NULL)
{
g_string_append_printf (summary, "\n %-24s", command->name);
if (command->description != NULL)
g_string_append_printf (summary, "%s", command->description);
if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0)
{
g_string_append_printf (summary, "\n %-24s", command->name);
if (command->description != NULL)
g_string_append_printf (summary, "%s", command->description);
}
command++;
}
+3 -1
View File
@@ -96,7 +96,9 @@ deployment_print_status (OstreeSysroot *sysroot,
GKeyFile *origin = ostree_deployment_get_origin (deployment);
const char *deployment_status = "";
if (is_pending)
if (ostree_deployment_is_staged (deployment))
deployment_status = " (staged)";
else if (is_pending)
deployment_status = " (pending)";
else if (is_rollback)
deployment_status = " (rollback)";
+1
View File
@@ -40,6 +40,7 @@ BUILTINPROTO(undeploy);
BUILTINPROTO(deploy);
BUILTINPROTO(cleanup);
BUILTINPROTO(pin);
BUILTINPROTO(finalize_staged);
BUILTINPROTO(unlock);
BUILTINPROTO(status);
BUILTINPROTO(set_origin);
+11 -5
View File
@@ -45,9 +45,9 @@ static OstreeCommand admin_subcommands[] = {
{ "init-fs", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_init_fs,
"Initialize a root filesystem" },
{ "instutil", OSTREE_BUILTIN_FLAG_NO_REPO,
{ "instutil", OSTREE_BUILTIN_FLAG_NO_REPO | OSTREE_BUILTIN_FLAG_HIDDEN,
ot_admin_builtin_instutil,
"Provide instutil commands, allow admin to change boot configuration and relabel selinux " },
"Deprecated commands intended for installer programs" },
{ "os-init", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_os_init,
"Initialize empty state for given operating system" },
@@ -57,6 +57,9 @@ static OstreeCommand admin_subcommands[] = {
{ "pin", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_pin,
"Change the \"pinning\" state of a deployment" },
{ "finalize-staged", OSTREE_BUILTIN_FLAG_NO_REPO | OSTREE_BUILTIN_FLAG_HIDDEN,
ot_admin_builtin_finalize_staged,
"Internal command to run at shutdown time" },
{ "status", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_status,
"List deployments" },
@@ -85,9 +88,12 @@ ostree_admin_option_context_new_with_commands (void)
while (command->name != NULL)
{
g_string_append_printf (summary, "\n %-19s", command->name);
if (command->description != NULL)
g_string_append_printf (summary, "%s", command->description);
if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0)
{
g_string_append_printf (summary, "\n %-19s", command->name);
if (command->description != NULL)
g_string_append_printf (summary, "%s", command->description);
}
command++;
}
+1 -6
View File
@@ -41,7 +41,6 @@ static GOptionEntry options[] =
{ NULL }
};
/* TODO: Add a man page. */
gboolean
ostree_builtin_create_usb (int argc,
char **argv,
@@ -201,11 +200,7 @@ ostree_builtin_create_usb (int argc,
/* FIXME: It should be possible to work without this, but find_remotes_cb() in
* ostree-repo-pull.c currently assumes a summary file (signed or unsigned) is
* present. */
struct stat stbuf;
if (!glnx_fstatat_allow_noent (ostree_repo_get_dfd (dest_repo), "summary", &stbuf, 0, error))
return FALSE;
if (errno == ENOENT &&
!ostree_repo_regenerate_summary (dest_repo, NULL, cancellable, error))
if (!ostree_repo_regenerate_summary (dest_repo, NULL, cancellable, error))
return FALSE;
/* Add the symlinks .ostree/repos.d/@symlink_name → @dest_repo_path, unless
+40 -7
View File
@@ -53,6 +53,8 @@ static gboolean
fsck_one_object (OstreeRepo *repo,
const char *checksum,
OstreeObjectType objtype,
GHashTable *object_parents,
GVariant *key,
gboolean *out_found_corruption,
GCancellable *cancellable,
GError **error)
@@ -60,12 +62,14 @@ fsck_one_object (OstreeRepo *repo,
g_autoptr(GError) temp_error = NULL;
if (!ostree_repo_fsck_object (repo, objtype, checksum, cancellable, &temp_error))
{
gboolean object_missing = FALSE;
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
g_printerr ("Object missing: %s.%s\n", checksum,
ostree_object_type_to_string (objtype));
*out_found_corruption = TRUE;
object_missing = TRUE;
}
else
{
@@ -73,7 +77,7 @@ fsck_one_object (OstreeRepo *repo,
{
g_printerr ("%s\n", temp_error->message);
(void) ostree_repo_delete_object (repo, objtype, checksum, cancellable, NULL);
*out_found_corruption = TRUE;
object_missing = TRUE;
}
else
{
@@ -81,6 +85,33 @@ fsck_one_object (OstreeRepo *repo,
return FALSE;
}
}
if (object_missing)
{
*out_found_corruption = TRUE;
if (object_parents != NULL && objtype != OSTREE_OBJECT_TYPE_COMMIT)
{
g_auto(GStrv) parent_commits = ostree_repo_traverse_parents_get_commits (object_parents, key);
int i;
/* The commit was missing or deleted, mark the commit partial */
for (i = 0; parent_commits[i] != NULL; i++)
{
const char *parent_commit = parent_commits[i];
OstreeRepoCommitState state;
if (!ostree_repo_load_commit (repo, parent_commit, NULL,
&state, error))
return FALSE;
if ((state & OSTREE_REPO_COMMIT_STATE_PARTIAL) == 0)
{
g_printerr ("Marking commit as partial: %s\n", parent_commit);
if (!ostree_repo_mark_commit_partial (repo, parent_commit, TRUE, error))
return FALSE;
}
}
}
}
}
return TRUE;
@@ -94,6 +125,7 @@ fsck_reachable_objects_from_commits (OstreeRepo *repo,
GError **error)
{
g_autoptr(GHashTable) reachable_objects = ostree_repo_traverse_new_reachable ();
g_autoptr(GHashTable) object_parents = ostree_repo_traverse_new_parents ();
GHashTableIter hash_iter;
gpointer key, value;
@@ -108,8 +140,8 @@ fsck_reachable_objects_from_commits (OstreeRepo *repo,
g_assert (objtype == OSTREE_OBJECT_TYPE_COMMIT);
if (!ostree_repo_traverse_commit_union (repo, checksum, 0, reachable_objects,
cancellable, error))
if (!ostree_repo_traverse_commit_union_with_parents (repo, checksum, 0, reachable_objects, object_parents,
cancellable, error))
return FALSE;
}
@@ -127,8 +159,9 @@ fsck_reachable_objects_from_commits (OstreeRepo *repo,
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
if (!fsck_one_object (repo, checksum, objtype, out_found_corruption,
cancellable, error))
if (!fsck_one_object (repo, checksum, objtype,
object_parents, serialized_key,
out_found_corruption, cancellable, error))
return FALSE;
i++;
@@ -150,7 +183,7 @@ fsck_commit_for_ref (OstreeRepo *repo,
GError **error)
{
if (!fsck_one_object (repo, checksum, OSTREE_OBJECT_TYPE_COMMIT,
found_corruption,
NULL, NULL, found_corruption,
cancellable, error))
return FALSE;
+1 -1
View File
@@ -38,7 +38,7 @@ static char *opt_collection_id = NULL;
*/
static GOptionEntry options[] = {
{ "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, archive)", NULL },
{ "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, bare-user, bare-user-only, archive)", NULL },
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
{ "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id,
"Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" },
+6 -4
View File
@@ -73,10 +73,12 @@ remote_option_context_new_with_commands (void)
while (subcommand->name != NULL)
{
g_string_append_printf (summary, "\n %-18s", subcommand->name);
if (subcommand->description != NULL)
g_string_append_printf (summary, "%s", subcommand->description);
if ((subcommand->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0)
{
g_string_append_printf (summary, "\n %-18s", subcommand->name);
if (subcommand->description != NULL)
g_string_append_printf (summary, "%s", subcommand->description);
}
subcommand++;
}
+2 -1
View File
@@ -117,7 +117,8 @@ static_delta_usage (char **argv,
while (command->name)
{
print_func (" %-17s%s\n", command->name, command->description ?: "");
if ((command->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0)
print_func (" %-17s%s\n", command->name, command->description ?: "");
command++;
}
+7 -4
View File
@@ -46,7 +46,7 @@ static GOptionEntry global_entries[] = {
};
static GOptionEntry repo_entry[] = {
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to current directory or /sysroot/ostree/repo)", "PATH" },
{ NULL }
};
@@ -66,10 +66,13 @@ ostree_option_context_new_with_commands (OstreeCommand *commands)
while (commands->name != NULL)
{
g_string_append_printf (summary, "\n %-18s", commands->name);
if ((commands->flags & OSTREE_BUILTIN_FLAG_HIDDEN) == 0)
{
g_string_append_printf (summary, "\n %-18s", commands->name);
if (commands->description != NULL )
g_string_append_printf (summary, "%s", commands->description);
if (commands->description != NULL )
g_string_append_printf (summary, "%s", commands->description);
}
commands++;
}
+2 -1
View File
@@ -29,7 +29,8 @@
typedef enum {
OSTREE_BUILTIN_FLAG_NONE = 0,
OSTREE_BUILTIN_FLAG_NO_REPO = 1 << 0,
OSTREE_BUILTIN_FLAG_NO_CHECK = 1 << 1
OSTREE_BUILTIN_FLAG_NO_CHECK = 1 << 1,
OSTREE_BUILTIN_FLAG_HIDDEN = 1 << 2,
} OstreeBuiltinFlags;
typedef enum {
File diff suppressed because it is too large. Load diff
+24 -12
View File
@@ -39,6 +39,7 @@
#include <fcntl.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
@@ -48,6 +49,9 @@
#include "ostree-mount-util.h"
/* Initialized early in main */
static bool running_as_pid1;
static char*
resolve_deploy_path (const char * root_mountpoint)
{
@@ -60,7 +64,6 @@ resolve_deploy_path (const char * root_mountpoint)
errx (EXIT_FAILURE, "No OSTree target; expected ostree=/ostree/boot.N/...");
snprintf (destpath, sizeof(destpath), "%s/%s", root_mountpoint, ostree_target);
printf ("Examining %s\n", destpath);
if (lstat (destpath, &stbuf) < 0)
err (EXIT_FAILURE, "Couldn't find specified OSTree root '%s'", destpath);
if (!S_ISLNK (stbuf.st_mode))
@@ -68,7 +71,9 @@ resolve_deploy_path (const char * root_mountpoint)
deploy_path = realpath (destpath, NULL);
if (deploy_path == NULL)
err (EXIT_FAILURE, "realpath(%s) failed", destpath);
printf ("Resolved OSTree target to: %s\n", deploy_path);
/* Quiet logs if there's no journal */
if (!running_as_pid1)
printf ("Resolved OSTree target to: %s\n", deploy_path);
return deploy_path;
}
@@ -81,13 +86,18 @@ pivot_root(const char * new_root, const char * put_old)
int
main(int argc, char *argv[])
{
const char *root_mountpoint = NULL, *root_arg = NULL;
char *deploy_path = NULL;
char srcpath[PATH_MAX];
struct stat stbuf;
int we_mounted_proc = 0;
/* If we're pid 1, that means there's no initramfs; in this situation
* various defaults change:
*
* - Assume that the target root is /
* - Quiet logging as there's no journal
* etc.
*/
running_as_pid1 = (getpid () == 1);
if (getpid() == 1)
const char *root_arg = NULL;
bool we_mounted_proc = false;
if (running_as_pid1)
{
root_arg = "/";
}
@@ -98,6 +108,7 @@ main(int argc, char *argv[])
root_arg = argv[1];
}
struct stat stbuf;
if (stat ("/proc/cmdline", &stbuf) < 0)
{
if (errno != ENOENT)
@@ -109,10 +120,10 @@ main(int argc, char *argv[])
we_mounted_proc = 1;
}
root_mountpoint = realpath (root_arg, NULL);
const char *root_mountpoint = realpath (root_arg, NULL);
if (root_mountpoint == NULL)
err (EXIT_FAILURE, "realpath(\"%s\")", root_arg);
deploy_path = resolve_deploy_path (root_mountpoint);
char *deploy_path = resolve_deploy_path (root_mountpoint);
if (we_mounted_proc)
{
@@ -147,6 +158,7 @@ main(int argc, char *argv[])
err (EXIT_FAILURE, "failed to bind mount ../../var to var");
#endif
char srcpath[PATH_MAX];
/* If /boot is on the same partition, use a bind mount to make it visible
* at /boot inside the deployment. */
snprintf (srcpath, sizeof(srcpath), "%s/boot/loader", root_mountpoint);
@@ -193,7 +205,7 @@ main(int argc, char *argv[])
* not pid 1. Otherwise it's handled later via ostree-remount.service.
* https://mail.gnome.org/archives/ostree-list/2018-March/msg00012.html
*/
if (getpid () != 1)
if (!running_as_pid1)
touch_run_ostree ();
if (strcmp(root_mountpoint, "/") == 0)
@@ -246,7 +258,7 @@ main(int argc, char *argv[])
if (mount ("none", "sysroot", NULL, MS_PRIVATE, NULL) < 0)
err (EXIT_FAILURE, "remounting 'sysroot' private");
if (getpid() == 1)
if (running_as_pid1)
{
execl ("/sbin/init", "/sbin/init", NULL);
err (EXIT_FAILURE, "failed to exec init inside ostree");