New upstream version 2018.4

This commit is contained in:
Simon McVittie committed 2018-03-24 18:19:31 +00:00
commit de3c1878b1
85 files changed
+1520 -1199

No files matched your search

+2
View File
@@ -18,6 +18,8 @@
***/
/* 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
+6
View File
@@ -458,6 +458,12 @@ LIBOSTREE_2018.2 {
ostree_commit_get_content_checksum;
} LIBOSTREE_2018.1;
LIBOSTREE_2018.3 {
ostree_deployment_origin_remove_transient_state;
ostree_sysroot_deployment_set_pinned;
ostree_deployment_is_pinned;
} LIBOSTREE_2018.2;
/* NOTE: Only add more content here in release commits! See the
* comments at the top of this file.
*/
+5
View File
@@ -1239,6 +1239,8 @@ ostree_object_type_to_string (OstreeObjectType objtype)
return "tombstone-commit";
case OSTREE_OBJECT_TYPE_COMMIT_META:
return "commitmeta";
case OSTREE_OBJECT_TYPE_PAYLOAD_LINK:
return "payload-link";
default:
g_assert_not_reached ();
return NULL;
@@ -1266,6 +1268,8 @@ ostree_object_type_from_string (const char *str)
return OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT;
else if (!strcmp (str, "commitmeta"))
return OSTREE_OBJECT_TYPE_COMMIT_META;
else if (!strcmp (str, "payload-link"))
return OSTREE_OBJECT_TYPE_PAYLOAD_LINK;
g_assert_not_reached ();
return 0;
}
@@ -2122,6 +2126,7 @@ _ostree_validate_structureof_metadata (OstreeObjectType objtype,
break;
case OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT:
case OSTREE_OBJECT_TYPE_COMMIT_META:
case OSTREE_OBJECT_TYPE_PAYLOAD_LINK:
/* TODO */
break;
case OSTREE_OBJECT_TYPE_FILE:
+3 -1
View File
@@ -68,6 +68,7 @@ G_BEGIN_DECLS
* @OSTREE_OBJECT_TYPE_COMMIT: Toplevel object, refers to tree and dirmeta for root
* @OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT: Toplevel object, refers to a deleted commit
* @OSTREE_OBJECT_TYPE_COMMIT_META: Detached metadata for a commit
* @OSTREE_OBJECT_TYPE_PAYLOAD_LINK: Symlink to a .file given its checksum on the payload only.
*
* Enumeration for core object types; %OSTREE_OBJECT_TYPE_FILE is for
* content, the other types are metadata.
@@ -79,6 +80,7 @@ typedef enum {
OSTREE_OBJECT_TYPE_COMMIT = 4, /* .commit */
OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT = 5, /* .commit-tombstone */
OSTREE_OBJECT_TYPE_COMMIT_META = 6, /* .commitmeta */
OSTREE_OBJECT_TYPE_PAYLOAD_LINK = 7, /* .payload-link */
} OstreeObjectType;
/**
@@ -94,7 +96,7 @@ typedef enum {
*
* Last valid object type; use this to validate ranges.
*/
#define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_COMMIT_META
#define OSTREE_OBJECT_TYPE_LAST OSTREE_OBJECT_TYPE_PAYLOAD_LINK
/**
* OSTREE_DIRMETA_GVARIANT_FORMAT:
+46
View File
@@ -121,6 +121,35 @@ ostree_deployment_set_origin (OstreeDeployment *self, GKeyFile *origin)
self->origin = g_key_file_ref (origin);
}
/**
* ostree_deployment_origin_remove_transient_state:
* @origin: An origin
*
* The intention of an origin file is primarily describe the "inputs" that
* resulted in a deployment, and it's commonly used to derive the new state. For
* example, a key value (in pure libostree mode) is the "refspec". However,
* libostree (or other applications) may want to store "transient" state that
* should not be carried across upgrades.
*
* This function just removes all members of the `libostree-transient` group.
* The name of that group is available to all libostree users; best practice
* would be to prefix values underneath there with a short identifier for your
* software.
*
* Additionally, this function will remove the `origin/unlocked` and
* `origin/override-commit` members; these should be considered transient state
* that should have been under an explicit group.
*
* Since: 2018.3
*/
void
ostree_deployment_origin_remove_transient_state (GKeyFile *origin)
{
g_key_file_remove_group (origin, OSTREE_ORIGIN_TRANSIENT_GROUP, NULL);
g_key_file_remove_key (origin, "origin", "override-commit", NULL);
g_key_file_remove_key (origin, "origin", "unlocked", NULL);
}
void
_ostree_deployment_set_bootcsum (OstreeDeployment *self,
const char *bootcsum)
@@ -293,3 +322,20 @@ ostree_deployment_get_unlocked (OstreeDeployment *self)
{
return self->unlocked;
}
/**
* ostree_deployment_is_pinned:
* @self: Deployment
*
* See ostree_sysroot_deployment_set_pinned().
*
* Returns: `TRUE` if deployment will not be subject to GC
* Since: 2018.3
*/
gboolean
ostree_deployment_is_pinned (OstreeDeployment *self)
{
if (!self->origin)
return FALSE;
return g_key_file_get_boolean (self->origin, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL);
}
+18
View File
@@ -27,6 +27,17 @@ G_BEGIN_DECLS
#define OSTREE_DEPLOYMENT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_DEPLOYMENT, OstreeDeployment))
#define OSTREE_IS_DEPLOYMENT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_DEPLOYMENT))
/**
* OSTREE_ORIGIN_TRANSIENT_GROUP:
*
* The name of a `GKeyFile` group for data that should not
* be carried across upgrades. For more information,
* see ostree_deployment_origin_remove_transient_state().
*
* Since: 2018.3
*/
#define OSTREE_ORIGIN_TRANSIENT_GROUP "libostree-transient"
typedef struct _OstreeDeployment OstreeDeployment;
_OSTREE_PUBLIC
@@ -62,6 +73,10 @@ OstreeBootconfigParser *ostree_deployment_get_bootconfig (OstreeDeployment *self
_OSTREE_PUBLIC
GKeyFile *ostree_deployment_get_origin (OstreeDeployment *self);
_OSTREE_PUBLIC
gboolean ostree_deployment_is_pinned (OstreeDeployment *self);
_OSTREE_PUBLIC
void ostree_deployment_set_index (OstreeDeployment *self, int index);
_OSTREE_PUBLIC
@@ -71,6 +86,9 @@ void ostree_deployment_set_bootconfig (OstreeDeployment *self, OstreeBootconfigP
_OSTREE_PUBLIC
void ostree_deployment_set_origin (OstreeDeployment *self, GKeyFile *origin);
_OSTREE_PUBLIC
void ostree_deployment_origin_remove_transient_state (GKeyFile *origin);
_OSTREE_PUBLIC
OstreeDeployment *ostree_deployment_clone (OstreeDeployment *self);
+16 -1
View File
@@ -77,6 +77,7 @@ struct OstreeFetcher
char *proxy;
struct curl_slist *extra_headers;
int tmpdir_dfd;
char *custom_user_agent;
GMainContext *mainctx;
CURLM *multi;
@@ -180,6 +181,7 @@ _ostree_fetcher_finalize (GObject *object)
g_clear_pointer (&self->timer_event, (GDestroyNotify)destroy_and_unref_source);
if (self->mainctx)
g_main_context_unref (self->mainctx);
g_clear_pointer (&self->custom_user_agent, (GDestroyNotify)g_free);
G_OBJECT_CLASS (_ostree_fetcher_parent_class)->finalize (object);
}
@@ -676,6 +678,18 @@ _ostree_fetcher_set_extra_headers (OstreeFetcher *self,
}
}
void
_ostree_fetcher_set_extra_user_agent (OstreeFetcher *self,
const char *extra_user_agent)
{
g_clear_pointer (&self->custom_user_agent, (GDestroyNotify)g_free);
if (extra_user_agent)
{
self->custom_user_agent =
g_strdup_printf ("%s %s", OSTREE_FETCHER_USERAGENT_STRING, extra_user_agent);
}
}
/* Re-bind all of the outstanding curl items to our new main context */
static void
adopt_steal_mainctx (OstreeFetcher *self,
@@ -716,7 +730,8 @@ initiate_next_curl_request (FetcherRequest *req,
curl_easy_setopt (req->easy, CURLOPT_URL, uri);
}
curl_easy_setopt (req->easy, CURLOPT_USERAGENT, OSTREE_FETCHER_USERAGENT_STRING);
curl_easy_setopt (req->easy, CURLOPT_USERAGENT,
self->custom_user_agent ?: OSTREE_FETCHER_USERAGENT_STRING);
if (self->extra_headers)
curl_easy_setopt (req->easy, CURLOPT_HTTPHEADER, self->extra_headers);
+28
View File
@@ -374,6 +374,24 @@ session_thread_set_tls_database_cb (ThreadClosure *thread_closure,
}
}
static void
session_thread_set_extra_user_agent_cb (ThreadClosure *thread_closure,
gpointer data)
{
const char *extra_user_agent = data;
if (extra_user_agent != NULL)
{
g_autofree char *ua =
g_strdup_printf ("%s %s", OSTREE_FETCHER_USERAGENT_STRING, extra_user_agent);
g_object_set (thread_closure->session, SOUP_SESSION_USER_AGENT, ua, NULL);
}
else
{
g_object_set (thread_closure->session, SOUP_SESSION_USER_AGENT,
OSTREE_FETCHER_USERAGENT_STRING, NULL);
}
}
static void
on_request_sent (GObject *object, GAsyncResult *result, gpointer user_data);
@@ -774,6 +792,16 @@ _ostree_fetcher_set_extra_headers (OstreeFetcher *self,
(GDestroyNotify) g_variant_unref);
}
void
_ostree_fetcher_set_extra_user_agent (OstreeFetcher *self,
const char *extra_user_agent)
{
session_thread_idle_add (self->thread_closure,
session_thread_set_extra_user_agent_cb,
g_strdup (extra_user_agent),
(GDestroyNotify) g_free);
}
static gboolean
finish_stream (OstreeFetcherPendingURI *pending,
GCancellable *cancellable,
+3
View File
@@ -114,6 +114,9 @@ void _ostree_fetcher_set_tls_database (OstreeFetcher *self,
void _ostree_fetcher_set_extra_headers (OstreeFetcher *self,
GVariant *extra_headers);
void _ostree_fetcher_set_extra_user_agent (OstreeFetcher *self,
const char *extra_user_agent);
guint64 _ostree_fetcher_bytes_transferred (OstreeFetcher *self);
void _ostree_fetcher_request_to_tmpfile (OstreeFetcher *self,
+1
View File
@@ -149,6 +149,7 @@ ostree_remote_unref (OstreeRemote *remote)
if (g_atomic_int_dec_and_test (&remote->ref_count))
{
g_clear_pointer (&remote->name, g_free);
g_clear_pointer (&remote->refspec_name, g_free);
g_clear_pointer (&remote->group, g_free);
g_clear_pointer (&remote->keyring, g_free);
g_clear_object (&remote->file);
+247 -4
View File
@@ -30,6 +30,8 @@
#include <gio/gunixoutputstream.h>
#include <sys/xattr.h>
#include <glib/gprintf.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include "otutil.h"
#include "ostree.h"
@@ -40,6 +42,12 @@
#include "ostree-checksum-input-stream.h"
#include "ostree-varint.h"
/* The standardized version of BTRFS_IOC_CLONE */
#ifndef FICLONE
#define FICLONE _IOW(0x94, 9, int)
#endif
/* If fsync is enabled and we're in a txn, we write into a staging dir for
* commit, but we also allow direct writes into objects/ for e.g. hardlink
* imports.
@@ -589,6 +597,192 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
return TRUE;
}
static gboolean
_check_support_reflink (OstreeRepo *self, 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)
{
g_auto(GLnxTmpfile) src_tmpf = { 0, };
g_auto(GLnxTmpfile) dest_tmpf = { 0, };
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", O_RDWR|O_CLOEXEC,
&src_tmpf, error))
return FALSE;
if (!glnx_open_tmpfile_linkable_at (commit_tmp_dfd (self), ".", 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);
else if (errno == EOPNOTSUPP) /* Ignore other kind of errors as they might be temporary failures */
g_atomic_int_set (&self->fs_support_reflink, -1);
}
*supported = g_atomic_int_get (&self->fs_support_reflink) >= 0;
return TRUE;
}
static gboolean
_create_payload_link (OstreeRepo *self,
const char *checksum,
const char *payload_checksum,
GFileInfo *file_info,
GCancellable *cancellable,
GError **error)
{
gboolean reflinks_supported = FALSE;
if (!_check_support_reflink (self, &reflinks_supported, error))
return FALSE;
if (!reflinks_supported)
return TRUE;
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR
|| !G_IN_SET(self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY))
return TRUE;
if (payload_checksum == NULL || g_file_info_get_size (file_info) < self->payload_link_threshold)
return TRUE;
char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN];
strcpy (target_buf, _OSTREE_PAYLOAD_LINK_PREFIX);
_ostree_loose_path (target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, checksum, OSTREE_OBJECT_TYPE_FILE, self->mode);
if (symlinkat (target_buf, commit_tmp_dfd (self), payload_checksum) < 0)
{
if (errno != EEXIST)
return glnx_throw_errno_prefix (error, "symlinkat");
}
else
{
g_auto(OtCleanupUnlinkat) tmp_unlinker = { commit_tmp_dfd (self), g_strdup (payload_checksum) };
if (!commit_path_final (self, payload_checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, &tmp_unlinker, cancellable, error))
return FALSE;
}
return TRUE;
}
static gboolean
_import_payload_link (OstreeRepo *self,
OstreeRepo *source,
const char *checksum,
GCancellable *cancellable,
GError **error)
{
gboolean reflinks_supported = FALSE;
g_autofree char *payload_checksum = NULL;
g_autoptr(GInputStream) is = NULL;
glnx_unref_object OtChecksumInstream *checksum_payload = NULL;
g_autoptr(GFileInfo) file_info = NULL;
if (!_check_support_reflink (self, &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))
return TRUE;
if (!ostree_repo_load_file (source, 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)
return TRUE;
checksum_payload = ot_checksum_instream_new (is, G_CHECKSUM_SHA256);
guint64 remaining = g_file_info_get_size (file_info);
while (remaining)
{
char buf[8192];
gssize ret = g_input_stream_read ((GInputStream *) checksum_payload, buf,
MIN (sizeof (buf), remaining), cancellable, error);
if (ret < 0)
return FALSE;
remaining -= ret;
}
payload_checksum = ot_checksum_instream_get_string (checksum_payload);
return _create_payload_link (self, checksum, payload_checksum, file_info, cancellable, error);
}
static gboolean
_try_clone_from_payload_link (OstreeRepo *self,
const char *payload_checksum,
GFileInfo *file_info,
GLnxTmpfile *tmpf,
GCancellable *cancellable,
GError **error)
{
gboolean reflinks_supported = FALSE;
int dfd_searches[] = { -1, self->objects_dir_fd };
if (self->commit_stagedir.initialized)
dfd_searches[0] = self->commit_stagedir.fd;
if (!_check_support_reflink (self, &reflinks_supported, error))
return FALSE;
if (!reflinks_supported)
return TRUE;
for (guint i = 0; i < G_N_ELEMENTS (dfd_searches); i++)
{
glnx_autofd int fdf = -1;
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
char loose_path_target_buf[_OSTREE_LOOSE_PATH_MAX];
char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN];
char target_checksum[OSTREE_SHA256_STRING_LEN+1];
int dfd = dfd_searches[i];
ssize_t size;
if (dfd == -1)
continue;
_ostree_loose_path (loose_path_buf, payload_checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, self->mode);
size = TEMP_FAILURE_RETRY (readlinkat (dfd, loose_path_buf, target_buf, sizeof (target_buf)));
if (size < 0)
{
if (errno == ENOENT)
continue;
return glnx_throw_errno_prefix (error, "readlinkat");
}
if (size < OSTREE_SHA256_STRING_LEN + _OSTREE_PAYLOAD_LINK_PREFIX_LEN)
return glnx_throw (error, "invalid data size for %s", loose_path_buf);
sprintf (target_checksum, "%.2s%.62s", target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN + 3);
_ostree_loose_path (loose_path_target_buf, target_checksum, OSTREE_OBJECT_TYPE_FILE, self->mode);
if (!ot_openat_ignore_enoent (dfd, loose_path_target_buf, &fdf, error))
return FALSE;
if (fdf < 0)
{
/* If the link is referring to an object that doesn't exist anymore in the repository, just unlink it. */
if (!glnx_unlinkat (dfd, loose_path_buf, 0, error))
return FALSE;
}
else
{
/* This undoes all of the previous writes; we want to generate reflinked data. */
if (ftruncate (tmpf->fd, 0) < 0)
return glnx_throw_errno_prefix (error, "ftruncate");
if (glnx_regfile_copy_bytes (fdf, tmpf->fd, -1) < 0)
return glnx_throw_errno_prefix (error, "regfile copy");
return TRUE;
}
}
if (self->parent_repo)
return _try_clone_from_payload_link (self->parent_repo, payload_checksum, file_info, tmpf, cancellable, error);
return TRUE;
}
/* The main driver for writing a content (regfile or symlink) object.
* There are a variety of tricky cases here; for example, bare-user
* repos store symlinks as regular files. Computing checksums
@@ -616,6 +810,8 @@ write_content_object (OstreeRepo *self,
GInputStream *file_input; /* Unowned alias */
g_autoptr(GInputStream) file_input_owned = NULL; /* We need a temporary for bare-user symlinks */
glnx_unref_object OtChecksumInstream *checksum_input = NULL;
glnx_unref_object OtChecksumInstream *checksum_payload_input = NULL;
const GFileType object_file_type = g_file_info_get_file_type (file_info);
if (out_csum)
{
/* Previously we checksummed the input verbatim; now
@@ -624,6 +820,7 @@ write_content_object (OstreeRepo *self,
* it's not that's not a serious problem because we're still computing a
* checksum over the data we actually use.
*/
gboolean reflinks_supported = FALSE;
g_autoptr(GBytes) header = _ostree_file_header_new (file_info, xattrs);
size_t len;
const guint8 *buf = g_bytes_get_data (header, &len);
@@ -633,13 +830,26 @@ write_content_object (OstreeRepo *self,
null_input = input = g_memory_input_stream_new_from_data ("", 0, NULL);
checksum_input = ot_checksum_instream_new_with_start (input, G_CHECKSUM_SHA256,
buf, len);
file_input = (GInputStream*)checksum_input;
if (!_check_support_reflink (self, &reflinks_supported, error))
return FALSE;
if (xattrs == NULL || !G_IN_SET(self->mode, OSTREE_REPO_MODE_BARE, OSTREE_REPO_MODE_BARE_USER, OSTREE_REPO_MODE_BARE_USER_ONLY) || object_file_type != G_FILE_TYPE_REGULAR ||
!reflinks_supported)
file_input = (GInputStream*)checksum_input;
else
{
/* The payload checksum-input reads from the full object checksum-input; this
* means it skips the header.
*/
checksum_payload_input = ot_checksum_instream_new ((GInputStream*)checksum_input, G_CHECKSUM_SHA256);
file_input = (GInputStream*)checksum_payload_input;
}
}
else
file_input = input;
gboolean phys_object_is_symlink = FALSE;
const GFileType object_file_type = g_file_info_get_file_type (file_info);
switch (object_file_type)
{
case G_FILE_TYPE_REGULAR:
@@ -765,6 +975,7 @@ write_content_object (OstreeRepo *self,
}
const char *actual_checksum = NULL;
g_autofree char *actual_payload_checksum = NULL;
g_autofree char *actual_checksum_owned = NULL;
if (!checksum_input)
actual_checksum = expected_checksum;
@@ -777,6 +988,9 @@ write_content_object (OstreeRepo *self,
error))
return FALSE;
}
if (checksum_payload_input)
actual_payload_checksum = ot_checksum_instream_get_string (checksum_payload_input);
}
g_assert (actual_checksum != NULL); /* Pacify static analysis */
@@ -794,6 +1008,10 @@ write_content_object (OstreeRepo *self,
g_mutex_lock (&self->txn_lock);
self->txn.stats.content_objects_total++;
g_mutex_unlock (&self->txn_lock);
if (!_create_payload_link (self, actual_checksum, actual_payload_checksum, file_info, cancellable, error))
return FALSE;
if (out_csum)
*out_csum = ostree_checksum_to_bytes (actual_checksum);
/* Note early return */
@@ -853,12 +1071,20 @@ write_content_object (OstreeRepo *self,
repo_store_size_entry (self, actual_checksum, unpacked_size, stbuf.st_size);
}
/* 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))
return FALSE;
/* This path is for regular files */
if (!commit_loose_regfile_object (self, actual_checksum, &tmpf,
uid, gid, mode,
xattrs,
cancellable, error))
return FALSE;
if (!_create_payload_link (self, actual_checksum, actual_payload_checksum, file_info, cancellable, error))
return FALSE;
}
/* Update statistics */
@@ -1927,6 +2153,12 @@ ostree_repo_abort_transaction (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
/* Always ignore the cancellable to avoid the chance that, if it gets
* canceled, the transaction may not be fully cleaned up.
* See https://github.com/ostreedev/ostree/issues/1491 .
*/
cancellable = NULL;
/* Note early return */
if (!self->in_transaction)
return TRUE;
@@ -3999,7 +4231,11 @@ import_one_object_direct (OstreeRepo *dest_repo,
if (!copy_detached_metadata (dest_repo, src_repo, checksum, cancellable, error))
return FALSE;
}
else if (objtype == OSTREE_OBJECT_TYPE_FILE)
{
if (!_import_payload_link (dest_repo, src_repo, checksum, cancellable, error))
return FALSE;
}
*out_was_supported = TRUE;
return TRUE;
}
@@ -4092,7 +4328,14 @@ _ostree_repo_import_object (OstreeRepo *self,
return FALSE;
/* If we have it, we're done */
if (has_object)
return TRUE;
{
if (objtype == OSTREE_OBJECT_TYPE_FILE)
{
if (!_import_payload_link (self, source, checksum, cancellable, error))
return FALSE;
}
return TRUE;
}
if (OSTREE_OBJECT_TYPE_IS_META (objtype))
{
+2 -1
View File
@@ -30,6 +30,7 @@
#include <glib-object.h>
#include <libglnx.h>
#include "ostree-autocleanups.h"
#include "ostree-remote-private.h"
#include "ostree-repo.h"
#include "ostree-repo-private.h"
@@ -176,7 +177,7 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
while (g_hash_table_iter_next (&iter, (gpointer *) &remote_name, (gpointer *) &supported_ref_to_checksum))
{
g_autoptr(GError) local_error = NULL;
OstreeRemote *remote;
g_autoptr(OstreeRemote) remote = NULL;
/* We don’t know what last-modified timestamp the remote has without
* making expensive HTTP queries, so leave that information blank. We
+4 -4
View File
@@ -52,7 +52,7 @@
* enumerated, and all OSTree repositories below it will be searched, in lexical
* order, for the requested #OstreeCollectionRefs. The names of the directories
* below `.ostree/repos.d` are irrelevant, apart from their lexical ordering.
* The directories `.ostree/repo`, `ostree/repo` and `var/lib/flatpak`
* The directories `.ostree/repo`, `ostree/repo` and `var/lib/flatpak/repo`
* will be searched after the others, if they exist.
* Non-removable volumes are ignored.
*
@@ -295,8 +295,8 @@ scan_and_add_repo (int dfd,
};
g_array_append_val (inout_repos_refs, val);
g_debug ("%s: Adding repo ‘%s’ (%ssortable)",
G_STRFUNC, path, sortable ? "" : "not ");
g_debug ("%s: Adding repo ‘%s’ on mount ‘%s’ (%ssortable)",
G_STRFUNC, path, mount_name, sortable ? "" : "not ");
}
}
@@ -439,7 +439,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
{
".ostree/repo",
"ostree/repo",
"var/lib/flatpak",
"var/lib/flatpak/repo",
};
for (i = 0; i < G_N_ELEMENTS (well_known_repos); i++)
+5 -8
View File
@@ -53,6 +53,9 @@ G_BEGIN_DECLS
#define OSTREE_SUMMARY_COLLECTION_ID "ostree.summary.collection-id"
#define OSTREE_SUMMARY_COLLECTION_MAP "ostree.summary.collection-map"
#define _OSTREE_PAYLOAD_LINK_PREFIX "../"
#define _OSTREE_PAYLOAD_LINK_PREFIX_LEN (sizeof (_OSTREE_PAYLOAD_LINK_PREFIX) - 1)
/* Well-known keys for the additional metadata field in a commit in a ref entry
* in a summary file. */
#define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp"
@@ -161,6 +164,8 @@ struct OstreeRepo {
gchar *collection_id;
gboolean add_remotes_config_dir; /* Add new remotes in remotes.d dir */
gint lock_timeout_seconds;
guint64 payload_link_threshold;
gint fs_support_reflink; /* The underlying filesystem has support for ioctl (FICLONE..) */
OstreeRepo *parent_repo;
};
@@ -237,14 +242,6 @@ _ostree_repo_ensure_loose_objdir_at (int dfd,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_repo_find_object (OstreeRepo *self,
OstreeObjectType objtype,
const char *checksum,
GFile **out_stored_path,
GCancellable *cancellable,
GError **error);
GFile *
_ostree_repo_get_commit_metadata_loose_path (OstreeRepo *self,
const char *checksum);
+49 -10
View File
@@ -46,40 +46,79 @@ maybe_prune_loose_object (OtPruneData *data,
GCancellable *cancellable,
GError **error)
{
gboolean reachable = FALSE;
g_autoptr(GVariant) key = NULL;
key = ostree_object_name_serialize (checksum, objtype);
if (!g_hash_table_lookup_extended (data->reachable, key, NULL, NULL))
if (g_hash_table_lookup_extended (data->reachable, key, NULL, NULL))
reachable = TRUE;
else
{
guint64 storage_size = 0;
g_debug ("Pruning unneeded object %s.%s", checksum,
ostree_object_type_to_string (objtype));
if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum,
&storage_size, cancellable, error))
return FALSE;
data->freed_bytes += storage_size;
if (!(flags & OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE))
{
guint64 storage_size = 0;
if (objtype == OSTREE_OBJECT_TYPE_PAYLOAD_LINK)
{
ssize_t size;
char loose_path_buf[_OSTREE_LOOSE_PATH_MAX];
char target_checksum[OSTREE_SHA256_STRING_LEN+1];
char target_buf[_OSTREE_LOOSE_PATH_MAX + _OSTREE_PAYLOAD_LINK_PREFIX_LEN];
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
_ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_PAYLOAD_LINK, data->repo->mode);
size = readlinkat (data->repo->objects_dir_fd, loose_path_buf, target_buf, sizeof (target_buf));
if (size < 0)
return glnx_throw_errno_prefix (error, "readlinkat");
if (size < OSTREE_SHA256_STRING_LEN + _OSTREE_PAYLOAD_LINK_PREFIX_LEN)
return glnx_throw (error, "invalid data size for %s", loose_path_buf);
sprintf (target_checksum, "%.2s%.62s", target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN, target_buf + _OSTREE_PAYLOAD_LINK_PREFIX_LEN + 3);
g_autoptr(GVariant) target_key = ostree_object_name_serialize (target_checksum, OSTREE_OBJECT_TYPE_FILE);
if (g_hash_table_lookup_extended (data->reachable, target_key, NULL, NULL))
{
guint64 target_storage_size = 0;
if (!ostree_repo_query_object_storage_size (data->repo, OSTREE_OBJECT_TYPE_FILE, target_checksum,
&target_storage_size, cancellable, error))
return FALSE;
reachable = target_storage_size >= data->repo->payload_link_threshold;
if (reachable)
goto exit;
}
}
else if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
{
if (!ostree_repo_mark_commit_partial (data->repo, checksum, FALSE, error))
return FALSE;
}
if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum,
&storage_size, cancellable, error))
return FALSE;
if (!ostree_repo_delete_object (data->repo, objtype, checksum,
cancellable, error))
return FALSE;
data->freed_bytes += storage_size;
}
if (OSTREE_OBJECT_TYPE_IS_META (objtype))
data->n_unreachable_meta++;
else
data->n_unreachable_content++;
}
else
exit:
if (reachable)
{
g_debug ("Keeping needed object %s.%s", checksum,
ostree_object_type_to_string (objtype));
@@ -283,7 +322,7 @@ repo_prune_internal (OstreeRepo *self,
* of traversing all commits, only refs will be used. Particularly
* when combined with @depth, this is a convenient way to delete
* history from the repository.
*
*
* Use the %OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE to just determine
* statistics on objects that would be deleted, without actually
* deleting them.
+18 -3
View File
@@ -87,6 +87,7 @@ typedef struct {
OstreeAsyncProgress *progress;
GVariant *extra_headers;
char *append_user_agent;
gboolean dry_run;
gboolean dry_run_emitted_progress;
@@ -2922,11 +2923,13 @@ repo_remote_fetch_summary (OstreeRepo *self,
const char *url_override = NULL;
g_autoptr(GVariant) extra_headers = NULL;
g_autoptr(GPtrArray) mirrorlist = NULL;
const char *append_user_agent = NULL;
if (options)
{
(void) g_variant_lookup (options, "override-url", "&s", &url_override);
(void) g_variant_lookup (options, "http-headers", "@a(ss)", &extra_headers);
(void) g_variant_lookup (options, "append-user-agent", "&s", &append_user_agent);
}
mainctx = g_main_context_new ();
@@ -2939,6 +2942,9 @@ repo_remote_fetch_summary (OstreeRepo *self,
if (extra_headers)
_ostree_fetcher_set_extra_headers (fetcher, extra_headers);
if (append_user_agent)
_ostree_fetcher_set_extra_user_agent (fetcher, append_user_agent);
{
g_autofree char *url_string = NULL;
if (metalink_url_string)
@@ -3055,6 +3061,9 @@ reinitialize_fetcher (OtPullData *pull_data, const char *remote_name,
if (pull_data->extra_headers)
_ostree_fetcher_set_extra_headers (pull_data->fetcher, pull_data->extra_headers);
if (pull_data->append_user_agent)
_ostree_fetcher_set_extra_user_agent (pull_data->fetcher, pull_data->append_user_agent);
return TRUE;
}
@@ -3240,6 +3249,7 @@ initiate_request (OtPullData *pull_data,
* * http-headers (a(ss)): Additional headers to add to all HTTP requests
* * update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid
* * localcache-repos (as): File paths for local repos to use as caches when doing remote fetches
* * append-user-agent (s): Additional string to append to the user agent
*/
gboolean
ostree_repo_pull_with_options (OstreeRepo *self,
@@ -3311,6 +3321,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
(void) g_variant_lookup (options, "update-frequency", "u", &update_frequency);
(void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos);
(void) g_variant_lookup (options, "timestamp-check", "b", &pull_data->timestamp_check);
(void) g_variant_lookup (options, "append-user-agent", "s", &pull_data->append_user_agent);
if (pull_data->remote_refspec_name != NULL)
pull_data->remote_name = g_strdup (pull_data->remote_refspec_name);
@@ -3365,7 +3376,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
(GDestroyNotify)g_free);
pull_data->ref_original_commits = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal,
(GDestroyNotify)NULL,
(GDestroyNotify)g_variant_unref);
(GDestroyNotify)g_free);
pull_data->gpg_verified_commits = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, NULL);
pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal,
@@ -4323,6 +4334,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_clear_pointer (&pull_data->localcache_repos, (GDestroyNotify)g_ptr_array_unref);
g_clear_object (&pull_data->remote_repo_local);
g_free (pull_data->remote_name);
g_free (pull_data->append_user_agent);
g_clear_pointer (&pull_data->meta_mirrorlist, (GDestroyNotify) g_ptr_array_unref);
g_clear_pointer (&pull_data->content_mirrorlist, (GDestroyNotify) g_ptr_array_unref);
g_clear_pointer (&pull_data->summary_data, (GDestroyNotify) g_bytes_unref);
@@ -5502,6 +5514,7 @@ ostree_repo_pull_from_remotes_async (OstreeRepo *self,
copy_option (&options_dict, &local_options_dict, "http-headers", G_VARIANT_TYPE ("a(ss)"));
copy_option (&options_dict, &local_options_dict, "subdirs", G_VARIANT_TYPE ("as"));
copy_option (&options_dict, &local_options_dict, "update-frequency", G_VARIANT_TYPE ("u"));
copy_option (&options_dict, &local_options_dict, "append-user-agent", G_VARIANT_TYPE ("s"));
local_options = g_variant_dict_end (&local_options_dict);
@@ -5645,7 +5658,7 @@ ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
{
gsize i;
g_auto(GStrv) remotes = NULL;
OstreeRemote *keyring_remote = NULL;
g_autoptr(OstreeRemote) keyring_remote = NULL;
g_return_val_if_fail (OSTREE_IS_REPO (self), NULL);
g_return_val_if_fail (ostree_validate_collection_id (collection_id, NULL), NULL);
@@ -5680,6 +5693,7 @@ ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
{
g_debug ("%s: Ignoring remote ‘%s’ as it has no keyring configured.",
G_STRFUNC, remotes[i]);
g_clear_object (&keyring_remote);
continue;
}
@@ -5695,7 +5709,7 @@ ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
}
if (keyring_remote != NULL)
return ostree_remote_ref (keyring_remote);
return g_steal_pointer (&keyring_remote);
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
@@ -5724,6 +5738,7 @@ ostree_repo_resolve_keyring_for_collection (OstreeRepo *self,
*
* - override-url (s): Fetch summary from this URL if remote specifies no metalink in options
* - http-headers (a(ss)): Additional headers to add to all HTTP requests
* - append-user-agent (s): Additional string to append to the user agent
*
* Returns: %TRUE on success, %FALSE on failure
*/
+25 -14
View File
@@ -617,6 +617,8 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Listing refs", error);
g_autofree char *remote = NULL;
g_autofree char *ref_prefix = NULL;
@@ -627,8 +629,24 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
const char *prefix_path;
const char *path;
if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
return FALSE;
/* special-case "<remote>:" and "<remote>:.", which ostree_parse_refspec won't like */
if (g_str_has_suffix (refspec_prefix, ":") ||
g_str_has_suffix (refspec_prefix, ":."))
{
const char *colon = strrchr (refspec_prefix, ':');
g_autofree char *r = g_strndup (refspec_prefix, colon - refspec_prefix);
if (ostree_validate_remote_name (r, NULL))
{
remote = g_steal_pointer (&r);
ref_prefix = g_strdup (".");
}
}
if (!ref_prefix)
{
if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
return FALSE;
}
if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES) && remote)
{
@@ -1029,10 +1047,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
{
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE,
&dfd, error))
{
g_prefix_error (error, "Opening %s: ", "refs/heads");
return FALSE;
}
return FALSE;
}
else if (remote == NULL && ref->collection_id != NULL)
{
@@ -1041,10 +1056,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
/* refs/mirrors might not exist in older repositories, so create it. */
if (!glnx_shutil_mkdir_p_at_open (self->repo_dir_fd, "refs/mirrors", 0777,
&refs_mirrors_dfd, cancellable, error))
{
g_prefix_error (error, "Opening %s: ", "refs/mirrors");
return FALSE;
}
return FALSE;
if (rev != NULL)
{
@@ -1063,10 +1075,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
if (!glnx_opendirat (self->repo_dir_fd, "refs/remotes", TRUE,
&refs_remotes_dfd, error))
{
g_prefix_error (error, "Opening %s: ", "refs/remotes");
return FALSE;
}
return FALSE;
if (rev != NULL)
{
@@ -1207,6 +1216,8 @@ ostree_repo_list_collection_refs (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Listing refs", error);
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@@ -241,14 +241,8 @@ finish_part (OstreeStaticDeltaBuilder *builder, GError **error)
g_variant_builder_add_value (&xattr_builder, part_builder->xattrs->pdata[j]);
{
g_autoptr(GBytes) payload_b;
g_autoptr(GBytes) operations_b;
payload_b = g_string_free_to_bytes (part_builder->payload);
part_builder->payload = NULL;
operations_b = g_string_free_to_bytes (part_builder->operations);
part_builder->operations = NULL;
g_autoptr(GBytes) payload_b = g_string_free_to_bytes (g_steal_pointer (&part_builder->payload));
g_autoptr(GBytes) operations_b = g_string_free_to_bytes (g_steal_pointer (&part_builder->operations));
delta_part_content = g_variant_new ("(a(uuu)aa(ayay)@ay@ay)",
&mode_builder, &xattr_builder,
@@ -38,10 +38,8 @@ _ostree_static_delta_parse_checksum_array (GVariant *array,
guint *out_n_checksums,
GError **error)
{
gsize n = g_variant_n_children (array);
guint n_checksums;
n_checksums = n / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN;
const gsize n = g_variant_n_children (array);
const guint n_checksums = n / OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN;
if (G_UNLIKELY(n > (G_MAXUINT32/OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN) ||
(n_checksums * OSTREE_STATIC_DELTA_OBJTYPE_CSUM_LEN) != n))
@@ -166,8 +164,8 @@ _ostree_repo_static_delta_part_have_all_objects (OstreeRepo *repo,
GCancellable *cancellable,
GError **error)
{
guint8 *checksums_data;
guint n_checksums;
guint8 *checksums_data = NULL;
guint n_checksums = 0;
gboolean have_object = TRUE;
if (!_ostree_static_delta_parse_checksum_array (checksum_array,
+17 -8
View File
@@ -2827,6 +2827,15 @@ reload_core_config (OstreeRepo *self,
return FALSE;
}
{ g_autofree char *payload_threshold = NULL;
if (!ot_keyfile_get_value_with_default (self->config, "core", "payload-link-threshold", "-1",
&payload_threshold, error))
return FALSE;
self->payload_link_threshold = g_ascii_strtoull (payload_threshold, NULL, 10);
}
return TRUE;
}
@@ -3278,6 +3287,8 @@ list_loose_objects_at (OstreeRepo *self,
objtype = OSTREE_OBJECT_TYPE_DIR_META;
else if (strcmp (dot, ".commit") == 0)
objtype = OSTREE_OBJECT_TYPE_COMMIT;
else if (strcmp (dot, ".payload-link") == 0)
objtype = OSTREE_OBJECT_TYPE_PAYLOAD_LINK;
else
continue;
@@ -4800,17 +4811,16 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
/* Note that fd is reused below */
glnx_close_fd (&fd);
g_autoptr(GVariant) existing_signatures = NULL;
g_autoptr(GVariant) metadata = NULL;
if (!ot_openat_ignore_enoent (self->repo_dir_fd, "summary.sig", &fd, error))
return FALSE;
if (fd != -1)
{
if (!ot_variant_read_fd (fd, 0, G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING),
FALSE, &existing_signatures, error))
FALSE, &metadata, error))
return FALSE;
}
g_autoptr(GVariant) new_metadata = NULL;
for (guint i = 0; key_id[i]; i++)
{
g_autoptr(GBytes) signature_data = NULL;
@@ -4819,10 +4829,11 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
cancellable, error))
return FALSE;
new_metadata = _ostree_detached_metadata_append_gpg_sig (existing_signatures, signature_data);
g_autoptr(GVariant) old_metadata = g_steal_pointer (&metadata);
metadata = _ostree_detached_metadata_append_gpg_sig (old_metadata, signature_data);
}
g_autoptr(GVariant) normalized = g_variant_get_normal_form (new_metadata);
g_autoptr(GVariant) normalized = g_variant_get_normal_form (metadata);
if (!_ostree_repo_file_replace_contents (self,
self->repo_dir_fd,
@@ -4914,7 +4925,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
g_autofree char *gpgkeypath = NULL;
/* Add the remote's keyring file if it exists. */
OstreeRemote *remote;
g_autoptr(OstreeRemote) remote = NULL;
remote = _ostree_repo_get_remote_inherited (self, remote_name, error);
if (remote == NULL)
@@ -4936,8 +4947,6 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
if (gpgkeypath)
_ostree_gpg_verifier_add_key_ascii_file (verifier, gpgkeypath);
ostree_remote_unref (remote);
}
if (add_global_keyring_dir)
+95 -128
View File
@@ -523,38 +523,33 @@ checkout_deployment_tree (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
OstreeRepoCheckoutAtOptions checkout_opts = { 0, };
const char *csum = ostree_deployment_get_csum (deployment);
g_autofree char *checkout_target_name = NULL;
g_autofree char *osdeploy_path = NULL;
glnx_autofd int osdeploy_dfd = -1;
int ret_fd;
osdeploy_path = g_strconcat ("ostree/deploy/", ostree_deployment_get_osname (deployment), "/deploy", NULL);
checkout_target_name = g_strdup_printf ("%s.%d", csum, ostree_deployment_get_deployserial (deployment));
GLNX_AUTO_PREFIX_ERROR ("Checking out deployment tree", error);
/* Find the directory with deployments for this stateroot */
g_autofree char *osdeploy_path =
g_strconcat ("ostree/deploy/", ostree_deployment_get_osname (deployment), "/deploy", NULL);
if (!glnx_shutil_mkdir_p_at (sysroot->sysroot_fd, osdeploy_path, 0775, cancellable, error))
goto out;
return FALSE;
glnx_autofd int osdeploy_dfd = -1;
if (!glnx_opendirat (sysroot->sysroot_fd, osdeploy_path, TRUE, &osdeploy_dfd, error))
goto out;
return FALSE;
/* Clean up anything that was there before, from e.g. an interrupted checkout */
const char *csum = ostree_deployment_get_csum (deployment);
g_autofree char *checkout_target_name =
g_strdup_printf ("%s.%d", csum, ostree_deployment_get_deployserial (deployment));
if (!glnx_shutil_rm_rf_at (osdeploy_dfd, checkout_target_name, cancellable, error))
goto out;
return FALSE;
/* Generate hardlink farm, then opendir it */
OstreeRepoCheckoutAtOptions checkout_opts = { 0, };
if (!ostree_repo_checkout_at (repo, &checkout_opts, osdeploy_dfd,
checkout_target_name, csum,
cancellable, error))
goto out;
return FALSE;
if (!glnx_opendirat (osdeploy_dfd, checkout_target_name, TRUE, &ret_fd, error))
goto out;
ret = TRUE;
*out_deployment_dfd = ret_fd;
out:
return ret;
return glnx_opendirat (osdeploy_dfd, checkout_target_name, TRUE, out_deployment_dfd,
error);
}
static char *
@@ -672,27 +667,21 @@ selinux_relabel_dir (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GPtrArray) path_parts = g_ptr_array_new ();
g_autoptr(GFileInfo) root_info = NULL;
root_info = g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
g_autoptr(GFileInfo) root_info =
g_file_query_info (dir, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
if (!root_info)
goto out;
return FALSE;
g_autoptr(GPtrArray) path_parts = g_ptr_array_new ();
g_ptr_array_add (path_parts, (char*)prefix);
if (!relabel_recursively (sysroot, sepolicy, dir, root_info, path_parts,
cancellable, error))
{
g_prefix_error (error, "Relabeling /%s: ", prefix);
goto out;
}
return glnx_prefix_error (error, "Relabeling /%s", prefix);
ret = TRUE;
out:
return ret;
return TRUE;
}
/* Handles SELinux labeling for /var; this is slated to be deleted. See
@@ -767,16 +756,12 @@ merge_configuration (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("During /etc merge", error);
g_autoptr(OstreeSePolicy) sepolicy = NULL;
if (previous_deployment)
{
g_autoptr(GFile) previous_path = NULL;
OstreeBootconfigParser *previous_bootconfig;
previous_path = ostree_sysroot_get_deployment_directory (sysroot, previous_deployment);
previous_bootconfig = ostree_deployment_get_bootconfig (previous_deployment);
OstreeBootconfigParser *previous_bootconfig = ostree_deployment_get_bootconfig (previous_deployment);
if (previous_bootconfig)
{
const char *previous_options = ostree_bootconfig_parser_get (previous_bootconfig, "options");
@@ -847,30 +832,39 @@ merge_configuration (OstreeSysroot *sysroot,
return TRUE;
}
/* Write the origin file for a deployment. */
/* Write the origin file for a deployment; this does not bump the mtime, under
* the assumption the caller may be writing multiple.
*/
static gboolean
write_origin_file_internal (OstreeSysroot *sysroot,
OstreeSePolicy *sepolicy,
OstreeDeployment *deployment,
GKeyFile *new_origin,
GLnxFileReplaceFlags flags,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Writing out origin file", error);
GKeyFile *origin =
new_origin ? new_origin : ostree_deployment_get_origin (deployment);
if (origin)
{
g_autofree char *origin_path = NULL;
g_autofree char *contents = NULL;
g_auto(OstreeSepolicyFsCreatecon) con = { 0, };
if (!_ostree_sepolicy_preparefscreatecon (&con, sepolicy,
"/etc/ostree/remotes.d/dummy.conf",
0644, error))
return FALSE;
g_autofree char *origin_path =
g_strdup_printf ("ostree/deploy/%s/deploy/%s.%d.origin",
ostree_deployment_get_osname (deployment),
ostree_deployment_get_csum (deployment),
ostree_deployment_get_deployserial (deployment));
gsize len;
origin_path = g_strdup_printf ("ostree/deploy/%s/deploy/%s.%d.origin",
ostree_deployment_get_osname (deployment),
ostree_deployment_get_csum (deployment),
ostree_deployment_get_deployserial (deployment));
contents = g_key_file_to_data (origin, &len, error);
g_autofree char *contents = g_key_file_to_data (origin, &len, error);
if (!contents)
return FALSE;
@@ -903,9 +897,20 @@ ostree_sysroot_write_origin_file (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
return write_origin_file_internal (sysroot, deployment, new_origin,
GLNX_FILE_REPLACE_DATASYNC_NEW,
cancellable, error);
g_autoptr(GFile) rootfs = g_file_new_for_path ("/");
g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new (rootfs, cancellable, error);
if (!sepolicy)
return FALSE;
if (!write_origin_file_internal (sysroot, sepolicy, deployment, new_origin,
GLNX_FILE_REPLACE_DATASYNC_NEW,
cancellable, error))
return FALSE;
if (!_ostree_sysroot_bump_mtime (sysroot, error))
return FALSE;
return TRUE;
}
typedef struct {
@@ -1497,6 +1502,7 @@ create_new_bootlinks (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Creating new current bootlinks", error);
glnx_autofd int ostree_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error))
return FALSE;
@@ -1559,6 +1565,7 @@ swap_bootlinks (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Swapping new version bootlinks", error);
glnx_autofd int ostree_dfd = -1;
if (!glnx_opendirat (self->sysroot_fd, "ostree", TRUE, &ostree_dfd, error))
return FALSE;
@@ -1628,6 +1635,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
GError **error)
{
GLNX_AUTO_PREFIX_ERROR ("Installing kernel", error);
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
g_autofree char *deployment_dirpath = ostree_sysroot_get_deployment_dirpath (sysroot, deployment);
glnx_autofd int deployment_dfd = -1;
@@ -1936,23 +1944,18 @@ deployment_bootconfigs_equal (OstreeDeployment *a,
return FALSE;
{
OstreeBootconfigParser *a_bootconfig = ostree_deployment_get_bootconfig (a);
OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b);
const char *a_boot_options = ostree_bootconfig_parser_get (a_bootconfig, "options");
const char *b_boot_options = ostree_bootconfig_parser_get (b_bootconfig, "options");
g_autoptr(OstreeKernelArgs) a_kargs = NULL;
g_autoptr(OstreeKernelArgs) b_kargs = NULL;
g_autofree char *a_boot_options_without_ostree = NULL;
g_autofree char *b_boot_options_without_ostree = NULL;
/* We checksum the kernel arguments *except* ostree= */
a_kargs = _ostree_kernel_args_from_string (a_boot_options);
OstreeBootconfigParser *a_bootconfig = ostree_deployment_get_bootconfig (a);
const char *a_boot_options = ostree_bootconfig_parser_get (a_bootconfig, "options");
g_autoptr(OstreeKernelArgs) a_kargs = _ostree_kernel_args_from_string (a_boot_options);
_ostree_kernel_args_replace (a_kargs, "ostree");
a_boot_options_without_ostree = _ostree_kernel_args_to_string (a_kargs);
g_autofree char *a_boot_options_without_ostree = _ostree_kernel_args_to_string (a_kargs);
b_kargs = _ostree_kernel_args_from_string (b_boot_options);
OstreeBootconfigParser *b_bootconfig = ostree_deployment_get_bootconfig (b);
const char *b_boot_options = ostree_bootconfig_parser_get (b_bootconfig, "options");
g_autoptr(OstreeKernelArgs) b_kargs = _ostree_kernel_args_from_string (b_boot_options);
_ostree_kernel_args_replace (b_kargs, "ostree");
b_boot_options_without_ostree = _ostree_kernel_args_to_string (b_kargs);
g_autofree char *b_boot_options_without_ostree = _ostree_kernel_args_to_string (b_kargs);
if (strcmp (a_boot_options_without_ostree, b_boot_options_without_ostree) != 0)
return FALSE;
@@ -2083,12 +2086,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
GError **error)
{
gboolean ret = FALSE;
guint i;
gboolean requires_new_bootversion = FALSE;
gboolean found_booted_deployment = FALSE;
gboolean bootloader_is_atomic = FALSE;
gboolean boot_was_ro_mount = FALSE;
SyncStats syncstats = { 0, };
g_autoptr(OstreeBootloader) bootloader = NULL;
g_assert (self->loaded);
@@ -2102,11 +2100,12 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
* matching bootloader configuration, then we can just swap the
* subbootversion bootlinks.
*/
gboolean requires_new_bootversion = FALSE;
if (new_deployments->len != self->deployments->len)
requires_new_bootversion = TRUE;
else
{
for (i = 0; i < new_deployments->len; i++)
for (guint i = 0; i < new_deployments->len; i++)
{
if (!deployment_bootconfigs_equal (new_deployments->pdata[i],
self->deployments->pdata[i]))
@@ -2117,7 +2116,8 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
}
}
for (i = 0; i < new_deployments->len; i++)
gboolean found_booted_deployment = FALSE;
for (guint i = 0; i < new_deployments->len; i++)
{
OstreeDeployment *deployment = new_deployments->pdata[i];
g_autoptr(GFile) deployment_root = NULL;
@@ -2143,15 +2143,14 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
goto out;
}
gboolean bootloader_is_atomic = FALSE;
SyncStats syncstats = { 0, };
if (!requires_new_bootversion)
{
if (!create_new_bootlinks (self, self->bootversion,
new_deployments,
cancellable, error))
{
g_prefix_error (error, "Creating new current bootlinks: ");
goto out;
}
goto out;
if (!full_system_sync (self, &syncstats, cancellable, error))
{
@@ -2162,10 +2161,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
if (!swap_bootlinks (self, self->bootversion,
new_deployments,
cancellable, error))
{
g_prefix_error (error, "Swapping current bootlinks: ");
goto out;
}
goto out;
bootloader_is_atomic = TRUE;
}
@@ -2208,13 +2204,10 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
/* Only show the osname in bootloader titles if there are multiple
* osname's among the new deployments. Check for that here. */
for (i = 1; i < new_deployments->len; i++)
for (guint i = 1; i < new_deployments->len; i++)
{
const gchar *osname_0, *osname_i;
osname_0 = ostree_deployment_get_osname (new_deployments->pdata[0]);
osname_i = ostree_deployment_get_osname (new_deployments->pdata[i]);
const char *osname_0 = ostree_deployment_get_osname (new_deployments->pdata[0]);
const char *osname_i = ostree_deployment_get_osname (new_deployments->pdata[i]);
if (!g_str_equal (osname_0, osname_i))
{
show_osname = TRUE;
@@ -2222,32 +2215,23 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
}
}
for (i = 0; i < new_deployments->len; i++)
for (guint i = 0; i < new_deployments->len; i++)
{
OstreeDeployment *deployment = new_deployments->pdata[i];
if (!install_deployment_kernel (self, repo, new_bootversion,
deployment, new_deployments->len,
show_osname, cancellable, error))
{
g_prefix_error (error, "Installing kernel: ");
goto out;
}
goto out;
}
/* Create and swap bootlinks for *new* version */
if (!create_new_bootlinks (self, new_bootversion,
new_deployments,
cancellable, error))
{
g_prefix_error (error, "Creating new version bootlinks: ");
goto out;
}
goto out;
if (!swap_bootlinks (self, new_bootversion, new_deployments,
cancellable, error))
{
g_prefix_error (error, "Swapping new version bootlinks: ");
goto out;
}
goto out;
g_debug ("Using bootloader: %s", bootloader ?
g_type_name (G_TYPE_FROM_INSTANCE (bootloader)) : "(none)");
@@ -2438,10 +2422,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
glnx_autofd int deployment_dfd = -1;
if (!checkout_deployment_tree (self, repo, new_deployment, &deployment_dfd,
cancellable, error))
{
g_prefix_error (error, "Checking out tree: ");
return FALSE;
}
return FALSE;
g_autoptr(OstreeKernelLayout) kernel_layout = NULL;
if (!get_kernel_from_tree (deployment_dfd, &kernel_layout,
@@ -2461,10 +2442,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
deployment_dfd,
&sepolicy,
cancellable, error))
{
g_prefix_error (error, "During /etc merge: ");
return FALSE;
}
return FALSE;
if (!selinux_relabel_var_if_needed (self, sepolicy, os_deploy_dfd,
cancellable, error))
@@ -2477,24 +2455,13 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
return FALSE;
}
{ g_auto(OstreeSepolicyFsCreatecon) con = { 0, };
if (!_ostree_sepolicy_preparefscreatecon (&con, sepolicy,
"/etc/ostree/remotes.d/dummy.conf",
0644, error))
return FALSE;
/* Don't fsync here, as we assume that's all done in
* ostree_sysroot_write_deployments().
*/
if (!write_origin_file_internal (self, new_deployment, NULL,
GLNX_FILE_REPLACE_NODATASYNC,
cancellable, error))
{
g_prefix_error (error, "Writing out origin file: ");
return FALSE;
}
}
/* Don't fsync here, as we assume that's all done in
* ostree_sysroot_write_deployments().
*/
if (!write_origin_file_internal (self, sepolicy, new_deployment, NULL,
GLNX_FILE_REPLACE_NODATASYNC,
cancellable, error))
return FALSE;
/* After this, install_deployment_kernel() will set the other boot
* options and write it out to disk.
+5
View File
@@ -50,6 +50,11 @@ struct OstreeSysroot {
GLnxLockFile lock;
gboolean loaded;
gboolean ostree_booted;
gboolean root_is_sysroot; /* TRUE if sysroot_fd is pointed to rootfs "/" */
/* The device/inode for /, used to detect booted deployment */
dev_t root_device;
ino_t root_inode;
gboolean is_physical; /* TRUE if we're pointed at physical storage root and not a deployment */
GPtrArray *deployments;
+114 -114
View File
@@ -37,13 +37,6 @@
#include "ostree-bootloader-syslinux.h"
#include "ostree-bootloader-grub2.h"
static gboolean
find_booted_deployment (OstreeSysroot *self,
GPtrArray *deployments,
OstreeDeployment **out_deployment,
GCancellable *cancellable,
GError **error);
/**
* SECTION:ostree-sysroot
* @title: Root partition mount point
@@ -642,6 +635,24 @@ parse_deployment (OstreeSysroot *self,
&deployment_dfd, error))
return FALSE;
/* See if this is the booted deployment */
const gboolean looking_for_booted_deployment =
(self->ostree_booted && self->root_is_sysroot &&
!self->booted_deployment);
gboolean is_booted_deployment = FALSE;
if (looking_for_booted_deployment)
{
struct stat stbuf;
if (!glnx_fstat (deployment_dfd, &stbuf, error))
return FALSE;
/* A bit ugly, we're assigning to a sysroot-owned variable from deep in
* this parsing code. But eh, if something fails the sysroot state can't
* be relied on anyways.
*/
is_booted_deployment = (stbuf.st_dev == self->root_device &&
stbuf.st_ino == self->root_inode);
}
g_autoptr(GKeyFile) origin = NULL;
if (!parse_origin (self, deployment_dfd, deploy_basename, &origin,
cancellable, error))
@@ -672,35 +683,32 @@ parse_deployment (OstreeSysroot *self,
g_debug ("Deployment %s.%d unlocked=%d", treecsum, deployserial, ret_deployment->unlocked);
if (is_booted_deployment)
self->booted_deployment = g_object_ref (ret_deployment);
if (out_deployment)
*out_deployment = g_steal_pointer (&ret_deployment);
return TRUE;
}
/* Given a bootloader config, return the value part of the ostree= kernel
* argument.
*/
static char *
get_ostree_kernel_arg_from_config (OstreeBootconfigParser *config)
{
const char *options;
char *ret = NULL;
char **opts, **iter;
options = ostree_bootconfig_parser_get (config, "options");
const char *options = ostree_bootconfig_parser_get (config, "options");
if (!options)
return NULL;
opts = g_strsplit (options, " ", -1);
for (iter = opts; *iter; iter++)
g_auto(GStrv) opts = g_strsplit (options, " ", -1);
for (char **iter = opts; *iter; iter++)
{
const char *opt = *iter;
if (g_str_has_prefix (opt, "ostree="))
{
ret = g_strdup (opt + strlen ("ostree="));
break;
}
return g_strdup (opt + strlen ("ostree="));
}
g_strfreev (opts);
return ret;
return NULL;
}
static gboolean
@@ -797,6 +805,32 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
if (!ensure_repo (self, error))
return FALSE;
/* Gather some global state; first if we have the global ostree-booted flag;
* we'll use it to sanity check that we found a booted deployment for example.
* Second, we also find out whether sysroot == /.
*/
if (!self->loaded)
{
if (!glnx_fstatat_allow_noent (AT_FDCWD, "/run/ostree-booted", NULL, 0, error))
return FALSE;
self->ostree_booted = (errno == 0);
{ struct stat root_stbuf;
if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error))
return FALSE;
self->root_device = root_stbuf.st_dev;
self->root_inode = root_stbuf.st_ino;
}
struct stat self_stbuf;
if (!glnx_fstat (self->sysroot_fd, &self_stbuf, error))
return FALSE;
self->root_is_sysroot =
(self->root_device == self_stbuf.st_dev &&
self->root_inode == self_stbuf.st_ino);
}
int bootversion = 0;
if (!read_current_bootversion (self, &bootversion, cancellable, error))
return FALSE;
@@ -837,11 +871,19 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
{
OstreeBootconfigParser *config = boot_loader_configs->pdata[i];
/* Note this also sets self->booted_deployment */
if (!list_deployments_process_one_boot_entry (self, config, deployments,
cancellable, error))
return FALSE;
{
g_clear_object (&self->booted_deployment);
return FALSE;
}
}
if (self->ostree_booted && self->root_is_sysroot
&& !self->booted_deployment)
return glnx_throw (error, "Unexpected state: /run/ostree-booted found and in / sysroot but not in a booted deployment");
g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed);
for (guint i = 0; i < deployments->len; i++)
{
@@ -849,10 +891,6 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
ostree_deployment_set_index (deployment, i);
}
if (!find_booted_deployment (self, deployments, &self->booted_deployment,
cancellable, error))
return FALSE;
/* Determine whether we're "physical" or not, the first time we initialize */
if (!self->loaded)
{
@@ -920,13 +958,10 @@ ostree_sysroot_get_booted_deployment (OstreeSysroot *self)
GPtrArray *
ostree_sysroot_get_deployments (OstreeSysroot *self)
{
GPtrArray *copy;
guint i;
g_return_val_if_fail (self->loaded, NULL);
copy = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
for (i = 0; i < self->deployments->len; i++)
GPtrArray *copy = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
for (guint i = 0; i < self->deployments->len; i++)
g_ptr_array_add (copy, g_object_ref (self->deployments->pdata[i]));
return copy;
}
@@ -1071,10 +1106,9 @@ char *
_ostree_sysroot_join_lines (GPtrArray *lines)
{
GString *buf = g_string_new ("");
guint i;
gboolean prev_was_empty = FALSE;
for (i = 0; i < lines->len; i++)
for (guint i = 0; i < lines->len; i++)
{
const char *line = lines->pdata[i];
/* Special bit to remove extraneous empty lines */
@@ -1091,84 +1125,6 @@ _ostree_sysroot_join_lines (GPtrArray *lines)
return g_string_free (buf, FALSE);
}
static gboolean
parse_kernel_commandline (OstreeKernelArgs **out_args,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GFile) proc_cmdline = g_file_new_for_path ("/proc/cmdline");
g_autofree char *contents = NULL;
gsize len;
if (!g_file_load_contents (proc_cmdline, cancellable, &contents, &len, NULL,
error))
return FALSE;
g_strchomp (contents);
*out_args = _ostree_kernel_args_from_string (contents);
return TRUE;
}
static gboolean
find_booted_deployment (OstreeSysroot *self,
GPtrArray *deployments,
OstreeDeployment **out_deployment,
GCancellable *cancellable,
GError **error)
{
struct stat root_stbuf;
struct stat self_stbuf;
g_autoptr(OstreeDeployment) ret_deployment = NULL;
if (stat ("/", &root_stbuf) != 0)
return glnx_throw_errno_prefix (error, "stat /");
if (!ensure_sysroot_fd (self, error))
return FALSE;
if (fstat (self->sysroot_fd, &self_stbuf) != 0)
return glnx_throw_errno_prefix (error, "fstat");
if (root_stbuf.st_dev == self_stbuf.st_dev &&
root_stbuf.st_ino == self_stbuf.st_ino)
{
g_autoptr(OstreeKernelArgs) kernel_args = NULL;
if (!parse_kernel_commandline (&kernel_args, cancellable, error))
return FALSE;
const char *bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree");
if (bootlink_arg)
{
for (guint i = 0; i < deployments->len; i++)
{
OstreeDeployment *deployment = deployments->pdata[i];
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
struct stat stbuf;
if (fstatat (self->sysroot_fd, deployment_path, &stbuf, 0) != 0)
return glnx_throw_errno_prefix (error, "fstatat");
if (stbuf.st_dev == root_stbuf.st_dev &&
stbuf.st_ino == root_stbuf.st_ino)
{
ret_deployment = g_object_ref (deployment);
break;
}
}
if (ret_deployment == NULL)
return glnx_throw (error, "Unexpected state: ostree= kernel argument found, but / is not a deployment root");
}
else
{
/* Not an ostree system */
}
}
ot_transfer_out_value (out_deployment, &ret_deployment);
return TRUE;
}
/**
* ostree_sysroot_query_deployments_for:
* @self: Sysroot
@@ -1202,6 +1158,10 @@ ostree_sysroot_query_deployments_for (OstreeSysroot *self,
{
OstreeDeployment *deployment = self->deployments->pdata[i];
/* Ignore deployments not for this osname */
if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
continue;
/* Is this deployment booted? If so, note we're past the booted */
if (self->booted_deployment != NULL &&
ostree_deployment_equal (deployment, self->booted_deployment))
@@ -1210,10 +1170,6 @@ ostree_sysroot_query_deployments_for (OstreeSysroot *self,
continue;
}
/* Ignore deployments not for this osname */
if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
continue;
if (!found_booted && !ret_pending)
ret_pending = g_object_ref (deployment);
else if (found_booted && !ret_rollback)
@@ -1572,12 +1528,14 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
/* Retain deployment if:
* - we're explicitly asked to, or
* - it's pinned
* - the deployment is for another osname, or
* - we're keeping pending deployments and this is a pending deployment, or
* - this is the merge or boot deployment, or
* - we're keeping rollback deployments and this is a rollback deployment
*/
if (retain
|| ostree_deployment_is_pinned (deployment)
|| !osname_matches
|| (retain_pending && !passed_crossover)
|| (is_booted || is_merge)
@@ -1832,3 +1790,45 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return TRUE;
}
/**
* ostree_sysroot_deployment_set_pinned:
* @self: Sysroot
* @deployment: A deployment
* @is_pinned: Whether or not deployment will be automatically GC'd
* @error: Error
*
* By default, deployments may be subject to garbage collection. Typical uses of
* libostree only retain at most 2 deployments. If @is_pinned is `TRUE`, a
* metadata bit will be set causing libostree to avoid automatic GC of the
* deployment. However, this is really an "advisory" note; it's still possible
* for e.g. older versions of libostree unaware of pinning to GC the deployment.
*
* This function does nothing and returns successfully if the deployment
* is already in the desired pinning state.
*
* Since: 2018.3
*/
gboolean
ostree_sysroot_deployment_set_pinned (OstreeSysroot *self,
OstreeDeployment *deployment,
gboolean is_pinned,
GError **error)
{
const gboolean current_pin = ostree_deployment_is_pinned (deployment);
if (is_pinned == current_pin)
return TRUE;
g_autoptr(OstreeDeployment) deployment_clone = ostree_deployment_clone (deployment);
GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone);
if (is_pinned)
g_key_file_set_boolean (origin_clone, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", TRUE);
else
g_key_file_remove_key (origin_clone, OSTREE_ORIGIN_TRANSIENT_GROUP, "pinned", NULL);
if (!ostree_sysroot_write_origin_file (self, deployment, origin_clone, NULL, error))
return FALSE;
return TRUE;
}
+6
View File
@@ -181,6 +181,12 @@ gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_set_pinned (OstreeSysroot *self,
OstreeDeployment *deployment,
gboolean is_pinned,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_unlock (OstreeSysroot *self,
OstreeDeployment *deployment,
+3 -3
View File
@@ -43,7 +43,7 @@
*
* Since: 2017.4
*/
#define OSTREE_RELEASE_VERSION (2)
#define OSTREE_RELEASE_VERSION (4)
/**
* OSTREE_VERSION
@@ -52,7 +52,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION (2018.2)
#define OSTREE_VERSION (2018.4)
/**
* OSTREE_VERSION_S:
@@ -62,7 +62,7 @@
*
* Since: 2017.4
*/
#define OSTREE_VERSION_S "2018.2"
#define OSTREE_VERSION_S "2018.4"
#define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release))
+4 -9
View File
@@ -141,15 +141,10 @@ main (int argc,
if (error != NULL)
{
int is_tty = isatty (1);
const char *prefix = "";
const char *suffix = "";
if (is_tty)
{
prefix = "\x1b[31m\x1b[1m"; /* red, bold */
suffix = "\x1b[22m\x1b[0m"; /* bold off, color reset */
}
g_printerr ("%serror: %s%s\n", prefix, suffix, error->message);
g_printerr ("%s%serror:%s%s %s\n",
ot_get_red_start (), ot_get_bold_start (),
ot_get_bold_end (), ot_get_red_end (),
error->message);
}
return ret;
+4 -9
View File
@@ -680,15 +680,10 @@ main (int argc,
if (!run (argc, argv, cancellable, &error))
{
int is_tty = isatty (1);
const char *prefix = "";
const char *suffix = "";
if (is_tty)
{
prefix = "\x1b[31m\x1b[1m"; /* red, bold */
suffix = "\x1b[22m\x1b[0m"; /* bold off, color reset */
}
g_printerr ("%serror: %s%s\n", prefix, suffix, error->message);
g_printerr ("%s%serror:%s%s %s\n",
ot_get_red_start (), ot_get_bold_start (),
ot_get_bold_end (), ot_get_red_end (),
error->message);
return 1;
}
-5
View File
@@ -30,11 +30,6 @@
#include <glib/gi18n.h>
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-cleanup.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ NULL }
};
-5
View File
@@ -45,11 +45,6 @@ static char *opt_osname;
static char *opt_origin_path;
static gboolean opt_kernel_arg_none;
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-deploy.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" },
{ "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" },
-5
View File
@@ -32,11 +32,6 @@
static char *opt_osname;
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-config-diff.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" },
{ NULL }
-5
View File
@@ -30,11 +30,6 @@
#include <glib/gi18n.h>
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-init-fs.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ NULL }
};
-5
View File
@@ -30,11 +30,6 @@
#include <glib/gi18n.h>
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-os-init.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ NULL }
};
+75
View File
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2018 Colin Walters <walters@verbum.org>
*
* 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 <stdlib.h>
#include "ot-main.h"
#include "ot-admin-builtins.h"
#include "ot-admin-functions.h"
#include "ostree.h"
#include "otutil.h"
static gboolean opt_unpin;
static GOptionEntry options[] = {
{ "unpin", 'u', 0, G_OPTION_ARG_NONE, &opt_unpin, "Unset pin", NULL },
{ NULL }
};
gboolean
ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context = g_option_context_new ("INDEX");
g_autoptr(OstreeSysroot) sysroot = NULL;
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
invocation, &sysroot, cancellable, error))
return FALSE;
if (argc < 2)
{
ot_util_usage_error (context, "INDEX must be specified", error);
return FALSE;
}
const char *deploy_index_str = argv[1];
const int deploy_index = atoi (deploy_index_str);
g_autoptr(OstreeDeployment) target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error);
if (!target_deployment)
return FALSE;
gboolean current_pin = ostree_deployment_is_pinned (target_deployment);
const gboolean desired_pin = !opt_unpin;
if (current_pin == desired_pin)
g_print ("Deployment is already %s\n", current_pin ? "pinned" : "unpinned");
else
{
if (!ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, error))
return FALSE;
g_print ("Deployment is now %s\n", desired_pin ? "pinned" : "unpinned");
}
return TRUE;
}
-5
View File
@@ -35,11 +35,6 @@
static int opt_index = -1;
static char **opt_set;
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-set-origin.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ "set", 's', 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" },
{ "index", 0, 0, G_OPTION_ARG_INT, &opt_index, "Operate on the deployment INDEX, starting from zero", "INDEX" },
+115 -99
View File
@@ -27,14 +27,10 @@
#include "ot-admin-builtins.h"
#include "ot-admin-functions.h"
#include "ostree.h"
#include "libglnx.h"
#include <glib/gi18n.h>
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-status.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ NULL }
};
@@ -66,13 +62,116 @@ deployment_get_gpg_verify (OstreeDeployment *deployment,
return gpg_verify;
}
static gboolean
deployment_print_status (OstreeSysroot *sysroot,
OstreeRepo *repo,
OstreeDeployment *deployment,
gboolean is_booted,
gboolean is_pending,
gboolean is_rollback,
GCancellable *cancellable,
GError **error)
{
const char *ref = ostree_deployment_get_csum (deployment);
/* Load the backing commit; shouldn't normally fail, but if it does,
* we stumble on.
*/
g_autoptr(GVariant) commit = NULL;
(void)ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, ref,
&commit, NULL);
g_autoptr(GVariant) commit_metadata = NULL;
if (commit)
commit_metadata = g_variant_get_child_value (commit, 0);
const char *version = NULL;
const char *source_title = NULL;
if (commit_metadata)
{
(void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_VERSION, "&s", &version);
(void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_SOURCE_TITLE, "&s", &source_title);
}
GKeyFile *origin = ostree_deployment_get_origin (deployment);
const char *deployment_status = "";
if (is_pending)
deployment_status = " (pending)";
else if (is_rollback)
deployment_status = " (rollback)";
g_print ("%c %s %s.%d%s\n",
is_booted ? '*' : ' ',
ostree_deployment_get_osname (deployment),
ostree_deployment_get_csum (deployment),
ostree_deployment_get_deployserial (deployment),
deployment_status);
if (version)
g_print (" Version: %s\n", version);
OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment);
switch (unlocked)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
break;
default:
g_print (" %s%sUnlocked: %s%s%s\n", ot_get_red_start (), ot_get_bold_start (),
ostree_deployment_unlocked_state_to_string (unlocked),
ot_get_bold_end (), ot_get_red_end ());
}
if (ostree_deployment_is_pinned (deployment))
g_print (" Pinned: yes\n");
if (!origin)
g_print (" origin: none\n");
else
{
g_autofree char *origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
if (!origin_refspec)
g_print (" origin: <unknown origin type>\n");
else
g_print (" origin refspec: %s\n", origin_refspec);
if (source_title)
g_print (" `- %s\n", source_title);
}
if (deployment_get_gpg_verify (deployment, repo))
{
g_autoptr(GString) output_buffer = g_string_sized_new (256);
/* Print any digital signatures on this commit. */
g_autoptr(GError) local_error = NULL;
g_autoptr(OstreeGpgVerifyResult) result =
ostree_repo_verify_commit_ext (repo, ref, NULL, NULL,
cancellable, &local_error);
/* G_IO_ERROR_NOT_FOUND just means the commit is not signed. */
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&local_error);
return TRUE;
}
else if (local_error != NULL)
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
const guint n_signatures = ostree_gpg_verify_result_count_all (result);
for (guint jj = 0; jj < n_signatures; jj++)
{
ostree_gpg_verify_result_describe (result, jj, output_buffer, " GPG: ",
OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
}
g_print ("%s", output_buffer->str);
}
return TRUE;
}
gboolean
ot_admin_builtin_status (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
const int is_tty = isatty (1);
const char *red_bold_prefix = is_tty ? "\x1b[31m\x1b[1m" : "";
const char *red_bold_suffix = is_tty ? "\x1b[22m\x1b[0m" : "";
g_autoptr(GOptionContext) context = g_option_context_new ("");
g_autoptr(OstreeSysroot) sysroot = NULL;
@@ -103,96 +202,13 @@ ot_admin_builtin_status (int argc, char **argv, OstreeCommandInvocation *invocat
for (guint i = 0; i < deployments->len; i++)
{
OstreeDeployment *deployment = deployments->pdata[i];
const char *ref = ostree_deployment_get_csum (deployment);
/* Load the backing commit; shouldn't normally fail, but if it does,
* we stumble on.
*/
g_autoptr(GVariant) commit = NULL;
(void)ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, ref,
&commit, NULL);
g_autoptr(GVariant) commit_metadata = NULL;
if (commit)
commit_metadata = g_variant_get_child_value (commit, 0);
const char *version = NULL;
const char *source_title = NULL;
if (commit_metadata)
{
(void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_VERSION, "&s", &version);
(void) g_variant_lookup (commit_metadata, OSTREE_COMMIT_META_KEY_SOURCE_TITLE, "&s", &source_title);
}
GKeyFile *origin = ostree_deployment_get_origin (deployment);
const char *deployment_status = "";
if (deployment == pending_deployment)
deployment_status = " (pending)";
else if (deployment == rollback_deployment)
deployment_status = " (rollback)";
g_print ("%c %s %s.%d%s\n",
deployment == booted_deployment ? '*' : ' ',
ostree_deployment_get_osname (deployment),
ostree_deployment_get_csum (deployment),
ostree_deployment_get_deployserial (deployment),
deployment_status);
if (version)
g_print (" Version: %s\n", version);
OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment);
switch (unlocked)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
break;
default:
g_print (" %sUnlocked: %s%s\n", red_bold_prefix,
ostree_deployment_unlocked_state_to_string (unlocked),
red_bold_suffix);
}
if (!origin)
g_print (" origin: none\n");
else
{
g_autofree char *origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
if (!origin_refspec)
g_print (" origin: <unknown origin type>\n");
else
g_print (" origin refspec: %s\n", origin_refspec);
if (source_title)
g_print (" `- %s\n", source_title);
}
if (deployment_get_gpg_verify (deployment, repo))
{
g_autoptr(GString) output_buffer = g_string_sized_new (256);
/* Print any digital signatures on this commit. */
g_autoptr(GError) local_error = NULL;
g_autoptr(OstreeGpgVerifyResult) result =
ostree_repo_verify_commit_ext (repo, ref, NULL, NULL,
cancellable, &local_error);
/* G_IO_ERROR_NOT_FOUND just means the commit is not signed. */
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&local_error);
continue;
}
else if (local_error != NULL)
{
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
}
const guint n_signatures = ostree_gpg_verify_result_count_all (result);
for (guint jj = 0; jj < n_signatures; jj++)
{
ostree_gpg_verify_result_describe (result, jj, output_buffer, " GPG: ",
OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT);
}
g_print ("%s", output_buffer->str);
}
if (!deployment_print_status (sysroot, repo, deployment,
deployment == booted_deployment,
deployment == pending_deployment,
deployment == rollback_deployment,
cancellable,
error))
return FALSE;
}
}
-5
View File
@@ -34,11 +34,6 @@
static gboolean opt_reboot;
static char *opt_osname;
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-switch.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after switching trees", NULL },
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" },
-5
View File
@@ -29,11 +29,6 @@
#include "ostree.h"
#include "otutil.h"
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-undeploy.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ NULL }
};
-5
View File
@@ -34,11 +34,6 @@
static gboolean opt_hotfix;
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-unlock.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ "hotfix", 0, 0, G_OPTION_ARG_NONE, &opt_hotfix, "Retain changes across reboots", NULL },
{ NULL }
+4 -24
View File
@@ -40,11 +40,6 @@ static gboolean opt_deploy_only;
static char *opt_osname;
static char *opt_override_commit;
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-upgrade.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" },
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after a successful upgrade", NULL },
@@ -88,33 +83,18 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeCommandInvocation *invoca
g_autoptr(GKeyFile) origin = ostree_sysroot_upgrader_dup_origin (upgrader);
if (origin != NULL)
{
gboolean origin_changed = FALSE;
/* Should we consider requiring --discard-hotfix here? */
ostree_deployment_origin_remove_transient_state (origin);
if (opt_override_commit != NULL)
{
/* Override the commit to pull and deploy. */
g_key_file_set_string (origin, "origin",
"override-commit",
opt_override_commit);
origin_changed = TRUE;
}
else
{
/* Strip any override-commit from the origin file so
* we always upgrade to the latest available commit. */
origin_changed = g_key_file_remove_key (origin, "origin",
"override-commit", NULL);
}
/* Should we consider requiring --discard-hotfix here? */
origin_changed |= g_key_file_remove_key (origin, "origin", "unlocked", NULL);
if (origin_changed)
{
/* XXX GCancellable parameter is not used. */
if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, NULL, error))
return FALSE;
}
if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, NULL, error))
return FALSE;
}
gboolean changed;
+1
View File
@@ -39,6 +39,7 @@ BUILTINPROTO(init_fs);
BUILTINPROTO(undeploy);
BUILTINPROTO(deploy);
BUILTINPROTO(cleanup);
BUILTINPROTO(pin);
BUILTINPROTO(unlock);
BUILTINPROTO(status);
BUILTINPROTO(set_origin);
@@ -28,11 +28,6 @@
#include "otutil.h"
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-instutil.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ NULL }
};
@@ -173,11 +173,6 @@ selinux_relabel_dir (OstreeSePolicy *sepolicy,
return ret;
}
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-instutil.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ NULL }
};
@@ -34,11 +34,6 @@ static gboolean opt_merge;
static char **opt_replace;
static char **opt_append;
/* ATTENTION:
* Please remember to update the bash-completion script (bash/ostree) and
* man page (man/ostree-admin-instutil.xml) when changing the option list.
*/
static GOptionEntry options[] = {
{ "import-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_proc_cmdline, "Import current /proc/cmdline", NULL },
{ "merge", 0, 0, G_OPTION_ARG_NONE, &opt_merge, "Merge with previous command line", NULL },
+3
View File
@@ -54,6 +54,9 @@ static OstreeCommand admin_subcommands[] = {
{ "set-origin", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_set_origin,
"Set Origin and create a new origin file" },
{ "pin", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_pin,
"Change the \"pinning\" state of a deployment" },
{ "status", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_status,
"List deployments" },
+9
View File
@@ -174,6 +174,15 @@ ostree_builtin_prune (int argc, char **argv, OstreeCommandInvocation *invocation
else if (!delete_commit (repo, opt_delete_commit, cancellable, error))
return FALSE;
}
else
{
/* In the future we should make this useful, but for now let's
* error out since what we were doing before was very misleading.
* https://github.com/ostreedev/ostree/issues/1479
*/
if (opt_static_deltas_only)
return glnx_throw (error, "--static-deltas-only requires --delete-commit; see https://github.com/ostreedev/ostree/issues/1479");
}
OstreeRepoPruneFlags pruneflags = 0;
if (opt_refs_only)
+7
View File
@@ -41,6 +41,7 @@ static gboolean opt_bareuseronly_files;
static char** opt_subpaths;
static char** opt_http_headers;
static char* opt_cache_dir;
static char* opt_append_user_agent;
static int opt_depth = 0;
static int opt_frequency = 0;
static char* opt_url;
@@ -69,6 +70,8 @@ static GOptionEntry options[] = {
{ "update-frequency", 0, 0, G_OPTION_ARG_INT, &opt_frequency, "Sets the update frequency, in milliseconds (0=1000ms) (default: 0)", "FREQUENCY" },
{ "localcache-repo", 'L', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_localcache_repos, "Add REPO as local cache source for objects during this pull", "REPO" },
{ "timestamp-check", 'T', 0, G_OPTION_ARG_NONE, &opt_timestamp_check, "Require fetched commits to have newer timestamps", NULL },
/* let's leave this hidden for now; we just need it for tests */
{ "append-user-agent", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &opt_append_user_agent, "Append string to user agent", NULL },
{ NULL }
};
@@ -333,6 +336,10 @@ ostree_builtin_pull (int argc, char **argv, OstreeCommandInvocation *invocation,
g_variant_new_variant (g_variant_builder_end (&hdr_builder)));
}
if (opt_append_user_agent)
g_variant_builder_add (&builder, "{s@v}", "append-user-agent",
g_variant_new_variant (g_variant_new_string (opt_append_user_agent)));
if (!opt_dry_run)
{
if (console.is_tty)
+15
View File
@@ -91,3 +91,18 @@ gboolean ostree_ensure_repo_writable (OstreeRepo *repo, GError **error);
void ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result);
gboolean ot_enable_tombstone_commits (OstreeRepo *repo, GError **error);
/* Copied from rpm-ostree's rpmostree-libbuiltin.h */
#define TERM_ESCAPE_SEQUENCE(type,seq) \
static inline const char* ot_get_##type (void) { \
if (glnx_stdout_is_tty ()) \
return seq; \
return ""; \
}
TERM_ESCAPE_SEQUENCE(red_start, "\x1b[31m")
TERM_ESCAPE_SEQUENCE(red_end, "\x1b[22m")
TERM_ESCAPE_SEQUENCE(bold_start, "\x1b[1m")
TERM_ESCAPE_SEQUENCE(bold_end, "\x1b[0m")
#undef TERM_ESCAPE_SEQUENCE
+15
View File
@@ -104,4 +104,19 @@ read_proc_cmdline_ostree (void)
return ret;
}
/* This is an API for other projects to determine whether or not the
* currently running system is ostree-controlled.
*/
static inline void
touch_run_ostree (void)
{
int fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY | O_CLOEXEC, 0640);
/* We ignore failures here in case /run isn't mounted...not much we
* can do about that, but we don't want to fail.
*/
if (fd == -1)
return;
(void) close (fd);
}
#endif /* __OSTREE_MOUNT_UTIL_H_ */
+7 -18
View File
@@ -48,23 +48,6 @@
#include "ostree-mount-util.h"
/* This is an API for other projects to determine whether or not the
* currently running system is ostree-controlled.
*/
static void
touch_run_ostree (void)
{
int fd;
fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY | O_CLOEXEC, 0640);
/* We ignore failures here in case /run isn't mounted...not much we
* can do about that, but we don't want to fail.
*/
if (fd == -1)
return;
(void) close (fd);
}
static char*
resolve_deploy_path (const char * root_mountpoint)
{
@@ -205,7 +188,13 @@ main(int argc, char *argv[])
err (EXIT_FAILURE, "failed to bind mount (class:readonly) /usr");
}
touch_run_ostree ();
/* We only stamp /run now if we're running in an initramfs, i.e. we're
* 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)
touch_run_ostree ();
if (strcmp(root_mountpoint, "/") == 0)
{
+10
View File
@@ -46,6 +46,16 @@ main(int argc, char *argv[])
struct stat stbuf;
int i;
/* See comments in ostree-prepare-root.c for this.
*
* This service is triggered via
* ConditionKernelCommandLine=ostree
* but it's a lot easier for various bits of userspace to check for
* a file versus parsing the kernel cmdline. So let's ensure
* the stamp file is created here too.
*/
touch_run_ostree ();
/* The /sysroot mount needs to be private to avoid having a mount for e.g. /var/cache
* also propagate to /sysroot/ostree/deploy/$stateroot/var/cache
*