New upstream version 2021.3
This commit is contained in:
commit
5e89318de3
106 files changed
+4795
-3705
No files matched your search
@@ -28,7 +28,7 @@ After=systemd-remount-fs.service
|
||||
# But we run *before* most other core bootup services that need write access to /etc and /var
|
||||
Before=local-fs.target umount.target
|
||||
Before=systemd-random-seed.service plymouth-read-write.service systemd-journal-flush.service
|
||||
Before=systemd-tmpfiles-setup.service
|
||||
Before=systemd-tmpfiles-setup.service systemd-rfkill.service systemd-rfkill.socket
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
||||
@@ -653,6 +653,14 @@ global:
|
||||
ostree_content_writer_finish;
|
||||
} LIBOSTREE_2021.1;
|
||||
|
||||
LIBOSTREE_2021.3 {
|
||||
global:
|
||||
ostree_repo_auto_lock_push;
|
||||
ostree_repo_auto_lock_cleanup;
|
||||
ostree_repo_lock_push;
|
||||
ostree_repo_lock_pop;
|
||||
} LIBOSTREE_2021.2;
|
||||
|
||||
/* NOTE: Only add more content here in release commits! See the
|
||||
* comments at the top of this file.
|
||||
*/
|
||||
@@ -160,11 +160,11 @@ ostree_validate_checksum_string (const char *sha256,
|
||||
* @out_ref: (out) (not nullable) (optional): Return location for the ref name
|
||||
* @error: Error
|
||||
*
|
||||
* Split a refspec like `gnome-ostree:gnome-ostree/buildmaster` or just
|
||||
* `gnome-ostree/buildmaster` into two parts. In the first case, @out_remote
|
||||
* will be set to `gnome-ostree`, and @out_ref to `gnome-ostree/buildmaster`.
|
||||
* Split a refspec like `gnome-ostree:gnome-ostree/buildmain` or just
|
||||
* `gnome-ostree/buildmain` into two parts. In the first case, @out_remote
|
||||
* will be set to `gnome-ostree`, and @out_ref to `gnome-ostree/buildmain`.
|
||||
* In the second case (a local ref), @out_remote will be %NULL, and @out_ref
|
||||
* will be `gnome-ostree/buildmaster`. In both cases, %TRUE will be returned.
|
||||
* will be `gnome-ostree/buildmain`. In both cases, %TRUE will be returned.
|
||||
*
|
||||
* Returns: %TRUE on successful parsing, %FALSE otherwise
|
||||
*/
|
||||
|
||||
@@ -117,3 +117,21 @@ _ostree_fetcher_uri_to_string (OstreeFetcherURI *uri)
|
||||
{
|
||||
return soup_uri_to_string ((SoupURI*)uri, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/* Only accept http, https, and file; particularly curl has a ton of other
|
||||
* backends like sftp that we don't want, and this also gracefully filters
|
||||
* out invalid input.
|
||||
*/
|
||||
gboolean
|
||||
_ostree_fetcher_uri_validate (OstreeFetcherURI *uri, GError **error)
|
||||
{
|
||||
const char *scheme = soup_uri_get_scheme ((SoupURI*)uri);
|
||||
// TODO only allow file if explicitly requested by a higher level
|
||||
if (!(g_str_equal (scheme, "http") || g_str_equal (scheme, "https") || g_str_equal (scheme, "file")))
|
||||
{
|
||||
g_autofree char *s = _ostree_fetcher_uri_to_string (uri);
|
||||
return glnx_throw (error, "Invalid URI scheme in %s", s);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -90,6 +90,9 @@ _ostree_fetcher_uri_get_path (OstreeFetcherURI *uri);
|
||||
char *
|
||||
_ostree_fetcher_uri_to_string (OstreeFetcherURI *uri);
|
||||
|
||||
gboolean
|
||||
_ostree_fetcher_uri_validate (OstreeFetcherURI *uri, GError **error);
|
||||
|
||||
GType _ostree_fetcher_get_type (void) G_GNUC_CONST;
|
||||
|
||||
OstreeFetcher *_ostree_fetcher_new (int tmpdir_dfd,
|
||||
|
||||
@@ -113,13 +113,43 @@ stateroot_from_ostree_cmdline (const char *ostree_cmdline,
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Implementation of ostree-system-generator */
|
||||
gboolean
|
||||
_ostree_impl_system_generator (const char *ostree_cmdline,
|
||||
const char *normal_dir,
|
||||
const char *early_dir,
|
||||
const char *late_dir,
|
||||
GError **error)
|
||||
/* Forcibly enable our internal units, since we detected ostree= on the kernel cmdline */
|
||||
static gboolean
|
||||
require_internal_units (const char *normal_dir,
|
||||
const char *early_dir,
|
||||
const char *late_dir,
|
||||
GError **error)
|
||||
{
|
||||
#ifdef SYSTEM_DATA_UNIT_PATH
|
||||
GCancellable *cancellable = NULL;
|
||||
|
||||
glnx_autofd int normal_dir_dfd = -1;
|
||||
if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (normal_dir_dfd, "local-fs.target.requires", 0755, cancellable, error))
|
||||
return FALSE;
|
||||
if (symlinkat (SYSTEM_DATA_UNIT_PATH "/ostree-remount.service", normal_dir_dfd, "local-fs.target.requires/ostree-remount.service") < 0)
|
||||
return glnx_throw_errno_prefix (error, "symlinkat");
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (normal_dir_dfd, "multi-user.target.wants", 0755, cancellable, error))
|
||||
return FALSE;
|
||||
if (symlinkat (SYSTEM_DATA_UNIT_PATH "/ostree-finalize-staged.path", normal_dir_dfd, "multi-user.target.wants/ostree-finalize-staged.path") < 0)
|
||||
return glnx_throw_errno_prefix (error, "symlinkat");
|
||||
|
||||
return TRUE;
|
||||
#else
|
||||
return glnx_throw (error, "Not implemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Generate var.mount */
|
||||
static gboolean
|
||||
fstab_generator (const char *ostree_cmdline,
|
||||
const char *normal_dir,
|
||||
const char *early_dir,
|
||||
const char *late_dir,
|
||||
GError **error)
|
||||
{
|
||||
#ifdef HAVE_LIBMOUNT
|
||||
/* Not currently cancellable, but define a var in case we care later */
|
||||
@@ -225,3 +255,19 @@ _ostree_impl_system_generator (const char *ostree_cmdline,
|
||||
return glnx_throw (error, "Not implemented");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Implementation of ostree-system-generator */
|
||||
gboolean
|
||||
_ostree_impl_system_generator (const char *ostree_cmdline,
|
||||
const char *normal_dir,
|
||||
const char *early_dir,
|
||||
const char *late_dir,
|
||||
GError **error)
|
||||
{
|
||||
if (!require_internal_units (normal_dir, early_dir, late_dir, error))
|
||||
return FALSE;
|
||||
if (!fstab_generator (ostree_cmdline, normal_dir, early_dir, late_dir, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1684,8 +1684,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;
|
||||
|
||||
@@ -2341,7 +2341,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, OSTREE_REPO_LOCK_SHARED, cancellable, error))
|
||||
return FALSE;
|
||||
self->txn_locked = FALSE;
|
||||
}
|
||||
@@ -2399,7 +2399,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, OSTREE_REPO_LOCK_SHARED, cancellable, error))
|
||||
return FALSE;
|
||||
self->txn_locked = FALSE;
|
||||
}
|
||||
@@ -3020,6 +3020,10 @@ create_empty_gvariant_dict (void)
|
||||
*
|
||||
* Write a commit metadata object, referencing @root_contents_checksum
|
||||
* and @root_metadata_checksum.
|
||||
* This uses the current time as the commit timestamp, but it can be
|
||||
* overridden with an explicit timestamp via the
|
||||
* [standard](https://reproducible-builds.org/specs/source-date-epoch/)
|
||||
* `SOURCE_DATE_EPOCH` environment flag.
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_write_commit (OstreeRepo *self,
|
||||
@@ -3032,9 +3036,26 @@ ostree_repo_write_commit (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GDateTime) now = g_date_time_new_now_utc ();
|
||||
gint64 timestamp = 0;
|
||||
const gchar *env_timestamp = g_getenv ("SOURCE_DATE_EPOCH");
|
||||
if (env_timestamp == NULL)
|
||||
{
|
||||
g_autoptr(GDateTime) now = g_date_time_new_now_utc ();
|
||||
timestamp = g_date_time_to_unix (now);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *ret = NULL;
|
||||
errno = 0;
|
||||
timestamp = g_ascii_strtoll (env_timestamp, &ret, 10);
|
||||
if (errno != 0)
|
||||
return glnx_throw_errno_prefix (error, "Parsing SOURCE_DATE_EPOCH");
|
||||
if (ret == env_timestamp)
|
||||
return glnx_throw (error, "Failed to convert SOURCE_DATE_EPOCH");
|
||||
}
|
||||
|
||||
return ostree_repo_write_commit_with_time (self, parent, subject, body,
|
||||
metadata, root, g_date_time_to_unix (now),
|
||||
metadata, root, timestamp,
|
||||
out_commit, cancellable, error);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,6 +104,13 @@ typedef struct {
|
||||
fsblkcnt_t max_blocks;
|
||||
} OstreeRepoTxn;
|
||||
|
||||
typedef struct {
|
||||
GMutex mutex; /* All other members should only be accessed with this held */
|
||||
int fd; /* The open file or flock file descriptor */
|
||||
guint shared; /* Number of shared locks curently held */
|
||||
guint exclusive; /* Number of exclusive locks currently held */
|
||||
} OstreeRepoLock;
|
||||
|
||||
typedef enum {
|
||||
_OSTREE_FEATURE_NO,
|
||||
_OSTREE_FEATURE_MAYBE,
|
||||
@@ -159,6 +166,8 @@ struct OstreeRepo {
|
||||
GWeakRef sysroot; /* Weak to avoid a circular ref; see also `is_system` */
|
||||
char *remotes_config_dir;
|
||||
|
||||
OstreeRepoLock lock;
|
||||
|
||||
GMutex txn_lock;
|
||||
OstreeRepoTxn txn;
|
||||
gboolean txn_locked;
|
||||
@@ -506,30 +515,6 @@ _ostree_repo_maybe_regenerate_summary (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* 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,
|
||||
OstreeRepoLockType lock_type,
|
||||
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)
|
||||
|
||||
gboolean _ostree_repo_parse_fsverity_config (OstreeRepo *self, GError **error);
|
||||
|
||||
|
||||
@@ -204,7 +204,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;
|
||||
|
||||
@@ -325,7 +325,7 @@ ostree_repo_traverse_reachable_refs (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(OstreeRepoAutoLock) lock =
|
||||
_ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_SHARED, cancellable, error);
|
||||
ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_SHARED, cancellable, error);
|
||||
if (!lock)
|
||||
return FALSE;
|
||||
|
||||
@@ -400,7 +400,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;
|
||||
|
||||
@@ -486,7 +486,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;
|
||||
|
||||
|
||||
@@ -3446,6 +3446,9 @@ compute_effective_mirrorlist (OstreeRepo *self,
|
||||
if (!baseuri)
|
||||
return FALSE;
|
||||
|
||||
if (!_ostree_fetcher_uri_validate (baseuri, error))
|
||||
return FALSE;
|
||||
|
||||
*out_mirrorlist =
|
||||
g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free);
|
||||
g_ptr_array_add (*out_mirrorlist, g_steal_pointer (&baseuri));
|
||||
|
||||
@@ -1270,7 +1270,7 @@ ostree_repo_static_delta_reindex (OstreeRepo *repo,
|
||||
|
||||
/* Protect against parallel prune operation */
|
||||
g_autoptr(OstreeRepoAutoLock) lock =
|
||||
_ostree_repo_auto_lock_push (repo, OSTREE_REPO_LOCK_SHARED, cancellable, error);
|
||||
ostree_repo_auto_lock_push (repo, OSTREE_REPO_LOCK_SHARED, cancellable, error);
|
||||
if (!lock)
|
||||
return FALSE;
|
||||
|
||||
|
||||
+204
-180
@@ -172,98 +172,84 @@ G_DEFINE_TYPE (OstreeRepo, ostree_repo, G_TYPE_OBJECT)
|
||||
/* Repository locking
|
||||
*
|
||||
* To guard against objects being deleted (e.g., prune) while they're in
|
||||
* use by another operation is accessing them (e.g., commit), the
|
||||
* use by another operation that is accessing them (e.g., commit), the
|
||||
* repository must be locked by concurrent writers.
|
||||
*
|
||||
* The locking is implemented by maintaining a thread local table of
|
||||
* lock stacks per repository. This allows thread safe locking since
|
||||
* each thread maintains its own lock stack. See the OstreeRepoLock type
|
||||
* below.
|
||||
* The repository locking has several important features:
|
||||
*
|
||||
* The actual locking is done using either open file descriptor locks or
|
||||
* flock locks. This allows the locking to work with concurrent
|
||||
* processes. The lock file is held on the ".lock" file within the
|
||||
* repository.
|
||||
* * There are 2 states - shared and exclusive. Multiple users can hold
|
||||
* a shared lock concurrently while only one user can hold an
|
||||
* exclusive lock.
|
||||
*
|
||||
* * The lock can be taken recursively so long as each acquisition is paired
|
||||
* with a matching release. The recursion is also latched to the strongest
|
||||
* state. Once an exclusive lock has been taken, it will remain exclusive
|
||||
* until all exclusive locks have been released.
|
||||
*
|
||||
* * It is both multiprocess- and multithread-safe. Threads that share
|
||||
* an OstreeRepo use the lock cooperatively while processes and
|
||||
* threads using separate OstreeRepo structures will block when
|
||||
* acquiring incompatible lock states.
|
||||
*
|
||||
* The actual locking is implemented using either open file descriptor
|
||||
* locks or flock locks. This allows the locking to work with concurrent
|
||||
* processes or concurrent threads using a separate OstreeRepo. The lock
|
||||
* file is held on the ".lock" file within the repository.
|
||||
*
|
||||
* The intended usage is to take a shared lock when writing objects or
|
||||
* reading objects in critical sections. Exclusive locks are taken when
|
||||
* deleting objects.
|
||||
*
|
||||
* To allow fine grained locking within libostree, the lock is
|
||||
* maintained as a stack. The core APIs then push or pop from the stack.
|
||||
* When pushing or popping a lock state identical to the existing or
|
||||
* next state, the stack is simply updated. Only when upgrading or
|
||||
* downgrading the lock (changing to/from unlocked, pushing exclusive on
|
||||
* shared or popping exclusive to shared) are actual locking operations
|
||||
* performed.
|
||||
* To allow fine grained locking, the lock state is maintained in shared and
|
||||
* exclusive counters. Callers then push or pop lock types to increment or
|
||||
* decrement the counters. When pushing or popping a lock type identical to
|
||||
* the existing or next state, the lock state is simply updated. Only when
|
||||
* upgrading or downgrading the lock (changing to/from unlocked, pushing
|
||||
* exclusive on shared or popping exclusive to shared) are actual locking
|
||||
* operations performed.
|
||||
*/
|
||||
|
||||
static void
|
||||
free_repo_lock_table (gpointer data)
|
||||
{
|
||||
GHashTable *lock_table = data;
|
||||
|
||||
if (lock_table != NULL)
|
||||
{
|
||||
g_debug ("Free lock table");
|
||||
g_hash_table_destroy (lock_table);
|
||||
}
|
||||
}
|
||||
|
||||
static GPrivate repo_lock_table = G_PRIVATE_INIT (free_repo_lock_table);
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
GQueue stack;
|
||||
} OstreeRepoLock;
|
||||
|
||||
typedef struct {
|
||||
guint len;
|
||||
int state;
|
||||
const char *name;
|
||||
} OstreeRepoLockInfo;
|
||||
|
||||
static void
|
||||
repo_lock_info (OstreeRepoLock *lock, OstreeRepoLockInfo *out_info)
|
||||
static const char *
|
||||
lock_state_name (int state)
|
||||
{
|
||||
g_assert (lock != NULL);
|
||||
g_assert (out_info != NULL);
|
||||
|
||||
OstreeRepoLockInfo info;
|
||||
info.len = g_queue_get_length (&lock->stack);
|
||||
if (info.len == 0)
|
||||
switch (state)
|
||||
{
|
||||
info.state = LOCK_UN;
|
||||
info.name = "unlocked";
|
||||
case LOCK_EX:
|
||||
return "exclusive";
|
||||
case LOCK_SH:
|
||||
return "shared";
|
||||
case LOCK_UN:
|
||||
return "unlocked";
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
else
|
||||
{
|
||||
info.state = GPOINTER_TO_INT (g_queue_peek_head (&lock->stack));
|
||||
info.name = (info.state == LOCK_EX) ? "exclusive" : "shared";
|
||||
}
|
||||
|
||||
*out_info = info;
|
||||
}
|
||||
|
||||
static void
|
||||
free_repo_lock (gpointer data)
|
||||
repo_lock_info (OstreeRepo *self, GMutexLocker *locker,
|
||||
OstreeRepoLockInfo *out_info)
|
||||
{
|
||||
OstreeRepoLock *lock = data;
|
||||
g_assert (self != NULL);
|
||||
g_assert (locker != NULL);
|
||||
g_assert (out_info != NULL);
|
||||
|
||||
if (lock != NULL)
|
||||
{
|
||||
OstreeRepoLockInfo info;
|
||||
repo_lock_info (lock, &info);
|
||||
OstreeRepoLockInfo info;
|
||||
info.len = self->lock.shared + self->lock.exclusive;
|
||||
if (info.len == 0)
|
||||
info.state = LOCK_UN;
|
||||
else if (self->lock.exclusive > 0)
|
||||
info.state = LOCK_EX;
|
||||
else
|
||||
info.state = LOCK_SH;
|
||||
info.name = lock_state_name (info.state);
|
||||
|
||||
g_debug ("Free lock: state=%s, depth=%u", info.name, info.len);
|
||||
g_queue_clear (&lock->stack);
|
||||
if (lock->fd >= 0)
|
||||
{
|
||||
g_debug ("Closing repo lock file");
|
||||
(void) close (lock->fd);
|
||||
}
|
||||
g_free (lock);
|
||||
}
|
||||
*out_info = info;
|
||||
}
|
||||
|
||||
/* Wrapper to handle flock vs OFD locking based on GLnxLockFile */
|
||||
@@ -339,125 +325,148 @@ push_repo_lock (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
int flags = (lock_type == OSTREE_REPO_LOCK_EXCLUSIVE) ? LOCK_EX : LOCK_SH;
|
||||
int next_state = flags;
|
||||
if (!blocking)
|
||||
flags |= LOCK_NB;
|
||||
|
||||
GHashTable *lock_table = g_private_get (&repo_lock_table);
|
||||
if (lock_table == NULL)
|
||||
{
|
||||
g_debug ("Creating repo lock table");
|
||||
lock_table = g_hash_table_new_full (NULL, NULL, NULL,
|
||||
(GDestroyNotify)free_repo_lock);
|
||||
g_private_set (&repo_lock_table, lock_table);
|
||||
}
|
||||
g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&self->lock.mutex);
|
||||
|
||||
OstreeRepoLock *lock = g_hash_table_lookup (lock_table, self);
|
||||
if (lock == NULL)
|
||||
if (self->lock.fd == -1)
|
||||
{
|
||||
lock = g_new0 (OstreeRepoLock, 1);
|
||||
g_queue_init (&lock->stack);
|
||||
g_debug ("Opening repo lock file");
|
||||
lock->fd = TEMP_FAILURE_RETRY (openat (self->repo_dir_fd, ".lock",
|
||||
O_CREAT | O_RDWR | O_CLOEXEC,
|
||||
DEFAULT_REGFILE_MODE));
|
||||
if (lock->fd < 0)
|
||||
{
|
||||
free_repo_lock (lock);
|
||||
return glnx_throw_errno_prefix (error,
|
||||
"Opening lock file %s/.lock failed",
|
||||
gs_file_get_path_cached (self->repodir));
|
||||
}
|
||||
g_hash_table_insert (lock_table, self, lock);
|
||||
self->lock.fd = TEMP_FAILURE_RETRY (openat (self->repo_dir_fd, ".lock",
|
||||
O_CREAT | O_RDWR | O_CLOEXEC,
|
||||
DEFAULT_REGFILE_MODE));
|
||||
if (self->lock.fd < 0)
|
||||
return glnx_throw_errno_prefix (error,
|
||||
"Opening lock file %s/.lock failed",
|
||||
gs_file_get_path_cached (self->repodir));
|
||||
}
|
||||
|
||||
OstreeRepoLockInfo info;
|
||||
repo_lock_info (lock, &info);
|
||||
repo_lock_info (self, locker, &info);
|
||||
g_debug ("Push lock: state=%s, depth=%u", info.name, info.len);
|
||||
|
||||
if (info.state == LOCK_EX)
|
||||
guint *counter;
|
||||
if (next_state == LOCK_EX)
|
||||
counter = &(self->lock.exclusive);
|
||||
else
|
||||
counter = &(self->lock.shared);
|
||||
|
||||
/* Check for overflow */
|
||||
if (*counter == G_MAXUINT)
|
||||
g_error ("Repo lock %s counter would overflow", lock_state_name (next_state));
|
||||
|
||||
if (info.state == LOCK_EX || info.state == next_state)
|
||||
{
|
||||
g_debug ("Repo already locked exclusively, extending stack");
|
||||
g_queue_push_head (&lock->stack, GINT_TO_POINTER (LOCK_EX));
|
||||
g_debug ("Repo already locked %s, maintaining state", info.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
int next_state = (flags & LOCK_EX) ? LOCK_EX : LOCK_SH;
|
||||
const char *next_state_name = (flags & LOCK_EX) ? "exclusive" : "shared";
|
||||
/* We should never upgrade from exclusive to shared */
|
||||
g_assert (!(info.state == LOCK_EX && next_state == LOCK_SH));
|
||||
|
||||
const char *next_state_name = lock_state_name (next_state);
|
||||
g_debug ("Locking repo %s", next_state_name);
|
||||
if (!do_repo_lock (lock->fd, flags))
|
||||
if (!do_repo_lock (self->lock.fd, flags))
|
||||
return glnx_throw_errno_prefix (error, "Locking repo %s failed",
|
||||
next_state_name);
|
||||
|
||||
g_queue_push_head (&lock->stack, GINT_TO_POINTER (next_state));
|
||||
}
|
||||
|
||||
/* Update state */
|
||||
(*counter)++;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
pop_repo_lock (OstreeRepo *self,
|
||||
gboolean blocking,
|
||||
GError **error)
|
||||
pop_repo_lock (OstreeRepo *self,
|
||||
OstreeRepoLockType lock_type,
|
||||
gboolean blocking,
|
||||
GError **error)
|
||||
{
|
||||
int flags = blocking ? 0 : LOCK_NB;
|
||||
|
||||
GHashTable *lock_table = g_private_get (&repo_lock_table);
|
||||
g_return_val_if_fail (lock_table != NULL, FALSE);
|
||||
|
||||
OstreeRepoLock *lock = g_hash_table_lookup (lock_table, self);
|
||||
g_return_val_if_fail (lock != NULL, FALSE);
|
||||
g_return_val_if_fail (lock->fd != -1, FALSE);
|
||||
g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&self->lock.mutex);
|
||||
if (self->lock.fd == -1)
|
||||
g_error ("Cannot pop repo never locked repo lock");
|
||||
|
||||
OstreeRepoLockInfo info;
|
||||
repo_lock_info (lock, &info);
|
||||
g_return_val_if_fail (info.len > 0, FALSE);
|
||||
|
||||
repo_lock_info (self, locker, &info);
|
||||
g_debug ("Pop lock: state=%s, depth=%u", info.name, info.len);
|
||||
if (info.len > 1)
|
||||
{
|
||||
int next_state = GPOINTER_TO_INT (g_queue_peek_nth (&lock->stack, 1));
|
||||
|
||||
/* Drop back to the previous lock state if it differs */
|
||||
if (next_state != info.state)
|
||||
{
|
||||
/* We should never drop from shared to exclusive */
|
||||
g_return_val_if_fail (next_state == LOCK_SH, FALSE);
|
||||
g_debug ("Returning lock state to shared");
|
||||
if (!do_repo_lock (lock->fd, next_state | flags))
|
||||
return glnx_throw_errno_prefix (error,
|
||||
"Setting repo lock to shared failed");
|
||||
}
|
||||
else
|
||||
g_debug ("Maintaining lock state as %s", info.name);
|
||||
if (info.len == 0 || info.state == LOCK_UN)
|
||||
g_error ("Cannot pop already unlocked repo lock");
|
||||
|
||||
int state_to_drop;
|
||||
guint *counter;
|
||||
if (lock_type == OSTREE_REPO_LOCK_EXCLUSIVE)
|
||||
{
|
||||
state_to_drop = LOCK_EX;
|
||||
counter = &(self->lock.exclusive);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Lock stack will be empty, unlock */
|
||||
g_debug ("Unlocking repo");
|
||||
if (!do_repo_unlock (lock->fd, flags))
|
||||
return glnx_throw_errno_prefix (error, "Unlocking repo failed");
|
||||
state_to_drop = LOCK_SH;
|
||||
counter = &(self->lock.shared);
|
||||
}
|
||||
|
||||
g_queue_pop_head (&lock->stack);
|
||||
/* Make sure caller specified a valid type to release */
|
||||
if (*counter == 0)
|
||||
g_error ("Repo %s lock pop requested, but none have been taken",
|
||||
lock_state_name (state_to_drop));
|
||||
|
||||
int next_state;
|
||||
if (info.len == 1)
|
||||
{
|
||||
/* Lock counters will be empty, unlock */
|
||||
next_state = LOCK_UN;
|
||||
}
|
||||
else if (state_to_drop == LOCK_EX)
|
||||
next_state = (self->lock.exclusive > 1) ? LOCK_EX : LOCK_SH;
|
||||
else
|
||||
next_state = (self->lock.exclusive > 0) ? LOCK_EX : LOCK_SH;
|
||||
|
||||
if (next_state == LOCK_UN)
|
||||
{
|
||||
g_debug ("Unlocking repo");
|
||||
if (!do_repo_unlock (self->lock.fd, flags))
|
||||
return glnx_throw_errno_prefix (error, "Unlocking repo failed");
|
||||
}
|
||||
else if (info.state == next_state)
|
||||
{
|
||||
g_debug ("Maintaining lock state as %s", info.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We should never drop from shared to exclusive */
|
||||
g_assert (next_state == LOCK_SH);
|
||||
g_debug ("Returning lock state to shared");
|
||||
if (!do_repo_lock (self->lock.fd, next_state | flags))
|
||||
return glnx_throw_errno_prefix (error,
|
||||
"Setting repo lock to shared failed");
|
||||
}
|
||||
|
||||
/* Update state */
|
||||
(*counter)--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* ostree_repo_lock_push:
|
||||
* @self: a #OstreeRepo
|
||||
* @lock_type: the type of lock to acquire
|
||||
* @cancellable: a #GCancellable
|
||||
* @error: a #GError
|
||||
*
|
||||
* Takes a lock on the repository and adds it to the lock stack. If @lock_type
|
||||
* Takes a lock on the repository and adds it to the lock state. If @lock_type
|
||||
* is %OSTREE_REPO_LOCK_SHARED, a shared lock is taken. If @lock_type is
|
||||
* %OSTREE_REPO_LOCK_EXCLUSIVE, an exclusive lock is taken. The actual lock
|
||||
* state is only changed when locking a previously unlocked repository or
|
||||
* upgrading the lock from shared to exclusive. If the requested lock state is
|
||||
* upgrading the lock from shared to exclusive. If the requested lock type is
|
||||
* unchanged or would represent a downgrade (exclusive to shared), the lock
|
||||
* state is not changed and the stack is simply updated.
|
||||
* state is not changed.
|
||||
*
|
||||
* ostree_repo_lock_push() waits for the lock depending on the repository's
|
||||
* lock-timeout-secs configuration. When lock-timeout-secs is -1, a blocking lock is
|
||||
@@ -470,12 +479,13 @@ pop_repo_lock (OstreeRepo *self,
|
||||
* %TRUE is returned.
|
||||
*
|
||||
* Returns: %TRUE on success, otherwise %FALSE with @error set
|
||||
* Since: 2021.3
|
||||
*/
|
||||
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);
|
||||
@@ -538,16 +548,19 @@ _ostree_repo_lock_push (OstreeRepo *self,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* _ostree_repo_lock_pop:
|
||||
/**
|
||||
* ostree_repo_lock_pop:
|
||||
* @self: a #OstreeRepo
|
||||
* @lock_type: the type of lock to release
|
||||
* @cancellable: a #GCancellable
|
||||
* @error: a #GError
|
||||
*
|
||||
* Remove the current repository lock state from the lock stack. If the lock
|
||||
* stack becomes empty, the repository is unlocked. Otherwise, the lock state
|
||||
* only changes when transitioning from an exclusive lock back to a shared
|
||||
* lock.
|
||||
* Release a lock of type @lock_type from the lock state. If the lock state
|
||||
* becomes empty, the repository is unlocked. Otherwise, the lock state only
|
||||
* changes when transitioning from an exclusive lock back to a shared lock. The
|
||||
* requested @lock_type must be the same type that was requested in the call to
|
||||
* ostree_repo_lock_push(). It is a programmer error if these do not match and
|
||||
* the program may abort if the lock would reach an invalid state.
|
||||
*
|
||||
* ostree_repo_lock_pop() waits for the lock depending on the repository's
|
||||
* lock-timeout-secs configuration. When lock-timeout-secs is -1, a blocking lock is
|
||||
@@ -560,11 +573,13 @@ _ostree_repo_lock_push (OstreeRepo *self,
|
||||
* %TRUE is returned.
|
||||
*
|
||||
* Returns: %TRUE on success, otherwise %FALSE with @error set
|
||||
* Since: 2021.3
|
||||
*/
|
||||
gboolean
|
||||
_ostree_repo_lock_pop (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
ostree_repo_lock_pop (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);
|
||||
@@ -581,7 +596,7 @@ _ostree_repo_lock_pop (OstreeRepo *self,
|
||||
else if (self->lock_timeout_seconds == REPO_LOCK_BLOCKING)
|
||||
{
|
||||
g_debug ("Popping lock blocking");
|
||||
return pop_repo_lock (self, TRUE, error);
|
||||
return pop_repo_lock (self, lock_type, TRUE, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -596,7 +611,7 @@ _ostree_repo_lock_pop (OstreeRepo *self,
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
if (pop_repo_lock (self, FALSE, &local_error))
|
||||
if (pop_repo_lock (self, lock_type, FALSE, &local_error))
|
||||
return TRUE;
|
||||
|
||||
if (!g_error_matches (local_error, G_IO_ERROR,
|
||||
@@ -627,60 +642,72 @@ _ostree_repo_lock_pop (OstreeRepo *self,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* _ostree_repo_auto_lock_push: (skip)
|
||||
struct OstreeRepoAutoLock {
|
||||
OstreeRepo *repo;
|
||||
OstreeRepoLockType lock_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* ostree_repo_auto_lock_push: (skip)
|
||||
* @self: a #OstreeRepo
|
||||
* @lock_type: the type of lock to acquire
|
||||
* @cancellable: a #GCancellable
|
||||
* @error: a #GError
|
||||
*
|
||||
* Like ostree_repo_lock_push(), but for usage with #OstreeRepoAutoLock.
|
||||
* The intended usage is to declare the #OstreeRepoAutoLock with
|
||||
* g_autoptr() so that ostree_repo_auto_lock_cleanup() is called when it
|
||||
* goes out of scope. This will automatically pop the lock status off
|
||||
* the stack if it was acquired successfully.
|
||||
* Like ostree_repo_lock_push(), but for usage with #OstreeRepoAutoLock. The
|
||||
* intended usage is to declare the #OstreeRepoAutoLock with g_autoptr() so
|
||||
* that ostree_repo_auto_lock_cleanup() is called when it goes out of scope.
|
||||
* This will automatically release the lock if it was acquired successfully.
|
||||
*
|
||||
* |[<!-- 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: 2021.3
|
||||
*/
|
||||
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;
|
||||
|
||||
OstreeRepoAutoLock *auto_lock = g_new (OstreeRepoAutoLock, 1);
|
||||
auto_lock->repo = self;
|
||||
auto_lock->lock_type = lock_type;
|
||||
return auto_lock;
|
||||
}
|
||||
|
||||
/*
|
||||
* _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: 2021.3
|
||||
*/
|
||||
void
|
||||
_ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *lock)
|
||||
ostree_repo_auto_lock_cleanup (OstreeRepoAutoLock *auto_lock)
|
||||
{
|
||||
OstreeRepo *repo = lock;
|
||||
if (repo)
|
||||
if (auto_lock != NULL)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
int errsv = errno;
|
||||
|
||||
if (!_ostree_repo_lock_pop (repo, NULL, &error))
|
||||
if (!ostree_repo_lock_pop (auto_lock->repo, auto_lock->lock_type, NULL, &error))
|
||||
g_critical ("Cleanup repo lock failed: %s", error->message);
|
||||
|
||||
errno = errsv;
|
||||
|
||||
g_free (auto_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1052,13 +1079,8 @@ ostree_repo_finalize (GObject *object)
|
||||
g_clear_pointer (&self->remotes, g_hash_table_destroy);
|
||||
g_mutex_clear (&self->remotes_lock);
|
||||
|
||||
GHashTable *lock_table = g_private_get (&repo_lock_table);
|
||||
if (lock_table)
|
||||
{
|
||||
g_hash_table_remove (lock_table, self);
|
||||
if (g_hash_table_size (lock_table) == 0)
|
||||
g_private_replace (&repo_lock_table, NULL);
|
||||
}
|
||||
glnx_close_fd (&self->lock.fd);
|
||||
g_mutex_clear (&self->lock.mutex);
|
||||
|
||||
G_OBJECT_CLASS (ostree_repo_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -1220,6 +1242,7 @@ ostree_repo_init (OstreeRepo *self)
|
||||
self->test_error_flags = g_parse_debug_string (g_getenv ("OSTREE_REPO_TEST_ERROR"),
|
||||
test_error_keys, G_N_ELEMENTS (test_error_keys));
|
||||
|
||||
g_mutex_init (&self->lock.mutex);
|
||||
g_mutex_init (&self->cache_lock);
|
||||
g_mutex_init (&self->txn_lock);
|
||||
|
||||
@@ -1233,6 +1256,7 @@ ostree_repo_init (OstreeRepo *self)
|
||||
self->tmp_dir_fd = -1;
|
||||
self->objects_dir_fd = -1;
|
||||
self->uncompressed_objects_dir_fd = -1;
|
||||
self->lock.fd = -1;
|
||||
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -3291,7 +3315,7 @@ ostree_repo_open (OstreeRepo *self,
|
||||
if (!glnx_opendirat (self->repo_dir_fd, "tmp", TRUE, &self->tmp_dir_fd, error))
|
||||
return FALSE;
|
||||
|
||||
if (self->writable)
|
||||
if (self->writable && getenv ("OSTREE_SKIP_CACHE") == NULL)
|
||||
{
|
||||
if (!glnx_shutil_mkdir_p_at (self->tmp_dir_fd, _OSTREE_CACHE_DIR, DEFAULT_DIRECTORY_MODE, cancellable, error))
|
||||
return FALSE;
|
||||
@@ -5791,8 +5815,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
|
||||
g_autoptr(OstreeRepoAutoLock) lock = NULL;
|
||||
gboolean no_deltas_in_summary = FALSE;
|
||||
|
||||
lock = _ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE,
|
||||
cancellable, error);
|
||||
lock = ostree_repo_auto_lock_push (self, OSTREE_REPO_LOCK_EXCLUSIVE,
|
||||
cancellable, error);
|
||||
if (!lock)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -1498,6 +1498,57 @@ gboolean ostree_repo_regenerate_summary (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
/**
|
||||
* OstreeRepoLockType:
|
||||
* @OSTREE_REPO_LOCK_SHARED: A "read only" lock; multiple readers are allowed.
|
||||
* @OSTREE_REPO_LOCK_EXCLUSIVE: A writable lock at most one writer can be active, and zero readers.
|
||||
*
|
||||
* Flags controlling repository locking.
|
||||
*
|
||||
* Since: 2021.3
|
||||
*/
|
||||
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,
|
||||
OstreeRepoLockType lock_type,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
/* C convenience API only */
|
||||
#ifndef __GI_SCANNER__
|
||||
|
||||
/**
|
||||
* OstreeRepoAutoLock: (skip)
|
||||
*
|
||||
* An opaque type for use with ostree_repo_auto_lock_push().
|
||||
*
|
||||
* Since: 2021.3
|
||||
*/
|
||||
typedef struct OstreeRepoAutoLock 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);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRepoAutoLock, ostree_repo_auto_lock_cleanup)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* OSTREE_REPO_METADATA_REF:
|
||||
*
|
||||
|
||||
@@ -505,7 +505,7 @@ ostree_sysroot_cleanup_prune_repo (OstreeSysroot *sysroot,
|
||||
* the prune.
|
||||
*/
|
||||
g_autoptr(OstreeRepoAutoLock) lock =
|
||||
_ostree_repo_auto_lock_push (repo, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
|
||||
ostree_repo_auto_lock_push (repo, OSTREE_REPO_LOCK_EXCLUSIVE, cancellable, error);
|
||||
if (!lock)
|
||||
return FALSE;
|
||||
|
||||
|
||||
@@ -2632,6 +2632,39 @@ _ostree_deployment_set_bootconfig_from_kargs (OstreeDeployment *deployment,
|
||||
}
|
||||
}
|
||||
|
||||
// Perform some basic static analysis and emit warnings for things
|
||||
// that are likely to fail later. This function only returns
|
||||
// a hard error if something unexpected (e.g. I/O error) occurs.
|
||||
static gboolean
|
||||
lint_deployment_fs (OstreeSysroot *self,
|
||||
OstreeDeployment *deployment,
|
||||
int deployment_dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
glnx_autofd int dest_dfd = -1;
|
||||
gboolean exists;
|
||||
|
||||
if (!ot_dfd_iter_init_allow_noent (deployment_dfd, "var", &dfd_iter, &exists, error))
|
||||
return FALSE;
|
||||
while (exists)
|
||||
{
|
||||
struct dirent *dent;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
fprintf (stderr, "note: Deploying commit %s which contains content in /var/%s that will be ignored.\n",
|
||||
ostree_deployment_get_csum (deployment),
|
||||
dent->d_name);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* The first part of writing a deployment. This primarily means doing the
|
||||
* hardlink farm checkout, but we also compute some initial state.
|
||||
*/
|
||||
@@ -2680,6 +2713,9 @@ sysroot_initialize_deployment (OstreeSysroot *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (!lint_deployment_fs (self, new_deployment, deployment_dfd, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
ot_transfer_out_value (out_new_deployment, &new_deployment);
|
||||
return TRUE;
|
||||
}
|
||||
@@ -3070,28 +3106,6 @@ ostree_sysroot_stage_tree_with_options (OstreeSysroot *self,
|
||||
if (booted_deployment == NULL)
|
||||
return glnx_prefix_error (error, "Cannot stage deployment");
|
||||
|
||||
/* This is used by the testsuite to exercise the path unit, until it becomes the default
|
||||
* (which is pending on the preset making it everywhere). */
|
||||
if ((self->debug_flags & OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH) == 0)
|
||||
{
|
||||
/* This is a bit of a hack. When adding a new service we have to end up getting
|
||||
* into the presets for downstream distros; see e.g. https://src.fedoraproject.org/rpms/ostree/pull-request/7
|
||||
*
|
||||
* Then again, it's perhaps a bit nicer to only start the service on-demand anyways.
|
||||
*/
|
||||
const char *const systemctl_argv[] = {"systemctl", "start", "ostree-finalize-staged.service", NULL};
|
||||
int estatus;
|
||||
if (!g_spawn_sync (NULL, (char**)systemctl_argv, NULL, G_SPAWN_SEARCH_PATH,
|
||||
NULL, NULL, NULL, NULL, &estatus, error))
|
||||
return FALSE;
|
||||
if (!g_spawn_check_exit_status (estatus, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_print ("test-staged-path: Not running `systemctl start`\n");
|
||||
} /* OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH */
|
||||
|
||||
g_autoptr(OstreeDeployment) deployment = NULL;
|
||||
if (!sysroot_initialize_deployment (self, osname, revision, origin, opts, &deployment,
|
||||
cancellable, error))
|
||||
|
||||
@@ -37,8 +37,7 @@ typedef enum {
|
||||
OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE = 1 << 2,
|
||||
/* This is a temporary flag until we fully drop the explicit `systemctl start
|
||||
* ostree-finalize-staged.service` so that tests can exercise the new path unit. */
|
||||
OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH = 1 << 3,
|
||||
OSTREE_SYSROOT_DEBUG_TEST_NO_DTB = 1 << 4, /* https://github.com/ostreedev/ostree/issues/2154 */
|
||||
OSTREE_SYSROOT_DEBUG_TEST_NO_DTB = 1 << 3, /* https://github.com/ostreedev/ostree/issues/2154 */
|
||||
} OstreeSysrootDebugFlags;
|
||||
|
||||
typedef enum {
|
||||
|
||||
@@ -190,7 +190,6 @@ ostree_sysroot_init (OstreeSysroot *self)
|
||||
{ "mutable-deployments", OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS },
|
||||
{ "test-fifreeze", OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE },
|
||||
{ "no-xattrs", OSTREE_SYSROOT_DEBUG_NO_XATTRS },
|
||||
{ "test-staged-path", OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH },
|
||||
{ "no-dtb", OSTREE_SYSROOT_DEBUG_TEST_NO_DTB },
|
||||
};
|
||||
|
||||
@@ -1063,7 +1062,7 @@ _ostree_sysroot_reload_staged (OstreeSysroot *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Loads the current bootversion, subbootversion, and deplyments, starting from the
|
||||
/* Loads the current bootversion, subbootversion, and deployments, starting from the
|
||||
* bootloader configs which are the source of truth.
|
||||
*/
|
||||
static gboolean
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_RELEASE_VERSION (2)
|
||||
#define OSTREE_RELEASE_VERSION (3)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION
|
||||
@@ -52,7 +52,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION (2021.2)
|
||||
#define OSTREE_VERSION (2021.3)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION_S:
|
||||
@@ -62,7 +62,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION_S "2021.2"
|
||||
#define OSTREE_VERSION_S "2021.3"
|
||||
|
||||
#define OSTREE_ENCODE_VERSION(year,release) \
|
||||
((year) << 16 | (release))
|
||||
@@ -100,4 +100,4 @@
|
||||
*
|
||||
* Since: 2019.3
|
||||
*/
|
||||
#define OSTREE_BUILT_FEATURES "libcurl libsoup gpgme ex-fsverity libarchive selinux openssl libmount systemd release p2p"
|
||||
#define OSTREE_BUILT_FEATURES "libsoup gpgme ex-fsverity libarchive selinux avahi libmount systemd release p2p"
|
||||
Reference in new issue
Block a user