New upstream version 2017.6

This commit is contained in:
Simon McVittie committed 2017-05-24 19:00:16 +01:00
commit e3060b1b87
168 files changed
+5181 -3686

No files matched your search

+31
View File
@@ -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;
+9 -2
View File
@@ -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
+1
View File
@@ -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
+241 -75
View File
@@ -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));
}
/**
+15
View File
@@ -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);
+4
View File
@@ -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
+15 -31
View File
@@ -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,
+1 -3
View File
@@ -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;
}
+1
View File
@@ -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,
+3
View File
@@ -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);
+8
View File
@@ -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
View File
@@ -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;
}
/**
+18 -7
View File
@@ -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)
+6
View File
@@ -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
View File
@@ -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;
}
/**
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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;
+16
View File
@@ -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 (&regex_initialized))
{
regex = g_regex_new ("^/ostree/boot.[01]/([^/]+)/", 0, 0, NULL);
g_assert (regex);
g_once_init_leave (&regex_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
}
+59
View File
@@ -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
+150
View File
@@ -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 (&regex_initialized))
{
regex = g_regex_new ("^remote \"(.+)\"$", 0, 0, NULL);
g_assert (regex);
g_once_init_leave (&regex_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
+63
View File
@@ -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
+36 -41
View File
@@ -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,
+42 -3
View File
@@ -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
+33 -68
View File
@@ -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
View File
@@ -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
*/
+57 -67
View File
@@ -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;
}
File diff suppressed because it is too large. Load diff
+5 -2
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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));
}
+53 -93
View File
@@ -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))
+27 -26
View File
@@ -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))
+2 -1
View File
@@ -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);
+43 -86
View File
@@ -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
View File
@@ -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 (&regex_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 (&regex_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 (&regex_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 (&regex_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;
}
/**
+4
View File
@@ -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
+3 -3
View File
@@ -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))
+3
View File
@@ -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>