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>
+18 -40
View File
@@ -47,7 +47,7 @@ ot_csum_from_gchecksum (GChecksum *checksum)
{
guchar *ret = g_malloc (32);
gsize len = 32;
g_checksum_get_digest (checksum, ret, &len);
g_assert (len == 32);
return ret;
@@ -62,13 +62,11 @@ ot_gio_write_update_checksum (GOutputStream *out,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
if (out)
{
if (!g_output_stream_write_all (out, data, len, out_bytes_written,
cancellable, error))
goto out;
return FALSE;
}
else if (out_bytes_written)
{
@@ -77,10 +75,7 @@ ot_gio_write_update_checksum (GOutputStream *out,
if (checksum)
g_checksum_update (checksum, data, len);
ret = TRUE;
out:
return ret;
return TRUE;
}
gboolean
@@ -90,8 +85,6 @@ ot_gio_splice_update_checksum (GOutputStream *out,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_return_val_if_fail (out != NULL || checksum != NULL, FALSE);
if (checksum != NULL)
@@ -101,24 +94,25 @@ ot_gio_splice_update_checksum (GOutputStream *out,
do
{
if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error))
goto out;
return FALSE;
if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum,
cancellable, error))
goto out;
return FALSE;
}
while (bytes_read > 0);
}
else if (out != NULL)
{
if (g_output_stream_splice (out, in, 0, cancellable, error) < 0)
goto out;
return FALSE;
}
ret = TRUE;
out:
return ret;
return TRUE;
}
/* Copy @in to @out, return in @out_csum the binary checksum for
* all data read.
*/
gboolean
ot_gio_splice_get_checksum (GOutputStream *out,
GInputStream *in,
@@ -126,22 +120,14 @@ ot_gio_splice_get_checksum (GOutputStream *out,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GChecksum *checksum = NULL;
g_autofree guchar *ret_csum = NULL;
checksum = g_checksum_new (G_CHECKSUM_SHA256);
g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256);
if (!ot_gio_splice_update_checksum (out, in, checksum, cancellable, error))
goto out;
return FALSE;
ret_csum = ot_csum_from_gchecksum (checksum);
ret = TRUE;
g_autofree guchar *ret_csum = ot_csum_from_gchecksum (checksum);
ot_transfer_out_value (out_csum, &ret_csum);
out:
g_clear_pointer (&checksum, (GDestroyNotify) g_checksum_free);
return ret;
return TRUE;
}
gboolean
@@ -162,21 +148,13 @@ ot_checksum_file_at (int dfd,
GCancellable *cancellable,
GError **error)
{
GChecksum *checksum = NULL;
char *ret = NULL;
g_autoptr(GInputStream) in = NULL;
if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error))
goto out;
checksum = g_checksum_new (checksum_type);
return FALSE;
g_autoptr(GChecksum) checksum = g_checksum_new (checksum_type);
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
goto out;
ret = g_strdup (g_checksum_get_string (checksum));
out:
g_clear_pointer (&checksum, (GDestroyNotify) g_checksum_free);
return ret;
return FALSE;
return g_strdup (g_checksum_get_string (checksum));
}
+25 -92
View File
@@ -35,98 +35,6 @@ ot_fdrel_to_gfile (int dfd, const char *path)
return g_file_new_for_path (abspath);
}
int
ot_opendirat (int dfd, const char *path, gboolean follow)
{
int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY;
if (!follow)
flags |= O_NOFOLLOW;
return openat (dfd, path, flags);
}
gboolean
ot_gopendirat (int dfd,
const char *path,
gboolean follow,
int *out_fd,
GError **error)
{
int ret = ot_opendirat (dfd, path, follow);
if (ret == -1)
{
glnx_set_error_from_errno (error);
return FALSE;
}
*out_fd = ret;
return TRUE;
}
GBytes *
ot_lgetxattrat (int dfd,
const char *path,
const char *attribute,
GError **error)
{
/* A workaround for the lack of lgetxattrat(), thanks to Florian Weimer:
* https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html
*/
g_autofree char *full_path = g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path);
GBytes *bytes = NULL;
ssize_t bytes_read, real_size;
char *buf;
do
bytes_read = lgetxattr (full_path, attribute, NULL, 0);
while (G_UNLIKELY (bytes_read < 0 && errno == EINTR));
if (G_UNLIKELY (bytes_read < 0))
{
glnx_set_error_from_errno (error);
goto out;
}
buf = g_malloc (bytes_read);
do
real_size = lgetxattr (full_path, attribute, buf, bytes_read);
while (G_UNLIKELY (real_size < 0 && errno == EINTR));
if (G_UNLIKELY (real_size < 0))
{
glnx_set_error_from_errno (error);
g_free (buf);
goto out;
}
bytes = g_bytes_new_take (buf, real_size);
out:
return bytes;
}
gboolean
ot_lsetxattrat (int dfd,
const char *path,
const char *attribute,
const void *value,
gsize value_size,
int flags,
GError **error)
{
/* A workaround for the lack of lsetxattrat(), thanks to Florian Weimer:
* https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html
*/
g_autofree char *full_path = g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path);
int res;
do
res = lsetxattr (full_path, "user.ostreemeta", value, value_size, flags);
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
glnx_set_error_from_errno (error);
return FALSE;
}
return TRUE;
}
gboolean
ot_readlinkat_gfile_info (int dfd,
const char *path,
@@ -264,6 +172,31 @@ ot_openat_ignore_enoent (int dfd,
return ret;
}
/* Like glnx_dirfd_iterator_init_at(), but if %ENOENT, then set
* @out_exists to %FALSE, and return successfully.
*/
gboolean
ot_dfd_iter_init_allow_noent (int dfd,
const char *path,
GLnxDirFdIterator *dfd_iter,
gboolean *out_exists,
GError **error)
{
glnx_fd_close int fd = glnx_opendirat_with_errno (dfd, path, TRUE);
if (fd < 0)
{
if (errno != ENOENT)
return glnx_throw_errno_prefix (error, "opendirat");
*out_exists = FALSE;
return TRUE;
}
if (!glnx_dirfd_iterator_init_take_fd (fd, dfd_iter, error))
return FALSE;
fd = -1;
*out_exists = TRUE;
return TRUE;
}
GBytes *
ot_file_mapat_bytes (int dfd,
const char *path,
+7 -20
View File
@@ -21,31 +21,12 @@
#pragma once
#include "ot-unix-utils.h"
#include "libglnx.h"
G_BEGIN_DECLS
GFile * ot_fdrel_to_gfile (int dfd, const char *path);
int ot_opendirat (int dfd, const char *path, gboolean follow);
gboolean ot_gopendirat (int dfd,
const char *path,
gboolean follow,
int *out_fd,
GError **error);
GBytes * ot_lgetxattrat (int dfd,
const char *path,
const char *attribute,
GError **error);
gboolean ot_lsetxattrat (int dfd,
const char *path,
const char *attribute,
const void *value,
gsize value_size,
int flags,
GError **error);
gboolean ot_readlinkat_gfile_info (int dfd,
const char *path,
GFileInfo *target_info,
@@ -73,6 +54,12 @@ gboolean ot_openat_ignore_enoent (int dfd,
int *out_fd,
GError **error);
gboolean ot_dfd_iter_init_allow_noent (int dfd,
const char *path,
GLnxDirFdIterator *dfd_iter,
gboolean *out_exists,
GError **error);
GBytes *ot_file_mapat_bytes (int dfd,
const char *path,
GError **error);
+1 -5
View File
@@ -67,7 +67,6 @@ ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error,
gboolean
ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx,
const char *tmp_dir,
char **out_tmp_home_dir,
GOutputStream **out_pubring_stream,
GCancellable *cancellable,
@@ -85,10 +84,7 @@ ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx,
* and hand the caller an open output stream to concatenate necessary
* keyring files. */
if (tmp_dir == NULL)
tmp_dir = g_get_tmp_dir ();
tmp_home_dir = g_build_filename (tmp_dir, "ostree-gpg-XXXXXX", NULL);
tmp_home_dir = g_build_filename (g_get_tmp_dir (), "ostree-gpg-XXXXXX", NULL);
if (mkdtemp (tmp_home_dir) == NULL)
{
-1
View File
@@ -34,7 +34,6 @@ GLNX_DEFINE_CLEANUP_FUNCTION0(gpgme_ctx_t, ot_cleanup_gpgme_ctx, gpgme_release)
void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error);
gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx,
const char *tmp_dir,
char **out_tmp_home_dir,
GOutputStream **out_pubring_stream,
GCancellable *cancellable,
+4 -4
View File
@@ -457,10 +457,10 @@ httpd_callback (SoupServer *server, SoupMessage *msg,
static void
on_dir_changed (GFileMonitor *mon,
GFile *file,
GFile *other,
GFileMonitorEvent event,
gpointer user_data)
GFile *file,
GFile *other,
GFileMonitorEvent event,
gpointer user_data)
{
OtTrivialHttpd *self = user_data;
+2 -7
View File
@@ -47,12 +47,9 @@ static GOptionContext *
ostree_admin_instutil_option_context_new_with_commands (void)
{
OstreeAdminInstUtilCommand *command = admin_instutil_subcommands;
GOptionContext *context;
GString *summary;
GOptionContext *context = g_option_context_new ("COMMAND");
context = g_option_context_new ("COMMAND");
summary = g_string_new ("Builtin \"admin instutil\" Commands:");
g_autoptr(GString) summary = g_string_new ("Builtin \"admin instutil\" Commands:");
while (command->name != NULL)
{
@@ -62,8 +59,6 @@ ostree_admin_instutil_option_context_new_with_commands (void)
g_option_context_set_summary (context, summary->str);
g_string_free (summary, TRUE);
return context;
}
+1 -3
View File
@@ -124,7 +124,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment);
g_autofree char *version = version_of_commit (repo, ref);
glnx_unref_object OstreeGpgVerifyResult *result = NULL;
GString *output_buffer;
guint jj, n_signatures;
GError *local_error = NULL;
@@ -159,6 +158,7 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
if (deployment_get_gpg_verify (deployment, repo))
{
g_autoptr(GString) output_buffer = g_string_sized_new (256);
/* Print any digital signatures on this commit. */
result = ostree_repo_verify_commit_ext (repo, ref, NULL, NULL,
@@ -176,7 +176,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
goto out;
}
output_buffer = g_string_sized_new (256);
n_signatures = ostree_gpg_verify_result_count_all (result);
for (jj = 0; jj < n_signatures; jj++)
@@ -186,7 +185,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
}
g_print ("%s", output_buffer->str);
g_string_free (output_buffer, TRUE);
}
}
}
+11 -17
View File
@@ -35,7 +35,6 @@ static GOptionEntry options[] = {
gboolean
ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error)
{
gboolean ret = FALSE;
g_autoptr(GOptionContext) context = NULL;
glnx_unref_object OstreeSysroot *sysroot = NULL;
const char *deploy_index_str;
@@ -48,16 +47,16 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
&sysroot, cancellable, error))
goto out;
return FALSE;
if (argc < 2)
{
ot_util_usage_error (context, "INDEX must be specified", error);
goto out;
return FALSE;
}
if (!ostree_sysroot_load (sysroot, cancellable, error))
goto out;
return FALSE;
current_deployments = ostree_sysroot_get_deployments (sysroot);
deploy_index_str = argv[1];
@@ -65,31 +64,26 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr
target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error);
if (!target_deployment)
goto out;
return FALSE;
if (target_deployment == ostree_sysroot_get_booted_deployment (sysroot))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
"Cannot undeploy currently booted deployment %i", deploy_index);
goto out;
return FALSE;
}
g_ptr_array_remove_index (current_deployments, deploy_index);
if (!ostree_sysroot_write_deployments (sysroot, current_deployments,
cancellable, error))
goto out;
return FALSE;
g_print ("Deleted deployment %s.%d\n", ostree_deployment_get_csum (target_deployment),
ostree_deployment_get_deployserial (target_deployment));
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
{
g_prefix_error (error, "Performing final cleanup: ");
goto out;
}
ret = TRUE;
out:
return ret;
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
return glnx_prefix_error (error, "Performing final cleanup");
return TRUE;
}
+5 -17
View File
@@ -33,20 +33,11 @@ ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
OstreeDeployment *booted_deployment =
ostree_sysroot_get_booted_deployment (sysroot);
if (booted_deployment == NULL && osname == NULL)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Not currently booted into an OSTree system and no --os= argument given");
goto out;
}
ret = TRUE;
out:
return ret;
return glnx_throw (error, "Not currently booted into an OSTree system and no --os= argument given");
return TRUE;
}
/**
@@ -141,7 +132,7 @@ ot_admin_sysroot_lock (OstreeSysroot *sysroot,
g_source_set_callback (timeout_src, (GSourceFunc)on_sysroot_lock_timeout, &state, NULL);
g_source_attach (timeout_src, state.mainctx);
g_source_unref (timeout_src);
on_sysroot_lock_timeout (&state);
ostree_sysroot_lock_async (sysroot, NULL, (GAsyncReadyCallback)on_sysroot_lock_acquired, &state);
@@ -161,14 +152,11 @@ gboolean
ot_admin_execve_reboot (OstreeSysroot *sysroot, GError **error)
{
g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/");
if (g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
{
if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
return glnx_throw_errno (error);
}
return TRUE;
+2 -7
View File
@@ -56,12 +56,9 @@ static GOptionContext *
ostree_admin_option_context_new_with_commands (void)
{
OstreeAdminCommand *command = admin_subcommands;
GOptionContext *context;
GString *summary;
GOptionContext *context = g_option_context_new ("--print-current-dir|COMMAND");
context = g_option_context_new ("--print-current-dir|COMMAND");
summary = g_string_new ("Builtin \"admin\" Commands:");
g_autoptr(GString) summary = g_string_new ("Builtin \"admin\" Commands:");
while (command->name != NULL)
{
@@ -71,8 +68,6 @@ ostree_admin_option_context_new_with_commands (void)
g_option_context_set_summary (context, summary->str);
g_string_free (summary, TRUE);
return context;
}
+10 -2
View File
@@ -42,6 +42,7 @@ static gboolean opt_from_stdin;
static char *opt_from_file;
static gboolean opt_disable_fsync;
static gboolean opt_require_hardlinks;
static gboolean opt_force_copy;
static gboolean
parse_fsync_cb (const char *option_name,
@@ -62,7 +63,7 @@ parse_fsync_cb (const char *option_name,
static GOptionEntry options[] = {
{ "user-mode", 'U', 0, G_OPTION_ARG_NONE, &opt_user_mode, "Do not change file ownership or initialize extended attributes", NULL },
{ "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Do not update or use the internal repository uncompressed object cache", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
{ "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL },
{ "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL },
{ "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL },
@@ -71,6 +72,7 @@ static GOptionEntry options[] = {
{ "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" },
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
{ "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL },
{ "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL },
{ NULL }
};
@@ -89,7 +91,7 @@ process_one_checkout (OstreeRepo *repo,
* `ostree_repo_checkout_at` until such time as we have a more
* convenient infrastructure for testing C APIs with data.
*/
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add)
if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add || opt_force_copy)
{
OstreeRepoCheckoutAtOptions options = { 0, };
@@ -102,6 +104,11 @@ process_one_checkout (OstreeRepo *repo,
"Cannot specify both --union and --union-add");
goto out;
}
if (opt_require_hardlinks && opt_force_copy)
{
glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy");
goto out;
}
else if (opt_union)
options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
else if (opt_union_add)
@@ -111,6 +118,7 @@ process_one_checkout (OstreeRepo *repo,
if (subpath)
options.subpath = subpath;
options.no_copy_fallback = opt_require_hardlinks;
options.force_copy = opt_force_copy;
if (!ostree_repo_checkout_at (repo, &options,
AT_FDCWD, destination,
+3 -5
View File
@@ -76,7 +76,7 @@ static GOptionEntry options[] = {
{ "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent ref, or \"none\"", "REF" },
{ "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject", "SUBJECT" },
{ "body", 'm', 0, G_OPTION_ARG_STRING, &opt_body, "Full description", "BODY" },
{ "body-file", 'F', 0, G_OPTION_ARG_STRING, &opt_body_file, "Commit message from FILE path", "FILE" },
{ "body-file", 'F', 0, G_OPTION_ARG_FILENAME, &opt_body_file, "Commit message from FILE path", "FILE" },
{ "editor", 'e', 0, G_OPTION_ARG_NONE, &opt_editor, "Use an editor to write the commit message", NULL },
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &opt_branch, "Branch", "BRANCH" },
{ "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL },
@@ -94,7 +94,7 @@ static GOptionEntry options[] = {
{ "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" },
{ "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL },
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"},
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
{ "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes, "Generate size information along with commit metadata", NULL },
{ "disable-fsync", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
@@ -218,7 +218,7 @@ commit_editor (OstreeRepo *repo,
g_autofree char *input = NULL;
g_autofree char *output = NULL;
gboolean ret = FALSE;
GString *bodybuf = NULL;
g_autoptr(GString) bodybuf = NULL;
char **lines = NULL;
int i;
@@ -288,8 +288,6 @@ commit_editor (OstreeRepo *repo,
out:
g_strfreev (lines);
if (bodybuf)
g_string_free (bodybuf, TRUE);
return ret;
}
+3 -3
View File
@@ -39,9 +39,9 @@ static gboolean opt_no_xattrs;
static GOptionEntry options[] = {
{ "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Skip output of extended attributes", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
{ "prefix", 0, 0, G_OPTION_ARG_STRING, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" },
{ "output", 'o', 0, G_OPTION_ARG_STRING, &opt_output_path, "Output to PATH ", "PATH" },
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" },
{ "prefix", 0, 0, G_OPTION_ARG_FILENAME, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" },
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_path, "Output to PATH ", "PATH" },
{ NULL }
};
+22
View File
@@ -246,6 +246,7 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError **
gpointer key, value;
gboolean found_corruption = FALSE;
guint n_partial = 0;
g_autoptr(GHashTable) all_refs = NULL;
g_autoptr(GHashTable) objects = NULL;
g_autoptr(GHashTable) commits = NULL;
g_autoptr(GPtrArray) tombstones = NULL;
@@ -254,6 +255,27 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError **
if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
goto out;
if (!opt_quiet)
g_print ("Validating refs...\n");
/* Validate that the commit for each ref is available */
if (!ostree_repo_list_refs (repo, NULL, &all_refs,
cancellable, error))
return FALSE;
g_hash_table_iter_init (&hash_iter, all_refs);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *refname = key;
const char *checksum = value;
g_autoptr(GVariant) commit = NULL;
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT,
checksum, &commit, error))
{
g_prefix_error (error, "Loading commit for ref %s: ", refname);
goto out;
}
}
if (!opt_quiet)
g_print ("Enumerating objects...\n");
+5 -4
View File
@@ -26,13 +26,14 @@
#include "ot-builtins.h"
#include "ostree.h"
#include "otutil.h"
#include "ostree-core-private.h"
static gboolean opt_delete;
static char *opt_gpg_homedir;
static GOptionEntry options[] = {
{ "delete", 'd', 0, G_OPTION_ARG_NONE, &opt_delete, "Delete signatures having any of the GPG KEY-IDs" },
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" },
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" },
{ NULL }
};
@@ -85,7 +86,7 @@ delete_signatures (OstreeRepo *repo,
g_variant_dict_init (&metadata_dict, old_metadata);
signature_data = g_variant_dict_lookup_value (&metadata_dict,
"ostree.gpgsigs",
_OSTREE_METADATA_GPGSIGS_NAME,
G_VARIANT_TYPE ("aay"));
/* Taking the approach of deleting whatever matches we find for the
@@ -154,7 +155,7 @@ delete_signatures (OstreeRepo *repo,
/* Update the metadata dictionary. */
if (g_queue_is_empty (&signatures))
{
g_variant_dict_remove (&metadata_dict, "ostree.gpgsigs");
g_variant_dict_remove (&metadata_dict, _OSTREE_METADATA_GPGSIGS_NAME);
}
else
{
@@ -170,7 +171,7 @@ delete_signatures (OstreeRepo *repo,
}
g_variant_dict_insert_value (&metadata_dict,
"ostree.gpgsigs",
_OSTREE_METADATA_GPGSIGS_NAME,
g_variant_builder_end (&signature_builder));
}
+1 -5
View File
@@ -47,15 +47,13 @@ static void
print_one_file_text (GFile *f,
GFileInfo *file_info)
{
GString *buf = NULL;
g_autoptr(GString) buf = g_string_new ("");
char type_c;
guint32 mode;
guint32 type;
if (!ostree_repo_file_ensure_resolved ((OstreeRepoFile*)f, NULL))
g_assert_not_reached ();
buf = g_string_new ("");
type_c = '?';
mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode");
@@ -119,8 +117,6 @@ print_one_file_text (GFile *f,
g_string_append_printf (buf, " -> %s", g_file_info_get_attribute_byte_string (file_info, "standard::symlink-target"));
g_print ("%s\n", buf->str);
g_string_free (buf, TRUE);
}
static void
+15 -14
View File
@@ -43,12 +43,12 @@ static char* opt_url;
static GOptionEntry options[] = {
{ "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL },
{ "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL },
{ "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL },
{ "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL },
{ "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_disable_static_deltas, "Do not use static deltas", NULL },
{ "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL },
{ "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL },
{ "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL },
{ "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL },
{ "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL },
{ "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" },
@@ -84,27 +84,29 @@ dry_run_console_progress_changed (OstreeAsyncProgress *progress,
guint fetched_delta_parts, total_delta_parts;
guint fetched_delta_part_fallbacks, total_delta_part_fallbacks;
guint64 fetched_delta_part_size, total_delta_part_size, total_delta_part_usize;
GString *buf;
g_assert (!printed_console_progress);
printed_console_progress = TRUE;
/* Number of parts */
fetched_delta_parts = ostree_async_progress_get_uint (progress, "fetched-delta-parts");
total_delta_parts = ostree_async_progress_get_uint (progress, "total-delta-parts");
fetched_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "fetched-delta-fallbacks");
total_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "total-delta-fallbacks");
ostree_async_progress_get (progress,
/* Number of parts */
"fetched-delta-parts", "u", &fetched_delta_parts,
"total-delta-parts", "u", &total_delta_parts,
"fetched-delta-fallbacks", "u", &fetched_delta_part_fallbacks,
"total-delta-fallbacks", "u", &total_delta_part_fallbacks,
/* Size variables */
"fetched-delta-part-size", "t", &fetched_delta_part_size,
"total-delta-part-size", "t", &total_delta_part_size,
"total-delta-part-usize", "t", &total_delta_part_usize,
NULL);
/* Fold the count of deltaparts + fallbacks for simplicity; if changing this,
* please change ostree_repo_pull_default_console_progress_changed() first.
*/
fetched_delta_parts += fetched_delta_part_fallbacks;
total_delta_parts += total_delta_part_fallbacks;
/* Size variables */
fetched_delta_part_size = ostree_async_progress_get_uint64 (progress, "fetched-delta-part-size");
total_delta_part_size = ostree_async_progress_get_uint64 (progress, "total-delta-part-size");
total_delta_part_usize = ostree_async_progress_get_uint64 (progress, "total-delta-part-usize");
buf = g_string_new ("");
g_autoptr(GString) buf = g_string_new ("");
{ g_autofree char *formatted_fetched =
g_format_size (fetched_delta_part_size);
@@ -119,7 +121,6 @@ dry_run_console_progress_changed (OstreeAsyncProgress *progress,
formatted_usize);
}
g_print ("%s\n", buf->str);
g_string_free (buf, TRUE);
}
gboolean
+2 -7
View File
@@ -51,12 +51,9 @@ static GOptionContext *
remote_option_context_new_with_commands (void)
{
OstreeRemoteCommand *subcommand = remote_subcommands;
GOptionContext *context;
GString *summary;
GOptionContext *context = g_option_context_new ("COMMAND");
context = g_option_context_new ("COMMAND");
summary = g_string_new ("Builtin \"remote\" Commands:");
g_autoptr(GString) summary = g_string_new ("Builtin \"remote\" Commands:");
while (subcommand->name != NULL)
{
@@ -66,8 +63,6 @@ remote_option_context_new_with_commands (void)
g_option_context_set_summary (context, summary->str);
g_string_free (summary, TRUE);
return context;
}
+1 -1
View File
@@ -42,7 +42,7 @@ static GOptionEntry options[] = {
{ "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" },
{ "print-detached-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_detached_metadata_key, "Print string value of detached metadata key", "KEY" },
{ "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" },
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
{ "gpg-verify-remote", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_verify_remote, "Use REMOTE name for GPG configuration", "REMOTE"},
{ NULL }
};
+1 -1
View File
@@ -72,7 +72,7 @@ static GOptionEntry generate_options[] = {
{ "min-fallback-size", 0, 0, G_OPTION_ARG_STRING, &opt_min_fallback_size, "Minimum uncompressed size in megabytes for individual HTTP request", NULL},
{ "max-bsdiff-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_bsdiff_size, "Maximum size in megabytes to consider bsdiff compression for input files", NULL},
{ "max-chunk-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_chunk_size, "Maximum size of delta chunks in megabytes", NULL},
{ "filename", 0, 0, G_OPTION_ARG_STRING, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"},
{ "filename", 0, 0, G_OPTION_ARG_FILENAME, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"},
{ NULL }
};
+20 -2
View File
@@ -20,19 +20,23 @@
#include "config.h"
#include "ostree-repo-private.h"
#include "ot-dump.h"
#include "ot-main.h"
#include "ot-builtins.h"
#include "ostree.h"
#include "otutil.h"
static gboolean opt_update;
static gboolean opt_update, opt_view, opt_raw;
static char **opt_key_ids;
static char *opt_gpg_homedir;
static GOptionEntry options[] = {
{ "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL },
{ "view", 'v', 0, G_OPTION_ARG_NONE, &opt_view, "View the local summary file", NULL },
{ "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "View the raw bytes of the summary file", NULL },
{ "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"},
{ "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
{ "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
{ NULL }
};
@@ -42,6 +46,7 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError
gboolean ret = FALSE;
g_autoptr(GOptionContext) context = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
OstreeDumpFlags flags = OSTREE_DUMP_NONE;
context = g_option_context_new ("Manage summary metadata");
@@ -66,6 +71,19 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError
goto out;
}
}
else if (opt_view)
{
g_autoptr(GBytes) summary_data = NULL;
if (opt_raw)
flags |= OSTREE_DUMP_RAW;
summary_data = ot_file_mapat_bytes (repo->repo_dir_fd, "summary", error);
if (!summary_data)
goto out;
ot_dump_summary_bytes (summary_data, flags);
}
else
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+42 -4
View File
@@ -26,6 +26,8 @@
#include <err.h>
#include "ostree-repo-private.h"
#include "ostree-repo-static-delta-private.h"
#include "ot-dump.h"
#include "otutil.h"
#include "ot-admin-functions.h"
@@ -199,6 +201,18 @@ dump_summary_ref (const char *ref_name,
}
}
static gchar *
uint64_secs_to_iso8601 (guint64 secs)
{
g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs);
g_autoptr(GDateTime) local = (dt != NULL) ? g_date_time_to_local (dt) : NULL;
if (local != NULL)
return g_date_time_format (local, "%FT%T%:::z");
else
return g_strdup ("invalid");
}
void
ot_dump_summary_bytes (GBytes *summary_bytes,
OstreeDumpFlags flags)
@@ -251,11 +265,35 @@ ot_dump_summary_bytes (GBytes *summary_bytes,
g_variant_iter_init (&iter, exts);
/* XXX Should we print something more human-friendly for
* known extension names like 'ostree.static-deltas'? */
while (g_variant_iter_loop (&iter, "{sv}", &key, &value))
{
g_autofree char *string = g_variant_print (value, FALSE);
g_print ("%s: %s\n", key, string);
g_autofree gchar *value_str = NULL;
const gchar *pretty_key = NULL;
if (g_strcmp0 (key, OSTREE_SUMMARY_STATIC_DELTAS) == 0)
{
pretty_key = "Static Deltas";
value_str = g_variant_print (value, FALSE);
}
else if (g_strcmp0 (key, OSTREE_SUMMARY_LAST_MODIFIED) == 0)
{
pretty_key = "Last-Modified";
value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value)));
}
else if (g_strcmp0 (key, OSTREE_SUMMARY_EXPIRES) == 0)
{
pretty_key = "Expires";
value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value)));
}
else
{
value_str = g_variant_print (value, FALSE);
}
/* Print out. */
if (pretty_key != NULL)
g_print ("%s (%s): %s\n", pretty_key, key, value_str);
else
g_print ("%s: %s\n", key, value_str);
}
}
+23 -53
View File
@@ -45,26 +45,23 @@ static GOptionEntry global_entries[] = {
};
static GOptionEntry repo_entry[] = {
{ "repo", 0, 0, G_OPTION_ARG_STRING, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
{ "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" },
{ NULL }
};
static GOptionEntry global_admin_entries[] = {
/* No description since it's hidden from --help output. */
{ "print-current-dir", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_print_current_dir, NULL, NULL },
{ "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" },
{ "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" },
{ NULL }
};
static GOptionContext *
ostree_option_context_new_with_commands (OstreeCommand *commands)
{
GOptionContext *context;
GString *summary;
GOptionContext *context = g_option_context_new ("COMMAND");
context = g_option_context_new ("COMMAND");
summary = g_string_new ("Builtin Commands:");
g_autoptr(GString) summary = g_string_new ("Builtin Commands:");
while (commands->name != NULL)
{
@@ -74,8 +71,6 @@ ostree_option_context_new_with_commands (OstreeCommand *commands)
g_option_context_set_summary (context, summary->str);
g_string_free (summary, TRUE);
return context;
}
@@ -223,7 +218,6 @@ ostree_option_context_parse (GOptionContext *context,
GError **error)
{
glnx_unref_object OstreeRepo *repo = NULL;
gboolean success = FALSE;
/* Entries are listed in --help output in the order added. We add the
* main entries ourselves so that we can add the --repo entry first. */
@@ -278,7 +272,7 @@ ostree_option_context_parse (GOptionContext *context,
{
g_propagate_error (error, g_steal_pointer (&local_error));
}
goto out;
return FALSE;
}
}
else if (opt_repo != NULL)
@@ -289,17 +283,14 @@ ostree_option_context_parse (GOptionContext *context,
if (!(flags & OSTREE_BUILTIN_FLAG_NO_CHECK))
{
if (!ostree_repo_open (repo, cancellable, error))
goto out;
return FALSE;
}
}
if (out_repo)
*out_repo = g_steal_pointer (&repo);
success = TRUE;
out:
return success;
return TRUE;
}
gboolean
@@ -312,22 +303,19 @@ ostree_admin_option_context_parse (GOptionContext *context,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GFile) sysroot_path = NULL;
glnx_unref_object OstreeSysroot *sysroot = NULL;
gboolean success = FALSE;
/* Entries are listed in --help output in the order added. We add the
* main entries ourselves so that we can add the --sysroot entry first. */
g_option_context_add_main_entries (context, global_admin_entries, NULL);
if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error))
goto out;
return FALSE;
g_autoptr(GFile) sysroot_path = NULL;
if (opt_sysroot != NULL)
sysroot_path = g_file_new_for_path (opt_sysroot);
sysroot = ostree_sysroot_new (sysroot_path);
glnx_unref_object OstreeSysroot *sysroot = ostree_sysroot_new (sysroot_path);
if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER)
{
@@ -338,7 +326,7 @@ ostree_admin_option_context_parse (GOptionContext *context,
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
"You must be root to perform this command");
goto out;
return FALSE;
}
}
@@ -350,15 +338,11 @@ ostree_admin_option_context_parse (GOptionContext *context,
g_autofree char *deployment_path = NULL;
if (!ostree_sysroot_load (sysroot, cancellable, error))
goto out;
return FALSE;
deployments = ostree_sysroot_get_deployments (sysroot);
if (deployments->len == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Unable to find a deployment in sysroot");
goto out;
}
return glnx_throw (error, "Unable to find a deployment in sysroot");
first_deployment = deployments->pdata[0];
deployment_file = ostree_sysroot_get_deployment_directory (sysroot, first_deployment);
deployment_path = g_file_get_path (deployment_file);
@@ -379,46 +363,36 @@ ostree_admin_option_context_parse (GOptionContext *context,
{
/* Released when sysroot is finalized, or on process exit */
if (!ot_admin_sysroot_lock (sysroot, error))
goto out;
return FALSE;
}
if (out_sysroot)
*out_sysroot = g_steal_pointer (&sysroot);
success = TRUE;
out:
return success;
return TRUE;
}
gboolean
ostree_ensure_repo_writable (OstreeRepo *repo,
GError **error)
{
gboolean ret;
ret = ostree_repo_is_writable (repo, error);
g_prefix_error (error, "Cannot write to repository: ");
return ret;
if (!ostree_repo_is_writable (repo, error))
return glnx_prefix_error (error, "Cannot write to repository");
return TRUE;
}
void
ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result)
{
GString *buffer;
guint n_sigs, ii;
n_sigs = ostree_gpg_verify_result_count_all (result);
guint n_sigs = ostree_gpg_verify_result_count_all (result);
/* XXX If we ever add internationalization, use ngettext() here. */
g_print ("GPG: Verification enabled, found %u signature%s:\n",
n_sigs, n_sigs == 1 ? "" : "s");
buffer = g_string_sized_new (256);
g_autoptr(GString) buffer = g_string_sized_new (256);
for (ii = 0; ii < n_sigs; ii++)
for (guint ii = 0; ii < n_sigs; ii++)
{
g_string_append_c (buffer, '\n');
ostree_gpg_verify_result_describe (result, ii, buffer, " ",
@@ -426,13 +400,11 @@ ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result)
}
g_print ("%s", buffer->str);
g_string_free (buffer, TRUE);
}
gboolean
ot_enable_tombstone_commits (OstreeRepo *repo, GError **error)
{
gboolean ret = FALSE;
gboolean tombstone_commits = FALSE;
GKeyFile *config = ostree_repo_get_config (repo);
@@ -442,10 +414,8 @@ ot_enable_tombstone_commits (OstreeRepo *repo, GError **error)
{
g_key_file_set_boolean (config, "core", "tombstone-commits", TRUE);
if (!ostree_repo_write_config (repo, config, error))
goto out;
return FALSE;
}
ret = TRUE;
out:
return ret;
return TRUE;
}
+1 -1
View File
@@ -28,7 +28,7 @@
static char* opt_cache_dir;
static GOptionEntry option_entries[] = {
{ "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL },
{ "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL },
{ NULL }
};
+1 -1
View File
@@ -31,7 +31,7 @@ static gboolean opt_raw;
static char* opt_cache_dir;
static GOptionEntry option_entries[] = {
{ "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL },
{ "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL },
{ "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data", NULL },
{ NULL }
};
+6 -2
View File
@@ -298,14 +298,18 @@ ot_list_cookies_at (int dfd, const char *jar_path, GError **error)
while (ot_parse_cookies_next (parser))
{
g_autoptr(GDateTime) expires = g_date_time_new_from_unix_utc (parser->expiration);
g_autofree char *expires_str = g_date_time_format (expires, "%Y-%m-%d %H:%M:%S +0000");
g_autofree char *expires_str = NULL;
if (expires != NULL)
expires_str = g_date_time_format (expires, "%Y-%m-%d %H:%M:%S +0000");
g_print ("--\n");
g_print ("Domain: %s\n", parser->domain);
g_print ("Path: %s\n", parser->path);
g_print ("Name: %s\n", parser->name);
g_print ("Secure: %s\n", parser->secure);
g_print ("Expires: %s\n", expires_str);
if (expires_str != NULL)
g_print ("Expires: %s\n", expires_str);
g_print ("Value: %s\n", parser->value);
}
#else
+39 -40
View File
@@ -56,12 +56,12 @@ callback_getattr (const char *path, struct stat *st_data)
if (!*path)
{
if (fstat (basefd, st_data) == -1)
return -errno;
return -errno;
}
else
{
if (fstatat (basefd, path, st_data, AT_SYMLINK_NOFOLLOW) == -1)
return -errno;
return -errno;
}
return 0;
}
@@ -85,7 +85,7 @@ callback_readlink (const char *path, char *buf, size_t size)
static int
callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
off_t offset, struct fuse_file_info *fi)
{
DIR *dp;
struct dirent *de;
@@ -102,7 +102,7 @@ callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
{
dfd = openat (basefd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
if (dfd == -1)
return -errno;
return -errno;
}
/* Transfers ownership of fd */
@@ -117,7 +117,7 @@ callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
st.st_ino = de->d_ino;
st.st_mode = de->d_type << 12;
if (filler (buf, de->d_name, &st, 0))
break;
break;
}
(void) closedir (dp);
@@ -170,7 +170,7 @@ callback_symlink (const char *from, const char *to)
if (fstatat (basefd, to, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
{
fprintf (stderr, "Failed to find newly created symlink '%s': %s\n",
to, g_strerror (errno));
to, g_strerror (errno));
exit (EXIT_FAILURE);
}
return 0;
@@ -209,19 +209,19 @@ can_write (const char *path)
if (fstatat (basefd, path, &stbuf, 0) == -1)
{
if (errno == ENOENT)
return 0;
return 0;
else
return -errno;
return -errno;
}
if (stbuf_is_regfile_hardlinked (&stbuf))
return -EROFS;
return 0;
}
#define VERIFY_WRITE(path) do { \
int r = can_write (path); \
if (r != 0) \
return r; \
#define VERIFY_WRITE(path) do { \
int r = can_write (path); \
if (r != 0) \
return r; \
} while (0)
static int
@@ -366,7 +366,7 @@ callback_read_buf (const char *path, struct fuse_bufvec **bufp,
static int
callback_read (const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *finfo)
struct fuse_file_info *finfo)
{
int r;
r = pread (finfo->fh, buf, size, offset);
@@ -390,7 +390,7 @@ callback_write_buf (const char *path, struct fuse_bufvec *buf, off_t offset,
static int
callback_write (const char *path, const char *buf, size_t size, off_t offset,
struct fuse_file_info *finfo)
struct fuse_file_info *finfo)
{
int r;
r = pwrite (finfo->fh, buf, size, offset);
@@ -426,7 +426,7 @@ static int
callback_access (const char *path, int mode)
{
path = ENSURE_RELPATH (path);
/* Apparently at least GNU coreutils rm calls `faccessat(W_OK)`
* before trying to do an unlink. So...we'll just lie about
* writable access here.
@@ -438,14 +438,14 @@ callback_access (const char *path, int mode)
static int
callback_setxattr (const char *path, const char *name, const char *value,
size_t size, int flags)
size_t size, int flags)
{
return -ENOTSUP;
}
static int
callback_getxattr (const char *path, const char *name, char *value,
size_t size)
size_t size)
{
return -ENOTSUP;
}
@@ -503,8 +503,7 @@ struct fuse_operations callback_oper = {
.removexattr = callback_removexattr
};
enum
{
enum {
KEY_HELP,
KEY_VERSION,
};
@@ -513,19 +512,19 @@ static void
usage (const char *progname)
{
fprintf (stdout,
"usage: %s basepath mountpoint [options]\n"
"\n"
" Makes basepath visible at mountpoint such that files are read-only, directories are writable\n"
"\n"
"general options:\n"
" -o opt,[opt...] mount options\n"
" -h --help print help\n"
"\n", progname);
"usage: %s basepath mountpoint [options]\n"
"\n"
" Makes basepath visible at mountpoint such that files are read-only, directories are writable\n"
"\n"
"general options:\n"
" -o opt,[opt...] mount options\n"
" -h --help print help\n"
"\n", progname);
}
static int
rofs_parse_opt (void *data, const char *arg, int key,
struct fuse_args *outargs)
struct fuse_args *outargs)
{
(void) data;
@@ -533,19 +532,19 @@ rofs_parse_opt (void *data, const char *arg, int key,
{
case FUSE_OPT_KEY_NONOPT:
if (basefd == -1)
{
basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
if (basefd == -1)
{
perror ("openat");
exit (EXIT_FAILURE);
}
return 0;
}
{
basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
if (basefd == -1)
{
perror ("openat");
exit (EXIT_FAILURE);
}
return 0;
}
else
{
return 1;
}
{
return 1;
}
case FUSE_OPT_KEY_OPT:
return 1;
case KEY_HELP:
+66
View File
@@ -25,6 +25,10 @@
#include <err.h>
#include <stdlib.h>
#include <sys/statvfs.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
static inline int
path_is_on_readonly_fs (char *path)
@@ -37,4 +41,66 @@ path_is_on_readonly_fs (char *path)
return (stvfsbuf.f_flag & ST_RDONLY) != 0;
}
static inline char *
read_proc_cmdline (void)
{
FILE *f = fopen("/proc/cmdline", "r");
char *cmdline = NULL;
size_t len;
if (!f)
goto out;
/* Note that /proc/cmdline will not end in a newline, so getline
* will fail unelss we provide a length.
*/
if (getline (&cmdline, &len, f) < 0)
goto out;
/* ... but the length will be the size of the malloc buffer, not
* strlen(). Fix that.
*/
len = strlen (cmdline);
if (cmdline[len-1] == '\n')
cmdline[len-1] = '\0';
out:
if (f)
fclose (f);
return cmdline;
}
static inline char *
read_proc_cmdline_ostree (void)
{
char *cmdline = NULL;
const char *iter;
char *ret = NULL;
cmdline = read_proc_cmdline ();
if (!cmdline)
err (EXIT_FAILURE, "failed to read /proc/cmdline");
iter = cmdline;
while (iter != NULL)
{
const char *next = strchr (iter, ' ');
const char *next_nonspc = next;
while (next_nonspc && *next_nonspc == ' ')
next_nonspc += 1;
if (strncmp (iter, "ostree=", strlen ("ostree=")) == 0)
{
const char *start = iter + strlen ("ostree=");
if (next)
ret = strndup (start, next - start);
else
ret = strdup (start);
break;
}
iter = next_nonspc;
}
free (cmdline);
return ret;
}
#endif /* __OSTREE_MOUNT_UTIL_H_ */
+15 -74
View File
@@ -1,13 +1,13 @@
/* -*- c-file-style: "gnu" -*-
* Switch to new root directory and start init.
*
*
* Copyright 2011,2012,2013 Colin Walters <walters@verbum.org>
*
* Based on code from util-linux/sys-utils/switch_root.c,
* Based on code from util-linux/sys-utils/switch_root.c,
* Copyright 2002-2009 Red Hat, Inc. All rights reserved.
* Authors:
* Peter Jones <pjones@redhat.com>
* Jeremy Katz <katzj@redhat.com>
* Peter Jones <pjones@redhat.com>
* Jeremy Katz <katzj@redhat.com>
*
* Relicensed with permission to LGPLv2+.
*
@@ -46,68 +46,6 @@
#include "ostree-mount-util.h"
static char *
read_proc_cmdline (void)
{
FILE *f = fopen("/proc/cmdline", "r");
char *cmdline = NULL;
size_t len;
if (!f)
goto out;
/* Note that /proc/cmdline will not end in a newline, so getline
* will fail unelss we provide a length.
*/
if (getline (&cmdline, &len, f) < 0)
goto out;
/* ... but the length will be the size of the malloc buffer, not
* strlen(). Fix that.
*/
len = strlen (cmdline);
if (cmdline[len-1] == '\n')
cmdline[len-1] = '\0';
out:
if (f)
fclose (f);
return cmdline;
}
static char *
parse_ostree_cmdline (void)
{
char *cmdline = NULL;
const char *iter;
char *ret = NULL;
cmdline = read_proc_cmdline ();
if (!cmdline)
err (EXIT_FAILURE, "failed to read /proc/cmdline");
iter = cmdline;
while (iter != NULL)
{
const char *next = strchr (iter, ' ');
const char *next_nonspc = next;
while (next_nonspc && *next_nonspc == ' ')
next_nonspc += 1;
if (strncmp (iter, "ostree=", strlen ("ostree=")) == 0)
{
const char *start = iter + strlen ("ostree=");
if (next)
ret = strndup (start, next - start);
else
ret = strdup (start);
break;
}
iter = next_nonspc;
}
free (cmdline);
return ret;
}
/* This is an API for other projects to determine whether or not the
* currently running system is ostree-controlled.
*/
@@ -115,8 +53,8 @@ static void
touch_run_ostree (void)
{
int fd;
fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY, 0640);
fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY | O_CLOEXEC, 0640);
/* We ignore failures here in case /run isn't mounted...not much we
* can do about that, but we don't want to fail.
*/
@@ -132,7 +70,7 @@ resolve_deploy_path (const char * root_mountpoint)
struct stat stbuf;
char *ostree_target, *deploy_path;
ostree_target = parse_ostree_cmdline ();
ostree_target = read_proc_cmdline_ostree ();
if (!ostree_target)
errx (EXIT_FAILURE, "No OSTree target; expected ostree=/ostree/boot.N/...");
@@ -211,9 +149,12 @@ main(int argc, char *argv[])
if (chdir (deploy_path) < 0)
err (EXIT_FAILURE, "failed to chdir to deploy_path");
/* In the systemd case, this is handled by ostree-system-generator */
#ifndef HAVE_SYSTEMD_AND_LIBMOUNT
/* Link to the deployment's /var */
if (mount ("../../var", "var", NULL, MS_MGC_VAL|MS_BIND, NULL) < 0)
err (EXIT_FAILURE, "failed to bind mount ../../var to var");
#endif
/* If /boot is on the same partition, use a bind mount to make it visible
* at /boot inside the deployment. */
@@ -239,11 +180,11 @@ main(int argc, char *argv[])
* later boot and `systemd-remount-fs.service`.
*/
if (path_is_on_readonly_fs ("."))
{
if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
err (EXIT_FAILURE, "failed to remount rootfs writable (for overlayfs)");
}
{
if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
err (EXIT_FAILURE, "failed to remount rootfs writable (for overlayfs)");
}
if (mount ("overlay", "usr", "overlay", 0, usr_ovl_options) < 0)
err (EXIT_FAILURE, "failed to mount /usr overlayfs");
}
+13 -25
View File
@@ -38,28 +38,10 @@
#include "ostree-mount-util.h"
/* Having a writeable /var is necessary for full system functioning.
* If /var isn't writeable, we mount tmpfs over it. While this is
* somewhat outside of ostree's scope, having all /var twiddling
* in one place will make future maintenance easier.
*/
static void
maybe_mount_tmpfs_on_var (void)
{
if (!path_is_on_readonly_fs ("/var"))
return;
if (umount ("/var") < 0 && errno != EINVAL)
warn ("failed to unmount /var prior to mounting tmpfs, mounting over");
if (mount ("tmpfs", "/var", "tmpfs", 0, NULL) < 0)
err (EXIT_FAILURE, "failed to mount tmpfs on /var");
}
int
main(int argc, char *argv[])
{
const char *remounts[] = { "/sysroot", "/etc", "/home", "/root", "/tmp", "/var", NULL };
const char *remounts[] = { "/sysroot", "/var", NULL };
struct stat stbuf;
int i;
@@ -69,8 +51,6 @@ main(int argc, char *argv[])
* to clear the readonly flag in that case.
*/
maybe_mount_tmpfs_on_var ();
exit (EXIT_SUCCESS);
}
@@ -84,17 +64,25 @@ main(int argc, char *argv[])
*/
if (S_ISLNK (stbuf.st_mode))
continue;
/* If not a mountpoint, skip it */
struct statvfs stvfsbuf;
if (statvfs (target, &stvfsbuf) == -1)
continue;
/* If no read-only flag, skip it */
if ((stvfsbuf.f_flag & ST_RDONLY) == 0)
continue;
/* It's a mounted, read-only fs; remount it */
if (mount (target, target, NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
{
{
/* Also ignore ENINVAL - if the target isn't a mountpoint
* already, then assume things are OK.
*/
if (errno != EINVAL)
err (EXIT_FAILURE, "failed to remount %s", target);
}
}
else
printf ("Remounted: %s\n", target);
}
maybe_mount_tmpfs_on_var ();
exit (EXIT_SUCCESS);
}
+67
View File
@@ -0,0 +1,67 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2017 Colin Walters <walters@verbum.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <err.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include "ostree-cmdprivate.h"
#include "ostree-mount-util.h"
static const char *arg_dest = "/tmp";
static const char *arg_dest_late = "/tmp";
/* This program is a simple stub that calls the implementation that
* lives inside libostree.
*/
int
main(int argc, char *argv[])
{
/* Important: if this isn't an ostree-booted system, do nothing; people could
* have the package installed as a dependency for flatpak or whatever.
*/
{ struct stat stbuf;
if (fstatat (AT_FDCWD, "/run/ostree-booted", &stbuf, 0) < 0)
exit (EXIT_SUCCESS);
}
if (argc > 1 && argc != 4)
errx (EXIT_FAILURE, "This program takes three or no arguments");
if (argc > 1)
arg_dest = argv[1];
if (argc > 3)
arg_dest_late = argv[3];
char *ostree_cmdline = read_proc_cmdline_ostree ();
if (!ostree_cmdline)
errx (EXIT_FAILURE, "Failed to find ostree= kernel argument");
{ g_autoptr(GError) local_error = NULL;
if (!ostree_cmd__private__()->ostree_system_generator (ostree_cmdline, arg_dest, NULL, arg_dest_late, &local_error))
errx (EXIT_FAILURE, "%s", local_error->message);
}
exit (EXIT_SUCCESS);
}