New upstream version 2017.6
This commit is contained in:
commit
e3060b1b87
168 files changed
+5181
-3686
No files matched your search
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright © 2017 Endless Mobile, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* - Philip Withnall <withnall@endlessm.com>
|
||||
*/
|
||||
|
||||
/* Symbols in this file are added to the build if OSTree is configured with
|
||||
* --enable-experimental-api. They are not stable or officially supported, and
|
||||
* might disappear or change in future releases. */
|
||||
|
||||
LIBOSTREE_2017.6_EXPERIMENTAL {
|
||||
global:
|
||||
ostree_remote_ref;
|
||||
ostree_remote_unref;
|
||||
} LIBOSTREE_2017.6;
|
||||
@@ -389,17 +389,24 @@ global:
|
||||
ostree_sysroot_write_deployments_with_options;
|
||||
} LIBOSTREE_2017.3;
|
||||
|
||||
LIBOSTREE_2017.6 {
|
||||
global:
|
||||
ostree_async_progress_get;
|
||||
ostree_async_progress_set;
|
||||
ostree_async_progress_get_variant;
|
||||
ostree_async_progress_set_variant;
|
||||
} LIBOSTREE_2017.4;
|
||||
|
||||
/* NOTE NOTE NOTE
|
||||
* Versions above here are released. Only add symbols below this line.
|
||||
* NOTE NOTE NOTE
|
||||
*/
|
||||
|
||||
/* Uncomment when adding the first new symbol */
|
||||
/*
|
||||
LIBOSTREE_2017.$NEWVERSION {
|
||||
global:
|
||||
someostree_symbol_deleteme;
|
||||
} LIBOSTREE_2017.4;
|
||||
} LIBOSTREE_2017.6;
|
||||
*/
|
||||
|
||||
/* Stub section for the stable release *after* this development one; don't
|
||||
|
||||
@@ -2,6 +2,7 @@ prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
features=@OSTREE_FEATURES@
|
||||
|
||||
Name: OSTree
|
||||
Description: Git for operating system binaries
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#include "ostree-async-progress.h"
|
||||
|
||||
#include "libglnx.h"
|
||||
|
||||
/**
|
||||
* SECTION:ostree-async-progress
|
||||
* @title: Progress notification system for asynchronous operations
|
||||
@@ -37,14 +39,13 @@
|
||||
* handles thread safety, ensuring that the progress change
|
||||
* notification occurs in the thread-default context of the calling
|
||||
* operation.
|
||||
*
|
||||
* The ostree_async_progress_get_status() and ostree_async_progress_set_status()
|
||||
* methods get and set a well-known `status` key of type %G_VARIANT_TYPE_STRING.
|
||||
* This key may be accessed using the other #OstreeAsyncProgress methods, but it
|
||||
* must always have the correct type.
|
||||
*/
|
||||
|
||||
#if GLIB_SIZEOF_VOID_P == 8
|
||||
#define _OSTREE_HAVE_LP64 1
|
||||
#else
|
||||
#define _OSTREE_HAVE_LP64 0
|
||||
#endif
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
LAST_SIGNAL
|
||||
@@ -59,12 +60,9 @@ struct OstreeAsyncProgress
|
||||
GMutex lock;
|
||||
GMainContext *maincontext;
|
||||
GSource *idle_source;
|
||||
GHashTable *uint_values;
|
||||
GHashTable *uint64_values;
|
||||
GHashTable *values; /* (element-type uint GVariant) */
|
||||
|
||||
gboolean dead;
|
||||
|
||||
char *status;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (OstreeAsyncProgress, ostree_async_progress, G_TYPE_OBJECT)
|
||||
@@ -79,9 +77,7 @@ ostree_async_progress_finalize (GObject *object)
|
||||
g_mutex_clear (&self->lock);
|
||||
g_clear_pointer (&self->maincontext, g_main_context_unref);
|
||||
g_clear_pointer (&self->idle_source, g_source_unref);
|
||||
g_hash_table_unref (self->uint_values);
|
||||
g_hash_table_unref (self->uint64_values);
|
||||
g_free (self->status);
|
||||
g_hash_table_unref (self->values);
|
||||
|
||||
G_OBJECT_CLASS (ostree_async_progress_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -114,46 +110,115 @@ ostree_async_progress_init (OstreeAsyncProgress *self)
|
||||
{
|
||||
g_mutex_init (&self->lock);
|
||||
self->maincontext = g_main_context_ref_thread_default ();
|
||||
self->uint_values = g_hash_table_new (NULL, NULL);
|
||||
#if _OSTREE_HAVE_LP64
|
||||
self->uint64_values = g_hash_table_new (NULL, NULL);
|
||||
#else
|
||||
self->uint64_values = g_hash_table_new_full (NULL, NULL,
|
||||
NULL, g_free);
|
||||
#endif
|
||||
self->values = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_variant_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_async_progress_get_variant:
|
||||
* @self: an #OstreeAsyncProgress
|
||||
* @key: a key to look up
|
||||
*
|
||||
* Look up a key in the #OstreeAsyncProgress and return the #GVariant associated
|
||||
* with it. The lookup is thread-safe.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): value for the given @key, or %NULL if
|
||||
* it was not set
|
||||
* Since: 2017.6
|
||||
*/
|
||||
GVariant *
|
||||
ostree_async_progress_get_variant (OstreeAsyncProgress *self,
|
||||
const char *key)
|
||||
{
|
||||
GVariant *rval;
|
||||
|
||||
g_return_val_if_fail (OSTREE_IS_ASYNC_PROGRESS (self), NULL);
|
||||
g_return_val_if_fail (key != NULL, NULL);
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
rval = g_hash_table_lookup (self->values, GUINT_TO_POINTER (g_quark_from_string (key)));
|
||||
if (rval != NULL)
|
||||
g_variant_ref (rval);
|
||||
g_mutex_unlock (&self->lock);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
guint
|
||||
ostree_async_progress_get_uint (OstreeAsyncProgress *self,
|
||||
const char *key)
|
||||
{
|
||||
guint rval;
|
||||
g_mutex_lock (&self->lock);
|
||||
rval = GPOINTER_TO_UINT (g_hash_table_lookup (self->uint_values,
|
||||
GUINT_TO_POINTER (g_quark_from_string (key))));
|
||||
g_mutex_unlock (&self->lock);
|
||||
return rval;
|
||||
g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, key);
|
||||
return (rval != NULL) ? g_variant_get_uint32 (rval) : 0;
|
||||
}
|
||||
|
||||
guint64
|
||||
ostree_async_progress_get_uint64 (OstreeAsyncProgress *self,
|
||||
const char *key)
|
||||
{
|
||||
#if _OSTREE_HAVE_LP64
|
||||
guint64 rval;
|
||||
g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, key);
|
||||
return (rval != NULL) ? g_variant_get_uint64 (rval) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_async_progress_get:
|
||||
* @self: an #OstreeAsyncProgress
|
||||
* @...: key name, format string, #GVariant return locations, …, followed by %NULL
|
||||
*
|
||||
* Get the values corresponding to zero or more keys from the
|
||||
* #OstreeAsyncProgress. Each key is specified in @... as the key name, followed
|
||||
* by a #GVariant format string, followed by the necessary arguments for that
|
||||
* format string, just as for g_variant_get(). After those arguments is the
|
||||
* next key name. The varargs list must be %NULL-terminated.
|
||||
*
|
||||
* Each format string must make deep copies of its value, as the values stored
|
||||
* in the #OstreeAsyncProgress may be freed from another thread after this
|
||||
* function returns.
|
||||
*
|
||||
* This operation is thread-safe, and all the keys are queried atomically.
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* guint32 outstanding_fetches;
|
||||
* guint64 bytes_received;
|
||||
* g_autofree gchar *status = NULL;
|
||||
* g_autoptr(GVariant) refs_variant = NULL;
|
||||
*
|
||||
* ostree_async_progress_get (progress,
|
||||
* "outstanding-fetches", "u", &outstanding_fetches,
|
||||
* "bytes-received", "t", &bytes_received,
|
||||
* "status", "s", &status,
|
||||
* "refs", "@a{ss}", &refs_variant,
|
||||
* NULL);
|
||||
* ]|
|
||||
*
|
||||
* Since: 2017.6
|
||||
*/
|
||||
void
|
||||
ostree_async_progress_get (OstreeAsyncProgress *self,
|
||||
...)
|
||||
{
|
||||
va_list ap;
|
||||
const char *key, *format_string;
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
rval = (guint64) g_hash_table_lookup (self->uint64_values, GUINT_TO_POINTER (g_quark_from_string (key)));
|
||||
va_start (ap, self);
|
||||
|
||||
for (key = va_arg (ap, const char *), format_string = va_arg (ap, const char *);
|
||||
key != NULL;
|
||||
key = va_arg (ap, const char *), format_string = va_arg (ap, const char *))
|
||||
{
|
||||
GVariant *variant;
|
||||
|
||||
g_assert (format_string != NULL);
|
||||
|
||||
variant = g_hash_table_lookup (self->values, GUINT_TO_POINTER (g_quark_from_string (key)));
|
||||
g_assert (variant != NULL);
|
||||
g_assert (g_variant_check_format_string (variant, format_string, TRUE));
|
||||
|
||||
g_variant_get_va (variant, format_string, NULL, &ap);
|
||||
}
|
||||
|
||||
va_end (ap);
|
||||
g_mutex_unlock (&self->lock);
|
||||
return rval;
|
||||
#else
|
||||
guint64 *rval;
|
||||
g_mutex_lock (&self->lock);
|
||||
rval = g_hash_table_lookup (self->uint64_values, (gpointer)g_quark_from_string (key));
|
||||
g_mutex_unlock (&self->lock);
|
||||
if (rval)
|
||||
return *rval;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -180,50 +245,162 @@ ensure_callback_locked (OstreeAsyncProgress *self)
|
||||
g_source_attach (self->idle_source, self->maincontext);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_async_progress_set_status:
|
||||
* @self: an #OstreeAsyncProgress
|
||||
* @status: (nullable): new status string, or %NULL to clear the status
|
||||
*
|
||||
* Set the human-readable status string for the #OstreeAsyncProgress. This
|
||||
* operation is thread-safe. %NULL may be passed to clear the status.
|
||||
*
|
||||
* This is a convenience function to set the well-known `status` key.
|
||||
*
|
||||
* Since: 2017.6
|
||||
*/
|
||||
void
|
||||
ostree_async_progress_set_status (OstreeAsyncProgress *self,
|
||||
const char *status)
|
||||
{
|
||||
g_mutex_lock (&self->lock);
|
||||
if (!self->dead)
|
||||
{
|
||||
g_free (self->status);
|
||||
self->status = g_strdup (status);
|
||||
ensure_callback_locked (self);
|
||||
}
|
||||
g_mutex_unlock (&self->lock);
|
||||
ostree_async_progress_set_variant (self, "status",
|
||||
g_variant_new_string ((status != NULL) ? status : ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_async_progress_get_status:
|
||||
* @self: an #OstreeAsyncProgress
|
||||
*
|
||||
* Get the human-readable status string from the #OstreeAsyncProgress. This
|
||||
* operation is thread-safe. The retuned value may be %NULL if no status is
|
||||
* set.
|
||||
*
|
||||
* This is a convenience function to get the well-known `status` key.
|
||||
*
|
||||
* Returns: (transfer full) (nullable): the current status, or %NULL if none is set
|
||||
* Since: 2017.6
|
||||
*/
|
||||
char *
|
||||
ostree_async_progress_get_status (OstreeAsyncProgress *self)
|
||||
{
|
||||
char *ret;
|
||||
g_mutex_lock (&self->lock);
|
||||
ret = g_strdup (self->status);
|
||||
g_mutex_unlock (&self->lock);
|
||||
return ret;
|
||||
g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, "status");
|
||||
const gchar *status = (rval != NULL) ? g_variant_get_string (rval, NULL) : NULL;
|
||||
if (status != NULL && *status == '\0')
|
||||
status = NULL;
|
||||
return g_strdup (status);
|
||||
}
|
||||
|
||||
static void
|
||||
update_key (OstreeAsyncProgress *self,
|
||||
GHashTable *hash,
|
||||
const char *key,
|
||||
gpointer value)
|
||||
/**
|
||||
* ostree_async_progress_set:
|
||||
* @self: an #OstreeAsyncProgress
|
||||
* @...: key name, format string, #GVariant parameters, …, followed by %NULL
|
||||
*
|
||||
* Set the values for zero or more keys in the #OstreeAsyncProgress. Each key is
|
||||
* specified in @... as the key name, followed by a #GVariant format string,
|
||||
* followed by the necessary arguments for that format string, just as for
|
||||
* g_variant_new(). After those arguments is the next key name. The varargs list
|
||||
* must be %NULL-terminated.
|
||||
*
|
||||
* g_variant_ref_sink() will be called as appropriate on the #GVariant
|
||||
* parameters, so they may be floating.
|
||||
*
|
||||
* This operation is thread-safe, and all the keys are set atomically.
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* guint32 outstanding_fetches = 15;
|
||||
* guint64 bytes_received = 1000;
|
||||
*
|
||||
* ostree_async_progress_set (progress,
|
||||
* "outstanding-fetches", "u", outstanding_fetches,
|
||||
* "bytes-received", "t", bytes_received,
|
||||
* "status", "s", "Updated status",
|
||||
* "refs", "@a{ss}", g_variant_new_parsed ("@a{ss} {}"),
|
||||
* NULL);
|
||||
* ]|
|
||||
*
|
||||
* Since: 2017.6
|
||||
*/
|
||||
void
|
||||
ostree_async_progress_set (OstreeAsyncProgress *self,
|
||||
...)
|
||||
{
|
||||
gpointer orig_value;
|
||||
gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key));
|
||||
va_list ap;
|
||||
const char *key, *format_string;
|
||||
gboolean changed;
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
|
||||
if (self->dead)
|
||||
goto out;
|
||||
|
||||
if (g_hash_table_lookup_extended (hash, qkey, NULL, &orig_value))
|
||||
changed = FALSE;
|
||||
|
||||
va_start (ap, self);
|
||||
|
||||
for (key = va_arg (ap, const char *), format_string = va_arg (ap, const char *);
|
||||
key != NULL;
|
||||
key = va_arg (ap, const char *), format_string = va_arg (ap, const char *))
|
||||
{
|
||||
if (orig_value == value)
|
||||
GVariant *orig_value;
|
||||
g_autoptr(GVariant) new_value = NULL;
|
||||
gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key));
|
||||
|
||||
new_value = g_variant_ref_sink (g_variant_new_va (format_string, NULL, &ap));
|
||||
|
||||
if (g_hash_table_lookup_extended (self->values, qkey, NULL, (gpointer *) &orig_value) &&
|
||||
g_variant_equal (orig_value, new_value))
|
||||
continue;
|
||||
|
||||
g_hash_table_replace (self->values, qkey, g_steal_pointer (&new_value));
|
||||
changed = TRUE;
|
||||
}
|
||||
|
||||
va_end (ap);
|
||||
|
||||
if (changed)
|
||||
ensure_callback_locked (self);
|
||||
|
||||
out:
|
||||
g_mutex_unlock (&self->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_async_progress_set_variant:
|
||||
* @self: an #OstreeAsyncProgress
|
||||
* @key: a key to set
|
||||
* @value: the value to assign to @key
|
||||
*
|
||||
* Assign a new @value to the given @key, replacing any existing value. The
|
||||
* operation is thread-safe. @value may be a floating reference;
|
||||
* g_variant_ref_sink() will be called on it.
|
||||
*
|
||||
* Any watchers of the #OstreeAsyncProgress will be notified of the change if
|
||||
* @value differs from the existing value for @key.
|
||||
*
|
||||
* Since: 2017.6
|
||||
*/
|
||||
void
|
||||
ostree_async_progress_set_variant (OstreeAsyncProgress *self,
|
||||
const char *key,
|
||||
GVariant *value)
|
||||
{
|
||||
GVariant *orig_value;
|
||||
g_autoptr(GVariant) new_value = g_variant_ref_sink (value);
|
||||
gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key));
|
||||
|
||||
g_return_if_fail (OSTREE_IS_ASYNC_PROGRESS (self));
|
||||
g_return_if_fail (key != NULL);
|
||||
g_return_if_fail (value != NULL);
|
||||
|
||||
g_mutex_lock (&self->lock);
|
||||
|
||||
if (self->dead)
|
||||
goto out;
|
||||
|
||||
if (g_hash_table_lookup_extended (self->values, qkey, NULL, (gpointer *) &orig_value))
|
||||
{
|
||||
if (g_variant_equal (orig_value, new_value))
|
||||
goto out;
|
||||
}
|
||||
g_hash_table_replace (hash, qkey, value);
|
||||
g_hash_table_replace (self->values, qkey, g_steal_pointer (&new_value));
|
||||
ensure_callback_locked (self);
|
||||
|
||||
out:
|
||||
@@ -235,7 +412,7 @@ ostree_async_progress_set_uint (OstreeAsyncProgress *self,
|
||||
const char *key,
|
||||
guint value)
|
||||
{
|
||||
update_key (self, self->uint_values, key, GUINT_TO_POINTER (value));
|
||||
ostree_async_progress_set_variant (self, key, g_variant_new_uint32 (value));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -243,18 +420,7 @@ ostree_async_progress_set_uint64 (OstreeAsyncProgress *self,
|
||||
const char *key,
|
||||
guint64 value)
|
||||
{
|
||||
gpointer valuep;
|
||||
|
||||
#if _OSTREE_HAVE_LP64
|
||||
valuep = (gpointer)value;
|
||||
#else
|
||||
{
|
||||
guint64 *boxed = g_malloc (sizeof (guint64));
|
||||
*boxed = value;
|
||||
valuep = boxed;
|
||||
}
|
||||
#endif
|
||||
update_key (self, self->uint64_values, key, valuep);
|
||||
ostree_async_progress_set_variant (self, key, g_variant_new_uint64 (value));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,17 +53,28 @@ OstreeAsyncProgress *ostree_async_progress_new_and_connect (void (*changed) (Ost
|
||||
_OSTREE_PUBLIC
|
||||
char *ostree_async_progress_get_status (OstreeAsyncProgress *self);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_async_progress_get (OstreeAsyncProgress *self,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
guint ostree_async_progress_get_uint (OstreeAsyncProgress *self,
|
||||
const char *key);
|
||||
_OSTREE_PUBLIC
|
||||
guint64 ostree_async_progress_get_uint64 (OstreeAsyncProgress *self,
|
||||
const char *key);
|
||||
_OSTREE_PUBLIC
|
||||
GVariant *ostree_async_progress_get_variant (OstreeAsyncProgress *self,
|
||||
const char *key);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_async_progress_set_status (OstreeAsyncProgress *self,
|
||||
const char *status);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_async_progress_set (OstreeAsyncProgress *self,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_async_progress_set_uint (OstreeAsyncProgress *self,
|
||||
const char *key,
|
||||
@@ -72,6 +83,10 @@ _OSTREE_PUBLIC
|
||||
void ostree_async_progress_set_uint64 (OstreeAsyncProgress *self,
|
||||
const char *key,
|
||||
guint64 value);
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_async_progress_set_variant (OstreeAsyncProgress *self,
|
||||
const char *key,
|
||||
GVariant *value);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_async_progress_finish (OstreeAsyncProgress *self);
|
||||
|
||||
@@ -59,6 +59,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysrootUpgrader, g_object_unref)
|
||||
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (OstreeRepoCommitTraverseIter, ostree_repo_commit_traverse_iter_clear)
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRemote, ostree_remote_unref)
|
||||
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
@@ -79,23 +79,18 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *contents = NULL;
|
||||
char **lines = NULL;
|
||||
char **iter = NULL;
|
||||
|
||||
g_return_val_if_fail (!self->parsed, FALSE);
|
||||
|
||||
contents = glnx_file_get_contents_utf8_at (dfd, path, NULL, cancellable, error);
|
||||
g_autofree char *contents = glnx_file_get_contents_utf8_at (dfd, path, NULL, cancellable, error);
|
||||
if (!contents)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
lines = g_strsplit (contents, "\n", -1);
|
||||
for (iter = lines; *iter; iter++)
|
||||
g_auto(GStrv) lines = g_strsplit (contents, "\n", -1);
|
||||
for (char **iter = lines; *iter; iter++)
|
||||
{
|
||||
const char *line = *iter;
|
||||
char *keyname = "";
|
||||
|
||||
|
||||
if (g_ascii_isalpha (*line))
|
||||
{
|
||||
char **items = NULL;
|
||||
@@ -115,11 +110,8 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
|
||||
}
|
||||
|
||||
self->parsed = TRUE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
return ret;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -166,16 +158,10 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GHashTableIter hashiter;
|
||||
gpointer hashkey, hashvalue;
|
||||
GString *buf = g_string_new ("");
|
||||
guint i;
|
||||
g_autoptr(GHashTable) written_overrides = NULL;
|
||||
g_autoptr(GString) buf = g_string_new ("");
|
||||
g_autoptr(GHashTable) written_overrides = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
written_overrides = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
for (i = 0; i < self->lines->len; i++)
|
||||
for (guint i = 0; i < self->lines->len; i++)
|
||||
{
|
||||
GVariant *linedata = self->lines->pdata[i];
|
||||
const char *key;
|
||||
@@ -197,6 +183,8 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
|
||||
}
|
||||
}
|
||||
|
||||
GHashTableIter hashiter;
|
||||
gpointer hashkey, hashvalue;
|
||||
g_hash_table_iter_init (&hashiter, self->options);
|
||||
while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
|
||||
{
|
||||
@@ -208,15 +196,11 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
|
||||
if (!glnx_file_replace_contents_at (dfd, path, (guint8*)buf->str, buf->len,
|
||||
GLNX_FILE_REPLACE_NODATASYNC,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (buf)
|
||||
g_string_free (buf, TRUE);
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
ostree_bootconfig_parser_write (OstreeBootconfigParser *self,
|
||||
GFile *output,
|
||||
|
||||
@@ -148,7 +148,7 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GString *output = g_string_new ("");
|
||||
g_autoptr(GString) output = g_string_new ("");
|
||||
g_autoptr(GOutputStream) out_stream = NULL;
|
||||
g_autoptr(GPtrArray) loader_configs = NULL;
|
||||
guint i;
|
||||
@@ -260,8 +260,6 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (output)
|
||||
g_string_free (output, TRUE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ const OstreeCmdPrivateVTable *
|
||||
ostree_cmd__private__ (void)
|
||||
{
|
||||
static OstreeCmdPrivateVTable table = {
|
||||
_ostree_impl_system_generator,
|
||||
impl_ostree_generate_grub2_config,
|
||||
_ostree_repo_static_delta_dump,
|
||||
_ostree_repo_static_delta_query_exists,
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
gboolean _ostree_impl_system_generator (const char *ostree_cmdline, const char *normal_dir, const char *early_dir, const char *late_dir, GError **error);
|
||||
|
||||
typedef struct {
|
||||
gboolean (* ostree_system_generator) (const char *ostree_cmdline, const char *normal_dir, const char *early_dir, const char *late_dir, GError **error);
|
||||
gboolean (* ostree_generate_grub2_config) (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error);
|
||||
gboolean (* ostree_static_delta_dump) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error);
|
||||
gboolean (* ostree_static_delta_query_exists) (OstreeRepo *repo, const char *delta_id, gboolean *out_exists, GCancellable *cancellable, GError **error);
|
||||
|
||||
@@ -90,6 +90,14 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd,
|
||||
|
||||
GFileInfo * _ostree_header_gfile_info_new (mode_t mode, uid_t uid, gid_t gid);
|
||||
|
||||
static inline void
|
||||
_ostree_checksum_inplace_from_bytes_v (GVariant *csum_v, char *buf)
|
||||
{
|
||||
const guint8*csum = ostree_checksum_bytes_peek (csum_v);
|
||||
g_assert (csum);
|
||||
ostree_checksum_inplace_from_bytes (csum, buf);
|
||||
}
|
||||
|
||||
/* XX/checksum-2.extension, but let's just use 256 for a
|
||||
* bit of overkill.
|
||||
*/
|
||||
|
||||
+69
-135
@@ -579,57 +579,45 @@ ostree_content_stream_parse (gboolean compressed,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint32 archive_header_size;
|
||||
guchar dummy[4];
|
||||
gsize bytes_read;
|
||||
g_autoptr(GInputStream) ret_input = NULL;
|
||||
g_autoptr(GFileInfo) ret_file_info = NULL;
|
||||
g_autoptr(GVariant) ret_xattrs = NULL;
|
||||
g_autoptr(GVariant) file_header = NULL;
|
||||
g_autofree guchar *buf = NULL;
|
||||
|
||||
if (!g_input_stream_read_all (input,
|
||||
&archive_header_size, 4, &bytes_read,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
archive_header_size = GUINT32_FROM_BE (archive_header_size);
|
||||
if (archive_header_size > input_length)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"File header size %u exceeds size %" G_GUINT64_FORMAT,
|
||||
(guint)archive_header_size, input_length);
|
||||
goto out;
|
||||
}
|
||||
if (archive_header_size == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"File header size is zero");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "File header size %u exceeds size %" G_GUINT64_FORMAT,
|
||||
(guint)archive_header_size, input_length);
|
||||
else if (archive_header_size == 0)
|
||||
return glnx_throw (error, "File header size is zero");
|
||||
|
||||
/* Skip over padding */
|
||||
if (!g_input_stream_read_all (input,
|
||||
dummy, 4, &bytes_read,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
buf = g_malloc (archive_header_size);
|
||||
g_autofree guchar *buf = g_malloc (archive_header_size);
|
||||
if (!g_input_stream_read_all (input, buf, archive_header_size, &bytes_read,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
file_header = g_variant_new_from_data (compressed ? _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT : _OSTREE_FILE_HEADER_GVARIANT_FORMAT,
|
||||
buf, archive_header_size, trusted,
|
||||
g_free, buf);
|
||||
return FALSE;
|
||||
g_autoptr(GVariant) file_header =
|
||||
g_variant_new_from_data (compressed ? _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT : _OSTREE_FILE_HEADER_GVARIANT_FORMAT,
|
||||
buf, archive_header_size, trusted,
|
||||
g_free, buf);
|
||||
buf = NULL;
|
||||
|
||||
g_autoptr(GFileInfo) ret_file_info = NULL;
|
||||
g_autoptr(GVariant) ret_xattrs = NULL;
|
||||
if (compressed)
|
||||
{
|
||||
if (!zlib_file_header_parse (file_header,
|
||||
out_file_info ? &ret_file_info : NULL,
|
||||
out_xattrs ? &ret_xattrs : NULL,
|
||||
error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -637,11 +625,12 @@ ostree_content_stream_parse (gboolean compressed,
|
||||
out_file_info ? &ret_file_info : NULL,
|
||||
out_xattrs ? &ret_xattrs : NULL,
|
||||
error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (ret_file_info)
|
||||
g_file_info_set_size (ret_file_info, input_length - archive_header_size - 8);
|
||||
}
|
||||
|
||||
|
||||
g_autoptr(GInputStream) ret_input = NULL;
|
||||
if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR
|
||||
&& out_input)
|
||||
{
|
||||
@@ -658,12 +647,10 @@ ostree_content_stream_parse (gboolean compressed,
|
||||
ret_input = g_object_ref (input);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value (out_input, &ret_input);
|
||||
ot_transfer_out_value (out_file_info, &ret_file_info);
|
||||
ot_transfer_out_value (out_xattrs, &ret_xattrs);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -820,43 +807,39 @@ ostree_checksum_file (GFile *f,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFileInfo) file_info = NULL;
|
||||
g_autoptr(GInputStream) in = NULL;
|
||||
g_autoptr(GVariant) xattrs = NULL;
|
||||
g_autofree guchar *ret_csum = NULL;
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
file_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, error);
|
||||
g_autoptr(GFileInfo) file_info =
|
||||
g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, error);
|
||||
if (!file_info)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GInputStream) in = NULL;
|
||||
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
in = (GInputStream*)g_file_read (f, cancellable, error);
|
||||
if (!in)
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autoptr(GVariant) xattrs = NULL;
|
||||
if (objtype == OSTREE_OBJECT_TYPE_FILE)
|
||||
{
|
||||
if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f),
|
||||
&xattrs, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autofree guchar *ret_csum = NULL;
|
||||
if (!ostree_checksum_file_from_input (file_info, xattrs, in, objtype,
|
||||
&ret_csum, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_csum, &ret_csum);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@@ -1623,27 +1606,21 @@ file_header_parse (GVariant *metadata,
|
||||
GVariant **out_xattrs,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint32 uid, gid, mode, rdev;
|
||||
const char *symlink_target;
|
||||
g_autoptr(GFileInfo) ret_file_info = NULL;
|
||||
g_autoptr(GVariant) ret_xattrs = NULL;
|
||||
|
||||
g_variant_get (metadata, "(uuuu&s@a(ayay))",
|
||||
&uid, &gid, &mode, &rdev,
|
||||
&symlink_target, &ret_xattrs);
|
||||
if (rdev != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev));
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev));
|
||||
|
||||
uid = GUINT32_FROM_BE (uid);
|
||||
gid = GUINT32_FROM_BE (gid);
|
||||
mode = GUINT32_FROM_BE (mode);
|
||||
|
||||
ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid);
|
||||
g_autoptr(GFileInfo) ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid);
|
||||
|
||||
if (S_ISREG (mode))
|
||||
{
|
||||
@@ -1655,16 +1632,12 @@ file_header_parse (GVariant *metadata,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted archive file; invalid mode %u", mode);
|
||||
goto out;
|
||||
return glnx_throw (error, "Corrupted archive file; invalid mode %u", mode);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_file_info, &ret_file_info);
|
||||
ot_transfer_out_value(out_xattrs, &ret_xattrs);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1683,28 +1656,21 @@ zlib_file_header_parse (GVariant *metadata,
|
||||
GVariant **out_xattrs,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint64 size;
|
||||
guint32 uid, gid, mode, rdev;
|
||||
const char *symlink_target;
|
||||
g_autoptr(GFileInfo) ret_file_info = NULL;
|
||||
g_autoptr(GVariant) ret_xattrs = NULL;
|
||||
|
||||
g_variant_get (metadata, "(tuuuu&s@a(ayay))", &size,
|
||||
&uid, &gid, &mode, &rdev,
|
||||
&symlink_target, &ret_xattrs);
|
||||
if (rdev != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev));
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev));
|
||||
|
||||
uid = GUINT32_FROM_BE (uid);
|
||||
gid = GUINT32_FROM_BE (gid);
|
||||
mode = GUINT32_FROM_BE (mode);
|
||||
ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid);
|
||||
|
||||
g_autoptr(GFileInfo) ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid);
|
||||
g_file_info_set_size (ret_file_info, GUINT64_FROM_BE (size));
|
||||
|
||||
if (S_ISREG (mode))
|
||||
@@ -1717,16 +1683,12 @@ zlib_file_header_parse (GVariant *metadata,
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Corrupted archive file; invalid mode %u", mode);
|
||||
goto out;
|
||||
return glnx_throw (error, "Corrupted archive file; invalid mode %u", mode);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_file_info, &ret_file_info);
|
||||
ot_transfer_out_value(out_xattrs, &ret_xattrs);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1829,34 +1791,30 @@ gboolean
|
||||
ostree_validate_structureof_commit (GVariant *commit,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GVariant) parent_csum_v = NULL;
|
||||
g_autoptr(GVariant) content_csum_v = NULL;
|
||||
g_autoptr(GVariant) metadata_csum_v = NULL;
|
||||
gsize n_elts;
|
||||
|
||||
if (!validate_variant (commit, OSTREE_COMMIT_GVARIANT_FORMAT, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GVariant) parent_csum_v = NULL;
|
||||
g_variant_get_child (commit, 1, "@ay", &parent_csum_v);
|
||||
gsize n_elts;
|
||||
(void) g_variant_get_fixed_array (parent_csum_v, &n_elts, 1);
|
||||
if (n_elts > 0)
|
||||
{
|
||||
if (!ostree_validate_structureof_csum_v (parent_csum_v, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autoptr(GVariant) content_csum_v = NULL;
|
||||
g_variant_get_child (commit, 6, "@ay", &content_csum_v);
|
||||
if (!ostree_validate_structureof_csum_v (content_csum_v, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GVariant) metadata_csum_v = NULL;
|
||||
g_variant_get_child (commit, 7, "@ay", &metadata_csum_v);
|
||||
if (!ostree_validate_structureof_csum_v (metadata_csum_v, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1873,14 +1831,13 @@ gboolean
|
||||
ostree_validate_structureof_dirtree (GVariant *dirtree,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *filename;
|
||||
g_autoptr(GVariant) content_csum_v = NULL;
|
||||
g_autoptr(GVariant) meta_csum_v = NULL;
|
||||
GVariantIter *contents_iter = NULL;
|
||||
g_autoptr(GVariantIter) contents_iter = NULL;
|
||||
|
||||
if (!validate_variant (dirtree, OSTREE_TREE_GVARIANT_FORMAT, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_variant_get_child (dirtree, 0, "a(say)", &contents_iter);
|
||||
|
||||
@@ -1888,10 +1845,13 @@ ostree_validate_structureof_dirtree (GVariant *dirtree,
|
||||
&filename, &content_csum_v))
|
||||
{
|
||||
if (!ot_util_filename_validate (filename, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (!ostree_validate_structureof_csum_v (content_csum_v, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
/* Note we only use autoptr in case we broke out of the loop early;
|
||||
* g_variant_iter_loop() has special semantics.
|
||||
*/
|
||||
content_csum_v = NULL;
|
||||
|
||||
g_variant_iter_free (contents_iter);
|
||||
@@ -1901,68 +1861,49 @@ ostree_validate_structureof_dirtree (GVariant *dirtree,
|
||||
&filename, &content_csum_v, &meta_csum_v))
|
||||
{
|
||||
if (!ot_util_filename_validate (filename, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (!ostree_validate_structureof_csum_v (content_csum_v, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (!ostree_validate_structureof_csum_v (meta_csum_v, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
content_csum_v = NULL;
|
||||
meta_csum_v = NULL;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (contents_iter)
|
||||
g_variant_iter_free (contents_iter);
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
validate_stat_mode_perms (guint32 mode,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint32 otherbits = (~S_IFMT & ~S_IRWXU & ~S_IRWXG & ~S_IRWXO &
|
||||
~S_ISUID & ~S_ISGID & ~S_ISVTX);
|
||||
|
||||
if (mode & otherbits)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid mode %u; invalid bits in mode", mode);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid mode %u; invalid bits in mode", mode);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_validate_structureof_file_mode:
|
||||
* @mode: A Unix filesystem mode
|
||||
* @error: Error
|
||||
*
|
||||
*
|
||||
* Returns: %TRUE if @mode represents a valid file type and permissions
|
||||
*/
|
||||
gboolean
|
||||
ostree_validate_structureof_file_mode (guint32 mode,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (!(S_ISREG (mode) || S_ISLNK (mode)))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid file metadata mode %u; not a valid file type", mode);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid file metadata mode %u; not a valid file type", mode);
|
||||
|
||||
if (!validate_stat_mode_perms (mode, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1978,28 +1919,21 @@ gboolean
|
||||
ostree_validate_structureof_dirmeta (GVariant *dirmeta,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint32 mode;
|
||||
|
||||
if (!validate_variant (dirmeta, OSTREE_DIRMETA_GVARIANT_FORMAT, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_variant_get_child (dirmeta, 2, "u", &mode);
|
||||
mode = GUINT32_FROM_BE (mode);
|
||||
|
||||
if (!S_ISDIR (mode))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid directory metadata mode %u; not a directory", mode);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid directory metadata mode %u; not a directory", mode);
|
||||
|
||||
if (!validate_stat_mode_perms (mode, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -104,9 +104,9 @@ typedef enum {
|
||||
/**
|
||||
* OSTREE_DIRMETA_GVARIANT_FORMAT:
|
||||
*
|
||||
* - u - uid
|
||||
* - u - gid
|
||||
* - u - mode
|
||||
* - u - uid (big-endian)
|
||||
* - u - gid (big-endian)
|
||||
* - u - mode (big-endian)
|
||||
* - a(ayay) - xattrs
|
||||
*/
|
||||
#define OSTREE_DIRMETA_GVARIANT_STRING "(uuua(ayay))"
|
||||
@@ -120,9 +120,9 @@ typedef enum {
|
||||
* can't store in the real filesystem but we can still use a regular .file object
|
||||
* that we can hardlink to in the case of a user-mode checkout.
|
||||
*
|
||||
* - u - uid
|
||||
* - u - gid
|
||||
* - u - mode
|
||||
* - u - uid (big-endian)
|
||||
* - u - gid (big-endian)
|
||||
* - u - mode (big-endian)
|
||||
* - a(ayay) - xattrs
|
||||
*/
|
||||
#define OSTREE_FILEMETA_GVARIANT_STRING "(uuua(ayay))"
|
||||
@@ -145,7 +145,7 @@ typedef enum {
|
||||
* - a(say) - Related objects
|
||||
* - s - subject
|
||||
* - s - body
|
||||
* - t - Timestamp in seconds since the epoch (UTC)
|
||||
* - t - Timestamp in seconds since the epoch (UTC, big-endian)
|
||||
* - ay - Root tree contents
|
||||
* - ay - Root tree metadata
|
||||
*/
|
||||
@@ -158,6 +158,17 @@ typedef enum {
|
||||
* - a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name
|
||||
* - a{sv} - Additional metadata, at the current time the following are defined:
|
||||
* - key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum
|
||||
* - key: "ostree.summary.last-modified", value: t, timestamp (seconds since
|
||||
* the Unix epoch in UTC, big-endian) when the summary was last regenerated
|
||||
* (similar to the HTTP `Last-Modified` header)
|
||||
* - key: "ostree.summary.expires", value: t, timestamp (seconds since the
|
||||
* Unix epoch in UTC, big-endian) after which the summary is considered
|
||||
* stale and should be re-downloaded if possible (similar to the HTTP
|
||||
* `Expires` header)
|
||||
*
|
||||
* The currently defined keys for the `a{sv}` of additional metadata for each commit are:
|
||||
* - key: `ostree.commit.timestamp`, value: `t`, timestamp (seconds since the
|
||||
* Unix epoch in UTC, big-endian) when the commit was committed
|
||||
*/
|
||||
#define OSTREE_SUMMARY_GVARIANT_STRING "(a(s(taya{sv}))a{sv})"
|
||||
#define OSTREE_SUMMARY_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_GVARIANT_STRING)
|
||||
|
||||
@@ -39,6 +39,12 @@ ostree_deployment_get_bootcsum (OstreeDeployment *self)
|
||||
return self->bootcsum;
|
||||
}
|
||||
|
||||
/*
|
||||
* ostree_deployment_get_osname:
|
||||
* @self: Deployemnt
|
||||
*
|
||||
* Returns: The "stateroot" name, also known as an "osname"
|
||||
*/
|
||||
const char *
|
||||
ostree_deployment_get_osname (OstreeDeployment *self)
|
||||
{
|
||||
|
||||
+26
-44
@@ -35,9 +35,7 @@ get_file_checksum (OstreeDiffFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *ret_checksum = NULL;
|
||||
g_autofree guchar *csum = NULL;
|
||||
|
||||
if (OSTREE_IS_REPO_FILE (f))
|
||||
{
|
||||
@@ -52,27 +50,26 @@ get_file_checksum (OstreeDiffFlags flags,
|
||||
{
|
||||
if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f),
|
||||
&xattrs, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (g_file_info_get_file_type (f_info) == G_FILE_TYPE_REGULAR)
|
||||
{
|
||||
in = (GInputStream*)g_file_read (f, cancellable, error);
|
||||
if (!in)
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autofree guchar *csum = NULL;
|
||||
if (!ostree_checksum_file_from_input (f_info, xattrs, in,
|
||||
OSTREE_OBJECT_TYPE_FILE,
|
||||
&csum, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
ret_checksum = ostree_checksum_from_bytes (csum);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_checksum, &ret_checksum);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
OstreeDiffItem *
|
||||
@@ -130,28 +127,22 @@ diff_files (OstreeDiffFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *checksum_a = NULL;
|
||||
g_autofree char *checksum_b = NULL;
|
||||
OstreeDiffItem *ret_item = NULL;
|
||||
|
||||
if (!get_file_checksum (flags, a, a_info, &checksum_a, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (!get_file_checksum (flags, b, b_info, &checksum_b, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(OstreeDiffItem) ret_item = NULL;
|
||||
if (strcmp (checksum_a, checksum_b) != 0)
|
||||
{
|
||||
ret_item = diff_item_new (a, a_info, b, b_info,
|
||||
checksum_a, checksum_b);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value(out_item, &ret_item);
|
||||
out:
|
||||
if (ret_item)
|
||||
ostree_diff_item_unref (ret_item);
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -160,47 +151,38 @@ diff_add_dir_recurse (GFile *d,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GError *temp_error = NULL;
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
g_autoptr(GFile) child = NULL;
|
||||
g_autoptr(GFileInfo) child_info = NULL;
|
||||
|
||||
dir_enum = g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable,
|
||||
error);
|
||||
g_autoptr(GFileEnumerator) dir_enum =
|
||||
g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable,
|
||||
error);
|
||||
if (!dir_enum)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
|
||||
while (TRUE)
|
||||
{
|
||||
GFileInfo *child_info;
|
||||
const char *name;
|
||||
|
||||
if (!g_file_enumerator_iterate (dir_enum, &child_info, NULL,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
if (child_info == NULL)
|
||||
break;
|
||||
|
||||
name = g_file_info_get_name (child_info);
|
||||
|
||||
g_clear_object (&child);
|
||||
child = g_file_get_child (d, name);
|
||||
|
||||
g_autoptr(GFile) child = g_file_get_child (d, name);
|
||||
g_ptr_array_add (added, g_object_ref (child));
|
||||
|
||||
if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
|
||||
{
|
||||
if (!diff_add_dir_recurse (child, added, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_clear_object (&child_info);
|
||||
}
|
||||
if (temp_error != NULL)
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -272,7 +272,7 @@ ensure_tmpfile (FetcherRequest *req, GError **error)
|
||||
if (req->out_tmpfile_fd == -1)
|
||||
{
|
||||
if (!glnx_open_tmpfile_linkable_at (req->fetcher->tmpdir_dfd, ".",
|
||||
O_WRONLY, &req->out_tmpfile_fd,
|
||||
O_WRONLY | O_CLOEXEC, &req->out_tmpfile_fd,
|
||||
&req->out_tmpfile,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
@@ -116,7 +116,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
|
||||
if (result == NULL)
|
||||
goto out;
|
||||
|
||||
if (!ot_gpgme_ctx_tmp_home_dir (result->context, NULL,
|
||||
if (!ot_gpgme_ctx_tmp_home_dir (result->context,
|
||||
&tmp_dir, &target_stream,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
@@ -562,6 +562,14 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant,
|
||||
key_id = (len > 16) ? fingerprint + len - 16 : fingerprint;
|
||||
|
||||
date_time_utc = g_date_time_new_from_unix_utc (timestamp);
|
||||
if (date_time_utc == NULL)
|
||||
{
|
||||
g_string_append_printf (output_buffer,
|
||||
"Can't check signature: timestamp %" G_GINT64_FORMAT " is invalid\n",
|
||||
timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
date_time_local = g_date_time_to_local (date_time_utc);
|
||||
formatted_date_time = g_date_time_format (date_time_local, "%c");
|
||||
|
||||
@@ -606,6 +614,14 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant,
|
||||
if (exp_timestamp > 0)
|
||||
{
|
||||
date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp);
|
||||
if (date_time_utc == NULL)
|
||||
{
|
||||
g_string_append_printf (output_buffer,
|
||||
"Signature expiry timestamp (%" G_GINT64_FORMAT ") is invalid\n",
|
||||
exp_timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
date_time_local = g_date_time_to_local (date_time_utc);
|
||||
formatted_date_time = g_date_time_format (date_time_local, "%c");
|
||||
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
|
||||
*
|
||||
* 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 <glib-unix.h>
|
||||
#include <gio/gunixoutputstream.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_LIBMOUNT
|
||||
#include <libmount.h>
|
||||
#endif
|
||||
#include <stdbool.h>
|
||||
#include "otutil.h"
|
||||
|
||||
#include "ostree.h"
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-cmdprivate.h"
|
||||
|
||||
#ifdef HAVE_LIBMOUNT
|
||||
typedef FILE OtLibMountFile;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtLibMountFile, endmntent);
|
||||
|
||||
/* Taken from systemd path-util.c */
|
||||
static bool
|
||||
is_path (const char *p)
|
||||
{
|
||||
return !!strchr (p, '/');
|
||||
}
|
||||
|
||||
/* Taken from systemd path-util.c */
|
||||
static char*
|
||||
path_kill_slashes (char *path)
|
||||
{
|
||||
char *f, *t;
|
||||
bool slash = false;
|
||||
|
||||
/* Removes redundant inner and trailing slashes. Modifies the
|
||||
* passed string in-place.
|
||||
*
|
||||
* For example: ///foo///bar/ becomes /foo/bar
|
||||
*/
|
||||
|
||||
for (f = path, t = path; *f; f++)
|
||||
{
|
||||
if (*f == '/')
|
||||
{
|
||||
slash = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slash)
|
||||
{
|
||||
slash = false;
|
||||
*(t++) = '/';
|
||||
}
|
||||
|
||||
*(t++) = *f;
|
||||
}
|
||||
|
||||
/* Special rule, if we are talking of the root directory, a
|
||||
trailing slash is good */
|
||||
|
||||
if (t == path && slash)
|
||||
*(t++) = '/';
|
||||
|
||||
*t = 0;
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Written by ostree-sysroot-deploy.c. We parse out the stateroot here since we
|
||||
* need to know it to mount /var. Unfortunately we can't easily use the
|
||||
* libostree API to find the booted deployment since /boot might not have been
|
||||
* mounted yet.
|
||||
*/
|
||||
static char *
|
||||
stateroot_from_ostree_cmdline (const char *ostree_cmdline,
|
||||
GError **error)
|
||||
{
|
||||
static GRegex *regex;
|
||||
static gsize regex_initialized;
|
||||
if (g_once_init_enter (®ex_initialized))
|
||||
{
|
||||
regex = g_regex_new ("^/ostree/boot.[01]/([^/]+)/", 0, 0, NULL);
|
||||
g_assert (regex);
|
||||
g_once_init_leave (®ex_initialized, 1);
|
||||
}
|
||||
|
||||
g_autoptr(GMatchInfo) match = NULL;
|
||||
if (!g_regex_match (regex, ostree_cmdline, 0, &match))
|
||||
return glnx_null_throw (error, "Failed to parse %s", ostree_cmdline);
|
||||
|
||||
return g_match_info_fetch (match, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Implementation of ostree-system-generator */
|
||||
gboolean
|
||||
_ostree_impl_system_generator (const char *ostree_cmdline,
|
||||
const char *normal_dir,
|
||||
const char *early_dir,
|
||||
const char *late_dir,
|
||||
GError **error)
|
||||
{
|
||||
#ifdef HAVE_LIBMOUNT
|
||||
/* Not currently cancellable, but define a var in case we care later */
|
||||
GCancellable *cancellable = NULL;
|
||||
/* Some path constants to avoid typos */
|
||||
static const char fstab_path[] = "/etc/fstab";
|
||||
static const char var_path[] = "/var";
|
||||
|
||||
/* ostree-prepare-root was patched to write the stateroot to this file */
|
||||
g_autofree char *stateroot = stateroot_from_ostree_cmdline (ostree_cmdline, error);
|
||||
if (!stateroot)
|
||||
return FALSE;
|
||||
|
||||
/* Load /etc/fstab if it exists, and look for a /var mount */
|
||||
g_autoptr(OtLibMountFile) fstab = setmntent (fstab_path, "re");
|
||||
gboolean found_var_mnt = FALSE;
|
||||
if (!fstab)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return glnx_throw_errno_prefix (error, "Reading %s", fstab_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Parse it */
|
||||
struct mntent *me;
|
||||
while ((me = getmntent (fstab)))
|
||||
{
|
||||
g_autofree char *where = g_strdup (me->mnt_dir);
|
||||
if (is_path (where))
|
||||
path_kill_slashes (where);
|
||||
|
||||
/* We're only looking for /var here */
|
||||
if (strcmp (where, var_path) != 0)
|
||||
continue;
|
||||
|
||||
found_var_mnt = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we found /var, we're done */
|
||||
if (found_var_mnt)
|
||||
return TRUE;
|
||||
|
||||
/* Prepare to write to the output unit dir; we use the "normal" dir
|
||||
* that overrides /usr, but not /etc.
|
||||
*/
|
||||
glnx_fd_close int normal_dir_dfd = -1;
|
||||
if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
/* Generate our bind mount unit */
|
||||
const char *stateroot_var_path = glnx_strjoina ("/sysroot/ostree/deploy/", stateroot, "/var");
|
||||
|
||||
glnx_fd_close int tmpfd = -1;
|
||||
g_autofree char *tmppath = NULL;
|
||||
if (!glnx_open_tmpfile_linkable_at (normal_dir_dfd, ".", O_WRONLY | O_CLOEXEC,
|
||||
&tmpfd, &tmppath, error))
|
||||
return FALSE;
|
||||
g_autoptr(GOutputStream) outstream = g_unix_output_stream_new (tmpfd, FALSE);
|
||||
gsize bytes_written;
|
||||
/* This code is inspired by systemd's fstab-generator.c.
|
||||
*
|
||||
* Note that our unit doesn't run if systemd.volatile is enabled;
|
||||
* see https://github.com/ostreedev/ostree/pull/856
|
||||
*/
|
||||
if (!g_output_stream_printf (outstream, &bytes_written, cancellable, error,
|
||||
"##\n# Automatically generated by ostree-system-generator\n##\n\n"
|
||||
"[Unit]\n"
|
||||
"Documentation=man:ostree(1)\n"
|
||||
"ConditionKernelCommandLine=!systemd.volatile\n"
|
||||
/* We need /sysroot mounted writable first */
|
||||
"After=ostree-remount.service\n"
|
||||
"Before=local-fs.target\n"
|
||||
"\n"
|
||||
"[Mount]\n"
|
||||
"Where=%s\n"
|
||||
"What=%s\n"
|
||||
"Options=bind\n",
|
||||
var_path,
|
||||
stateroot_var_path))
|
||||
return FALSE;
|
||||
if (!g_output_stream_flush (outstream, cancellable, error))
|
||||
return FALSE;
|
||||
g_clear_object (&outstream);
|
||||
/* It should be readable */
|
||||
if (fchmod (tmpfd, 0644) < 0)
|
||||
return glnx_throw_errno_prefix (error, "fchmod");
|
||||
/* Error out if somehow it already exists, that'll help us debug conflicts */
|
||||
if (!glnx_link_tmpfile_at (normal_dir_dfd, GLNX_LINK_TMPFILE_NOREPLACE,
|
||||
tmpfd, tmppath, normal_dir_dfd,
|
||||
"var.mount", error))
|
||||
return FALSE;
|
||||
|
||||
/* And ensure it's required; newer systemd will auto-inject fs dependencies
|
||||
* via RequiresMountsFor and the like, but on older versions (e.g. CentOS) we
|
||||
* need this. It's what the fstab generator does. And my mother always said,
|
||||
* listen to the fstab generator.
|
||||
*/
|
||||
if (!glnx_shutil_mkdir_p_at (normal_dir_dfd, "local-fs.target.requires", 0755, cancellable, error))
|
||||
return FALSE;
|
||||
if (symlinkat ("../var.mount", normal_dir_dfd, "local-fs.target.requires/var.mount") < 0)
|
||||
return glnx_throw_errno_prefix (error, "symlinkat");
|
||||
|
||||
return TRUE;
|
||||
#else
|
||||
return glnx_throw (error, "Not implemented");
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright © 2011 Colin Walters <walters@verbum.org>
|
||||
* Copyright © 2015 Red Hat, Inc.
|
||||
* Copyright © 2017 Endless Mobile, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* - Colin Walters <walters@verbum.org>
|
||||
* - Philip Withnall <withnall@endlessm.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "libglnx.h"
|
||||
#include "ostree-remote.h"
|
||||
#include "ostree-types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct OstreeRemote {
|
||||
volatile int ref_count;
|
||||
char *name;
|
||||
char *group; /* group name in options */
|
||||
char *keyring; /* keyring name (NAME.trustedkeys.gpg) */
|
||||
GFile *file; /* NULL if remote defined in repo/config */
|
||||
GKeyFile *options;
|
||||
};
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
OstreeRemote *ostree_remote_new (void);
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
OstreeRemote *ostree_remote_new_from_keyfile (GKeyFile *keyfile,
|
||||
const gchar *group);
|
||||
|
||||
#if (defined(OSTREE_COMPILATION) || GLIB_CHECK_VERSION(2, 44, 0)) && !defined(OSTREE_ENABLE_EXPERIMENTAL_API)
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRemote, ostree_remote_unref)
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
@@ -0,0 +1,150 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright © 2011 Colin Walters <walters@verbum.org>
|
||||
* Copyright © 2015 Red Hat, Inc.
|
||||
* Copyright © 2017 Endless Mobile, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* - Colin Walters <walters@verbum.org>
|
||||
* - Philip Withnall <withnall@endlessm.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ostree-remote.h"
|
||||
#include "ostree-remote-private.h"
|
||||
#include "ot-keyfile-utils.h"
|
||||
|
||||
/**
|
||||
* SECTION:remote
|
||||
*
|
||||
* The #OstreeRemote structure represents the configuration for a single remote
|
||||
* repository. Currently, all configuration is handled internally, and
|
||||
* #OstreeRemote objects are represented by their textual name handle, or by an
|
||||
* opaque pointer (which can be reference counted if needed).
|
||||
*
|
||||
* #OstreeRemote provides configuration for accessing a remote, but does not
|
||||
* provide the results of accessing a remote, such as information about what
|
||||
* refs are currently on a remote, or the commits they currently point to. Use
|
||||
* #OstreeRepo in combination with an #OstreeRemote to query that information.
|
||||
*
|
||||
* Since: 2017.6
|
||||
*/
|
||||
|
||||
OstreeRemote *
|
||||
ostree_remote_new (void)
|
||||
{
|
||||
OstreeRemote *remote;
|
||||
|
||||
remote = g_slice_new0 (OstreeRemote);
|
||||
remote->ref_count = 1;
|
||||
remote->options = g_key_file_new ();
|
||||
|
||||
return remote;
|
||||
}
|
||||
|
||||
OstreeRemote *
|
||||
ostree_remote_new_from_keyfile (GKeyFile *keyfile,
|
||||
const gchar *group)
|
||||
{
|
||||
g_autoptr(GMatchInfo) match = NULL;
|
||||
OstreeRemote *remote;
|
||||
|
||||
static gsize regex_initialized;
|
||||
static GRegex *regex;
|
||||
|
||||
if (g_once_init_enter (®ex_initialized))
|
||||
{
|
||||
regex = g_regex_new ("^remote \"(.+)\"$", 0, 0, NULL);
|
||||
g_assert (regex);
|
||||
g_once_init_leave (®ex_initialized, 1);
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
g_return_val_if_fail (g_key_file_has_group (keyfile, group), NULL);
|
||||
|
||||
/* If group name doesn't fit the pattern, fail. */
|
||||
if (!g_regex_match (regex, group, 0, &match))
|
||||
return NULL;
|
||||
|
||||
remote = ostree_remote_new ();
|
||||
remote->name = g_match_info_fetch (match, 1);
|
||||
remote->group = g_strdup (group);
|
||||
remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", remote->name);
|
||||
|
||||
ot_keyfile_copy_group (keyfile, remote->options, group);
|
||||
|
||||
return remote;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_remote_ref:
|
||||
* @remote: an #OstreeRemote
|
||||
*
|
||||
* Increase the reference count on the given @remote.
|
||||
*
|
||||
* Returns: (transfer full): a copy of @remote, for convenience
|
||||
* Since: 2017.6
|
||||
*/
|
||||
OstreeRemote *
|
||||
ostree_remote_ref (OstreeRemote *remote)
|
||||
{
|
||||
gint refcount;
|
||||
g_return_val_if_fail (remote != NULL, NULL);
|
||||
refcount = g_atomic_int_add (&remote->ref_count, 1);
|
||||
g_assert (refcount > 0);
|
||||
return remote;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_remote_unref:
|
||||
* @remote: (transfer full): an #OstreeRemote
|
||||
*
|
||||
* Decrease the reference count on the given @remote and free it if the
|
||||
* reference count reaches 0.
|
||||
*
|
||||
* Since: 2017.6
|
||||
*/
|
||||
void
|
||||
ostree_remote_unref (OstreeRemote *remote)
|
||||
{
|
||||
g_return_if_fail (remote != NULL);
|
||||
g_return_if_fail (remote->ref_count > 0);
|
||||
|
||||
if (g_atomic_int_dec_and_test (&remote->ref_count))
|
||||
{
|
||||
g_clear_pointer (&remote->name, g_free);
|
||||
g_clear_pointer (&remote->group, g_free);
|
||||
g_clear_pointer (&remote->keyring, g_free);
|
||||
g_clear_object (&remote->file);
|
||||
g_clear_pointer (&remote->options, g_key_file_free);
|
||||
g_slice_free (OstreeRemote, remote);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
G_DEFINE_BOXED_TYPE(OstreeRemote, ostree_remote,
|
||||
ostree_remote_ref,
|
||||
ostree_remote_unref);
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright © 2011 Colin Walters <walters@verbum.org>
|
||||
* Copyright © 2015 Red Hat, Inc.
|
||||
* Copyright © 2017 Endless Mobile, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Authors:
|
||||
* - Colin Walters <walters@verbum.org>
|
||||
* - Philip Withnall <withnall@endlessm.com>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "ostree-types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* OstreeRemote:
|
||||
*
|
||||
* This represents the configuration for a single remote repository. Currently,
|
||||
* remotes can only be passed around as (reference counted) opaque handles. In
|
||||
* future, more API may be added to create and interrogate them.
|
||||
*
|
||||
* Since: 2016.7
|
||||
*/
|
||||
#ifndef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
/* This is in ostree-types.h otherwise */
|
||||
typedef struct OstreeRemote OstreeRemote;
|
||||
#endif
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
_OSTREE_PUBLIC
|
||||
GType ostree_remote_get_type (void) G_GNUC_CONST;
|
||||
#else
|
||||
#ifndef __GI_SCANNER__
|
||||
_OSTREE_PUBLIC
|
||||
OstreeRemote *ostree_remote_ref (OstreeRemote *remote);
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_remote_unref (OstreeRemote *remote);
|
||||
#endif /* GI_SCANNER */
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
File diff suppressed because it is too large.
Load diff
@@ -433,7 +433,7 @@ add_size_index_to_metadata (OstreeRepo *self,
|
||||
{
|
||||
guint8 csum[OSTREE_SHA256_DIGEST_LEN];
|
||||
const char *e_checksum = sorted_keys->pdata[i];
|
||||
GString *buffer = g_string_new (NULL);
|
||||
g_autoptr(GString) buffer = g_string_new (NULL);
|
||||
|
||||
ostree_checksum_inplace_to_bytes (e_checksum, csum);
|
||||
g_string_append_len (buffer, (char*)csum, sizeof (csum));
|
||||
@@ -444,7 +444,6 @@ add_size_index_to_metadata (OstreeRepo *self,
|
||||
|
||||
g_variant_builder_add (&index_builder, "@ay",
|
||||
ot_gvariant_new_bytearray ((guint8*)buffer->str, buffer->len));
|
||||
g_string_free (buffer, TRUE);
|
||||
}
|
||||
|
||||
g_variant_builder_add (builder, "{sv}", "ostree.sizes",
|
||||
@@ -459,29 +458,19 @@ add_size_index_to_metadata (OstreeRepo *self,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fallocate_stream (GFileDescriptorBased *stream,
|
||||
goffset size,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
ot_fallocate (int fd, goffset size, GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int fd = g_file_descriptor_based_get_fd (stream);
|
||||
if (size == 0)
|
||||
return TRUE;
|
||||
|
||||
if (size > 0)
|
||||
int r = posix_fallocate (fd, 0, size);
|
||||
if (r != 0)
|
||||
{
|
||||
int r = posix_fallocate (fd, 0, size);
|
||||
if (r != 0)
|
||||
{
|
||||
/* posix_fallocate is a weird deviation from errno standards */
|
||||
errno = r;
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
/* posix_fallocate is a weird deviation from errno standards */
|
||||
errno = r;
|
||||
return glnx_throw_errno_prefix (error, "fallocate");
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -511,11 +500,10 @@ _ostree_repo_open_content_bare (OstreeRepo *self,
|
||||
&fd, &temp_filename, error))
|
||||
goto out;
|
||||
|
||||
ret_stream = g_unix_output_stream_new (fd, TRUE);
|
||||
|
||||
if (!fallocate_stream ((GFileDescriptorBased*)ret_stream, content_len,
|
||||
cancellable, error))
|
||||
if (!ot_fallocate (fd, content_len, error))
|
||||
goto out;
|
||||
|
||||
ret_stream = g_unix_output_stream_new (fd, TRUE);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
@@ -570,7 +558,6 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GOutputStream) temp_out = NULL;
|
||||
glnx_fd_close int temp_fd = -1;
|
||||
g_autofree char *temp_filename = NULL;
|
||||
|
||||
@@ -578,20 +565,27 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
|
||||
&temp_fd, &temp_filename,
|
||||
error))
|
||||
return FALSE;
|
||||
temp_out = g_unix_output_stream_new (temp_fd, FALSE);
|
||||
|
||||
if (!fallocate_stream ((GFileDescriptorBased*)temp_out, length,
|
||||
cancellable, error))
|
||||
if (!ot_fallocate (temp_fd, length, error))
|
||||
return FALSE;
|
||||
|
||||
if (g_output_stream_splice (temp_out, input, 0,
|
||||
cancellable, error) < 0)
|
||||
return FALSE;
|
||||
if (fchmod (temp_fd, 0644) < 0)
|
||||
if (G_IS_FILE_DESCRIPTOR_BASED (input))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input);
|
||||
if (glnx_regfile_copy_bytes (infd, temp_fd, (off_t)length, TRUE) < 0)
|
||||
return glnx_throw_errno_prefix (error, "regfile copy");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autoptr(GOutputStream) temp_out = g_unix_output_stream_new (temp_fd, FALSE);
|
||||
if (g_output_stream_splice (temp_out, input, 0,
|
||||
cancellable, error) < 0)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (fchmod (temp_fd, 0644) < 0)
|
||||
return glnx_throw_errno_prefix (error, "fchmod");
|
||||
|
||||
*out_fd = temp_fd; temp_fd = -1;
|
||||
*out_path = g_steal_pointer (&temp_filename);
|
||||
return TRUE;
|
||||
@@ -608,7 +602,8 @@ write_object (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *actual_checksum;
|
||||
const char *actual_checksum = NULL;
|
||||
g_autofree char *actual_checksum_owned = NULL;
|
||||
gboolean do_commit;
|
||||
OstreeRepoMode repo_mode;
|
||||
g_autofree char *temp_filename = NULL;
|
||||
@@ -773,7 +768,7 @@ write_object (OstreeRepo *self,
|
||||
actual_checksum = expected_checksum;
|
||||
else
|
||||
{
|
||||
actual_checksum = ot_checksum_instream_get_string (checksum_input);
|
||||
actual_checksum = actual_checksum_owned = ot_checksum_instream_get_string (checksum_input);
|
||||
if (expected_checksum && strcmp (actual_checksum, expected_checksum) != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
@@ -1306,7 +1301,7 @@ ensure_txn_refs (OstreeRepo *self)
|
||||
* ostree_repo_transaction_set_refspec:
|
||||
* @self: An #OstreeRepo
|
||||
* @refspec: The refspec to write
|
||||
* @checksum: The checksum to point it to
|
||||
* @checksum: (nullable): The checksum to point it to
|
||||
*
|
||||
* Like ostree_repo_transaction_set_ref(), but takes concatenated
|
||||
* @refspec format as input instead of separate remote and name
|
||||
@@ -1329,7 +1324,7 @@ ostree_repo_transaction_set_refspec (OstreeRepo *self,
|
||||
* @self: An #OstreeRepo
|
||||
* @remote: (allow-none): A remote for the ref
|
||||
* @ref: The ref to write
|
||||
* @checksum: The checksum to point it to
|
||||
* @checksum: (nullable): The checksum to point it to
|
||||
*
|
||||
* If @checksum is not %NULL, then record it as the target of ref named
|
||||
* @ref; if @remote is provided, the ref will appear to originate from that
|
||||
@@ -2014,13 +2009,13 @@ ostree_repo_read_commit_detached_metadata (OstreeRepo *self,
|
||||
!ot_util_variant_map_at (self->commit_stagedir_fd, buf,
|
||||
G_VARIANT_TYPE ("a{sv}"),
|
||||
OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error))
|
||||
return g_prefix_error (error, "Unable to read existing detached metadata: "), FALSE;
|
||||
return glnx_prefix_error (error, "Unable to read existing detached metadata");
|
||||
|
||||
if (ret_metadata == NULL &&
|
||||
!ot_util_variant_map_at (self->objects_dir_fd, buf,
|
||||
G_VARIANT_TYPE ("a{sv}"),
|
||||
OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error))
|
||||
return g_prefix_error (error, "Unable to read existing detached metadata: "), FALSE;
|
||||
return glnx_prefix_error (error, "Unable to read existing detached metadata");
|
||||
|
||||
if (ret_metadata == NULL && self->parent_repo)
|
||||
return ostree_repo_read_commit_detached_metadata (self->parent_repo,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "ostree-repo.h"
|
||||
#include "ostree-remote-private.h"
|
||||
#include "libglnx.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -43,6 +44,14 @@ G_BEGIN_DECLS
|
||||
* */
|
||||
#define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 16
|
||||
|
||||
/* Well-known keys for the additional metadata field in a summary file. */
|
||||
#define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified"
|
||||
#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires"
|
||||
|
||||
/* 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"
|
||||
|
||||
typedef enum {
|
||||
OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0)
|
||||
} OstreeRepoTestErrorFlags;
|
||||
@@ -78,7 +87,6 @@ struct OstreeRepo {
|
||||
|
||||
GFile *repodir;
|
||||
int repo_dir_fd;
|
||||
GFile *tmp_dir;
|
||||
int tmp_dir_fd;
|
||||
int cache_dir_fd;
|
||||
char *cache_dir;
|
||||
@@ -92,8 +100,9 @@ struct OstreeRepo {
|
||||
OstreeRepoTransactionStats txn_stats;
|
||||
|
||||
GMutex cache_lock;
|
||||
GPtrArray *cached_meta_indexes;
|
||||
GPtrArray *cached_content_indexes;
|
||||
guint dirmeta_cache_refcount;
|
||||
/* char * checksum → GVariant * for dirmeta objects, used in the checkout path */
|
||||
GHashTable *dirmeta_cache;
|
||||
|
||||
gboolean inited;
|
||||
gboolean writable;
|
||||
@@ -128,6 +137,24 @@ typedef struct {
|
||||
char checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
} OstreeDevIno;
|
||||
|
||||
/* A MemoryCacheRef is an in-memory cache of objects (currently just DIRMETA). This can
|
||||
* be used when performing an operation that traverses a repository in someway. Currently,
|
||||
* the primary use case is ostree_repo_checkout_at() avoiding lots of duplicate dirmeta
|
||||
* lookups.
|
||||
*/
|
||||
typedef struct {
|
||||
OstreeRepo *repo;
|
||||
} OstreeRepoMemoryCacheRef;
|
||||
|
||||
|
||||
void
|
||||
_ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state,
|
||||
OstreeRepo *repo);
|
||||
|
||||
void
|
||||
_ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state);
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy);
|
||||
|
||||
#define OSTREE_REPO_TMPDIR_STAGING "staging-"
|
||||
#define OSTREE_REPO_TMPDIR_FETCHER "fetcher-"
|
||||
|
||||
@@ -324,4 +351,16 @@ gboolean
|
||||
_ostree_repo_update_mtime (OstreeRepo *self,
|
||||
GError **error);
|
||||
|
||||
void
|
||||
_ostree_repo_add_remote (OstreeRepo *self,
|
||||
OstreeRemote *remote);
|
||||
OstreeRemote *
|
||||
_ostree_repo_get_remote (OstreeRepo *self,
|
||||
const char *name,
|
||||
GError **error);
|
||||
OstreeRemote *
|
||||
_ostree_repo_get_remote_inherited (OstreeRepo *self,
|
||||
const char *name,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -42,21 +42,14 @@ prune_commitpartial_file (OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *path = _ostree_get_commitpartial_path (checksum);
|
||||
|
||||
if (unlinkat (repo->repo_dir_fd, path, 0) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "unlinkat");
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -67,7 +60,6 @@ maybe_prune_loose_object (OtPruneData *data,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GVariant) key = NULL;
|
||||
|
||||
key = ostree_object_name_serialize (checksum, objtype);
|
||||
@@ -83,16 +75,16 @@ maybe_prune_loose_object (OtPruneData *data,
|
||||
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
|
||||
{
|
||||
if (!prune_commitpartial_file (data->repo, checksum, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum,
|
||||
&storage_size, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_repo_delete_object (data->repo, objtype, checksum,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
data->freed_bytes += storage_size;
|
||||
}
|
||||
@@ -111,9 +103,7 @@ maybe_prune_loose_object (OtPruneData *data,
|
||||
data->n_reachable_content++;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -121,25 +111,17 @@ _ostree_repo_prune_tmp (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
glnx_fd_close int fd = -1;
|
||||
|
||||
if (self->cache_dir_fd == -1)
|
||||
return TRUE;
|
||||
|
||||
fd = glnx_opendirat_with_errno (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, FALSE);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
ret = TRUE;
|
||||
else
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!glnx_dirfd_iterator_init_take_fd (dup (fd), &dfd_iter, error))
|
||||
goto out;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
gboolean exists;
|
||||
if (!ot_dfd_iter_init_allow_noent (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR,
|
||||
&dfd_iter, &exists, error))
|
||||
return FALSE;
|
||||
/* Note early return */
|
||||
if (!exists)
|
||||
return TRUE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
@@ -148,8 +130,7 @@ _ostree_repo_prune_tmp (OstreeRepo *self,
|
||||
struct dirent *dent;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
|
||||
goto out;
|
||||
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
@@ -166,18 +147,12 @@ _ostree_repo_prune_tmp (OstreeRepo *self,
|
||||
if (has_sig_suffix)
|
||||
dent->d_name[len - 4] = '.';
|
||||
|
||||
if (unlinkat (fd, dent->d_name, 0) < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
if (unlinkat (dfd_iter.fd, dent->d_name, 0) < 0)
|
||||
return glnx_throw_errno_prefix (error, "unlinkat");
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
@@ -198,22 +173,17 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GPtrArray) deltas = NULL;
|
||||
guint i;
|
||||
|
||||
if (!ostree_repo_list_static_delta_names (self, &deltas,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < deltas->len; i++)
|
||||
for (guint i = 0; i < deltas->len; i++)
|
||||
{
|
||||
const char *deltaname = deltas->pdata[i];
|
||||
const char *dash = strchr (deltaname, '-');
|
||||
const char *to = NULL;
|
||||
gboolean have_commit;
|
||||
g_autofree char *from = NULL;
|
||||
g_autofree char *deltadir = NULL;
|
||||
|
||||
if (!dash)
|
||||
{
|
||||
@@ -232,26 +202,24 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean have_commit;
|
||||
if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_COMMIT,
|
||||
to, &have_commit,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (have_commit)
|
||||
continue;
|
||||
}
|
||||
|
||||
g_debug ("Trying to prune static delta %s", deltaname);
|
||||
deltadir = _ostree_get_relative_static_delta_path (from, to, NULL);
|
||||
|
||||
g_autofree char *deltadir = _ostree_get_relative_static_delta_path (from, to, NULL);
|
||||
if (!glnx_shutil_rm_rf_at (self->repo_dir_fd, deltadir,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -264,13 +232,14 @@ repo_prune_internal (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GHashTableIter hash_iter;
|
||||
gpointer key, value;
|
||||
OtPruneData data = { 0, };
|
||||
|
||||
data.repo = self;
|
||||
data.reachable = g_hash_table_ref (options->reachable);
|
||||
/* We unref this when we're done */
|
||||
g_autoptr(GHashTable) reachable_owned = g_hash_table_ref (options->reachable);
|
||||
data.reachable = reachable_owned;
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, objects);
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
@@ -289,24 +258,20 @@ repo_prune_internal (OstreeRepo *self,
|
||||
|
||||
if (!maybe_prune_loose_object (&data, options->flags, checksum, objtype,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ostree_repo_prune_static_deltas (self, NULL, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!_ostree_repo_prune_tmp (self, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
*out_objects_total = (data.n_reachable_meta + data.n_unreachable_meta +
|
||||
data.n_reachable_content + data.n_unreachable_content);
|
||||
*out_objects_pruned = (data.n_unreachable_meta + data.n_unreachable_content);
|
||||
*out_pruned_object_size_total = data.freed_bytes;
|
||||
out:
|
||||
if (data.reachable)
|
||||
g_hash_table_unref (data.reachable);
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+233
-204
@@ -68,6 +68,7 @@ typedef struct {
|
||||
|
||||
gboolean gpg_verify;
|
||||
gboolean require_static_deltas;
|
||||
gboolean disable_static_deltas;
|
||||
gboolean gpg_verify_summary;
|
||||
gboolean has_tombstone_commits;
|
||||
|
||||
@@ -210,38 +211,38 @@ update_progress (gpointer user_data)
|
||||
n_scanned_metadata = pull_data->n_scanned_metadata;
|
||||
start_time = pull_data->start_time;
|
||||
|
||||
ostree_async_progress_set_uint (pull_data->progress, "outstanding-fetches", outstanding_fetches);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "outstanding-writes", outstanding_writes);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "fetched", fetched);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "requested", requested);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "scanning", g_queue_is_empty (&pull_data->scan_object_queue) ? 0 : 1);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "scanned-metadata", n_scanned_metadata);
|
||||
ostree_async_progress_set_uint64 (pull_data->progress, "bytes-transferred", bytes_transferred);
|
||||
ostree_async_progress_set_uint64 (pull_data->progress, "start-time", start_time);
|
||||
|
||||
/* Deltas */
|
||||
ostree_async_progress_set_uint (pull_data->progress, "fetched-delta-parts",
|
||||
pull_data->n_fetched_deltaparts);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "total-delta-parts",
|
||||
pull_data->n_total_deltaparts);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "fetched-delta-fallbacks",
|
||||
pull_data->n_fetched_deltapart_fallbacks);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "total-delta-fallbacks",
|
||||
pull_data->n_total_delta_fallbacks);
|
||||
ostree_async_progress_set_uint64 (pull_data->progress, "fetched-delta-part-size",
|
||||
pull_data->fetched_deltapart_size);
|
||||
ostree_async_progress_set_uint64 (pull_data->progress, "total-delta-part-size",
|
||||
pull_data->total_deltapart_size);
|
||||
ostree_async_progress_set_uint64 (pull_data->progress, "total-delta-part-usize",
|
||||
pull_data->total_deltapart_usize);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "total-delta-superblocks",
|
||||
pull_data->static_delta_superblocks->len);
|
||||
|
||||
/* We fetch metadata before content. These allow us to report metadata fetch progress specifically. */
|
||||
ostree_async_progress_set_uint (pull_data->progress, "outstanding-metadata-fetches", pull_data->n_outstanding_metadata_fetches);
|
||||
ostree_async_progress_set_uint (pull_data->progress, "metadata-fetched", pull_data->n_fetched_metadata);
|
||||
|
||||
ostree_async_progress_set_status (pull_data->progress, NULL);
|
||||
ostree_async_progress_set (pull_data->progress,
|
||||
"outstanding-fetches", "u", outstanding_fetches,
|
||||
"outstanding-writes", "u", outstanding_writes,
|
||||
"fetched", "u", fetched,
|
||||
"requested", "u", requested,
|
||||
"scanning", "u", g_queue_is_empty (&pull_data->scan_object_queue) ? 0 : 1,
|
||||
"scanned-metadata", "u", n_scanned_metadata,
|
||||
"bytes-transferred", "t", bytes_transferred,
|
||||
"start-time", "t", start_time,
|
||||
/* Deltas */
|
||||
"fetched-delta-parts",
|
||||
"u", pull_data->n_fetched_deltaparts,
|
||||
"total-delta-parts",
|
||||
"u", pull_data->n_total_deltaparts,
|
||||
"fetched-delta-fallbacks",
|
||||
"u", pull_data->n_fetched_deltapart_fallbacks,
|
||||
"total-delta-fallbacks",
|
||||
"u", pull_data->n_total_delta_fallbacks,
|
||||
"fetched-delta-part-size",
|
||||
"t", pull_data->fetched_deltapart_size,
|
||||
"total-delta-part-size",
|
||||
"t", pull_data->total_deltapart_size,
|
||||
"total-delta-part-usize",
|
||||
"t", pull_data->total_deltapart_usize,
|
||||
"total-delta-superblocks",
|
||||
"u", pull_data->static_delta_superblocks->len,
|
||||
/* We fetch metadata before content. These allow us to report metadata fetch progress specifically. */
|
||||
"outstanding-metadata-fetches", "u", pull_data->n_outstanding_metadata_fetches,
|
||||
"metadata-fetched", "u", pull_data->n_fetched_metadata,
|
||||
/* Overall status. */
|
||||
"status", "s", "",
|
||||
NULL);
|
||||
|
||||
if (pull_data->dry_run)
|
||||
pull_data->dry_run_emitted_progress = TRUE;
|
||||
@@ -436,32 +437,22 @@ fetch_mirrored_uri_contents_utf8_sync (OstreeFetcher *fetcher,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GBytes) bytes = NULL;
|
||||
g_autofree char *ret_contents = NULL;
|
||||
gsize len;
|
||||
|
||||
if (!_ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist,
|
||||
filename, TRUE, FALSE,
|
||||
&bytes,
|
||||
OSTREE_MAX_METADATA_SIZE,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret_contents = g_bytes_unref_to_data (bytes, &len);
|
||||
bytes = NULL;
|
||||
gsize len;
|
||||
g_autofree char *ret_contents = g_bytes_unref_to_data (g_steal_pointer (&bytes), &len);
|
||||
|
||||
if (!g_utf8_validate (ret_contents, -1, NULL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid UTF-8");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid UTF-8");
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value (out_contents, &ret_contents);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -484,16 +475,11 @@ write_commitpartial_for (OtPullData *pull_data,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum);
|
||||
glnx_fd_close int fd = -1;
|
||||
|
||||
fd = openat (pull_data->repo->repo_dir_fd, commitpartial_path, O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644);
|
||||
glnx_fd_close int fd = openat (pull_data->repo->repo_dir_fd, commitpartial_path, O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644);
|
||||
if (fd == -1)
|
||||
{
|
||||
if (errno != EEXIST)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "open(%s)", commitpartial_path);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
@@ -554,15 +540,12 @@ pull_matches_subdir (OtPullData *pull_data,
|
||||
const char *basename,
|
||||
gboolean basename_is_dir)
|
||||
{
|
||||
int i;
|
||||
g_autofree char *file = NULL;
|
||||
|
||||
if (pull_data->dirs == NULL)
|
||||
return TRUE;
|
||||
|
||||
file = g_strconcat (path, basename, NULL);
|
||||
g_autofree char *file = g_strconcat (path, basename, NULL);
|
||||
|
||||
for (i = 0; i < pull_data->dirs->len; i++)
|
||||
for (guint i = 0; i < pull_data->dirs->len; i++)
|
||||
{
|
||||
const char *pull_dir = g_ptr_array_index (pull_data->dirs, i);
|
||||
if (matches_pull_dir (file, pull_dir, basename_is_dir))
|
||||
@@ -580,30 +563,18 @@ scan_dirtree_object (OtPullData *pull_data,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int i, n;
|
||||
g_autoptr(GVariant) tree = NULL;
|
||||
g_autoptr(GVariant) files_variant = NULL;
|
||||
g_autoptr(GVariant) dirs_variant = NULL;
|
||||
const char *dirname = NULL;
|
||||
|
||||
if (recursion_depth > OSTREE_MAX_RECURSION)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Exceeded maximum recursion");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Exceeded maximum recursion");
|
||||
|
||||
g_autoptr(GVariant) tree = NULL;
|
||||
if (!ostree_repo_load_variant (pull_data->repo, OSTREE_OBJECT_TYPE_DIR_TREE, checksum,
|
||||
&tree, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
/* PARSE OSTREE_SERIALIZED_TREE_VARIANT */
|
||||
files_variant = g_variant_get_child_value (tree, 0);
|
||||
dirs_variant = g_variant_get_child_value (tree, 1);
|
||||
|
||||
n = g_variant_n_children (files_variant);
|
||||
for (i = 0; i < n; i++)
|
||||
g_autoptr(GVariant) files_variant = g_variant_get_child_value (tree, 0);
|
||||
const guint n = g_variant_n_children (files_variant);
|
||||
for (guint i = 0; i < n; i++)
|
||||
{
|
||||
const char *filename;
|
||||
gboolean file_is_stored;
|
||||
@@ -613,7 +584,7 @@ scan_dirtree_object (OtPullData *pull_data,
|
||||
g_variant_get_child (files_variant, i, "(&s@ay)", &filename, &csum);
|
||||
|
||||
if (!ot_util_filename_validate (filename, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
/* Skip files if we're traversing a request only directory, unless it exactly
|
||||
* matches the path */
|
||||
@@ -624,14 +595,14 @@ scan_dirtree_object (OtPullData *pull_data,
|
||||
|
||||
if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, file_checksum,
|
||||
&file_is_stored, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!file_is_stored && pull_data->remote_repo_local)
|
||||
{
|
||||
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, pull_data->remote_repo_local,
|
||||
OSTREE_OBJECT_TYPE_FILE, file_checksum, !pull_data->is_untrusted,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
else if (!file_is_stored && !g_hash_table_lookup (pull_data->requested_content, file_checksum))
|
||||
{
|
||||
@@ -641,44 +612,38 @@ scan_dirtree_object (OtPullData *pull_data,
|
||||
}
|
||||
}
|
||||
|
||||
n = g_variant_n_children (dirs_variant);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
g_autoptr(GVariant) dirs_variant = g_variant_get_child_value (tree, 1);
|
||||
const guint m = g_variant_n_children (dirs_variant);
|
||||
for (guint i = 0; i < m; i++)
|
||||
{
|
||||
const char *dirname = NULL;
|
||||
g_autoptr(GVariant) tree_csum = NULL;
|
||||
g_autoptr(GVariant) meta_csum = NULL;
|
||||
const guchar *tree_csum_bytes;
|
||||
const guchar *meta_csum_bytes;
|
||||
g_autofree char *subpath = NULL;
|
||||
|
||||
g_variant_get_child (dirs_variant, i, "(&s@ay@ay)",
|
||||
&dirname, &tree_csum, &meta_csum);
|
||||
|
||||
if (!ot_util_filename_validate (dirname, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!pull_matches_subdir (pull_data, path, dirname, TRUE))
|
||||
continue;
|
||||
|
||||
tree_csum_bytes = ostree_checksum_bytes_peek_validate (tree_csum, error);
|
||||
const guchar *tree_csum_bytes = ostree_checksum_bytes_peek_validate (tree_csum, error);
|
||||
if (tree_csum_bytes == NULL)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
meta_csum_bytes = ostree_checksum_bytes_peek_validate (meta_csum, error);
|
||||
const guchar *meta_csum_bytes = ostree_checksum_bytes_peek_validate (meta_csum, error);
|
||||
if (meta_csum_bytes == NULL)
|
||||
goto out;
|
||||
|
||||
subpath = g_strconcat (path, dirname, "/", NULL);
|
||||
return FALSE;
|
||||
|
||||
g_autofree char *subpath = g_strconcat (path, dirname, "/", NULL);
|
||||
queue_scan_one_metadata_object_c (pull_data, tree_csum_bytes,
|
||||
OSTREE_OBJECT_TYPE_DIR_TREE, subpath, recursion_depth + 1);
|
||||
queue_scan_one_metadata_object_c (pull_data, meta_csum_bytes,
|
||||
OSTREE_OBJECT_TYPE_DIR_META, subpath, recursion_depth + 1);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -688,27 +653,21 @@ fetch_ref_contents (OtPullData *pull_data,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *filename = g_build_filename ("refs", "heads", ref, NULL);
|
||||
g_autofree char *ret_contents = NULL;
|
||||
g_autofree char *filename = NULL;
|
||||
|
||||
filename = g_build_filename ("refs", "heads", ref, NULL);
|
||||
|
||||
if (!fetch_mirrored_uri_contents_utf8_sync (pull_data->fetcher,
|
||||
pull_data->meta_mirrorlist,
|
||||
filename, &ret_contents,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_strchomp (ret_contents);
|
||||
|
||||
if (!ostree_validate_checksum_string (ret_contents, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value (out_contents, &ret_contents);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -718,34 +677,23 @@ lookup_commit_checksum_from_summary (OtPullData *pull_data,
|
||||
gsize *out_size,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GVariant) refs = g_variant_get_child_value (pull_data->summary, 0);
|
||||
g_autoptr(GVariant) refdata = NULL;
|
||||
g_autoptr(GVariant) reftargetdata = NULL;
|
||||
int i;
|
||||
if (!ot_variant_bsearch_str (refs, ref, &i))
|
||||
return glnx_throw (error, "No such branch '%s' in repository summary", ref);
|
||||
|
||||
g_autoptr(GVariant) refdata = g_variant_get_child_value (refs, i);
|
||||
g_autoptr(GVariant) reftargetdata = g_variant_get_child_value (refdata, 1);
|
||||
guint64 commit_size;
|
||||
g_autoptr(GVariant) commit_csum_v = NULL;
|
||||
int i;
|
||||
|
||||
if (!ot_variant_bsearch_str (refs, ref, &i))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No such branch '%s' in repository summary",
|
||||
ref);
|
||||
goto out;
|
||||
}
|
||||
|
||||
refdata = g_variant_get_child_value (refs, i);
|
||||
reftargetdata = g_variant_get_child_value (refdata, 1);
|
||||
g_variant_get (reftargetdata, "(t@ay@a{sv})", &commit_size, &commit_csum_v, NULL);
|
||||
|
||||
if (!ostree_validate_structureof_csum_v (commit_csum_v, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
*out_checksum = ostree_checksum_from_bytes_v (commit_csum_v);
|
||||
*out_size = commit_size;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -771,7 +719,7 @@ content_fetch_on_write_complete (GObject *object,
|
||||
g_autofree char *checksum = NULL;
|
||||
g_autofree char *checksum_obj = NULL;
|
||||
|
||||
if (!ostree_repo_write_content_finish ((OstreeRepo*)object, result,
|
||||
if (!ostree_repo_write_content_finish ((OstreeRepo*)object, result,
|
||||
&csum, error))
|
||||
goto out;
|
||||
|
||||
@@ -1879,10 +1827,15 @@ process_one_static_delta (OtPullData *pull_data,
|
||||
/* Loop over the static delta data we got from the summary,
|
||||
* and find the newest commit for @out_from_revision that
|
||||
* goes to @to_revision.
|
||||
*
|
||||
* Additionally, @out_have_scratch_delta will be set to %TRUE
|
||||
* if there is a %NULL → @to_revision delta, also known as
|
||||
* a "from scratch" delta.
|
||||
*/
|
||||
static gboolean
|
||||
get_best_static_delta_start_for (OtPullData *pull_data,
|
||||
const char *to_revision,
|
||||
gboolean *out_have_scratch_delta,
|
||||
char **out_from_revision,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
@@ -1897,6 +1850,8 @@ get_best_static_delta_start_for (OtPullData *pull_data,
|
||||
g_assert (pull_data->summary_deltas_checksums != NULL);
|
||||
g_hash_table_iter_init (&hiter, pull_data->summary_deltas_checksums);
|
||||
|
||||
*out_have_scratch_delta = FALSE;
|
||||
|
||||
/* Loop over all deltas known from the summary file,
|
||||
* finding ones which go to to_revision */
|
||||
while (g_hash_table_iter_next (&hiter, &hkey, &hvalue))
|
||||
@@ -1915,6 +1870,8 @@ get_best_static_delta_start_for (OtPullData *pull_data,
|
||||
|
||||
if (cur_from_rev)
|
||||
g_ptr_array_add (candidates, g_steal_pointer (&cur_from_rev));
|
||||
else
|
||||
*out_have_scratch_delta = TRUE;
|
||||
}
|
||||
|
||||
/* Loop over our candidates, find the newest one */
|
||||
@@ -1963,6 +1920,16 @@ typedef struct {
|
||||
char *to_revision;
|
||||
} FetchDeltaSuperData;
|
||||
|
||||
static void
|
||||
set_required_deltas_error (GError **error,
|
||||
const char *from_revision,
|
||||
const char *to_revision)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Static deltas required, but none found for %s to %s",
|
||||
from_revision, to_revision);
|
||||
}
|
||||
|
||||
static void
|
||||
on_superblock_fetched (GObject *src,
|
||||
GAsyncResult *res,
|
||||
@@ -1984,14 +1951,11 @@ on_superblock_fetched (GObject *src,
|
||||
{
|
||||
if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
goto out;
|
||||
|
||||
g_clear_error (&local_error);
|
||||
|
||||
if (pull_data->require_static_deltas)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Static deltas required, but none found for %s to %s",
|
||||
from_revision, to_revision);
|
||||
set_required_deltas_error (error, from_revision, to_revision);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -2442,11 +2406,15 @@ repo_remote_fetch_summary (OstreeRepo *self,
|
||||
g_autoptr(GMainContext) mainctx = NULL;
|
||||
gboolean ret = FALSE;
|
||||
gboolean from_cache = FALSE;
|
||||
g_autofree char *url_override = NULL;
|
||||
const char *url_override = NULL;
|
||||
g_autoptr(GVariant) extra_headers = NULL;
|
||||
g_autoptr(GPtrArray) mirrorlist = NULL;
|
||||
|
||||
if (options)
|
||||
(void) g_variant_lookup (options, "override-url", "&s", &url_override);
|
||||
{
|
||||
(void) g_variant_lookup (options, "override-url", "&s", &url_override);
|
||||
(void) g_variant_lookup (options, "http-headers", "@a(ss)", &extra_headers);
|
||||
}
|
||||
|
||||
mainctx = g_main_context_new ();
|
||||
g_main_context_push_thread_default (mainctx);
|
||||
@@ -2455,6 +2423,9 @@ repo_remote_fetch_summary (OstreeRepo *self,
|
||||
if (fetcher == NULL)
|
||||
goto out;
|
||||
|
||||
if (extra_headers)
|
||||
_ostree_fetcher_set_extra_headers (fetcher, extra_headers);
|
||||
|
||||
{
|
||||
g_autofree char *url_string = NULL;
|
||||
if (metalink_url_string)
|
||||
@@ -2566,6 +2537,117 @@ reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **e
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Start a request for a static delta */
|
||||
static void
|
||||
initiate_delta_request (OtPullData *pull_data,
|
||||
const char *from_revision,
|
||||
const char *to_revision)
|
||||
{
|
||||
g_autofree char *delta_name =
|
||||
_ostree_get_relative_static_delta_superblock_path (from_revision, to_revision);
|
||||
FetchDeltaSuperData *fdata = g_new0(FetchDeltaSuperData, 1);
|
||||
fdata->pull_data = pull_data;
|
||||
fdata->from_revision = g_strdup (from_revision);
|
||||
fdata->to_revision = g_strdup (to_revision);
|
||||
|
||||
_ostree_fetcher_request_to_membuf (pull_data->fetcher,
|
||||
pull_data->content_mirrorlist,
|
||||
delta_name, 0,
|
||||
OSTREE_MAX_METADATA_SIZE,
|
||||
0, pull_data->cancellable,
|
||||
on_superblock_fetched, fdata);
|
||||
pull_data->n_outstanding_metadata_fetches++;
|
||||
pull_data->n_requested_metadata++;
|
||||
}
|
||||
|
||||
/* @ref - Optional ref name
|
||||
* @to_revision: Target commit revision we want to fetch
|
||||
*
|
||||
* Start a request for either a ref or a commit. In the
|
||||
* ref case, we know both the name and the target commit.
|
||||
*
|
||||
* This function primarily handles the semantics around
|
||||
* `disable_static_deltas` and `require_static_deltas`.
|
||||
*/
|
||||
static gboolean
|
||||
initiate_request (OtPullData *pull_data,
|
||||
const char *ref,
|
||||
const char *to_revision,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *delta_from_revision = NULL;
|
||||
|
||||
/* Are deltas disabled? OK, just start an object fetch and be done */
|
||||
if (pull_data->disable_static_deltas)
|
||||
{
|
||||
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* If we have a summary, we can use the newer logic */
|
||||
if (pull_data->summary)
|
||||
{
|
||||
gboolean have_scratch_delta = FALSE;
|
||||
|
||||
/* Look for a delta to @to_revision in the summary data */
|
||||
if (!get_best_static_delta_start_for (pull_data, to_revision,
|
||||
&have_scratch_delta, &delta_from_revision,
|
||||
pull_data->cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (delta_from_revision) /* Did we find a delta FROM commit? */
|
||||
initiate_delta_request (pull_data, delta_from_revision, to_revision);
|
||||
else if (have_scratch_delta) /* No delta FROM, do we have a scratch? */
|
||||
initiate_delta_request (pull_data, NULL, to_revision);
|
||||
else if (pull_data->require_static_deltas) /* No deltas found; are they required? */
|
||||
{
|
||||
set_required_deltas_error (error, ref, to_revision);
|
||||
return FALSE;
|
||||
}
|
||||
else /* No deltas, fall back to object fetches. */
|
||||
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
|
||||
}
|
||||
else if (ref != NULL)
|
||||
{
|
||||
/* Are we doing a delta via a ref? In that case we can fall back to the older
|
||||
* logic of just using the current tip of the ref as a delta FROM source. */
|
||||
if (!ostree_repo_resolve_rev (pull_data->repo, ref, TRUE,
|
||||
&delta_from_revision, error))
|
||||
return FALSE;
|
||||
|
||||
/* Determine whether the from revision we have is partial; this
|
||||
* can happen if e.g. one uses `ostree pull --commit-metadata-only`.
|
||||
* This mirrors the logic in get_best_static_delta_start_for().
|
||||
*/
|
||||
if (delta_from_revision)
|
||||
{
|
||||
OstreeRepoCommitState from_commitstate;
|
||||
|
||||
if (!ostree_repo_load_commit (pull_data->repo, delta_from_revision, NULL,
|
||||
&from_commitstate, error))
|
||||
return FALSE;
|
||||
|
||||
/* Was it partial? Then we can't use it. */
|
||||
if (commitstate_is_partial (pull_data, from_commitstate))
|
||||
g_clear_pointer (&delta_from_revision, g_free);
|
||||
}
|
||||
|
||||
/* This is similar to the below, except we *might* use the previous
|
||||
* commit, or we might do a scratch delta first.
|
||||
*/
|
||||
initiate_delta_request (pull_data, delta_from_revision ?: NULL, to_revision);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Legacy path without a summary file - let's try a scratch delta, if that
|
||||
* doesn't work, it'll drop down to object requests.
|
||||
*/
|
||||
initiate_delta_request (pull_data, NULL, to_revision);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------------------
|
||||
* Below is the libsoup-invariant API; these should match
|
||||
* the stub functions in the #else clause
|
||||
@@ -2597,7 +2679,7 @@ reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **e
|
||||
* * override-commit-ids (as): Array of specific commit IDs to fetch for refs
|
||||
* * dry-run (b): Only print information on what will be downloaded (requires static deltas)
|
||||
* * override-url (s): Fetch objects from this URL if remote specifies no metalink in options
|
||||
* * inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do mutliple pulls in one transaction.
|
||||
* * inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do multiple pulls in one transaction.
|
||||
* * 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
|
||||
*/
|
||||
@@ -2631,7 +2713,6 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
g_autofree char **refs_to_fetch = NULL;
|
||||
g_autofree char **override_commit_ids = NULL;
|
||||
GSource *update_timeout = NULL;
|
||||
gboolean disable_static_deltas = FALSE;
|
||||
gboolean opt_gpg_verify_set = FALSE;
|
||||
gboolean opt_gpg_verify_summary_set = FALSE;
|
||||
const char *url_override = NULL;
|
||||
@@ -2653,7 +2734,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
opt_gpg_verify_summary_set =
|
||||
g_variant_lookup (options, "gpg-verify-summary", "b", &pull_data->gpg_verify_summary);
|
||||
(void) g_variant_lookup (options, "depth", "i", &pull_data->maxdepth);
|
||||
(void) g_variant_lookup (options, "disable-static-deltas", "b", &disable_static_deltas);
|
||||
(void) g_variant_lookup (options, "disable-static-deltas", "b", &pull_data->disable_static_deltas);
|
||||
(void) g_variant_lookup (options, "require-static-deltas", "b", &pull_data->require_static_deltas);
|
||||
(void) g_variant_lookup (options, "override-commit-ids", "^a&s", &override_commit_ids);
|
||||
(void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run);
|
||||
@@ -2673,7 +2754,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
for (i = 0; dirs_to_pull != NULL && dirs_to_pull[i] != NULL; i++)
|
||||
g_return_val_if_fail (dirs_to_pull[i][0] == '/', FALSE);
|
||||
|
||||
g_return_val_if_fail (!(disable_static_deltas && pull_data->require_static_deltas), FALSE);
|
||||
g_return_val_if_fail (!(pull_data->disable_static_deltas && pull_data->require_static_deltas), FALSE);
|
||||
|
||||
/* We only do dry runs with static deltas, because we don't really have any
|
||||
* in-advance information for bare fetches.
|
||||
@@ -2952,7 +3033,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
* exact object files are copied.
|
||||
*/
|
||||
if (pull_data->remote_repo_local && !pull_data->require_static_deltas)
|
||||
disable_static_deltas = TRUE;
|
||||
pull_data->disable_static_deltas = TRUE;
|
||||
|
||||
/* We can't use static deltas if pulling into an archive-z2 repo. */
|
||||
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
|
||||
@@ -2963,13 +3044,13 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
"Can't use static deltas in an archive repo");
|
||||
goto out;
|
||||
}
|
||||
disable_static_deltas = TRUE;
|
||||
pull_data->disable_static_deltas = TRUE;
|
||||
}
|
||||
|
||||
/* It's not efficient to use static deltas if all we want is the commit
|
||||
* metadata. */
|
||||
if (pull_data->is_commit_only)
|
||||
disable_static_deltas = TRUE;
|
||||
pull_data->disable_static_deltas = TRUE;
|
||||
|
||||
pull_data->static_delta_superblocks = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
|
||||
|
||||
@@ -3239,78 +3320,23 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
if (pull_data->legacy_transaction_resuming)
|
||||
g_debug ("resuming legacy transaction");
|
||||
|
||||
/* Initiate requests for explicit commit revisions */
|
||||
g_hash_table_iter_init (&hash_iter, commits_to_fetch);
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
const char *commit = value;
|
||||
queue_scan_one_metadata_object (pull_data, commit, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
|
||||
if (!initiate_request (pull_data, NULL, commit, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Initiate requests for refs */
|
||||
g_hash_table_iter_init (&hash_iter, requested_refs_to_fetch);
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
g_autofree char *from_revision = NULL;
|
||||
const char *ref = key;
|
||||
const char *to_revision = value;
|
||||
gboolean have_valid_from_commit = TRUE;
|
||||
|
||||
/* If we have a summary, find the latest local commit we have
|
||||
* to use as a from revision for static deltas.
|
||||
*/
|
||||
if (pull_data->summary)
|
||||
{
|
||||
if (!get_best_static_delta_start_for (pull_data, to_revision, &from_revision,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ostree_repo_resolve_rev (pull_data->repo, ref, TRUE,
|
||||
&from_revision, error))
|
||||
goto out;
|
||||
|
||||
/* Determine whether the from revision we have is partial; this
|
||||
* can happen if e.g. one uses `ostree pull --commit-metadata-only`.
|
||||
* This mirrors the logic in get_best_static_delta_start_for().
|
||||
*/
|
||||
if (from_revision)
|
||||
{
|
||||
OstreeRepoCommitState from_commitstate;
|
||||
|
||||
if (!ostree_repo_load_commit (pull_data->repo, from_revision, NULL,
|
||||
&from_commitstate, error))
|
||||
goto out;
|
||||
|
||||
/* Was it partial? OK, we can't use it. */
|
||||
if (commitstate_is_partial (pull_data, from_commitstate))
|
||||
have_valid_from_commit = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!disable_static_deltas &&
|
||||
have_valid_from_commit &&
|
||||
(from_revision == NULL || g_strcmp0 (from_revision, to_revision) != 0))
|
||||
{
|
||||
g_autofree char *delta_name =
|
||||
_ostree_get_relative_static_delta_superblock_path (from_revision, to_revision);
|
||||
FetchDeltaSuperData *fdata = g_new0(FetchDeltaSuperData, 1);
|
||||
fdata->pull_data = pull_data;
|
||||
fdata->from_revision = g_strdup (from_revision);
|
||||
fdata->to_revision = g_strdup (to_revision);
|
||||
|
||||
_ostree_fetcher_request_to_membuf (pull_data->fetcher,
|
||||
pull_data->content_mirrorlist,
|
||||
delta_name, 0,
|
||||
OSTREE_MAX_METADATA_SIZE,
|
||||
0, pull_data->cancellable,
|
||||
on_superblock_fetched, fdata);
|
||||
pull_data->n_outstanding_metadata_fetches++;
|
||||
pull_data->n_requested_metadata++;
|
||||
}
|
||||
else
|
||||
{
|
||||
queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0);
|
||||
}
|
||||
if (!initiate_request (pull_data, ref, to_revision, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pull_data->progress)
|
||||
@@ -3402,8 +3428,11 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
bytes_transferred = _ostree_fetcher_bytes_transferred (pull_data->fetcher);
|
||||
if (bytes_transferred > 0 && pull_data->progress)
|
||||
{
|
||||
guint shift;
|
||||
GString *buf = g_string_new ("");
|
||||
guint shift;
|
||||
g_autoptr(GString) buf = g_string_new ("");
|
||||
|
||||
/* Ensure the rest of the progress keys are set appropriately. */
|
||||
update_progress (pull_data);
|
||||
|
||||
if (bytes_transferred < 1024)
|
||||
shift = 1;
|
||||
@@ -3424,7 +3453,6 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
(guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC));
|
||||
|
||||
ostree_async_progress_set_status (pull_data->progress, buf->str);
|
||||
g_string_free (buf, TRUE);
|
||||
}
|
||||
|
||||
/* iterate over commits fetched and delete any commitpartial files */
|
||||
@@ -3510,6 +3538,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
* The following are currently defined:
|
||||
*
|
||||
* - 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
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE on failure
|
||||
*/
|
||||
|
||||
@@ -73,99 +73,89 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GPtrArray) ret_deltas = NULL;
|
||||
glnx_fd_close int dfd = -1;
|
||||
g_autoptr(GPtrArray) ret_deltas = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
ret_deltas = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
dfd = glnx_opendirat_with_errno (self->repo_dir_fd, "deltas", TRUE);
|
||||
if (dfd < 0)
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
gboolean exists;
|
||||
if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, "deltas", &dfd_iter,
|
||||
&exists, error))
|
||||
return FALSE;
|
||||
if (!exists)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
/* Note early return */
|
||||
ot_transfer_out_value (out_deltas, &ret_deltas);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
|
||||
if (!glnx_dirfd_iterator_init_take_fd (dfd, &dfd_iter, error))
|
||||
while (TRUE)
|
||||
{
|
||||
g_auto(GLnxDirFdIterator) sub_dfd_iter = { 0, };
|
||||
struct dirent *dent;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE,
|
||||
&sub_dfd_iter, error))
|
||||
return FALSE;
|
||||
dfd = -1;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
g_auto(GLnxDirFdIterator) sub_dfd_iter = { 0, };
|
||||
struct dirent *dent;
|
||||
struct dirent *sub_dent;
|
||||
const char *name1;
|
||||
const char *name2;
|
||||
g_autofree char *superblock_subpath = NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
if (sub_dent == NULL)
|
||||
break;
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE,
|
||||
&sub_dfd_iter, error))
|
||||
return FALSE;
|
||||
name1 = dent->d_name;
|
||||
name2 = sub_dent->d_name;
|
||||
|
||||
while (TRUE)
|
||||
superblock_subpath = g_strconcat (name2, "/superblock", NULL);
|
||||
if (fstatat (sub_dfd_iter.fd, superblock_subpath, &stbuf, 0) < 0)
|
||||
{
|
||||
struct dirent *sub_dent;
|
||||
const char *name1;
|
||||
const char *name2;
|
||||
g_autofree char *superblock_subpath = NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
if (sub_dent == NULL)
|
||||
break;
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
name1 = dent->d_name;
|
||||
name2 = sub_dent->d_name;
|
||||
|
||||
superblock_subpath = g_strconcat (name2, "/superblock", NULL);
|
||||
if (fstatat (sub_dfd_iter.fd, superblock_subpath, &stbuf, 0) < 0)
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree char *buf = g_strconcat (name1, name2, NULL);
|
||||
GString *out = g_string_new ("");
|
||||
char checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
guchar csum[OSTREE_SHA256_DIGEST_LEN];
|
||||
const char *dash = strchr (buf, '-');
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree char *buf = g_strconcat (name1, name2, NULL);
|
||||
GString *out = g_string_new ("");
|
||||
char checksum[OSTREE_SHA256_STRING_LEN+1];
|
||||
guchar csum[OSTREE_SHA256_DIGEST_LEN];
|
||||
const char *dash = strchr (buf, '-');
|
||||
|
||||
ostree_checksum_b64_inplace_to_bytes (buf, csum);
|
||||
ostree_checksum_b64_inplace_to_bytes (buf, csum);
|
||||
ostree_checksum_inplace_from_bytes (csum, checksum);
|
||||
g_string_append (out, checksum);
|
||||
if (dash)
|
||||
{
|
||||
g_string_append_c (out, '-');
|
||||
ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
|
||||
ostree_checksum_inplace_from_bytes (csum, checksum);
|
||||
g_string_append (out, checksum);
|
||||
if (dash)
|
||||
{
|
||||
g_string_append_c (out, '-');
|
||||
ostree_checksum_b64_inplace_to_bytes (dash+1, csum);
|
||||
ostree_checksum_inplace_from_bytes (csum, checksum);
|
||||
g_string_append (out, checksum);
|
||||
}
|
||||
|
||||
g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
|
||||
}
|
||||
|
||||
g_ptr_array_add (ret_deltas, g_string_free (out, FALSE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (out_deltas)
|
||||
*out_deltas = g_steal_pointer (&ret_deltas);
|
||||
ot_transfer_out_value (out_deltas, &ret_deltas);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
+342
-502
File diff suppressed because it is too large.
Load diff
@@ -767,14 +767,17 @@ typedef struct {
|
||||
gboolean enable_fsync; /* Deprecated */
|
||||
gboolean process_whiteouts;
|
||||
gboolean no_copy_fallback;
|
||||
gboolean unused_bools[7];
|
||||
gboolean force_copy; /* Since: 2017.6 */
|
||||
gboolean unused_bools[6];
|
||||
|
||||
const char *subpath;
|
||||
|
||||
OstreeRepoDevInoCache *devino_to_csum_cache;
|
||||
|
||||
int unused_ints[6];
|
||||
gpointer unused_ptrs[7];
|
||||
gpointer unused_ptrs[5];
|
||||
OstreeSePolicy *sepolicy; /* Since: 2017.6 */
|
||||
const char *sepolicy_prefix;
|
||||
} OstreeRepoCheckoutAtOptions;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
|
||||
@@ -37,5 +37,6 @@ gboolean _ostree_sepolicy_preparefscreatecon (OstreeSepolicyFsCreatecon *con,
|
||||
guint32 mode,
|
||||
GError **error);
|
||||
|
||||
GVariant *_ostree_filter_selinux_xattr (GVariant *xattrs);
|
||||
|
||||
G_END_DECLS
|
||||
+110
-113
@@ -47,8 +47,6 @@ struct OstreeSePolicy {
|
||||
int rootfs_dfd_owned;
|
||||
GFile *path;
|
||||
|
||||
gboolean runtime_enabled;
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
GFile *selinux_policy_root;
|
||||
struct selabel_handle *selinux_hnd;
|
||||
@@ -198,24 +196,21 @@ get_policy_checksum (char **out_csum,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
const char *binary_policy_path = selinux_binary_policy_path ();
|
||||
const char *binfile_prefix = glnx_basename (binary_policy_path);
|
||||
g_autofree char *bindir_path = g_path_get_dirname (binary_policy_path);
|
||||
|
||||
glnx_fd_close int bindir_dfd = -1;
|
||||
|
||||
g_autofree char *best_policy = NULL;
|
||||
int best_version = 0;
|
||||
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0,};
|
||||
|
||||
glnx_fd_close int bindir_dfd = -1;
|
||||
if (!glnx_opendirat (AT_FDCWD, bindir_path, TRUE, &bindir_dfd, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0,};
|
||||
if (!glnx_dirfd_iterator_init_at (bindir_dfd, ".", FALSE, &dfd_iter, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
@@ -223,8 +218,7 @@ get_policy_checksum (char **out_csum,
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
@@ -259,44 +253,54 @@ get_policy_checksum (char **out_csum,
|
||||
}
|
||||
|
||||
if (!best_policy)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Could not find binary policy file");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Could not find binary policy file");
|
||||
|
||||
*out_csum = ot_checksum_file_at (bindir_dfd, best_policy, G_CHECKSUM_SHA256,
|
||||
cancellable, error);
|
||||
if (*out_csum == NULL)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Workaround for http://marc.info/?l=selinux&m=149323809332417&w=2 */
|
||||
#ifdef HAVE_SELINUX
|
||||
static gboolean
|
||||
cached_is_selinux_enabled (void)
|
||||
{
|
||||
static gsize initialized;
|
||||
static gboolean cached_enabled;
|
||||
if (g_once_init_enter (&initialized))
|
||||
{
|
||||
cached_enabled = is_selinux_enabled () == 1;
|
||||
g_once_init_leave (&initialized, 1);
|
||||
}
|
||||
return cached_enabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
static gboolean
|
||||
initable_init (GInitable *initable,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
gboolean ret = FALSE;
|
||||
OstreeSePolicy *self = OSTREE_SEPOLICY (initable);
|
||||
g_autoptr(GFile) path = NULL;
|
||||
g_autoptr(GFile) etc_selinux_dir = NULL;
|
||||
g_autoptr(GFile) policy_config_path = NULL;
|
||||
g_autoptr(GFile) policy_root = NULL;
|
||||
g_autoptr(GFileInputStream) filein = NULL;
|
||||
g_autoptr(GDataInputStream) datain = NULL;
|
||||
gboolean enabled = FALSE;
|
||||
g_autofree char *policytype = NULL;
|
||||
const char *selinux_prefix = "SELINUX=";
|
||||
const char *selinuxtype_prefix = "SELINUXTYPE=";
|
||||
|
||||
/* First thing here, call is_selinux_enabled() to prime the cache. See the
|
||||
* link above for more information why.
|
||||
*/
|
||||
(void) cached_is_selinux_enabled ();
|
||||
|
||||
/* TODO - use this below */
|
||||
g_autoptr(GFile) path = NULL;
|
||||
if (self->rootfs_dfd != -1)
|
||||
path = ot_fdrel_to_gfile (self->rootfs_dfd, ".");
|
||||
else if (self->path)
|
||||
@@ -306,45 +310,44 @@ initable_init (GInitable *initable,
|
||||
/* TODO - use this below */
|
||||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->path), TRUE,
|
||||
&self->rootfs_dfd_owned, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
self->rootfs_dfd = self->rootfs_dfd_owned;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
etc_selinux_dir = g_file_resolve_relative_path (path, "etc/selinux");
|
||||
g_autoptr(GFile) etc_selinux_dir = g_file_resolve_relative_path (path, "etc/selinux");
|
||||
if (!g_file_query_exists (etc_selinux_dir, NULL))
|
||||
{
|
||||
g_object_unref (etc_selinux_dir);
|
||||
etc_selinux_dir = g_file_resolve_relative_path (path, "usr/etc/selinux");
|
||||
}
|
||||
policy_config_path = g_file_get_child (etc_selinux_dir, "config");
|
||||
|
||||
g_autoptr(GFile) policy_config_path = g_file_get_child (etc_selinux_dir, "config");
|
||||
g_autoptr(GFile) policy_root = NULL;
|
||||
if (g_file_query_exists (policy_config_path, NULL))
|
||||
{
|
||||
filein = g_file_read (policy_config_path, cancellable, error);
|
||||
if (!filein)
|
||||
goto out;
|
||||
g_autoptr(GFileInputStream) filein = filein = g_file_read (policy_config_path, cancellable, error);
|
||||
|
||||
datain = g_data_input_stream_new ((GInputStream*)filein);
|
||||
if (!filein)
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GDataInputStream) datain = g_data_input_stream_new ((GInputStream*)filein);
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
gsize len;
|
||||
GError *temp_error = NULL;
|
||||
g_autoptr(GError) temp_error = NULL;
|
||||
g_autofree char *line = g_data_input_stream_read_line_utf8 (datain, &len,
|
||||
cancellable, &temp_error);
|
||||
|
||||
|
||||
if (temp_error)
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
return g_propagate_error (error, g_steal_pointer (&temp_error)), FALSE;
|
||||
|
||||
if (!line)
|
||||
break;
|
||||
|
||||
|
||||
if (g_str_has_prefix (line, selinuxtype_prefix))
|
||||
{
|
||||
policytype = g_strstrip (g_strdup (line + strlen (selinuxtype_prefix)));
|
||||
@@ -362,57 +365,32 @@ initable_init (GInitable *initable,
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
self->runtime_enabled = is_selinux_enabled () == 1;
|
||||
const char *policy_rootpath = gs_file_get_path_cached (policy_root);
|
||||
|
||||
g_setenv ("LIBSELINUX_DISABLE_PCRE_PRECOMPILED", "1", FALSE);
|
||||
if (selinux_set_policy_root (gs_file_get_path_cached (policy_root)) != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"selinux_set_policy_root(%s): %s",
|
||||
gs_file_get_path_cached (etc_selinux_dir),
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
if (selinux_set_policy_root (policy_rootpath) != 0)
|
||||
return glnx_throw_errno_prefix (error, "selinux_set_policy_root(%s)", policy_rootpath);
|
||||
|
||||
self->selinux_hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0);
|
||||
if (!self->selinux_hnd)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"With policy root '%s': selabel_open(SELABEL_CTX_FILE): %s",
|
||||
gs_file_get_path_cached (etc_selinux_dir),
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "With policy root '%s': selabel_open(SELABEL_CTX_FILE)",
|
||||
policy_rootpath);
|
||||
|
||||
{
|
||||
char *con = NULL;
|
||||
if (selabel_lookup_raw (self->selinux_hnd, &con, "/", 0755) != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"With policy root '%s': Failed to look up context of /: %s",
|
||||
gs_file_get_path_cached (etc_selinux_dir),
|
||||
strerror (errno));
|
||||
goto out;
|
||||
}
|
||||
freecon (con);
|
||||
}
|
||||
char *con = NULL;
|
||||
if (selabel_lookup_raw (self->selinux_hnd, &con, "/", 0755) != 0)
|
||||
return glnx_throw_errno_prefix (error, "With policy root '%s': Failed to look up context of /",
|
||||
policy_rootpath);
|
||||
freecon (con);
|
||||
|
||||
if (!get_policy_checksum (&self->selinux_policy_csum, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "While calculating SELinux checksum: ");
|
||||
goto out;
|
||||
}
|
||||
return glnx_prefix_error (error, "While calculating SELinux checksum");
|
||||
|
||||
self->selinux_policy_name = g_steal_pointer (&policytype);
|
||||
self->selinux_policy_root = g_object_ref (etc_selinux_dir);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
#else
|
||||
return TRUE;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -580,11 +558,7 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self,
|
||||
GError **error)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFileInfo) src_info = NULL;
|
||||
g_autofree char *label = NULL;
|
||||
gboolean do_relabel = TRUE;
|
||||
|
||||
if (info != NULL)
|
||||
src_info = g_object_ref (info);
|
||||
else
|
||||
@@ -593,9 +567,10 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, error);
|
||||
if (!src_info)
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean do_relabel = TRUE;
|
||||
if (flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING)
|
||||
{
|
||||
char *existing_con = NULL;
|
||||
@@ -607,42 +582,31 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self,
|
||||
}
|
||||
}
|
||||
|
||||
g_autofree char *label = NULL;
|
||||
if (do_relabel)
|
||||
{
|
||||
if (!ostree_sepolicy_get_label (self, path,
|
||||
if (!ostree_sepolicy_get_label (self, path,
|
||||
g_file_info_get_attribute_uint32 (src_info, "unix::mode"),
|
||||
&label,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!label)
|
||||
{
|
||||
if (!(flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No label found for '%s'", path);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "No label found for '%s'", path);
|
||||
}
|
||||
else
|
||||
{
|
||||
int res = lsetfilecon (gs_file_get_path_cached (target), label);
|
||||
if (res != 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
if (lsetfilecon (gs_file_get_path_cached (target), label) < 0)
|
||||
return glnx_throw_errno_prefix (error, "lsetfilecon");
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
if (out_new_label)
|
||||
*out_new_label = g_steal_pointer (&label);
|
||||
out:
|
||||
return ret;
|
||||
#else
|
||||
return TRUE;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -660,7 +624,6 @@ ostree_sepolicy_setfscreatecon (OstreeSePolicy *self,
|
||||
GError **error)
|
||||
{
|
||||
#ifdef HAVE_SELINUX
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *label = NULL;
|
||||
|
||||
/* setfscreatecon() will bomb out if the host has SELinux disabled,
|
||||
@@ -669,24 +632,17 @@ ostree_sepolicy_setfscreatecon (OstreeSePolicy *self,
|
||||
* request. To correctly handle the case of disabled host but
|
||||
* enabled target will require nontrivial work.
|
||||
*/
|
||||
if (!self->runtime_enabled)
|
||||
if (!cached_is_selinux_enabled ())
|
||||
return TRUE;
|
||||
|
||||
if (!ostree_sepolicy_get_label (self, path, mode, &label, NULL, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (setfscreatecon_raw (label) != 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "setfscreatecon");
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
#else
|
||||
return TRUE;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -730,3 +686,44 @@ _ostree_sepolicy_fscreatecon_clear (OstreeSepolicyFsCreatecon *con)
|
||||
return;
|
||||
ostree_sepolicy_fscreatecon_cleanup (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given @xattrs, filter out `security.selinux`, and return
|
||||
* a new GVariant without it. Supports @xattrs as %NULL to
|
||||
* mean "no xattrs", and also returns %NULL if no xattrs
|
||||
* would result (rather than a zero-length array).
|
||||
*/
|
||||
GVariant *
|
||||
_ostree_filter_selinux_xattr (GVariant *xattrs)
|
||||
{
|
||||
if (!xattrs)
|
||||
return NULL;
|
||||
|
||||
gboolean have_xattrs = FALSE;
|
||||
GVariantBuilder builder;
|
||||
guint n = g_variant_n_children (xattrs);
|
||||
for (guint i = 0; i < n; i++)
|
||||
{
|
||||
const char *name = NULL;
|
||||
g_autoptr(GVariant) value = NULL;
|
||||
|
||||
g_variant_get_child (xattrs, i, "(^&ay@ay)",
|
||||
&name, &value);
|
||||
|
||||
if (strcmp (name, "security.selinux") == 0)
|
||||
continue;
|
||||
/* Initialize builder lazily */
|
||||
if (!have_xattrs)
|
||||
{
|
||||
have_xattrs = TRUE;
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)"));
|
||||
}
|
||||
g_variant_builder_add (&builder, "(@ay@ay)",
|
||||
g_variant_new_bytestring (name),
|
||||
value);
|
||||
}
|
||||
/* Canonicalize zero length to NULL for efficiency */
|
||||
if (!have_xattrs)
|
||||
return NULL;
|
||||
return g_variant_ref_sink (g_variant_builder_end (&builder));
|
||||
}
|
||||
@@ -25,127 +25,87 @@
|
||||
|
||||
#include "ostree-sysroot-private.h"
|
||||
|
||||
/* @deploydir_dfd: Directory FD for ostree/deploy
|
||||
* @osname: Target osname
|
||||
* @inout_deployments: All deployments in this subdir will be appended to this array
|
||||
*/
|
||||
gboolean
|
||||
_ostree_sysroot_list_deployment_dirs_for_os (GFile *osdir,
|
||||
_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd,
|
||||
const char *osname,
|
||||
GPtrArray *inout_deployments,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *osname = glnx_basename (gs_file_get_path_cached (osdir));
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
g_autoptr(GFile) osdeploy_dir = NULL;
|
||||
GError *temp_error = NULL;
|
||||
|
||||
osdeploy_dir = g_file_get_child (osdir, "deploy");
|
||||
|
||||
dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL, &temp_error);
|
||||
if (!dir_enum)
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
g_clear_error (&temp_error);
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
gboolean exists;
|
||||
const char *osdeploy_path = glnx_strjoina (osname, "/deploy");
|
||||
if (!ot_dfd_iter_init_allow_noent (deploydir_dfd, osdeploy_path, &dfd_iter, &exists, error))
|
||||
return FALSE;
|
||||
if (!exists)
|
||||
return TRUE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
const char *name;
|
||||
GFileInfo *file_info = NULL;
|
||||
GFile *child = NULL;
|
||||
glnx_unref_object OstreeDeployment *deployment = NULL;
|
||||
g_autofree char *csum = NULL;
|
||||
gint deployserial;
|
||||
struct dirent *dent;
|
||||
|
||||
if (!g_file_enumerator_iterate (dir_enum, &file_info, &child,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
if (file_info == NULL)
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
name = g_file_info_get_name (file_info);
|
||||
|
||||
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
if (!_ostree_sysroot_parse_deploy_path_name (name, &csum, &deployserial, error))
|
||||
goto out;
|
||||
|
||||
deployment = ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1);
|
||||
g_ptr_array_add (inout_deployments, g_object_ref (deployment));
|
||||
g_autofree char *csum = NULL;
|
||||
gint deployserial;
|
||||
if (!_ostree_sysroot_parse_deploy_path_name (dent->d_name, &csum, &deployserial, error))
|
||||
return FALSE;
|
||||
|
||||
g_ptr_array_add (inout_deployments, ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1));
|
||||
}
|
||||
|
||||
done:
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return in @out_deployments a new array of OstreeDeployment loaded from the
|
||||
* filesystem state.
|
||||
*/
|
||||
static gboolean
|
||||
list_all_deployment_directories (OstreeSysroot *self,
|
||||
GPtrArray **out_deployments,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
g_autoptr(GFile) deploydir = NULL;
|
||||
g_autoptr(GPtrArray) ret_deployments = NULL;
|
||||
GError *temp_error = NULL;
|
||||
g_autoptr(GPtrArray) ret_deployments =
|
||||
g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
deploydir = g_file_resolve_relative_path (self->path, "ostree/deploy");
|
||||
|
||||
ret_deployments = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
dir_enum = g_file_enumerate_children (deploydir, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, &temp_error);
|
||||
if (!dir_enum)
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
{
|
||||
g_clear_error (&temp_error);
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, temp_error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
gboolean exists;
|
||||
if (!ot_dfd_iter_init_allow_noent (self->sysroot_fd, "ostree/deploy", &dfd_iter, &exists, error))
|
||||
return FALSE;
|
||||
if (!exists)
|
||||
return TRUE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
GFileInfo *file_info = NULL;
|
||||
GFile *child = NULL;
|
||||
struct dirent *dent;
|
||||
|
||||
if (!g_file_enumerator_iterate (dir_enum, &file_info, &child,
|
||||
NULL, error))
|
||||
goto out;
|
||||
if (file_info == NULL)
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
if (!_ostree_sysroot_list_deployment_dirs_for_os (child, ret_deployments,
|
||||
|
||||
if (!_ostree_sysroot_list_deployment_dirs_for_os (dfd_iter.fd, dent->d_name,
|
||||
ret_deployments,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
done:
|
||||
ret = TRUE;
|
||||
|
||||
ot_transfer_out_value (out_deployments, &ret_deployments);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -154,7 +114,7 @@ parse_bootdir_name (const char *name,
|
||||
char **out_csum)
|
||||
{
|
||||
const char *lastdash;
|
||||
|
||||
|
||||
if (out_osname)
|
||||
*out_osname = NULL;
|
||||
if (out_csum)
|
||||
@@ -164,7 +124,7 @@ parse_bootdir_name (const char *name,
|
||||
|
||||
if (!lastdash)
|
||||
return FALSE;
|
||||
|
||||
|
||||
if (!ostree_validate_checksum_string (lastdash + 1, NULL))
|
||||
return FALSE;
|
||||
|
||||
@@ -183,7 +143,6 @@ list_all_boot_directories (OstreeSysroot *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFileEnumerator) dir_enum = NULL;
|
||||
g_autoptr(GFile) boot_ostree = NULL;
|
||||
g_autoptr(GPtrArray) ret_bootdirs = NULL;
|
||||
GError *temp_error = NULL;
|
||||
@@ -192,9 +151,10 @@ list_all_boot_directories (OstreeSysroot *self,
|
||||
|
||||
ret_bootdirs = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
dir_enum = g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, &temp_error);
|
||||
g_autoptr(GFileEnumerator) dir_enum =
|
||||
g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
cancellable, &temp_error);
|
||||
if (!dir_enum)
|
||||
{
|
||||
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
|
||||
@@ -255,7 +255,7 @@ ensure_directory_from_template (int orig_etc_fd,
|
||||
g_assert (path != NULL);
|
||||
g_assert (*path != '/' && *path != '\0');
|
||||
|
||||
if (!ot_gopendirat (modified_etc_fd, path, TRUE, &src_dfd, error))
|
||||
if (!glnx_opendirat (modified_etc_fd, path, TRUE, &src_dfd, error))
|
||||
goto out;
|
||||
|
||||
/* Create with mode 0700, we'll fchmod/fchown later */
|
||||
@@ -293,7 +293,7 @@ ensure_directory_from_template (int orig_etc_fd,
|
||||
}
|
||||
}
|
||||
|
||||
if (!ot_gopendirat (new_etc_fd, path, TRUE, &target_dfd, error))
|
||||
if (!glnx_opendirat (new_etc_fd, path, TRUE, &target_dfd, error))
|
||||
goto out;
|
||||
|
||||
if (!dirfd_copy_attributes_and_xattrs (modified_etc_fd, path, src_dfd, target_dfd,
|
||||
@@ -767,6 +767,7 @@ selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
|
||||
|
||||
static gboolean
|
||||
merge_configuration (OstreeSysroot *sysroot,
|
||||
OstreeRepo *repo,
|
||||
OstreeDeployment *previous_deployment,
|
||||
OstreeDeployment *deployment,
|
||||
int deployment_dfd,
|
||||
@@ -829,19 +830,15 @@ merge_configuration (OstreeSysroot *sysroot,
|
||||
usretc_exists = TRUE;
|
||||
etc_exists = FALSE;
|
||||
}
|
||||
|
||||
|
||||
if (usretc_exists)
|
||||
{
|
||||
glnx_fd_close int deployment_usr_dfd = -1;
|
||||
|
||||
if (!glnx_opendirat (deployment_dfd, "usr", TRUE, &deployment_usr_dfd, error))
|
||||
goto out;
|
||||
|
||||
/* TODO - set out labels as we copy files */
|
||||
g_assert (!etc_exists);
|
||||
if (!copy_dir_recurse (deployment_usr_dfd, deployment_dfd, "etc",
|
||||
sysroot->debug_flags, cancellable, error))
|
||||
goto out;
|
||||
/* We need copies of /etc from /usr/etc (so admins can use vi), and if
|
||||
* SELinux is enabled, we need to relabel.
|
||||
*/
|
||||
OstreeRepoCheckoutAtOptions etc_co_opts = { .force_copy = TRUE,
|
||||
.subpath = "/usr/etc",
|
||||
.sepolicy_prefix = "/etc"};
|
||||
|
||||
/* Here, we initialize SELinux policy from the /usr/etc inside
|
||||
* the root - this is before we've finalized the configuration
|
||||
@@ -849,13 +846,15 @@ merge_configuration (OstreeSysroot *sysroot,
|
||||
sepolicy = ostree_sepolicy_new (deployment_path, cancellable, error);
|
||||
if (!sepolicy)
|
||||
goto out;
|
||||
|
||||
if (ostree_sepolicy_get_name (sepolicy) != NULL)
|
||||
{
|
||||
if (!selinux_relabel_dir (sysroot, sepolicy, deployment_etc_path, "etc",
|
||||
etc_co_opts.sepolicy = sepolicy;
|
||||
|
||||
/* Copy usr/etc → etc */
|
||||
if (!ostree_repo_checkout_at (repo, &etc_co_opts,
|
||||
deployment_dfd, "etc",
|
||||
ostree_deployment_get_csum (deployment),
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (source_etc_path)
|
||||
@@ -1307,7 +1306,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
contents = glnx_file_get_contents_utf8_at (deployment_dfd, "etc/os-release", NULL,
|
||||
cancellable, error);
|
||||
if (!contents)
|
||||
return g_prefix_error (error, "Reading /etc/os-release: "), FALSE;
|
||||
return glnx_prefix_error (error, "Reading /etc/os-release");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1315,7 +1314,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
contents = glnx_file_get_contents_utf8_at (deployment_dfd, "usr/lib/os-release", NULL,
|
||||
cancellable, error);
|
||||
if (!contents)
|
||||
return g_prefix_error (error, "Reading /usr/lib/os-release: "), FALSE;
|
||||
return glnx_prefix_error (error, "Reading /usr/lib/os-release");
|
||||
}
|
||||
|
||||
g_autoptr(GHashTable) osrelease_values = parse_os_release (contents, "\n");
|
||||
@@ -1380,6 +1379,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
|
||||
val = ostree_bootconfig_parser_get (bootconfig, "options");
|
||||
|
||||
/* Note this is parsed in ostree-impl-system-generator.c */
|
||||
g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d",
|
||||
new_bootversion, osname, bootcsum,
|
||||
ostree_deployment_get_bootserial (deployment));
|
||||
@@ -1899,19 +1899,20 @@ allocate_deployserial (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
guint i;
|
||||
int new_deployserial = 0;
|
||||
g_autoptr(GPtrArray) tmp_current_deployments =
|
||||
g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
const char *osdir_name = glnx_strjoina ("ostree/deploy/", osname);
|
||||
g_autoptr(GFile) osdir = g_file_resolve_relative_path (self->path, osdir_name);
|
||||
glnx_fd_close int deploy_dfd = -1;
|
||||
if (!glnx_opendirat (self->sysroot_fd, "ostree/deploy", TRUE, &deploy_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!_ostree_sysroot_list_deployment_dirs_for_os (osdir, tmp_current_deployments,
|
||||
if (!_ostree_sysroot_list_deployment_dirs_for_os (deploy_dfd, osname,
|
||||
tmp_current_deployments,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
for (i = 0; i < tmp_current_deployments->len; i++)
|
||||
for (guint i = 0; i < tmp_current_deployments->len; i++)
|
||||
{
|
||||
OstreeDeployment *deployment = tmp_current_deployments->pdata[i];
|
||||
|
||||
@@ -2017,7 +2018,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
||||
ostree_deployment_set_bootconfig (new_deployment, bootconfig);
|
||||
|
||||
glnx_unref_object OstreeSePolicy *sepolicy = NULL;
|
||||
if (!merge_configuration (self, merge_deployment, new_deployment,
|
||||
if (!merge_configuration (self, repo, merge_deployment, new_deployment,
|
||||
deployment_dfd,
|
||||
&sepolicy,
|
||||
cancellable, error))
|
||||
|
||||
@@ -87,7 +87,8 @@ _ostree_sysroot_parse_deploy_path_name (const char *name,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_sysroot_list_deployment_dirs_for_os (GFile *osdir,
|
||||
_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd,
|
||||
const char *osname,
|
||||
GPtrArray *inout_deployments,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "otutil.h"
|
||||
|
||||
#include "ostree.h"
|
||||
#include "ostree-sysroot-upgrader.h"
|
||||
|
||||
/**
|
||||
@@ -50,7 +51,7 @@ struct OstreeSysrootUpgrader {
|
||||
char *override_csum;
|
||||
|
||||
char *new_revision;
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
@@ -70,7 +71,6 @@ parse_refspec (OstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *origin_refspec = NULL;
|
||||
g_autofree char *unconfigured_state = NULL;
|
||||
g_autofree char *csum = NULL;
|
||||
@@ -82,37 +82,28 @@ parse_refspec (OstreeSysrootUpgrader *self,
|
||||
*/
|
||||
unconfigured_state = g_key_file_get_string (self->origin, "origin", "unconfigured-state", NULL);
|
||||
if (unconfigured_state)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"origin unconfigured-state: %s", unconfigured_state);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "origin unconfigured-state: %s", unconfigured_state);
|
||||
}
|
||||
|
||||
origin_refspec = g_key_file_get_string (self->origin, "origin", "refspec", NULL);
|
||||
if (!origin_refspec)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No origin/refspec in current deployment origin; cannot upgrade via ostree");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "No origin/refspec in current deployment origin; cannot upgrade via ostree");
|
||||
|
||||
g_clear_pointer (&self->origin_remote, g_free);
|
||||
g_clear_pointer (&self->origin_ref, g_free);
|
||||
if (!ostree_parse_refspec (origin_refspec,
|
||||
&self->origin_remote,
|
||||
&self->origin_remote,
|
||||
&self->origin_ref,
|
||||
error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
csum = g_key_file_get_string (self->origin, "origin", "override-commit", NULL);
|
||||
if (csum != NULL && !ostree_validate_checksum_string (csum, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
g_clear_pointer (&self->override_csum, g_free);
|
||||
self->override_csum = g_steal_pointer (&csum);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -120,17 +111,12 @@ ostree_sysroot_upgrader_initable_init (GInitable *initable,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
OstreeSysrootUpgrader *self = (OstreeSysrootUpgrader*)initable;
|
||||
OstreeDeployment *booted_deployment =
|
||||
ostree_sysroot_get_booted_deployment (self->sysroot);
|
||||
|
||||
if (booted_deployment == NULL && self->osname == NULL)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Not currently booted into an OSTree system and no OS specified");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Not currently booted into an OSTree system and no OS specified");
|
||||
|
||||
if (self->osname == NULL)
|
||||
{
|
||||
@@ -138,37 +124,23 @@ ostree_sysroot_upgrader_initable_init (GInitable *initable,
|
||||
self->osname = g_strdup (ostree_deployment_get_osname (booted_deployment));
|
||||
}
|
||||
else if (self->osname[0] == '\0')
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid empty osname");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid empty osname");
|
||||
|
||||
self->merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname);
|
||||
self->merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname);
|
||||
if (self->merge_deployment == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No previous deployment for OS '%s'", self->osname);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "No previous deployment for OS '%s'", self->osname);
|
||||
|
||||
self->origin = ostree_deployment_get_origin (self->merge_deployment);
|
||||
if (!self->origin)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No origin known for deployment %s.%d",
|
||||
ostree_deployment_get_csum (self->merge_deployment),
|
||||
ostree_deployment_get_deployserial (self->merge_deployment));
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "No origin known for deployment %s.%d",
|
||||
ostree_deployment_get_csum (self->merge_deployment),
|
||||
ostree_deployment_get_deployserial (self->merge_deployment));
|
||||
g_key_file_ref (self->origin);
|
||||
|
||||
if (!parse_refspec (self, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -401,19 +373,15 @@ ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_clear_pointer (&self->origin, g_key_file_unref);
|
||||
if (origin)
|
||||
{
|
||||
self->origin = g_key_file_ref (origin);
|
||||
if (!parse_refspec (self, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -447,21 +415,19 @@ ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo,
|
||||
const char *to_rev,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GVariant) old_commit = NULL;
|
||||
g_autoptr(GVariant) new_commit = NULL;
|
||||
|
||||
if (!ostree_repo_load_variant (repo,
|
||||
OSTREE_OBJECT_TYPE_COMMIT,
|
||||
from_rev,
|
||||
&old_commit,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GVariant) new_commit = NULL;
|
||||
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
|
||||
to_rev, &new_commit,
|
||||
error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (ostree_commit_get_timestamp (old_commit) > ostree_commit_get_timestamp (new_commit))
|
||||
{
|
||||
@@ -470,25 +436,23 @@ ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo,
|
||||
g_autofree char *old_ts_str = NULL;
|
||||
g_autofree char *new_ts_str = NULL;
|
||||
|
||||
g_assert (old_ts);
|
||||
g_assert (new_ts);
|
||||
if (old_ts == NULL || new_ts == NULL)
|
||||
return glnx_throw (error, "Upgrade target revision '%s' timestamp (%" G_GINT64_FORMAT ") or current revision '%s' timestamp (%" G_GINT64_FORMAT ") is invalid",
|
||||
to_rev, ostree_commit_get_timestamp (new_commit),
|
||||
from_rev, ostree_commit_get_timestamp (old_commit));
|
||||
|
||||
old_ts_str = g_date_time_format (old_ts, "%c");
|
||||
new_ts_str = g_date_time_format (new_ts, "%c");
|
||||
g_date_time_unref (old_ts);
|
||||
g_date_time_unref (new_ts);
|
||||
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit",
|
||||
to_rev, new_ts_str, from_rev, old_ts_str);
|
||||
goto out;
|
||||
return glnx_throw (error, "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit",
|
||||
to_rev, new_ts_str, from_rev, old_ts_str);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ostree_sysroot_upgrader_pull:
|
||||
* @self: Upgrader
|
||||
@@ -544,8 +508,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
g_autoptr(OstreeRepo) repo = NULL;
|
||||
char *refs_to_fetch[] = { NULL, NULL };
|
||||
const char *from_revision = NULL;
|
||||
g_autofree char *origin_refspec = NULL;
|
||||
@@ -556,7 +519,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
|
||||
refs_to_fetch[0] = self->origin_ref;
|
||||
|
||||
if (!ostree_sysroot_get_repo (self->sysroot, &repo, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (self->origin_remote)
|
||||
origin_refspec = g_strconcat (self->origin_remote, ":", self->origin_ref, NULL);
|
||||
@@ -572,7 +535,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
|
||||
if (!ostree_repo_pull_one_dir (repo, self->origin_remote, dir_to_pull, refs_to_fetch,
|
||||
flags, progress,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (progress)
|
||||
ostree_async_progress_finish (progress);
|
||||
@@ -586,7 +549,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
|
||||
self->override_csum,
|
||||
cancellable,
|
||||
error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
self->new_revision = g_strdup (self->override_csum);
|
||||
}
|
||||
@@ -594,7 +557,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
|
||||
{
|
||||
if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE,
|
||||
&self->new_revision, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
@@ -613,13 +576,11 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
|
||||
if (!ostree_sysroot_upgrader_check_timestamps (repo, from_revision,
|
||||
self->new_revision,
|
||||
error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -636,9 +597,7 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
glnx_unref_object OstreeDeployment *new_deployment = NULL;
|
||||
|
||||
g_autoptr(OstreeDeployment) new_deployment = NULL;
|
||||
if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname,
|
||||
self->new_revision,
|
||||
self->origin,
|
||||
@@ -646,18 +605,16 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
|
||||
NULL,
|
||||
&new_deployment,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname,
|
||||
new_deployment,
|
||||
self->merge_deployment,
|
||||
0,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GType
|
||||
|
||||
+156
-342
@@ -284,47 +284,33 @@ ostree_sysroot_ensure_initialized (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/repo", 0755,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/deploy", 0755,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
struct stat stbuf;
|
||||
if (fstatat (self->sysroot_fd, "ostree/repo/objects", &stbuf, 0) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "stat %s", "ostree/repo/objects");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "stat(ostree/repo/objects)");
|
||||
else
|
||||
{
|
||||
g_autoptr(GFile) repo_dir = g_file_resolve_relative_path (self->path, "ostree/repo");
|
||||
glnx_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir);
|
||||
if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
match_info_cleanup (void *loc)
|
||||
{
|
||||
GMatchInfo **match = (GMatchInfo**)loc;
|
||||
if (*match) g_match_info_unref (*match);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -333,13 +319,9 @@ _ostree_sysroot_parse_deploy_path_name (const char *name,
|
||||
int *out_serial,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
__attribute__((cleanup(match_info_cleanup))) GMatchInfo *match = NULL;
|
||||
g_autofree char *serial_str = NULL;
|
||||
|
||||
static gsize regex_initialized;
|
||||
static GRegex *regex;
|
||||
|
||||
if (g_once_init_enter (®ex_initialized))
|
||||
{
|
||||
regex = g_regex_new ("^([0-9a-f]+)\\.([0-9]+)$", 0, 0, NULL);
|
||||
@@ -347,20 +329,14 @@ _ostree_sysroot_parse_deploy_path_name (const char *name,
|
||||
g_once_init_leave (®ex_initialized, 1);
|
||||
}
|
||||
|
||||
g_autoptr(GMatchInfo) match = NULL;
|
||||
if (!g_regex_match (regex, name, 0, &match))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid deploy name '%s', expected CHECKSUM.TREESERIAL", name);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid deploy name '%s', expected CHECKSUM.TREESERIAL", name);
|
||||
|
||||
g_autofree char *serial_str = g_match_info_fetch (match, 2);
|
||||
*out_csum = g_match_info_fetch (match, 1);
|
||||
serial_str = g_match_info_fetch (match, 2);
|
||||
*out_serial = (int)g_ascii_strtoll (serial_str, NULL, 10);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -370,49 +346,36 @@ _ostree_sysroot_read_current_subbootversion (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
struct stat stbuf;
|
||||
g_autofree char *ostree_bootdir_name = g_strdup_printf ("ostree/boot.%d", bootversion);
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_autofree char *ostree_bootdir_name = g_strdup_printf ("ostree/boot.%d", bootversion);
|
||||
struct stat stbuf;
|
||||
if (fstatat (self->sysroot_fd, ostree_bootdir_name, &stbuf, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
*out_subbootversion = 0;
|
||||
else
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree char *current_subbootdir_name = NULL;
|
||||
|
||||
current_subbootdir_name = glnx_readlinkat_malloc (self->sysroot_fd, ostree_bootdir_name,
|
||||
cancellable, error);
|
||||
g_autofree char *current_subbootdir_name =
|
||||
glnx_readlinkat_malloc (self->sysroot_fd, ostree_bootdir_name,
|
||||
cancellable, error);
|
||||
if (!current_subbootdir_name)
|
||||
goto out;
|
||||
|
||||
return FALSE;
|
||||
|
||||
if (g_str_has_suffix (current_subbootdir_name, ".0"))
|
||||
*out_subbootversion = 0;
|
||||
else if (g_str_has_suffix (current_subbootdir_name, ".1"))
|
||||
*out_subbootversion = 1;
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid target '%s' in %s",
|
||||
current_subbootdir_name,
|
||||
ostree_bootdir_name);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid target '%s' in %s",
|
||||
current_subbootdir_name, ostree_bootdir_name);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
@@ -451,60 +414,46 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int fd; /* Temporary owned by iterator */
|
||||
g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion);
|
||||
g_autoptr(GPtrArray) ret_loader_configs = NULL;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret_loader_configs = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
|
||||
g_autoptr(GPtrArray) ret_loader_configs =
|
||||
g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
|
||||
|
||||
fd = glnx_opendirat_with_errno (self->sysroot_fd, entries_path, TRUE);
|
||||
if (fd == -1)
|
||||
g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion);
|
||||
gboolean entries_exists;
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
if (!ot_dfd_iter_init_allow_noent (self->sysroot_fd, entries_path,
|
||||
&dfd_iter, &entries_exists, error))
|
||||
return FALSE;
|
||||
if (!entries_exists)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
goto done;
|
||||
else
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
/* Note early return */
|
||||
*out_loader_configs = g_steal_pointer (&ret_loader_configs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!glnx_dirfd_iterator_init_take_fd (fd, &dfd_iter, error))
|
||||
goto out;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
struct dirent *dent;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
|
||||
goto out;
|
||||
|
||||
return FALSE;
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0) != 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno (error);
|
||||
|
||||
if (g_str_has_prefix (dent->d_name, "ostree-") &&
|
||||
g_str_has_suffix (dent->d_name, ".conf") &&
|
||||
S_ISREG (stbuf.st_mode))
|
||||
{
|
||||
glnx_unref_object OstreeBootconfigParser *config = ostree_bootconfig_parser_new ();
|
||||
|
||||
|
||||
if (!ostree_bootconfig_parser_parse_at (config, dfd_iter.fd, dent->d_name, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Parsing %s: ", dent->d_name);
|
||||
goto out;
|
||||
}
|
||||
return glnx_prefix_error (error, "Parsing %s", dent->d_name);
|
||||
|
||||
g_ptr_array_add (ret_loader_configs, g_object_ref (config));
|
||||
}
|
||||
@@ -512,13 +461,8 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
|
||||
|
||||
/* Callers expect us to give them a sorted array */
|
||||
g_ptr_array_sort (ret_loader_configs, compare_loader_configs_for_sorting);
|
||||
|
||||
done:
|
||||
if (out_loader_configs)
|
||||
*out_loader_configs = g_steal_pointer (&ret_loader_configs);
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
ot_transfer_out_value(out_loader_configs, &ret_loader_configs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -527,49 +471,34 @@ read_current_bootversion (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
int ret_bootversion;
|
||||
struct stat stbuf;
|
||||
|
||||
if (fstatat (self->sysroot_fd, "boot/loader", &stbuf, AT_SYMLINK_NOFOLLOW) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno (error);
|
||||
ret_bootversion = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_autofree char *target = NULL;
|
||||
|
||||
if (!S_ISLNK (stbuf.st_mode))
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Not a symbolic link: boot/loader");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Not a symbolic link: boot/loader");
|
||||
|
||||
target = glnx_readlinkat_malloc (self->sysroot_fd, "boot/loader", cancellable, error);
|
||||
g_autofree char *target =
|
||||
glnx_readlinkat_malloc (self->sysroot_fd, "boot/loader", cancellable, error);
|
||||
if (!target)
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (g_strcmp0 (target, "loader.0") == 0)
|
||||
ret_bootversion = 0;
|
||||
else if (g_strcmp0 (target, "loader.1") == 0)
|
||||
ret_bootversion = 1;
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid target '%s' in boot/loader", target);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Invalid target '%s' in boot/loader", target);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
*out_bootversion = ret_bootversion;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -580,42 +509,29 @@ parse_origin (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GKeyFile) ret_origin = NULL;
|
||||
g_autofree char *origin_path = g_strconcat ("../", deployment_name, ".origin", NULL);
|
||||
struct stat stbuf;
|
||||
g_autofree char *origin_contents = NULL;
|
||||
g_autoptr(GKeyFile) ret_origin = g_key_file_new ();
|
||||
|
||||
ret_origin = g_key_file_new ();
|
||||
|
||||
struct stat stbuf;
|
||||
if (fstatat (deployment_dfd, origin_path, &stbuf, 0) != 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
;
|
||||
else
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
if (errno != ENOENT)
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
origin_contents = glnx_file_get_contents_utf8_at (deployment_dfd, origin_path,
|
||||
NULL, cancellable, error);
|
||||
g_autofree char *origin_contents =
|
||||
glnx_file_get_contents_utf8_at (deployment_dfd, origin_path,
|
||||
NULL, cancellable, error);
|
||||
if (!origin_contents)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!g_key_file_load_from_data (ret_origin, origin_contents, -1, 0, error))
|
||||
goto out;
|
||||
return glnx_prefix_error (error, "Parsing %s", origin_path);
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
if (out_origin)
|
||||
*out_origin = g_steal_pointer (&ret_origin);
|
||||
out:
|
||||
if (error)
|
||||
g_prefix_error (error, "Parsing %s: ", origin_path);
|
||||
return ret;
|
||||
ot_transfer_out_value(out_origin, &ret_origin);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -626,14 +542,8 @@ parse_bootlink (const char *bootlink,
|
||||
int *out_treebootserial,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
__attribute__((cleanup(match_info_cleanup))) GMatchInfo *match = NULL;
|
||||
g_autofree char *bootversion_str = NULL;
|
||||
g_autofree char *treebootserial_str = NULL;
|
||||
|
||||
static gsize regex_initialized;
|
||||
static GRegex *regex;
|
||||
|
||||
if (g_once_init_enter (®ex_initialized))
|
||||
{
|
||||
regex = g_regex_new ("^/ostree/boot.([01])/([^/]+)/([^/]+)/([0-9]+)$", 0, 0, NULL);
|
||||
@@ -641,23 +551,17 @@ parse_bootlink (const char *bootlink,
|
||||
g_once_init_leave (®ex_initialized, 1);
|
||||
}
|
||||
|
||||
g_autoptr(GMatchInfo) match = NULL;
|
||||
if (!g_regex_match (regex, bootlink, 0, &match))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Invalid ostree= argument '%s', expected ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL", bootlink);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bootversion_str = g_match_info_fetch (match, 1);
|
||||
return glnx_throw (error, "Invalid ostree= argument '%s', expected ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL", bootlink);
|
||||
|
||||
g_autofree char *bootversion_str = g_match_info_fetch (match, 1);
|
||||
g_autofree char *treebootserial_str = g_match_info_fetch (match, 4);
|
||||
*out_entry_bootversion = (int)g_ascii_strtoll (bootversion_str, NULL, 10);
|
||||
*out_osname = g_match_info_fetch (match, 2);
|
||||
*out_bootcsum = g_match_info_fetch (match, 3);
|
||||
treebootserial_str = g_match_info_fetch (match, 4);
|
||||
*out_treebootserial = (int)g_ascii_strtoll (treebootserial_str, NULL, 10);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
@@ -677,60 +581,54 @@ parse_deployment (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *relative_boot_link;
|
||||
glnx_unref_object OstreeDeployment *ret_deployment = NULL;
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
return FALSE;
|
||||
|
||||
int entry_boot_version;
|
||||
int treebootserial = -1;
|
||||
int deployserial = -1;
|
||||
g_autofree char *osname = NULL;
|
||||
g_autofree char *bootcsum = NULL;
|
||||
g_autofree char *treecsum = NULL;
|
||||
glnx_fd_close int deployment_dfd = -1;
|
||||
const char *deploy_basename;
|
||||
g_autofree char *treebootserial_target = NULL;
|
||||
g_autoptr(GKeyFile) origin = NULL;
|
||||
g_autofree char *unlocked_development_path = NULL;
|
||||
struct stat stbuf;
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
|
||||
int treebootserial = -1;
|
||||
if (!parse_bootlink (boot_link, &entry_boot_version,
|
||||
&osname, &bootcsum, &treebootserial,
|
||||
error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
relative_boot_link = boot_link;
|
||||
const char *relative_boot_link = boot_link;
|
||||
if (*relative_boot_link == '/')
|
||||
relative_boot_link++;
|
||||
|
||||
treebootserial_target = glnx_readlinkat_malloc (self->sysroot_fd, relative_boot_link,
|
||||
cancellable, error);
|
||||
g_autofree char *treebootserial_target =
|
||||
glnx_readlinkat_malloc (self->sysroot_fd, relative_boot_link,
|
||||
cancellable, error);
|
||||
if (!treebootserial_target)
|
||||
goto out;
|
||||
|
||||
deploy_basename = glnx_basename (treebootserial_target);
|
||||
return FALSE;
|
||||
|
||||
const char *deploy_basename = glnx_basename (treebootserial_target);
|
||||
g_autofree char *treecsum = NULL;
|
||||
int deployserial = -1;
|
||||
if (!_ostree_sysroot_parse_deploy_path_name (deploy_basename,
|
||||
&treecsum, &deployserial, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
glnx_fd_close int deployment_dfd = -1;
|
||||
if (!glnx_opendirat (self->sysroot_fd, relative_boot_link, TRUE,
|
||||
&deployment_dfd, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GKeyFile) origin = NULL;
|
||||
if (!parse_origin (self, deployment_dfd, deploy_basename, &origin,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret_deployment = ostree_deployment_new (-1, osname, treecsum, deployserial,
|
||||
bootcsum, treebootserial);
|
||||
glnx_unref_object OstreeDeployment *ret_deployment
|
||||
= ostree_deployment_new (-1, osname, treecsum, deployserial,
|
||||
bootcsum, treebootserial);
|
||||
if (origin)
|
||||
ostree_deployment_set_origin (ret_deployment, origin);
|
||||
|
||||
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE;
|
||||
unlocked_development_path = get_unlocked_development_path (ret_deployment);
|
||||
g_autofree char *unlocked_development_path = get_unlocked_development_path (ret_deployment);
|
||||
struct stat stbuf;
|
||||
if (lstat (unlocked_development_path, &stbuf) == 0)
|
||||
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
|
||||
else
|
||||
@@ -747,11 +645,9 @@ parse_deployment (OstreeSysroot *self,
|
||||
|
||||
g_debug ("Deployment %s.%d unlocked=%d", treecsum, deployserial, ret_deployment->unlocked);
|
||||
|
||||
ret = TRUE;
|
||||
if (out_deployment)
|
||||
*out_deployment = g_steal_pointer (&ret_deployment);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
@@ -787,29 +683,19 @@ list_deployments_process_one_boot_entry (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autofree char *ostree_arg = NULL;
|
||||
glnx_unref_object OstreeDeployment *deployment = NULL;
|
||||
|
||||
ostree_arg = get_ostree_kernel_arg_from_config (config);
|
||||
g_autofree char *ostree_arg = get_ostree_kernel_arg_from_config (config);
|
||||
if (ostree_arg == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No ostree= kernel argument found");
|
||||
goto out;
|
||||
}
|
||||
|
||||
return glnx_throw (error, "No ostree= kernel argument found");
|
||||
|
||||
glnx_unref_object OstreeDeployment *deployment = NULL;
|
||||
if (!parse_deployment (self, ostree_arg, &deployment,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
return FALSE;
|
||||
|
||||
ostree_deployment_set_bootconfig (deployment, config);
|
||||
|
||||
g_ptr_array_add (inout_deployments, g_object_ref (deployment));
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gint
|
||||
@@ -847,29 +733,21 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
guint i;
|
||||
int bootversion = 0;
|
||||
int subbootversion = 0;
|
||||
struct stat stbuf;
|
||||
g_autoptr(GPtrArray) boot_loader_configs = NULL;
|
||||
g_autoptr(GPtrArray) deployments = NULL;
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
int bootversion = 0;
|
||||
if (!read_current_bootversion (self, &bootversion, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
int subbootversion = 0;
|
||||
if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &subbootversion,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
struct stat stbuf;
|
||||
if (fstatat (self->sysroot_fd, "ostree/deploy", &stbuf, 0) < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "fstatat");
|
||||
|
||||
if (out_changed)
|
||||
{
|
||||
@@ -877,8 +755,8 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
self->loaded_ts.tv_nsec == stbuf.st_mtim.tv_nsec)
|
||||
{
|
||||
*out_changed = FALSE;
|
||||
ret = TRUE;
|
||||
goto out;
|
||||
/* Note early return */
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -887,23 +765,24 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
self->bootversion = -1;
|
||||
self->subbootversion = -1;
|
||||
|
||||
g_autoptr(GPtrArray) boot_loader_configs = NULL;
|
||||
if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
|
||||
g_autoptr(GPtrArray) deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
|
||||
|
||||
for (i = 0; i < boot_loader_configs->len; i++)
|
||||
for (guint i = 0; i < boot_loader_configs->len; i++)
|
||||
{
|
||||
OstreeBootconfigParser *config = boot_loader_configs->pdata[i];
|
||||
|
||||
if (!list_deployments_process_one_boot_entry (self, config, deployments,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed);
|
||||
for (i = 0; i < deployments->len; i++)
|
||||
for (guint i = 0; i < deployments->len; i++)
|
||||
{
|
||||
OstreeDeployment *deployment = deployments->pdata[i];
|
||||
ostree_deployment_set_index (deployment, i);
|
||||
@@ -911,7 +790,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
|
||||
if (!find_booted_deployment (self, deployments, &self->booted_deployment,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
self->bootversion = bootversion;
|
||||
self->subbootversion = subbootversion;
|
||||
@@ -920,11 +799,9 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
self->loaded = TRUE;
|
||||
self->loaded_ts = stbuf.st_mtim;
|
||||
|
||||
ret = TRUE;
|
||||
if (out_changed)
|
||||
*out_changed = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -1039,18 +916,13 @@ ostree_sysroot_get_repo (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
/* ostree_repo_open() is idempotent. */
|
||||
if (!ostree_repo_open (self->repo, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (out_repo != NULL)
|
||||
*out_repo = g_object_ref (self->repo);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1066,37 +938,33 @@ _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gboolean is_active;
|
||||
glnx_unref_object OstreeBootloader *ret_loader = NULL;
|
||||
|
||||
ret_loader = (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot);
|
||||
glnx_unref_object OstreeBootloader *ret_loader =
|
||||
(OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot);
|
||||
if (!_ostree_bootloader_query (ret_loader, &is_active,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!is_active)
|
||||
{
|
||||
g_object_unref (ret_loader);
|
||||
ret_loader = (OstreeBootloader*)_ostree_bootloader_grub2_new (sysroot);
|
||||
if (!_ostree_bootloader_query (ret_loader, &is_active,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
if (!is_active)
|
||||
{
|
||||
g_object_unref (ret_loader);
|
||||
ret_loader = (OstreeBootloader*)_ostree_bootloader_uboot_new (sysroot);
|
||||
if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
if (!is_active)
|
||||
g_clear_object (&ret_loader);
|
||||
|
||||
ret = TRUE;
|
||||
if (out_bootloader)
|
||||
*out_bootloader = g_steal_pointer (&ret_loader);
|
||||
out:
|
||||
return ret;
|
||||
ot_transfer_out_value(out_bootloader, &ret_loader);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char *
|
||||
@@ -1128,21 +996,17 @@ parse_kernel_commandline (OstreeKernelArgs **out_args,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
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))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_strchomp (contents);
|
||||
|
||||
ret = TRUE;
|
||||
*out_args = _ostree_kernel_args_from_string (contents);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1152,50 +1016,37 @@ find_booted_deployment (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
struct stat root_stbuf;
|
||||
struct stat self_stbuf;
|
||||
glnx_unref_object OstreeDeployment *ret_deployment = NULL;
|
||||
|
||||
if (stat ("/", &root_stbuf) != 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "stat /");
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (fstat (self->sysroot_fd, &self_stbuf) != 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "fstat");
|
||||
|
||||
if (root_stbuf.st_dev == self_stbuf.st_dev &&
|
||||
root_stbuf.st_ino == self_stbuf.st_ino)
|
||||
{
|
||||
guint i;
|
||||
const char *bootlink_arg;
|
||||
{
|
||||
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kernel_args = NULL;
|
||||
|
||||
if (!parse_kernel_commandline (&kernel_args, cancellable, error))
|
||||
goto out;
|
||||
|
||||
bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree");
|
||||
return FALSE;
|
||||
|
||||
const char *bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree");
|
||||
if (bootlink_arg)
|
||||
{
|
||||
for (i = 0; i < deployments->len; i++)
|
||||
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)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "fstatat");
|
||||
|
||||
if (stbuf.st_dev == root_stbuf.st_dev &&
|
||||
stbuf.st_ino == root_stbuf.st_ino)
|
||||
@@ -1206,11 +1057,7 @@ find_booted_deployment (OstreeSysroot *self,
|
||||
}
|
||||
|
||||
if (ret_deployment == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Unexpected state: ostree= kernel argument found, but / is not a deployment root");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Unexpected state: ostree= kernel argument found, but / is not a deployment root");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1218,10 +1065,8 @@ find_booted_deployment (OstreeSysroot *self,
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
ot_transfer_out_value (out_deployment, &ret_deployment);
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1261,7 +1106,7 @@ ostree_sysroot_get_merge_deployment (OstreeSysroot *self,
|
||||
|
||||
if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0)
|
||||
continue;
|
||||
|
||||
|
||||
return g_object_ref (deployment);
|
||||
}
|
||||
}
|
||||
@@ -1325,11 +1170,10 @@ ostree_sysroot_try_lock (OstreeSysroot *self,
|
||||
gboolean *out_acquired,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
/* Note use of LOCK_NB */
|
||||
if (!glnx_make_lock_file (self->sysroot_fd, OSTREE_SYSROOT_LOCKFILE,
|
||||
@@ -1342,7 +1186,7 @@ ostree_sysroot_try_lock (OstreeSysroot *self,
|
||||
else
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&local_error));
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1350,9 +1194,7 @@ ostree_sysroot_try_lock (OstreeSysroot *self,
|
||||
*out_acquired = TRUE;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1383,7 +1225,7 @@ lock_in_thread (GTask *task,
|
||||
|
||||
if (g_cancellable_set_error_if_cancelled (cancellable, &local_error))
|
||||
ostree_sysroot_unlock (self);
|
||||
|
||||
|
||||
out:
|
||||
if (local_error)
|
||||
g_task_return_error (task, local_error);
|
||||
@@ -1444,77 +1286,49 @@ ostree_sysroot_init_osname (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
const char *deploydir = glnx_strjoina ("ostree/deploy/", osname);
|
||||
glnx_fd_close int dfd = -1;
|
||||
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
const char *deploydir = glnx_strjoina ("ostree/deploy/", osname);
|
||||
if (mkdirat (self->sysroot_fd, deploydir, 0777) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Creating %s", deploydir);
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "Creating %s", deploydir);
|
||||
|
||||
glnx_fd_close int dfd = -1;
|
||||
if (!glnx_opendirat (self->sysroot_fd, deploydir, TRUE, &dfd, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (mkdirat (dfd, "var", 0777) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Creating %s", "var");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "Creating %s", "var");
|
||||
|
||||
/* This is a bit of a legacy hack...but we have to keep it around
|
||||
* now. We're ensuring core subdirectories of /var exist.
|
||||
*/
|
||||
if (mkdirat (dfd, "var/tmp", 0777) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Creating %s", "var/tmp");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "Creating %s", "var/tmp");
|
||||
|
||||
if (fchmodat (dfd, "var/tmp", 01777, 0) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Fchmod %s", "var/tmp");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "fchmod %s", "var/tmp");
|
||||
|
||||
if (mkdirat (dfd, "var/lib", 0777) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Creating %s", "var/tmp");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "Creating %s", "var/tmp");
|
||||
|
||||
/* This needs to be available and properly labeled early during the boot
|
||||
* process (before tmpfiles.d kicks in), so that journald can flush logs from
|
||||
* the first boot there. https://bugzilla.redhat.com/show_bug.cgi?id=1265295
|
||||
* */
|
||||
if (mkdirat (dfd, "var/log", 0755) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Creating %s", "var/log");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "Creating %s", "var/log");
|
||||
|
||||
if (symlinkat ("../run", dfd, "var/run") < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Symlinking %s", "var/run");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "Symlinking %s", "var/run");
|
||||
|
||||
if (symlinkat ("../run/lock", dfd, "var/lock") < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "Symlinking %s", "var/lock");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "Symlinking %s", "var/lock");
|
||||
|
||||
if (!_ostree_sysroot_bump_mtime (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,4 +38,8 @@ typedef struct OstreeSysrootUpgrader OstreeSysrootUpgrader;
|
||||
typedef struct OstreeMutableTree OstreeMutableTree;
|
||||
typedef struct OstreeRepoFile OstreeRepoFile;
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
typedef struct OstreeRemote OstreeRemote;
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
@@ -40,14 +40,14 @@
|
||||
*
|
||||
* ostree release version component (e.g. 2 if %OSTREE_VERSION is 2017.2)
|
||||
*/
|
||||
#define OSTREE_RELEASE_VERSION (5)
|
||||
#define OSTREE_RELEASE_VERSION (6)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION
|
||||
*
|
||||
* ostree version.
|
||||
*/
|
||||
#define OSTREE_VERSION (2017.5)
|
||||
#define OSTREE_VERSION (2017.6)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION_S:
|
||||
@@ -55,7 +55,7 @@
|
||||
* ostree version, encoded as a string, useful for printing and
|
||||
* concatenation.
|
||||
*/
|
||||
#define OSTREE_VERSION_S "2017.5"
|
||||
#define OSTREE_VERSION_S "2017.6"
|
||||
|
||||
#define OSTREE_ENCODE_VERSION(year,release) \
|
||||
((year) << 16 | (release))
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
#include <ostree-core.h>
|
||||
#include <ostree-repo.h>
|
||||
#include <ostree-mutable-tree.h>
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
#include <ostree-remote.h>
|
||||
#endif
|
||||
#include <ostree-repo-file.h>
|
||||
#include <ostree-sysroot.h>
|
||||
#include <ostree-sysroot-upgrader.h>
|
||||
|
||||
@@ -47,7 +47,7 @@ ot_csum_from_gchecksum (GChecksum *checksum)
|
||||
{
|
||||
guchar *ret = g_malloc (32);
|
||||
gsize len = 32;
|
||||
|
||||
|
||||
g_checksum_get_digest (checksum, ret, &len);
|
||||
g_assert (len == 32);
|
||||
return ret;
|
||||
@@ -62,13 +62,11 @@ ot_gio_write_update_checksum (GOutputStream *out,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
if (out)
|
||||
{
|
||||
if (!g_output_stream_write_all (out, data, len, out_bytes_written,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
else if (out_bytes_written)
|
||||
{
|
||||
@@ -77,10 +75,7 @@ ot_gio_write_update_checksum (GOutputStream *out,
|
||||
|
||||
if (checksum)
|
||||
g_checksum_update (checksum, data, len);
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -90,8 +85,6 @@ ot_gio_splice_update_checksum (GOutputStream *out,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_return_val_if_fail (out != NULL || checksum != NULL, FALSE);
|
||||
|
||||
if (checksum != NULL)
|
||||
@@ -101,24 +94,25 @@ ot_gio_splice_update_checksum (GOutputStream *out,
|
||||
do
|
||||
{
|
||||
if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
while (bytes_read > 0);
|
||||
}
|
||||
else if (out != NULL)
|
||||
{
|
||||
if (g_output_stream_splice (out, in, 0, cancellable, error) < 0)
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Copy @in to @out, return in @out_csum the binary checksum for
|
||||
* all data read.
|
||||
*/
|
||||
gboolean
|
||||
ot_gio_splice_get_checksum (GOutputStream *out,
|
||||
GInputStream *in,
|
||||
@@ -126,22 +120,14 @@ ot_gio_splice_get_checksum (GOutputStream *out,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GChecksum *checksum = NULL;
|
||||
g_autofree guchar *ret_csum = NULL;
|
||||
|
||||
checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||
|
||||
if (!ot_gio_splice_update_checksum (out, in, checksum, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret_csum = ot_csum_from_gchecksum (checksum);
|
||||
|
||||
ret = TRUE;
|
||||
g_autofree guchar *ret_csum = ot_csum_from_gchecksum (checksum);
|
||||
ot_transfer_out_value (out_csum, &ret_csum);
|
||||
out:
|
||||
g_clear_pointer (&checksum, (GDestroyNotify) g_checksum_free);
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -162,21 +148,13 @@ ot_checksum_file_at (int dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GChecksum *checksum = NULL;
|
||||
char *ret = NULL;
|
||||
g_autoptr(GInputStream) in = NULL;
|
||||
|
||||
if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error))
|
||||
goto out;
|
||||
|
||||
checksum = g_checksum_new (checksum_type);
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GChecksum) checksum = g_checksum_new (checksum_type);
|
||||
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = g_strdup (g_checksum_get_string (checksum));
|
||||
out:
|
||||
g_clear_pointer (&checksum, (GDestroyNotify) g_checksum_free);
|
||||
return ret;
|
||||
return FALSE;
|
||||
|
||||
return g_strdup (g_checksum_get_string (checksum));
|
||||
}
|
||||
+25
-92
@@ -35,98 +35,6 @@ ot_fdrel_to_gfile (int dfd, const char *path)
|
||||
return g_file_new_for_path (abspath);
|
||||
}
|
||||
|
||||
int
|
||||
ot_opendirat (int dfd, const char *path, gboolean follow)
|
||||
{
|
||||
int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY;
|
||||
if (!follow)
|
||||
flags |= O_NOFOLLOW;
|
||||
return openat (dfd, path, flags);
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_gopendirat (int dfd,
|
||||
const char *path,
|
||||
gboolean follow,
|
||||
int *out_fd,
|
||||
GError **error)
|
||||
{
|
||||
int ret = ot_opendirat (dfd, path, follow);
|
||||
if (ret == -1)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
*out_fd = ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
ot_lgetxattrat (int dfd,
|
||||
const char *path,
|
||||
const char *attribute,
|
||||
GError **error)
|
||||
{
|
||||
/* A workaround for the lack of lgetxattrat(), thanks to Florian Weimer:
|
||||
* https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html
|
||||
*/
|
||||
g_autofree char *full_path = g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path);
|
||||
GBytes *bytes = NULL;
|
||||
ssize_t bytes_read, real_size;
|
||||
char *buf;
|
||||
|
||||
do
|
||||
bytes_read = lgetxattr (full_path, attribute, NULL, 0);
|
||||
while (G_UNLIKELY (bytes_read < 0 && errno == EINTR));
|
||||
if (G_UNLIKELY (bytes_read < 0))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = g_malloc (bytes_read);
|
||||
do
|
||||
real_size = lgetxattr (full_path, attribute, buf, bytes_read);
|
||||
while (G_UNLIKELY (real_size < 0 && errno == EINTR));
|
||||
if (G_UNLIKELY (real_size < 0))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
g_free (buf);
|
||||
goto out;
|
||||
}
|
||||
|
||||
bytes = g_bytes_new_take (buf, real_size);
|
||||
out:
|
||||
return bytes;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_lsetxattrat (int dfd,
|
||||
const char *path,
|
||||
const char *attribute,
|
||||
const void *value,
|
||||
gsize value_size,
|
||||
int flags,
|
||||
GError **error)
|
||||
{
|
||||
/* A workaround for the lack of lsetxattrat(), thanks to Florian Weimer:
|
||||
* https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html
|
||||
*/
|
||||
g_autofree char *full_path = g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path);
|
||||
int res;
|
||||
|
||||
do
|
||||
res = lsetxattr (full_path, "user.ostreemeta", value, value_size, flags);
|
||||
while (G_UNLIKELY (res == -1 && errno == EINTR));
|
||||
if (G_UNLIKELY (res == -1))
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_readlinkat_gfile_info (int dfd,
|
||||
const char *path,
|
||||
@@ -264,6 +172,31 @@ ot_openat_ignore_enoent (int dfd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Like glnx_dirfd_iterator_init_at(), but if %ENOENT, then set
|
||||
* @out_exists to %FALSE, and return successfully.
|
||||
*/
|
||||
gboolean
|
||||
ot_dfd_iter_init_allow_noent (int dfd,
|
||||
const char *path,
|
||||
GLnxDirFdIterator *dfd_iter,
|
||||
gboolean *out_exists,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int fd = glnx_opendirat_with_errno (dfd, path, TRUE);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return glnx_throw_errno_prefix (error, "opendirat");
|
||||
*out_exists = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
if (!glnx_dirfd_iterator_init_take_fd (fd, dfd_iter, error))
|
||||
return FALSE;
|
||||
fd = -1;
|
||||
*out_exists = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GBytes *
|
||||
ot_file_mapat_bytes (int dfd,
|
||||
const char *path,
|
||||
|
||||
@@ -21,31 +21,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "ot-unix-utils.h"
|
||||
#include "libglnx.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GFile * ot_fdrel_to_gfile (int dfd, const char *path);
|
||||
|
||||
int ot_opendirat (int dfd, const char *path, gboolean follow);
|
||||
gboolean ot_gopendirat (int dfd,
|
||||
const char *path,
|
||||
gboolean follow,
|
||||
int *out_fd,
|
||||
GError **error);
|
||||
|
||||
GBytes * ot_lgetxattrat (int dfd,
|
||||
const char *path,
|
||||
const char *attribute,
|
||||
GError **error);
|
||||
|
||||
gboolean ot_lsetxattrat (int dfd,
|
||||
const char *path,
|
||||
const char *attribute,
|
||||
const void *value,
|
||||
gsize value_size,
|
||||
int flags,
|
||||
GError **error);
|
||||
|
||||
gboolean ot_readlinkat_gfile_info (int dfd,
|
||||
const char *path,
|
||||
GFileInfo *target_info,
|
||||
@@ -73,6 +54,12 @@ gboolean ot_openat_ignore_enoent (int dfd,
|
||||
int *out_fd,
|
||||
GError **error);
|
||||
|
||||
gboolean ot_dfd_iter_init_allow_noent (int dfd,
|
||||
const char *path,
|
||||
GLnxDirFdIterator *dfd_iter,
|
||||
gboolean *out_exists,
|
||||
GError **error);
|
||||
|
||||
GBytes *ot_file_mapat_bytes (int dfd,
|
||||
const char *path,
|
||||
GError **error);
|
||||
|
||||
@@ -67,7 +67,6 @@ ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error,
|
||||
|
||||
gboolean
|
||||
ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx,
|
||||
const char *tmp_dir,
|
||||
char **out_tmp_home_dir,
|
||||
GOutputStream **out_pubring_stream,
|
||||
GCancellable *cancellable,
|
||||
@@ -85,10 +84,7 @@ ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx,
|
||||
* and hand the caller an open output stream to concatenate necessary
|
||||
* keyring files. */
|
||||
|
||||
if (tmp_dir == NULL)
|
||||
tmp_dir = g_get_tmp_dir ();
|
||||
|
||||
tmp_home_dir = g_build_filename (tmp_dir, "ostree-gpg-XXXXXX", NULL);
|
||||
tmp_home_dir = g_build_filename (g_get_tmp_dir (), "ostree-gpg-XXXXXX", NULL);
|
||||
|
||||
if (mkdtemp (tmp_home_dir) == NULL)
|
||||
{
|
||||
|
||||
@@ -34,7 +34,6 @@ GLNX_DEFINE_CLEANUP_FUNCTION0(gpgme_ctx_t, ot_cleanup_gpgme_ctx, gpgme_release)
|
||||
void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error);
|
||||
|
||||
gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx,
|
||||
const char *tmp_dir,
|
||||
char **out_tmp_home_dir,
|
||||
GOutputStream **out_pubring_stream,
|
||||
GCancellable *cancellable,
|
||||
|
||||
@@ -457,10 +457,10 @@ httpd_callback (SoupServer *server, SoupMessage *msg,
|
||||
|
||||
static void
|
||||
on_dir_changed (GFileMonitor *mon,
|
||||
GFile *file,
|
||||
GFile *other,
|
||||
GFileMonitorEvent event,
|
||||
gpointer user_data)
|
||||
GFile *file,
|
||||
GFile *other,
|
||||
GFileMonitorEvent event,
|
||||
gpointer user_data)
|
||||
{
|
||||
OtTrivialHttpd *self = user_data;
|
||||
|
||||
|
||||
@@ -47,12 +47,9 @@ static GOptionContext *
|
||||
ostree_admin_instutil_option_context_new_with_commands (void)
|
||||
{
|
||||
OstreeAdminInstUtilCommand *command = admin_instutil_subcommands;
|
||||
GOptionContext *context;
|
||||
GString *summary;
|
||||
GOptionContext *context = g_option_context_new ("COMMAND");
|
||||
|
||||
context = g_option_context_new ("COMMAND");
|
||||
|
||||
summary = g_string_new ("Builtin \"admin instutil\" Commands:");
|
||||
g_autoptr(GString) summary = g_string_new ("Builtin \"admin instutil\" Commands:");
|
||||
|
||||
while (command->name != NULL)
|
||||
{
|
||||
@@ -62,8 +59,6 @@ ostree_admin_instutil_option_context_new_with_commands (void)
|
||||
|
||||
g_option_context_set_summary (context, summary->str);
|
||||
|
||||
g_string_free (summary, TRUE);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment);
|
||||
g_autofree char *version = version_of_commit (repo, ref);
|
||||
glnx_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
GString *output_buffer;
|
||||
guint jj, n_signatures;
|
||||
GError *local_error = NULL;
|
||||
|
||||
@@ -159,6 +158,7 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
|
||||
if (deployment_get_gpg_verify (deployment, repo))
|
||||
{
|
||||
g_autoptr(GString) output_buffer = g_string_sized_new (256);
|
||||
/* Print any digital signatures on this commit. */
|
||||
|
||||
result = ostree_repo_verify_commit_ext (repo, ref, NULL, NULL,
|
||||
@@ -176,7 +176,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
goto out;
|
||||
}
|
||||
|
||||
output_buffer = g_string_sized_new (256);
|
||||
n_signatures = ostree_gpg_verify_result_count_all (result);
|
||||
|
||||
for (jj = 0; jj < n_signatures; jj++)
|
||||
@@ -186,7 +185,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
|
||||
}
|
||||
|
||||
g_print ("%s", output_buffer->str);
|
||||
g_string_free (output_buffer, TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ static GOptionEntry options[] = {
|
||||
gboolean
|
||||
ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
glnx_unref_object OstreeSysroot *sysroot = NULL;
|
||||
const char *deploy_index_str;
|
||||
@@ -48,16 +47,16 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr
|
||||
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
|
||||
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
|
||||
&sysroot, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
ot_util_usage_error (context, "INDEX must be specified", error);
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
current_deployments = ostree_sysroot_get_deployments (sysroot);
|
||||
|
||||
deploy_index_str = argv[1];
|
||||
@@ -65,31 +64,26 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr
|
||||
|
||||
target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error);
|
||||
if (!target_deployment)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (target_deployment == ostree_sysroot_get_booted_deployment (sysroot))
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"Cannot undeploy currently booted deployment %i", deploy_index);
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
g_ptr_array_remove_index (current_deployments, deploy_index);
|
||||
|
||||
if (!ostree_sysroot_write_deployments (sysroot, current_deployments,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_print ("Deleted deployment %s.%d\n", ostree_deployment_get_csum (target_deployment),
|
||||
ostree_deployment_get_deployserial (target_deployment));
|
||||
|
||||
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Performing final cleanup: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
|
||||
return glnx_prefix_error (error, "Performing final cleanup");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -33,20 +33,11 @@ ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
OstreeDeployment *booted_deployment =
|
||||
ostree_sysroot_get_booted_deployment (sysroot);
|
||||
|
||||
if (booted_deployment == NULL && osname == NULL)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Not currently booted into an OSTree system and no --os= argument given");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return glnx_throw (error, "Not currently booted into an OSTree system and no --os= argument given");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +132,7 @@ ot_admin_sysroot_lock (OstreeSysroot *sysroot,
|
||||
g_source_set_callback (timeout_src, (GSourceFunc)on_sysroot_lock_timeout, &state, NULL);
|
||||
g_source_attach (timeout_src, state.mainctx);
|
||||
g_source_unref (timeout_src);
|
||||
|
||||
|
||||
on_sysroot_lock_timeout (&state);
|
||||
|
||||
ostree_sysroot_lock_async (sysroot, NULL, (GAsyncReadyCallback)on_sysroot_lock_acquired, &state);
|
||||
@@ -161,14 +152,11 @@ gboolean
|
||||
ot_admin_execve_reboot (OstreeSysroot *sysroot, GError **error)
|
||||
{
|
||||
g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/");
|
||||
|
||||
|
||||
if (g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
|
||||
{
|
||||
if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0)
|
||||
{
|
||||
glnx_set_error_from_errno (error);
|
||||
return FALSE;
|
||||
}
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -56,12 +56,9 @@ static GOptionContext *
|
||||
ostree_admin_option_context_new_with_commands (void)
|
||||
{
|
||||
OstreeAdminCommand *command = admin_subcommands;
|
||||
GOptionContext *context;
|
||||
GString *summary;
|
||||
GOptionContext *context = g_option_context_new ("--print-current-dir|COMMAND");
|
||||
|
||||
context = g_option_context_new ("--print-current-dir|COMMAND");
|
||||
|
||||
summary = g_string_new ("Builtin \"admin\" Commands:");
|
||||
g_autoptr(GString) summary = g_string_new ("Builtin \"admin\" Commands:");
|
||||
|
||||
while (command->name != NULL)
|
||||
{
|
||||
@@ -71,8 +68,6 @@ ostree_admin_option_context_new_with_commands (void)
|
||||
|
||||
g_option_context_set_summary (context, summary->str);
|
||||
|
||||
g_string_free (summary, TRUE);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ static gboolean opt_from_stdin;
|
||||
static char *opt_from_file;
|
||||
static gboolean opt_disable_fsync;
|
||||
static gboolean opt_require_hardlinks;
|
||||
static gboolean opt_force_copy;
|
||||
|
||||
static gboolean
|
||||
parse_fsync_cb (const char *option_name,
|
||||
@@ -62,7 +63,7 @@ parse_fsync_cb (const char *option_name,
|
||||
static GOptionEntry options[] = {
|
||||
{ "user-mode", 'U', 0, G_OPTION_ARG_NONE, &opt_user_mode, "Do not change file ownership or initialize extended attributes", NULL },
|
||||
{ "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Do not update or use the internal repository uncompressed object cache", NULL },
|
||||
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
|
||||
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
|
||||
{ "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL },
|
||||
{ "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL },
|
||||
{ "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL },
|
||||
@@ -71,6 +72,7 @@ static GOptionEntry options[] = {
|
||||
{ "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" },
|
||||
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
|
||||
{ "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL },
|
||||
{ "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -89,7 +91,7 @@ process_one_checkout (OstreeRepo *repo,
|
||||
* `ostree_repo_checkout_at` until such time as we have a more
|
||||
* convenient infrastructure for testing C APIs with data.
|
||||
*/
|
||||
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add)
|
||||
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add || opt_force_copy)
|
||||
{
|
||||
OstreeRepoCheckoutAtOptions options = { 0, };
|
||||
|
||||
@@ -102,6 +104,11 @@ process_one_checkout (OstreeRepo *repo,
|
||||
"Cannot specify both --union and --union-add");
|
||||
goto out;
|
||||
}
|
||||
if (opt_require_hardlinks && opt_force_copy)
|
||||
{
|
||||
glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy");
|
||||
goto out;
|
||||
}
|
||||
else if (opt_union)
|
||||
options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
|
||||
else if (opt_union_add)
|
||||
@@ -111,6 +118,7 @@ process_one_checkout (OstreeRepo *repo,
|
||||
if (subpath)
|
||||
options.subpath = subpath;
|
||||
options.no_copy_fallback = opt_require_hardlinks;
|
||||
options.force_copy = opt_force_copy;
|
||||
|
||||
if (!ostree_repo_checkout_at (repo, &options,
|
||||
AT_FDCWD, destination,
|
||||
|
||||
@@ -76,7 +76,7 @@ static GOptionEntry options[] = {
|
||||
{ "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent ref, or \"none\"", "REF" },
|
||||
{ "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject", "SUBJECT" },
|
||||
{ "body", 'm', 0, G_OPTION_ARG_STRING, &opt_body, "Full description", "BODY" },
|
||||
{ "body-file", 'F', 0, G_OPTION_ARG_STRING, &opt_body_file, "Commit message from FILE path", "FILE" },
|
||||
{ "body-file", 'F', 0, G_OPTION_ARG_FILENAME, &opt_body_file, "Commit message from FILE path", "FILE" },
|
||||
{ "editor", 'e', 0, G_OPTION_ARG_NONE, &opt_editor, "Use an editor to write the commit message", NULL },
|
||||
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &opt_branch, "Branch", "BRANCH" },
|
||||
{ "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL },
|
||||
@@ -94,7 +94,7 @@ static GOptionEntry options[] = {
|
||||
{ "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" },
|
||||
{ "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL },
|
||||
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"},
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
{ "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes, "Generate size information along with commit metadata", NULL },
|
||||
{ "disable-fsync", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
|
||||
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
|
||||
@@ -218,7 +218,7 @@ commit_editor (OstreeRepo *repo,
|
||||
g_autofree char *input = NULL;
|
||||
g_autofree char *output = NULL;
|
||||
gboolean ret = FALSE;
|
||||
GString *bodybuf = NULL;
|
||||
g_autoptr(GString) bodybuf = NULL;
|
||||
char **lines = NULL;
|
||||
int i;
|
||||
|
||||
@@ -288,8 +288,6 @@ commit_editor (OstreeRepo *repo,
|
||||
|
||||
out:
|
||||
g_strfreev (lines);
|
||||
if (bodybuf)
|
||||
g_string_free (bodybuf, TRUE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ static gboolean opt_no_xattrs;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Skip output of extended attributes", NULL },
|
||||
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
|
||||
{ "prefix", 0, 0, G_OPTION_ARG_STRING, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" },
|
||||
{ "output", 'o', 0, G_OPTION_ARG_STRING, &opt_output_path, "Output to PATH ", "PATH" },
|
||||
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
|
||||
{ "prefix", 0, 0, G_OPTION_ARG_FILENAME, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" },
|
||||
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_path, "Output to PATH ", "PATH" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -246,6 +246,7 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError **
|
||||
gpointer key, value;
|
||||
gboolean found_corruption = FALSE;
|
||||
guint n_partial = 0;
|
||||
g_autoptr(GHashTable) all_refs = NULL;
|
||||
g_autoptr(GHashTable) objects = NULL;
|
||||
g_autoptr(GHashTable) commits = NULL;
|
||||
g_autoptr(GPtrArray) tombstones = NULL;
|
||||
@@ -254,6 +255,27 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError **
|
||||
if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!opt_quiet)
|
||||
g_print ("Validating refs...\n");
|
||||
|
||||
/* Validate that the commit for each ref is available */
|
||||
if (!ostree_repo_list_refs (repo, NULL, &all_refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
g_hash_table_iter_init (&hash_iter, all_refs);
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
const char *refname = key;
|
||||
const char *checksum = value;
|
||||
g_autoptr(GVariant) commit = NULL;
|
||||
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
|
||||
checksum, &commit, error))
|
||||
{
|
||||
g_prefix_error (error, "Loading commit for ref %s: ", refname);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt_quiet)
|
||||
g_print ("Enumerating objects...\n");
|
||||
|
||||
|
||||
@@ -26,13 +26,14 @@
|
||||
#include "ot-builtins.h"
|
||||
#include "ostree.h"
|
||||
#include "otutil.h"
|
||||
#include "ostree-core-private.h"
|
||||
|
||||
static gboolean opt_delete;
|
||||
static char *opt_gpg_homedir;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "delete", 'd', 0, G_OPTION_ARG_NONE, &opt_delete, "Delete signatures having any of the GPG KEY-IDs" },
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" },
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -85,7 +86,7 @@ delete_signatures (OstreeRepo *repo,
|
||||
g_variant_dict_init (&metadata_dict, old_metadata);
|
||||
|
||||
signature_data = g_variant_dict_lookup_value (&metadata_dict,
|
||||
"ostree.gpgsigs",
|
||||
_OSTREE_METADATA_GPGSIGS_NAME,
|
||||
G_VARIANT_TYPE ("aay"));
|
||||
|
||||
/* Taking the approach of deleting whatever matches we find for the
|
||||
@@ -154,7 +155,7 @@ delete_signatures (OstreeRepo *repo,
|
||||
/* Update the metadata dictionary. */
|
||||
if (g_queue_is_empty (&signatures))
|
||||
{
|
||||
g_variant_dict_remove (&metadata_dict, "ostree.gpgsigs");
|
||||
g_variant_dict_remove (&metadata_dict, _OSTREE_METADATA_GPGSIGS_NAME);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -170,7 +171,7 @@ delete_signatures (OstreeRepo *repo,
|
||||
}
|
||||
|
||||
g_variant_dict_insert_value (&metadata_dict,
|
||||
"ostree.gpgsigs",
|
||||
_OSTREE_METADATA_GPGSIGS_NAME,
|
||||
g_variant_builder_end (&signature_builder));
|
||||
}
|
||||
|
||||
|
||||
@@ -47,15 +47,13 @@ static void
|
||||
print_one_file_text (GFile *f,
|
||||
GFileInfo *file_info)
|
||||
{
|
||||
GString *buf = NULL;
|
||||
g_autoptr(GString) buf = g_string_new ("");
|
||||
char type_c;
|
||||
guint32 mode;
|
||||
guint32 type;
|
||||
|
||||
if (!ostree_repo_file_ensure_resolved ((OstreeRepoFile*)f, NULL))
|
||||
g_assert_not_reached ();
|
||||
|
||||
buf = g_string_new ("");
|
||||
|
||||
type_c = '?';
|
||||
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
|
||||
@@ -119,8 +117,6 @@ print_one_file_text (GFile *f,
|
||||
g_string_append_printf (buf, " -> %s", g_file_info_get_attribute_byte_string (file_info, "standard::symlink-target"));
|
||||
|
||||
g_print ("%s\n", buf->str);
|
||||
|
||||
g_string_free (buf, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -43,12 +43,12 @@ static char* opt_url;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL },
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
{ "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
|
||||
{ "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_disable_static_deltas, "Do not use static deltas", NULL },
|
||||
{ "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL },
|
||||
{ "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL },
|
||||
{ "subpath", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL },
|
||||
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL },
|
||||
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL },
|
||||
{ "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL },
|
||||
{ "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" },
|
||||
@@ -84,27 +84,29 @@ dry_run_console_progress_changed (OstreeAsyncProgress *progress,
|
||||
guint fetched_delta_parts, total_delta_parts;
|
||||
guint fetched_delta_part_fallbacks, total_delta_part_fallbacks;
|
||||
guint64 fetched_delta_part_size, total_delta_part_size, total_delta_part_usize;
|
||||
GString *buf;
|
||||
|
||||
g_assert (!printed_console_progress);
|
||||
printed_console_progress = TRUE;
|
||||
|
||||
/* Number of parts */
|
||||
fetched_delta_parts = ostree_async_progress_get_uint (progress, "fetched-delta-parts");
|
||||
total_delta_parts = ostree_async_progress_get_uint (progress, "total-delta-parts");
|
||||
fetched_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "fetched-delta-fallbacks");
|
||||
total_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "total-delta-fallbacks");
|
||||
ostree_async_progress_get (progress,
|
||||
/* Number of parts */
|
||||
"fetched-delta-parts", "u", &fetched_delta_parts,
|
||||
"total-delta-parts", "u", &total_delta_parts,
|
||||
"fetched-delta-fallbacks", "u", &fetched_delta_part_fallbacks,
|
||||
"total-delta-fallbacks", "u", &total_delta_part_fallbacks,
|
||||
/* Size variables */
|
||||
"fetched-delta-part-size", "t", &fetched_delta_part_size,
|
||||
"total-delta-part-size", "t", &total_delta_part_size,
|
||||
"total-delta-part-usize", "t", &total_delta_part_usize,
|
||||
NULL);
|
||||
|
||||
/* Fold the count of deltaparts + fallbacks for simplicity; if changing this,
|
||||
* please change ostree_repo_pull_default_console_progress_changed() first.
|
||||
*/
|
||||
fetched_delta_parts += fetched_delta_part_fallbacks;
|
||||
total_delta_parts += total_delta_part_fallbacks;
|
||||
/* Size variables */
|
||||
fetched_delta_part_size = ostree_async_progress_get_uint64 (progress, "fetched-delta-part-size");
|
||||
total_delta_part_size = ostree_async_progress_get_uint64 (progress, "total-delta-part-size");
|
||||
total_delta_part_usize = ostree_async_progress_get_uint64 (progress, "total-delta-part-usize");
|
||||
|
||||
buf = g_string_new ("");
|
||||
g_autoptr(GString) buf = g_string_new ("");
|
||||
|
||||
{ g_autofree char *formatted_fetched =
|
||||
g_format_size (fetched_delta_part_size);
|
||||
@@ -119,7 +121,6 @@ dry_run_console_progress_changed (OstreeAsyncProgress *progress,
|
||||
formatted_usize);
|
||||
}
|
||||
g_print ("%s\n", buf->str);
|
||||
g_string_free (buf, TRUE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
||||
@@ -51,12 +51,9 @@ static GOptionContext *
|
||||
remote_option_context_new_with_commands (void)
|
||||
{
|
||||
OstreeRemoteCommand *subcommand = remote_subcommands;
|
||||
GOptionContext *context;
|
||||
GString *summary;
|
||||
GOptionContext *context = g_option_context_new ("COMMAND");
|
||||
|
||||
context = g_option_context_new ("COMMAND");
|
||||
|
||||
summary = g_string_new ("Builtin \"remote\" Commands:");
|
||||
g_autoptr(GString) summary = g_string_new ("Builtin \"remote\" Commands:");
|
||||
|
||||
while (subcommand->name != NULL)
|
||||
{
|
||||
@@ -66,8 +63,6 @@ remote_option_context_new_with_commands (void)
|
||||
|
||||
g_option_context_set_summary (context, summary->str);
|
||||
|
||||
g_string_free (summary, TRUE);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ static GOptionEntry options[] = {
|
||||
{ "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" },
|
||||
{ "print-detached-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_detached_metadata_key, "Print string value of detached metadata key", "KEY" },
|
||||
{ "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" },
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
{ "gpg-verify-remote", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_verify_remote, "Use REMOTE name for GPG configuration", "REMOTE"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -72,7 +72,7 @@ static GOptionEntry generate_options[] = {
|
||||
{ "min-fallback-size", 0, 0, G_OPTION_ARG_STRING, &opt_min_fallback_size, "Minimum uncompressed size in megabytes for individual HTTP request", NULL},
|
||||
{ "max-bsdiff-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_bsdiff_size, "Maximum size in megabytes to consider bsdiff compression for input files", NULL},
|
||||
{ "max-chunk-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_chunk_size, "Maximum size of delta chunks in megabytes", NULL},
|
||||
{ "filename", 0, 0, G_OPTION_ARG_STRING, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"},
|
||||
{ "filename", 0, 0, G_OPTION_ARG_FILENAME, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -20,19 +20,23 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ot-dump.h"
|
||||
#include "ot-main.h"
|
||||
#include "ot-builtins.h"
|
||||
#include "ostree.h"
|
||||
#include "otutil.h"
|
||||
|
||||
static gboolean opt_update;
|
||||
static gboolean opt_update, opt_view, opt_raw;
|
||||
static char **opt_key_ids;
|
||||
static char *opt_gpg_homedir;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL },
|
||||
{ "view", 'v', 0, G_OPTION_ARG_NONE, &opt_view, "View the local summary file", NULL },
|
||||
{ "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "View the raw bytes of the summary file", NULL },
|
||||
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"},
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -42,6 +46,7 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
OstreeDumpFlags flags = OSTREE_DUMP_NONE;
|
||||
|
||||
context = g_option_context_new ("Manage summary metadata");
|
||||
|
||||
@@ -66,6 +71,19 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
else if (opt_view)
|
||||
{
|
||||
g_autoptr(GBytes) summary_data = NULL;
|
||||
|
||||
if (opt_raw)
|
||||
flags |= OSTREE_DUMP_RAW;
|
||||
|
||||
summary_data = ot_file_mapat_bytes (repo->repo_dir_fd, "summary", error);
|
||||
if (!summary_data)
|
||||
goto out;
|
||||
|
||||
ot_dump_summary_bytes (summary_data, flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
|
||||
+42
-4
@@ -26,6 +26,8 @@
|
||||
|
||||
#include <err.h>
|
||||
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ostree-repo-static-delta-private.h"
|
||||
#include "ot-dump.h"
|
||||
#include "otutil.h"
|
||||
#include "ot-admin-functions.h"
|
||||
@@ -199,6 +201,18 @@ dump_summary_ref (const char *ref_name,
|
||||
}
|
||||
}
|
||||
|
||||
static gchar *
|
||||
uint64_secs_to_iso8601 (guint64 secs)
|
||||
{
|
||||
g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs);
|
||||
g_autoptr(GDateTime) local = (dt != NULL) ? g_date_time_to_local (dt) : NULL;
|
||||
|
||||
if (local != NULL)
|
||||
return g_date_time_format (local, "%FT%T%:::z");
|
||||
else
|
||||
return g_strdup ("invalid");
|
||||
}
|
||||
|
||||
void
|
||||
ot_dump_summary_bytes (GBytes *summary_bytes,
|
||||
OstreeDumpFlags flags)
|
||||
@@ -251,11 +265,35 @@ ot_dump_summary_bytes (GBytes *summary_bytes,
|
||||
|
||||
g_variant_iter_init (&iter, exts);
|
||||
|
||||
/* XXX Should we print something more human-friendly for
|
||||
* known extension names like 'ostree.static-deltas'? */
|
||||
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
|
||||
{
|
||||
g_autofree char *string = g_variant_print (value, FALSE);
|
||||
g_print ("%s: %s\n", key, string);
|
||||
g_autofree gchar *value_str = NULL;
|
||||
const gchar *pretty_key = NULL;
|
||||
|
||||
if (g_strcmp0 (key, OSTREE_SUMMARY_STATIC_DELTAS) == 0)
|
||||
{
|
||||
pretty_key = "Static Deltas";
|
||||
value_str = g_variant_print (value, FALSE);
|
||||
}
|
||||
else if (g_strcmp0 (key, OSTREE_SUMMARY_LAST_MODIFIED) == 0)
|
||||
{
|
||||
pretty_key = "Last-Modified";
|
||||
value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value)));
|
||||
}
|
||||
else if (g_strcmp0 (key, OSTREE_SUMMARY_EXPIRES) == 0)
|
||||
{
|
||||
pretty_key = "Expires";
|
||||
value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value)));
|
||||
}
|
||||
else
|
||||
{
|
||||
value_str = g_variant_print (value, FALSE);
|
||||
}
|
||||
|
||||
/* Print out. */
|
||||
if (pretty_key != NULL)
|
||||
g_print ("%s (%s): %s\n", pretty_key, key, value_str);
|
||||
else
|
||||
g_print ("%s: %s\n", key, value_str);
|
||||
}
|
||||
}
|
||||
+23
-53
@@ -45,26 +45,23 @@ static GOptionEntry global_entries[] = {
|
||||
};
|
||||
|
||||
static GOptionEntry repo_entry[] = {
|
||||
{ "repo", 0, 0, G_OPTION_ARG_STRING, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
|
||||
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static GOptionEntry global_admin_entries[] = {
|
||||
/* No description since it's hidden from --help output. */
|
||||
{ "print-current-dir", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_print_current_dir, NULL, NULL },
|
||||
{ "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" },
|
||||
{ "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static GOptionContext *
|
||||
ostree_option_context_new_with_commands (OstreeCommand *commands)
|
||||
{
|
||||
GOptionContext *context;
|
||||
GString *summary;
|
||||
GOptionContext *context = g_option_context_new ("COMMAND");
|
||||
|
||||
context = g_option_context_new ("COMMAND");
|
||||
|
||||
summary = g_string_new ("Builtin Commands:");
|
||||
g_autoptr(GString) summary = g_string_new ("Builtin Commands:");
|
||||
|
||||
while (commands->name != NULL)
|
||||
{
|
||||
@@ -74,8 +71,6 @@ ostree_option_context_new_with_commands (OstreeCommand *commands)
|
||||
|
||||
g_option_context_set_summary (context, summary->str);
|
||||
|
||||
g_string_free (summary, TRUE);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -223,7 +218,6 @@ ostree_option_context_parse (GOptionContext *context,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
gboolean success = FALSE;
|
||||
|
||||
/* Entries are listed in --help output in the order added. We add the
|
||||
* main entries ourselves so that we can add the --repo entry first. */
|
||||
@@ -278,7 +272,7 @@ ostree_option_context_parse (GOptionContext *context,
|
||||
{
|
||||
g_propagate_error (error, g_steal_pointer (&local_error));
|
||||
}
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (opt_repo != NULL)
|
||||
@@ -289,17 +283,14 @@ ostree_option_context_parse (GOptionContext *context,
|
||||
if (!(flags & OSTREE_BUILTIN_FLAG_NO_CHECK))
|
||||
{
|
||||
if (!ostree_repo_open (repo, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_repo)
|
||||
*out_repo = g_steal_pointer (&repo);
|
||||
|
||||
success = TRUE;
|
||||
|
||||
out:
|
||||
return success;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -312,22 +303,19 @@ ostree_admin_option_context_parse (GOptionContext *context,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFile) sysroot_path = NULL;
|
||||
glnx_unref_object OstreeSysroot *sysroot = NULL;
|
||||
gboolean success = FALSE;
|
||||
|
||||
/* Entries are listed in --help output in the order added. We add the
|
||||
* main entries ourselves so that we can add the --sysroot entry first. */
|
||||
|
||||
g_option_context_add_main_entries (context, global_admin_entries, NULL);
|
||||
|
||||
if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GFile) sysroot_path = NULL;
|
||||
if (opt_sysroot != NULL)
|
||||
sysroot_path = g_file_new_for_path (opt_sysroot);
|
||||
|
||||
sysroot = ostree_sysroot_new (sysroot_path);
|
||||
glnx_unref_object OstreeSysroot *sysroot = ostree_sysroot_new (sysroot_path);
|
||||
|
||||
if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER)
|
||||
{
|
||||
@@ -338,7 +326,7 @@ ostree_admin_option_context_parse (GOptionContext *context,
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
||||
"You must be root to perform this command");
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,15 +338,11 @@ ostree_admin_option_context_parse (GOptionContext *context,
|
||||
g_autofree char *deployment_path = NULL;
|
||||
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
deployments = ostree_sysroot_get_deployments (sysroot);
|
||||
if (deployments->len == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Unable to find a deployment in sysroot");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Unable to find a deployment in sysroot");
|
||||
first_deployment = deployments->pdata[0];
|
||||
deployment_file = ostree_sysroot_get_deployment_directory (sysroot, first_deployment);
|
||||
deployment_path = g_file_get_path (deployment_file);
|
||||
@@ -379,46 +363,36 @@ ostree_admin_option_context_parse (GOptionContext *context,
|
||||
{
|
||||
/* Released when sysroot is finalized, or on process exit */
|
||||
if (!ot_admin_sysroot_lock (sysroot, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (out_sysroot)
|
||||
*out_sysroot = g_steal_pointer (&sysroot);
|
||||
|
||||
success = TRUE;
|
||||
|
||||
out:
|
||||
return success;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
ostree_ensure_repo_writable (OstreeRepo *repo,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret;
|
||||
|
||||
ret = ostree_repo_is_writable (repo, error);
|
||||
|
||||
g_prefix_error (error, "Cannot write to repository: ");
|
||||
|
||||
return ret;
|
||||
if (!ostree_repo_is_writable (repo, error))
|
||||
return glnx_prefix_error (error, "Cannot write to repository");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result)
|
||||
{
|
||||
GString *buffer;
|
||||
guint n_sigs, ii;
|
||||
|
||||
n_sigs = ostree_gpg_verify_result_count_all (result);
|
||||
guint n_sigs = ostree_gpg_verify_result_count_all (result);
|
||||
|
||||
/* XXX If we ever add internationalization, use ngettext() here. */
|
||||
g_print ("GPG: Verification enabled, found %u signature%s:\n",
|
||||
n_sigs, n_sigs == 1 ? "" : "s");
|
||||
|
||||
buffer = g_string_sized_new (256);
|
||||
g_autoptr(GString) buffer = g_string_sized_new (256);
|
||||
|
||||
for (ii = 0; ii < n_sigs; ii++)
|
||||
for (guint ii = 0; ii < n_sigs; ii++)
|
||||
{
|
||||
g_string_append_c (buffer, '\n');
|
||||
ostree_gpg_verify_result_describe (result, ii, buffer, " ",
|
||||
@@ -426,13 +400,11 @@ ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result)
|
||||
}
|
||||
|
||||
g_print ("%s", buffer->str);
|
||||
g_string_free (buffer, TRUE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
ot_enable_tombstone_commits (OstreeRepo *repo, GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
gboolean tombstone_commits = FALSE;
|
||||
GKeyFile *config = ostree_repo_get_config (repo);
|
||||
|
||||
@@ -442,10 +414,8 @@ ot_enable_tombstone_commits (OstreeRepo *repo, GError **error)
|
||||
{
|
||||
g_key_file_set_boolean (config, "core", "tombstone-commits", TRUE);
|
||||
if (!ostree_repo_write_config (repo, config, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
static char* opt_cache_dir;
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ static gboolean opt_raw;
|
||||
static char* opt_cache_dir;
|
||||
|
||||
static GOptionEntry option_entries[] = {
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
{ "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL },
|
||||
{ "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -298,14 +298,18 @@ ot_list_cookies_at (int dfd, const char *jar_path, GError **error)
|
||||
while (ot_parse_cookies_next (parser))
|
||||
{
|
||||
g_autoptr(GDateTime) expires = g_date_time_new_from_unix_utc (parser->expiration);
|
||||
g_autofree char *expires_str = g_date_time_format (expires, "%Y-%m-%d %H:%M:%S +0000");
|
||||
g_autofree char *expires_str = NULL;
|
||||
|
||||
if (expires != NULL)
|
||||
expires_str = g_date_time_format (expires, "%Y-%m-%d %H:%M:%S +0000");
|
||||
|
||||
g_print ("--\n");
|
||||
g_print ("Domain: %s\n", parser->domain);
|
||||
g_print ("Path: %s\n", parser->path);
|
||||
g_print ("Name: %s\n", parser->name);
|
||||
g_print ("Secure: %s\n", parser->secure);
|
||||
g_print ("Expires: %s\n", expires_str);
|
||||
if (expires_str != NULL)
|
||||
g_print ("Expires: %s\n", expires_str);
|
||||
g_print ("Value: %s\n", parser->value);
|
||||
}
|
||||
#else
|
||||
|
||||
+39
-40
@@ -56,12 +56,12 @@ callback_getattr (const char *path, struct stat *st_data)
|
||||
if (!*path)
|
||||
{
|
||||
if (fstat (basefd, st_data) == -1)
|
||||
return -errno;
|
||||
return -errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fstatat (basefd, path, st_data, AT_SYMLINK_NOFOLLOW) == -1)
|
||||
return -errno;
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ callback_readlink (const char *path, char *buf, size_t size)
|
||||
|
||||
static int
|
||||
callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
{
|
||||
DIR *dp;
|
||||
struct dirent *de;
|
||||
@@ -102,7 +102,7 @@ callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
{
|
||||
dfd = openat (basefd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
|
||||
if (dfd == -1)
|
||||
return -errno;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
/* Transfers ownership of fd */
|
||||
@@ -117,7 +117,7 @@ callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
|
||||
st.st_ino = de->d_ino;
|
||||
st.st_mode = de->d_type << 12;
|
||||
if (filler (buf, de->d_name, &st, 0))
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
(void) closedir (dp);
|
||||
@@ -170,7 +170,7 @@ callback_symlink (const char *from, const char *to)
|
||||
if (fstatat (basefd, to, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
|
||||
{
|
||||
fprintf (stderr, "Failed to find newly created symlink '%s': %s\n",
|
||||
to, g_strerror (errno));
|
||||
to, g_strerror (errno));
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
@@ -209,19 +209,19 @@ can_write (const char *path)
|
||||
if (fstatat (basefd, path, &stbuf, 0) == -1)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
return 0;
|
||||
else
|
||||
return -errno;
|
||||
return -errno;
|
||||
}
|
||||
if (stbuf_is_regfile_hardlinked (&stbuf))
|
||||
return -EROFS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define VERIFY_WRITE(path) do { \
|
||||
int r = can_write (path); \
|
||||
if (r != 0) \
|
||||
return r; \
|
||||
#define VERIFY_WRITE(path) do { \
|
||||
int r = can_write (path); \
|
||||
if (r != 0) \
|
||||
return r; \
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
@@ -366,7 +366,7 @@ callback_read_buf (const char *path, struct fuse_bufvec **bufp,
|
||||
|
||||
static int
|
||||
callback_read (const char *path, char *buf, size_t size, off_t offset,
|
||||
struct fuse_file_info *finfo)
|
||||
struct fuse_file_info *finfo)
|
||||
{
|
||||
int r;
|
||||
r = pread (finfo->fh, buf, size, offset);
|
||||
@@ -390,7 +390,7 @@ callback_write_buf (const char *path, struct fuse_bufvec *buf, off_t offset,
|
||||
|
||||
static int
|
||||
callback_write (const char *path, const char *buf, size_t size, off_t offset,
|
||||
struct fuse_file_info *finfo)
|
||||
struct fuse_file_info *finfo)
|
||||
{
|
||||
int r;
|
||||
r = pwrite (finfo->fh, buf, size, offset);
|
||||
@@ -426,7 +426,7 @@ static int
|
||||
callback_access (const char *path, int mode)
|
||||
{
|
||||
path = ENSURE_RELPATH (path);
|
||||
|
||||
|
||||
/* Apparently at least GNU coreutils rm calls `faccessat(W_OK)`
|
||||
* before trying to do an unlink. So...we'll just lie about
|
||||
* writable access here.
|
||||
@@ -438,14 +438,14 @@ callback_access (const char *path, int mode)
|
||||
|
||||
static int
|
||||
callback_setxattr (const char *path, const char *name, const char *value,
|
||||
size_t size, int flags)
|
||||
size_t size, int flags)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
static int
|
||||
callback_getxattr (const char *path, const char *name, char *value,
|
||||
size_t size)
|
||||
size_t size)
|
||||
{
|
||||
return -ENOTSUP;
|
||||
}
|
||||
@@ -503,8 +503,7 @@ struct fuse_operations callback_oper = {
|
||||
.removexattr = callback_removexattr
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
KEY_HELP,
|
||||
KEY_VERSION,
|
||||
};
|
||||
@@ -513,19 +512,19 @@ static void
|
||||
usage (const char *progname)
|
||||
{
|
||||
fprintf (stdout,
|
||||
"usage: %s basepath mountpoint [options]\n"
|
||||
"\n"
|
||||
" Makes basepath visible at mountpoint such that files are read-only, directories are writable\n"
|
||||
"\n"
|
||||
"general options:\n"
|
||||
" -o opt,[opt...] mount options\n"
|
||||
" -h --help print help\n"
|
||||
"\n", progname);
|
||||
"usage: %s basepath mountpoint [options]\n"
|
||||
"\n"
|
||||
" Makes basepath visible at mountpoint such that files are read-only, directories are writable\n"
|
||||
"\n"
|
||||
"general options:\n"
|
||||
" -o opt,[opt...] mount options\n"
|
||||
" -h --help print help\n"
|
||||
"\n", progname);
|
||||
}
|
||||
|
||||
static int
|
||||
rofs_parse_opt (void *data, const char *arg, int key,
|
||||
struct fuse_args *outargs)
|
||||
struct fuse_args *outargs)
|
||||
{
|
||||
(void) data;
|
||||
|
||||
@@ -533,19 +532,19 @@ rofs_parse_opt (void *data, const char *arg, int key,
|
||||
{
|
||||
case FUSE_OPT_KEY_NONOPT:
|
||||
if (basefd == -1)
|
||||
{
|
||||
basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
|
||||
if (basefd == -1)
|
||||
{
|
||||
perror ("openat");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
{
|
||||
basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
|
||||
if (basefd == -1)
|
||||
{
|
||||
perror ("openat");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
case FUSE_OPT_KEY_OPT:
|
||||
return 1;
|
||||
case KEY_HELP:
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
#include <err.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
static inline int
|
||||
path_is_on_readonly_fs (char *path)
|
||||
@@ -37,4 +41,66 @@ path_is_on_readonly_fs (char *path)
|
||||
return (stvfsbuf.f_flag & ST_RDONLY) != 0;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
read_proc_cmdline (void)
|
||||
{
|
||||
FILE *f = fopen("/proc/cmdline", "r");
|
||||
char *cmdline = NULL;
|
||||
size_t len;
|
||||
|
||||
if (!f)
|
||||
goto out;
|
||||
|
||||
/* Note that /proc/cmdline will not end in a newline, so getline
|
||||
* will fail unelss we provide a length.
|
||||
*/
|
||||
if (getline (&cmdline, &len, f) < 0)
|
||||
goto out;
|
||||
/* ... but the length will be the size of the malloc buffer, not
|
||||
* strlen(). Fix that.
|
||||
*/
|
||||
len = strlen (cmdline);
|
||||
|
||||
if (cmdline[len-1] == '\n')
|
||||
cmdline[len-1] = '\0';
|
||||
out:
|
||||
if (f)
|
||||
fclose (f);
|
||||
return cmdline;
|
||||
}
|
||||
|
||||
static inline char *
|
||||
read_proc_cmdline_ostree (void)
|
||||
{
|
||||
char *cmdline = NULL;
|
||||
const char *iter;
|
||||
char *ret = NULL;
|
||||
|
||||
cmdline = read_proc_cmdline ();
|
||||
if (!cmdline)
|
||||
err (EXIT_FAILURE, "failed to read /proc/cmdline");
|
||||
|
||||
iter = cmdline;
|
||||
while (iter != NULL)
|
||||
{
|
||||
const char *next = strchr (iter, ' ');
|
||||
const char *next_nonspc = next;
|
||||
while (next_nonspc && *next_nonspc == ' ')
|
||||
next_nonspc += 1;
|
||||
if (strncmp (iter, "ostree=", strlen ("ostree=")) == 0)
|
||||
{
|
||||
const char *start = iter + strlen ("ostree=");
|
||||
if (next)
|
||||
ret = strndup (start, next - start);
|
||||
else
|
||||
ret = strdup (start);
|
||||
break;
|
||||
}
|
||||
iter = next_nonspc;
|
||||
}
|
||||
|
||||
free (cmdline);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* __OSTREE_MOUNT_UTIL_H_ */
|
||||
@@ -1,13 +1,13 @@
|
||||
/* -*- c-file-style: "gnu" -*-
|
||||
* Switch to new root directory and start init.
|
||||
*
|
||||
*
|
||||
* Copyright 2011,2012,2013 Colin Walters <walters@verbum.org>
|
||||
*
|
||||
* Based on code from util-linux/sys-utils/switch_root.c,
|
||||
* Based on code from util-linux/sys-utils/switch_root.c,
|
||||
* Copyright 2002-2009 Red Hat, Inc. All rights reserved.
|
||||
* Authors:
|
||||
* Peter Jones <pjones@redhat.com>
|
||||
* Jeremy Katz <katzj@redhat.com>
|
||||
* Peter Jones <pjones@redhat.com>
|
||||
* Jeremy Katz <katzj@redhat.com>
|
||||
*
|
||||
* Relicensed with permission to LGPLv2+.
|
||||
*
|
||||
@@ -46,68 +46,6 @@
|
||||
|
||||
#include "ostree-mount-util.h"
|
||||
|
||||
static char *
|
||||
read_proc_cmdline (void)
|
||||
{
|
||||
FILE *f = fopen("/proc/cmdline", "r");
|
||||
char *cmdline = NULL;
|
||||
size_t len;
|
||||
|
||||
if (!f)
|
||||
goto out;
|
||||
|
||||
/* Note that /proc/cmdline will not end in a newline, so getline
|
||||
* will fail unelss we provide a length.
|
||||
*/
|
||||
if (getline (&cmdline, &len, f) < 0)
|
||||
goto out;
|
||||
/* ... but the length will be the size of the malloc buffer, not
|
||||
* strlen(). Fix that.
|
||||
*/
|
||||
len = strlen (cmdline);
|
||||
|
||||
if (cmdline[len-1] == '\n')
|
||||
cmdline[len-1] = '\0';
|
||||
out:
|
||||
if (f)
|
||||
fclose (f);
|
||||
return cmdline;
|
||||
}
|
||||
|
||||
static char *
|
||||
parse_ostree_cmdline (void)
|
||||
{
|
||||
char *cmdline = NULL;
|
||||
const char *iter;
|
||||
char *ret = NULL;
|
||||
|
||||
cmdline = read_proc_cmdline ();
|
||||
if (!cmdline)
|
||||
err (EXIT_FAILURE, "failed to read /proc/cmdline");
|
||||
|
||||
iter = cmdline;
|
||||
while (iter != NULL)
|
||||
{
|
||||
const char *next = strchr (iter, ' ');
|
||||
const char *next_nonspc = next;
|
||||
while (next_nonspc && *next_nonspc == ' ')
|
||||
next_nonspc += 1;
|
||||
if (strncmp (iter, "ostree=", strlen ("ostree=")) == 0)
|
||||
{
|
||||
const char *start = iter + strlen ("ostree=");
|
||||
if (next)
|
||||
ret = strndup (start, next - start);
|
||||
else
|
||||
ret = strdup (start);
|
||||
break;
|
||||
}
|
||||
iter = next_nonspc;
|
||||
}
|
||||
|
||||
free (cmdline);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* This is an API for other projects to determine whether or not the
|
||||
* currently running system is ostree-controlled.
|
||||
*/
|
||||
@@ -115,8 +53,8 @@ static void
|
||||
touch_run_ostree (void)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY, 0640);
|
||||
|
||||
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.
|
||||
*/
|
||||
@@ -132,7 +70,7 @@ resolve_deploy_path (const char * root_mountpoint)
|
||||
struct stat stbuf;
|
||||
char *ostree_target, *deploy_path;
|
||||
|
||||
ostree_target = parse_ostree_cmdline ();
|
||||
ostree_target = read_proc_cmdline_ostree ();
|
||||
if (!ostree_target)
|
||||
errx (EXIT_FAILURE, "No OSTree target; expected ostree=/ostree/boot.N/...");
|
||||
|
||||
@@ -211,9 +149,12 @@ main(int argc, char *argv[])
|
||||
if (chdir (deploy_path) < 0)
|
||||
err (EXIT_FAILURE, "failed to chdir to deploy_path");
|
||||
|
||||
/* In the systemd case, this is handled by ostree-system-generator */
|
||||
#ifndef HAVE_SYSTEMD_AND_LIBMOUNT
|
||||
/* Link to the deployment's /var */
|
||||
if (mount ("../../var", "var", NULL, MS_MGC_VAL|MS_BIND, NULL) < 0)
|
||||
err (EXIT_FAILURE, "failed to bind mount ../../var to var");
|
||||
#endif
|
||||
|
||||
/* If /boot is on the same partition, use a bind mount to make it visible
|
||||
* at /boot inside the deployment. */
|
||||
@@ -239,11 +180,11 @@ main(int argc, char *argv[])
|
||||
* later boot and `systemd-remount-fs.service`.
|
||||
*/
|
||||
if (path_is_on_readonly_fs ("."))
|
||||
{
|
||||
if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
|
||||
err (EXIT_FAILURE, "failed to remount rootfs writable (for overlayfs)");
|
||||
}
|
||||
|
||||
{
|
||||
if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
|
||||
err (EXIT_FAILURE, "failed to remount rootfs writable (for overlayfs)");
|
||||
}
|
||||
|
||||
if (mount ("overlay", "usr", "overlay", 0, usr_ovl_options) < 0)
|
||||
err (EXIT_FAILURE, "failed to mount /usr overlayfs");
|
||||
}
|
||||
|
||||
@@ -38,28 +38,10 @@
|
||||
|
||||
#include "ostree-mount-util.h"
|
||||
|
||||
/* Having a writeable /var is necessary for full system functioning.
|
||||
* If /var isn't writeable, we mount tmpfs over it. While this is
|
||||
* somewhat outside of ostree's scope, having all /var twiddling
|
||||
* in one place will make future maintenance easier.
|
||||
*/
|
||||
static void
|
||||
maybe_mount_tmpfs_on_var (void)
|
||||
{
|
||||
if (!path_is_on_readonly_fs ("/var"))
|
||||
return;
|
||||
|
||||
if (umount ("/var") < 0 && errno != EINVAL)
|
||||
warn ("failed to unmount /var prior to mounting tmpfs, mounting over");
|
||||
|
||||
if (mount ("tmpfs", "/var", "tmpfs", 0, NULL) < 0)
|
||||
err (EXIT_FAILURE, "failed to mount tmpfs on /var");
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
const char *remounts[] = { "/sysroot", "/etc", "/home", "/root", "/tmp", "/var", NULL };
|
||||
const char *remounts[] = { "/sysroot", "/var", NULL };
|
||||
struct stat stbuf;
|
||||
int i;
|
||||
|
||||
@@ -69,8 +51,6 @@ main(int argc, char *argv[])
|
||||
* to clear the readonly flag in that case.
|
||||
*/
|
||||
|
||||
maybe_mount_tmpfs_on_var ();
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -84,17 +64,25 @@ main(int argc, char *argv[])
|
||||
*/
|
||||
if (S_ISLNK (stbuf.st_mode))
|
||||
continue;
|
||||
/* If not a mountpoint, skip it */
|
||||
struct statvfs stvfsbuf;
|
||||
if (statvfs (target, &stvfsbuf) == -1)
|
||||
continue;
|
||||
/* If no read-only flag, skip it */
|
||||
if ((stvfsbuf.f_flag & ST_RDONLY) == 0)
|
||||
continue;
|
||||
/* It's a mounted, read-only fs; remount it */
|
||||
if (mount (target, target, NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
|
||||
{
|
||||
{
|
||||
/* Also ignore ENINVAL - if the target isn't a mountpoint
|
||||
* already, then assume things are OK.
|
||||
*/
|
||||
if (errno != EINVAL)
|
||||
err (EXIT_FAILURE, "failed to remount %s", target);
|
||||
}
|
||||
}
|
||||
else
|
||||
printf ("Remounted: %s\n", target);
|
||||
}
|
||||
|
||||
maybe_mount_tmpfs_on_var ();
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
|
||||
*
|
||||
* 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 <err.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ostree-cmdprivate.h"
|
||||
#include "ostree-mount-util.h"
|
||||
|
||||
static const char *arg_dest = "/tmp";
|
||||
static const char *arg_dest_late = "/tmp";
|
||||
|
||||
/* This program is a simple stub that calls the implementation that
|
||||
* lives inside libostree.
|
||||
*/
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
/* Important: if this isn't an ostree-booted system, do nothing; people could
|
||||
* have the package installed as a dependency for flatpak or whatever.
|
||||
*/
|
||||
{ struct stat stbuf;
|
||||
if (fstatat (AT_FDCWD, "/run/ostree-booted", &stbuf, 0) < 0)
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (argc > 1 && argc != 4)
|
||||
errx (EXIT_FAILURE, "This program takes three or no arguments");
|
||||
|
||||
if (argc > 1)
|
||||
arg_dest = argv[1];
|
||||
if (argc > 3)
|
||||
arg_dest_late = argv[3];
|
||||
|
||||
char *ostree_cmdline = read_proc_cmdline_ostree ();
|
||||
if (!ostree_cmdline)
|
||||
errx (EXIT_FAILURE, "Failed to find ostree= kernel argument");
|
||||
|
||||
{ g_autoptr(GError) local_error = NULL;
|
||||
if (!ostree_cmd__private__()->ostree_system_generator (ostree_cmdline, arg_dest, NULL, arg_dest_late, &local_error))
|
||||
errx (EXIT_FAILURE, "%s", local_error->message);
|
||||
}
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
Reference in new issue
Block a user