New upstream version 2018.4
This commit is contained in:
commit
de3c1878b1
85 files changed
+1520
-1199
No files matched your search
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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" },
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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 }
|
||||
};
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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" },
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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_ */
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user