New upstream version 2017.10
This commit is contained in:
commit
592e798794
140 files changed
+4813
-1216
No files matched your search
@@ -18,8 +18,6 @@
|
||||
***/
|
||||
|
||||
/* Add new symbols here. Release commits should copy this section into -released.sym. */
|
||||
LIBOSTREE_2017.10 {
|
||||
};
|
||||
|
||||
/* Stub section for the stable release *after* this development one; don't
|
||||
* edit this other than to update the last number. This is just a copy/paste
|
||||
|
||||
@@ -70,6 +70,7 @@ global:
|
||||
ostree_repo_list_collection_refs;
|
||||
ostree_repo_pull_from_remotes_async;
|
||||
ostree_repo_pull_from_remotes_finish;
|
||||
ostree_repo_remote_list_collection_refs;
|
||||
ostree_repo_resolve_keyring_for_collection;
|
||||
ostree_repo_set_collection_id;
|
||||
ostree_repo_set_collection_ref_immediate;
|
||||
|
||||
@@ -416,6 +416,17 @@ global:
|
||||
LIBOSTREE_2017.9 {
|
||||
};
|
||||
|
||||
LIBOSTREE_2017.10 {
|
||||
ostree_gpg_error_quark;
|
||||
ostree_repo_set_alias_ref_immediate;
|
||||
ostree_repo_open_at;
|
||||
ostree_repo_create_at;
|
||||
/* Inherit from .8 since .9 is empty and is also broken
|
||||
* in that it doesn't have a parent currently;
|
||||
* <https://github.com/ostreedev/ostree/issues/1087>
|
||||
*/
|
||||
} LIBOSTREE_2017.8;
|
||||
|
||||
/* NOTE: Only add more content here in release commits! See the
|
||||
* comments at the top of this file.
|
||||
*/
|
||||
@@ -38,9 +38,19 @@
|
||||
* among others.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define GRUB2_USES_16 1
|
||||
#define GRUB2_SUFFIX "16"
|
||||
#else
|
||||
#define GRUB2_USES_16 0
|
||||
#define GRUB2_SUFFIX ""
|
||||
#endif
|
||||
/* https://github.com/projectatomic/rpm-ostree-toolbox/issues/102#issuecomment-316483554
|
||||
* https://github.com/rhboot/grubby/blob/34b1436ccbd56eab8024314cab48f2fc880eef08/grubby.c#L63
|
||||
*
|
||||
* This is true at least on Fedora/Red Hat Enterprise Linux for aarch64.
|
||||
*/
|
||||
#if defined(__aarch64__)
|
||||
#define GRUB2_EFI_SUFFIX ""
|
||||
#else
|
||||
#define GRUB2_EFI_SUFFIX "efi"
|
||||
#endif
|
||||
|
||||
struct _OstreeBootloaderGrub2
|
||||
@@ -214,16 +224,12 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
|
||||
"No \"linux\" key in bootloader config");
|
||||
goto out;
|
||||
}
|
||||
g_string_append (output, "linux");
|
||||
if (is_efi)
|
||||
g_string_append (output, "linuxefi ");
|
||||
g_string_append (output, GRUB2_EFI_SUFFIX);
|
||||
else
|
||||
{
|
||||
#if GRUB2_USES_16
|
||||
g_string_append (output, "linux16 ");
|
||||
#else
|
||||
g_string_append (output, "linux ");
|
||||
#endif
|
||||
}
|
||||
g_string_append (output, GRUB2_SUFFIX);
|
||||
g_string_append_c (output, ' ');
|
||||
g_string_append (output, kernel);
|
||||
|
||||
options = ostree_bootconfig_parser_get (config, "options");
|
||||
@@ -237,16 +243,12 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot
|
||||
initrd = ostree_bootconfig_parser_get (config, "initrd");
|
||||
if (initrd)
|
||||
{
|
||||
g_string_append (output, "initrd");
|
||||
if (is_efi)
|
||||
g_string_append (output, "initrdefi ");
|
||||
g_string_append (output, GRUB2_EFI_SUFFIX);
|
||||
else
|
||||
{
|
||||
#if GRUB2_USES_16
|
||||
g_string_append (output, "initrd16 ");
|
||||
#else
|
||||
g_string_append (output, "initrd ");
|
||||
#endif
|
||||
}
|
||||
g_string_append (output, GRUB2_SUFFIX);
|
||||
g_string_append_c (output, ' ');
|
||||
g_string_append (output, initrd);
|
||||
g_string_append_c (output, '\n');
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "otutil.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -48,6 +49,7 @@ struct _OstreeBootloaderInterface
|
||||
GError **error);
|
||||
gboolean (* is_atomic) (OstreeBootloader *self);
|
||||
};
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeBootloader, g_object_unref)
|
||||
|
||||
GType _ostree_bootloader_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "otutil.h"
|
||||
#include "ostree.h"
|
||||
#include "ostree-deployment-private.h"
|
||||
#include "libglnx.h"
|
||||
|
||||
typedef GObjectClass OstreeDeploymentClass;
|
||||
|
||||
@@ -138,7 +139,7 @@ _ostree_deployment_set_bootcsum (OstreeDeployment *self,
|
||||
OstreeDeployment *
|
||||
ostree_deployment_clone (OstreeDeployment *self)
|
||||
{
|
||||
glnx_unref_object OstreeBootconfigParser *new_bootconfig = NULL;
|
||||
g_autoptr(OstreeBootconfigParser) new_bootconfig = NULL;
|
||||
OstreeDeployment *ret = ostree_deployment_new (self->index, self->osname, self->csum,
|
||||
self->deployserial,
|
||||
self->bootcsum, self->bootserial);
|
||||
@@ -159,7 +160,7 @@ ostree_deployment_clone (OstreeDeployment *self)
|
||||
new_origin = g_key_file_new ();
|
||||
success = g_key_file_load_from_data (new_origin, data, len, 0, NULL);
|
||||
g_assert (success);
|
||||
|
||||
|
||||
ostree_deployment_set_origin (ret, new_origin);
|
||||
}
|
||||
return ret;
|
||||
@@ -186,8 +187,8 @@ ostree_deployment_equal (gconstpointer ap, gconstpointer bp)
|
||||
{
|
||||
OstreeDeployment *a = (OstreeDeployment*)ap;
|
||||
OstreeDeployment *b = (OstreeDeployment*)bp;
|
||||
|
||||
if (a == NULL && b == NULL)
|
||||
|
||||
if (a == b)
|
||||
return TRUE;
|
||||
else if (a != NULL && b != NULL)
|
||||
return g_str_equal (ostree_deployment_get_osname (a),
|
||||
@@ -195,7 +196,7 @@ ostree_deployment_equal (gconstpointer ap, gconstpointer bp)
|
||||
g_str_equal (ostree_deployment_get_csum (a),
|
||||
ostree_deployment_get_csum (b)) &&
|
||||
ostree_deployment_get_deployserial (a) == ostree_deployment_get_deployserial (b);
|
||||
else
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -235,7 +236,7 @@ ostree_deployment_new (int index,
|
||||
int bootserial)
|
||||
{
|
||||
OstreeDeployment *self;
|
||||
|
||||
|
||||
/* index may be -1 */
|
||||
g_return_val_if_fail (osname != NULL, NULL);
|
||||
g_return_val_if_fail (csum != NULL, NULL);
|
||||
|
||||
@@ -425,11 +425,9 @@ static gboolean
|
||||
timer_cb (gpointer data)
|
||||
{
|
||||
OstreeFetcher *fetcher = data;
|
||||
CURLMcode rc;
|
||||
GSource *orig_src = fetcher->timer_event;
|
||||
|
||||
rc = curl_multi_socket_action (fetcher->multi, CURL_SOCKET_TIMEOUT, 0, &fetcher->curl_running);
|
||||
g_assert (rc == CURLM_OK);
|
||||
(void)curl_multi_socket_action (fetcher->multi, CURL_SOCKET_TIMEOUT, 0, &fetcher->curl_running);
|
||||
check_multi_info (fetcher);
|
||||
if (fetcher->timer_event == orig_src)
|
||||
fetcher->timer_event = NULL;
|
||||
@@ -460,15 +458,12 @@ static gboolean
|
||||
event_cb (int fd, GIOCondition condition, gpointer data)
|
||||
{
|
||||
OstreeFetcher *fetcher = data;
|
||||
CURLMcode rc;
|
||||
|
||||
int action =
|
||||
(condition & G_IO_IN ? CURL_CSELECT_IN : 0) |
|
||||
(condition & G_IO_OUT ? CURL_CSELECT_OUT : 0);
|
||||
|
||||
rc = curl_multi_socket_action (fetcher->multi, fd, action, &fetcher->curl_running);
|
||||
g_assert (rc == CURLM_OK);
|
||||
|
||||
(void)curl_multi_socket_action (fetcher->multi, fd, action, &fetcher->curl_running);
|
||||
check_multi_info (fetcher);
|
||||
if (fetcher->curl_running > 0)
|
||||
{
|
||||
|
||||
@@ -350,7 +350,7 @@ session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure,
|
||||
const char *cert_and_key_path = data; /* str\0str\0 in one malloc buf */
|
||||
const char *cert_path = cert_and_key_path;
|
||||
const char *key_path = cert_and_key_path + strlen (cert_and_key_path) + 1;
|
||||
glnx_unref_object OstreeTlsCertInteraction *interaction = NULL;
|
||||
g_autoptr(OstreeTlsCertInteraction) interaction = NULL;
|
||||
|
||||
/* The GTlsInteraction instance must be created in the
|
||||
* session thread so it uses the correct GMainContext. */
|
||||
|
||||
@@ -40,6 +40,7 @@ struct OstreeGpgVerifier {
|
||||
GObject parent;
|
||||
|
||||
GList *keyrings;
|
||||
GPtrArray *keyring_data;
|
||||
GPtrArray *key_ascii_files;
|
||||
};
|
||||
|
||||
@@ -53,6 +54,7 @@ ostree_gpg_verifier_finalize (GObject *object)
|
||||
g_list_free_full (self->keyrings, g_object_unref);
|
||||
if (self->key_ascii_files)
|
||||
g_ptr_array_unref (self->key_ascii_files);
|
||||
g_clear_pointer (&self->keyring_data, (GDestroyNotify)g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (_ostree_gpg_verifier_parent_class)->finalize (object);
|
||||
}
|
||||
@@ -71,6 +73,7 @@ _ostree_gpg_verifier_class_init (OstreeGpgVerifierClass *klass)
|
||||
static void
|
||||
_ostree_gpg_verifier_init (OstreeGpgVerifier *self)
|
||||
{
|
||||
self->keyring_data = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -95,8 +98,8 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
|
||||
{
|
||||
GLNX_AUTO_PREFIX_ERROR("GPG", error);
|
||||
gpgme_error_t gpg_error = 0;
|
||||
ot_auto_gpgme_data gpgme_data_t data_buffer = NULL;
|
||||
ot_auto_gpgme_data gpgme_data_t signature_buffer = NULL;
|
||||
g_auto(gpgme_data_t) data_buffer = NULL;
|
||||
g_auto(gpgme_data_t) signature_buffer = NULL;
|
||||
g_autofree char *tmp_dir = NULL;
|
||||
g_autoptr(GOutputStream) target_stream = NULL;
|
||||
OstreeGpgVerifyResult *result = NULL;
|
||||
@@ -151,6 +154,17 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (guint i = 0; i < self->keyring_data->len; i++)
|
||||
{
|
||||
GBytes *keyringd = self->keyring_data->pdata[i];
|
||||
gsize len;
|
||||
gsize bytes_written;
|
||||
const guint8 *buf = g_bytes_get_data (keyringd, &len);
|
||||
if (!g_output_stream_write_all (target_stream, buf, len, &bytes_written,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_output_stream_close (target_stream, cancellable, error))
|
||||
goto out;
|
||||
|
||||
@@ -165,7 +179,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
|
||||
{
|
||||
const char *path = self->key_ascii_files->pdata[i];
|
||||
glnx_fd_close int fd = -1;
|
||||
ot_auto_gpgme_data gpgme_data_t kdata = NULL;
|
||||
g_auto(gpgme_data_t) kdata = NULL;
|
||||
|
||||
if (!glnx_openat_rdonly (AT_FDCWD, path, TRUE, &fd, error))
|
||||
goto out;
|
||||
@@ -253,15 +267,28 @@ out:
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Given @path which should contain a GPG keyring file, add it
|
||||
* to the list of trusted keys.
|
||||
*/
|
||||
void
|
||||
_ostree_gpg_verifier_add_keyring (OstreeGpgVerifier *self,
|
||||
GFile *path)
|
||||
_ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self,
|
||||
GFile *path)
|
||||
{
|
||||
g_return_if_fail (G_IS_FILE (path));
|
||||
|
||||
self->keyrings = g_list_append (self->keyrings, g_object_ref (path));
|
||||
}
|
||||
|
||||
/* Given @keyring which should be the contents of a GPG keyring file, add it to
|
||||
* the list of trusted keys.
|
||||
*/
|
||||
void
|
||||
_ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self,
|
||||
GBytes *keyring)
|
||||
{
|
||||
g_ptr_array_add (self->keyring_data, g_bytes_ref (keyring));
|
||||
}
|
||||
|
||||
void
|
||||
_ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self,
|
||||
const char *path)
|
||||
@@ -276,32 +303,39 @@ _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self,
|
||||
GFile *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
g_autoptr(GFileEnumerator) enumerator = NULL;
|
||||
|
||||
enumerator = g_file_enumerate_children (path, OSTREE_GIO_FAST_QUERYINFO,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
cancellable, error);
|
||||
if (!enumerator)
|
||||
goto out;
|
||||
return _ostree_gpg_verifier_add_keyring_dir_at (self, AT_FDCWD,
|
||||
gs_file_get_path_cached (path),
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self,
|
||||
int dfd,
|
||||
const char *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
|
||||
{
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
if (!glnx_dirfd_iterator_init_at (dfd, path, FALSE,
|
||||
&dfd_iter, error))
|
||||
return FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
GFileInfo *file_info;
|
||||
GFile *path;
|
||||
const char *name;
|
||||
struct dirent *dent;
|
||||
|
||||
if (!g_file_enumerator_iterate (enumerator, &file_info, &path,
|
||||
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;
|
||||
|
||||
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR)
|
||||
if (dent->d_type != DT_REG)
|
||||
continue;
|
||||
|
||||
name = g_file_info_get_name (file_info);
|
||||
const char *name = dent->d_name;
|
||||
|
||||
/* Files with a .gpg suffix are typically keyrings except
|
||||
* for trustdb.gpg, which is the GPG trust database. */
|
||||
@@ -315,12 +349,18 @@ _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self,
|
||||
if (g_str_equal (name, "secring.gpg"))
|
||||
continue;
|
||||
|
||||
self->keyrings = g_list_append (self->keyrings, g_object_ref (path));
|
||||
glnx_fd_close int fd = -1;
|
||||
if (!glnx_openat_rdonly (dfd_iter.fd, dent->d_name, TRUE, &fd, error))
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GBytes) data = glnx_fd_readall_bytes (fd, cancellable, error);
|
||||
if (!data)
|
||||
return FALSE;
|
||||
|
||||
g_ptr_array_add (self->keyring_data, g_steal_pointer (&data));
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
||||
@@ -55,12 +55,20 @@ gboolean _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean _ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self,
|
||||
int dfd,
|
||||
const char *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean _ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
void _ostree_gpg_verifier_add_keyring (OstreeGpgVerifier *self,
|
||||
GFile *path);
|
||||
void _ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self,
|
||||
GBytes *data);
|
||||
void _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self,
|
||||
GFile *path);
|
||||
|
||||
void _ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self,
|
||||
const char *path);
|
||||
|
||||
@@ -237,34 +237,49 @@ ostree_gpg_verify_result_lookup (OstreeGpgVerifyResult *result,
|
||||
const gchar *key_id,
|
||||
guint *out_signature_index)
|
||||
{
|
||||
g_autofree char *key_id_upper = NULL;
|
||||
g_auto(gpgme_key_t) lookup_key = NULL;
|
||||
gpgme_signature_t signature;
|
||||
guint signature_index;
|
||||
gboolean ret = FALSE;
|
||||
|
||||
g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), FALSE);
|
||||
g_return_val_if_fail (key_id != NULL, FALSE);
|
||||
|
||||
/* signature->fpr is always upper-case. */
|
||||
key_id_upper = g_ascii_strup (key_id, -1);
|
||||
/* fetch requested key_id from keyring to canonicalise ID */
|
||||
(void) gpgme_get_key (result->context, key_id, &lookup_key, 0);
|
||||
|
||||
if (lookup_key == NULL)
|
||||
{
|
||||
g_debug ("Could not find key ID %s to lookup signature.", key_id);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (signature = result->details->signatures, signature_index = 0;
|
||||
signature != NULL;
|
||||
signature = signature->next, signature_index++)
|
||||
{
|
||||
if (signature->fpr == NULL)
|
||||
continue;
|
||||
g_auto(gpgme_key_t) signature_key = NULL;
|
||||
|
||||
if (g_str_has_suffix (signature->fpr, key_id_upper))
|
||||
(void) gpgme_get_key (result->context, signature->fpr, &signature_key, 0);
|
||||
|
||||
if (signature_key == NULL)
|
||||
{
|
||||
g_debug ("Could not find key when looking up signature from %s.", signature->fpr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* the first subkey in the list is the primary key */
|
||||
if (!g_strcmp0 (lookup_key->subkeys->fpr,
|
||||
signature_key->subkeys->fpr))
|
||||
{
|
||||
if (out_signature_index != NULL)
|
||||
*out_signature_index = signature_index;
|
||||
ret = TRUE;
|
||||
break;
|
||||
/* Note early return */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,7 +306,7 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result,
|
||||
guint n_attrs)
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
gpgme_key_t key = NULL;
|
||||
g_auto(gpgme_key_t) key = NULL;
|
||||
gpgme_signature_t signature;
|
||||
guint ii;
|
||||
|
||||
@@ -313,7 +328,8 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result,
|
||||
* (OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING). */
|
||||
for (ii = 0; ii < n_attrs; ii++)
|
||||
{
|
||||
if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME ||
|
||||
if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT ||
|
||||
attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME ||
|
||||
attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL)
|
||||
{
|
||||
(void) gpgme_get_key (result->context, signature->fpr, &key, 0);
|
||||
@@ -357,7 +373,11 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result,
|
||||
break;
|
||||
|
||||
case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT:
|
||||
child = g_variant_new_string (signature->fpr);
|
||||
if (key != NULL && key->subkeys != NULL)
|
||||
v_string = key->subkeys->fpr;
|
||||
else
|
||||
v_string = signature->fpr;
|
||||
child = g_variant_new_string (v_string);
|
||||
break;
|
||||
|
||||
case OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP:
|
||||
@@ -407,9 +427,6 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result,
|
||||
g_variant_builder_add_value (&builder, child);
|
||||
}
|
||||
|
||||
if (key != NULL)
|
||||
gpgme_key_unref (key);
|
||||
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
@@ -665,9 +682,12 @@ ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result,
|
||||
|
||||
if (ostree_gpg_verify_result_count_valid (result) == 0)
|
||||
{
|
||||
return glnx_throw (error, "%s",
|
||||
"GPG signatures found, but none are in trusted keyring");
|
||||
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_MISSING_KEY,
|
||||
"GPG signatures found, but none are in trusted keyring");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
G_DEFINE_QUARK (OstreeGpgError, ostree_gpg_error)
|
||||
@@ -137,4 +137,25 @@ _OSTREE_PUBLIC
|
||||
gboolean ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* OstreeGpgError:
|
||||
* @OSTREE_GPG_ERROR_NO_SIGNATURE: A signature was expected, but not found.
|
||||
* @OSTREE_GPG_ERROR_INVALID_SIGNATURE: A signature was malformed.
|
||||
* @OSTREE_GPG_ERROR_MISSING_KEY: A signature was found, but was created with a key not in the configured keyrings.
|
||||
*
|
||||
* Errors returned by signature creation and verification operations in OSTree.
|
||||
* These may be returned by any API which creates or verifies signatures.
|
||||
*
|
||||
* Since: 2017.10
|
||||
*/
|
||||
typedef enum {
|
||||
OSTREE_GPG_ERROR_NO_SIGNATURE = 0,
|
||||
OSTREE_GPG_ERROR_INVALID_SIGNATURE,
|
||||
OSTREE_GPG_ERROR_MISSING_KEY,
|
||||
} OstreeGpgError;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
GQuark ostree_gpg_error_quark (void);
|
||||
#define OSTREE_GPG_ERROR (ostree_gpg_error_quark ())
|
||||
|
||||
G_END_DECLS
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
#ifdef HAVE_LIBMOUNT
|
||||
typedef FILE OtLibMountFile;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtLibMountFile, endmntent);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtLibMountFile, endmntent)
|
||||
|
||||
/* Taken from systemd path-util.c */
|
||||
static bool
|
||||
|
||||
@@ -22,8 +22,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include "libglnx.h"
|
||||
#include "otutil.h"
|
||||
#ifdef HAVE_LIBARCHIVE
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
@@ -32,14 +34,10 @@
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef HAVE_LIBARCHIVE
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION (void *, flatpak_local_free_write_archive, archive_write_free)
|
||||
#define ot_cleanup_write_archive __attribute__((cleanup (flatpak_local_free_write_archive)))
|
||||
|
||||
GLNX_DEFINE_CLEANUP_FUNCTION (void *, flatpak_local_free_read_archive, archive_read_free)
|
||||
#define ot_cleanup_read_archive __attribute__((cleanup (flatpak_local_free_read_archive)))
|
||||
#else
|
||||
#define ot_cleanup_write_archive
|
||||
#define ot_cleanup_read_archive
|
||||
typedef struct archive OtAutoArchiveWrite;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveWrite, archive_write_free)
|
||||
typedef struct archive OtAutoArchiveRead;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveRead, archive_read_free)
|
||||
#endif
|
||||
|
||||
G_END_DECLS
|
||||
@@ -40,6 +40,7 @@ struct OstreeMetalinkClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMetalink, g_object_unref)
|
||||
|
||||
GType _ostree_metalink_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ostree-mutable-tree.h"
|
||||
#include "otutil.h"
|
||||
#include "ostree-core.h"
|
||||
#include "ostree.h"
|
||||
|
||||
/**
|
||||
* SECTION:ostree-mutable-tree
|
||||
@@ -183,7 +182,7 @@ ostree_mutable_tree_ensure_dir (OstreeMutableTree *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
glnx_unref_object OstreeMutableTree *ret_dir = NULL;
|
||||
g_autoptr(OstreeMutableTree) ret_dir = NULL;
|
||||
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
|
||||
@@ -219,7 +218,7 @@ ostree_mutable_tree_lookup (OstreeMutableTree *self,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
glnx_unref_object OstreeMutableTree *ret_subdir = NULL;
|
||||
g_autoptr(OstreeMutableTree) ret_subdir = NULL;
|
||||
g_autofree char *ret_file_checksum = NULL;
|
||||
|
||||
ret_subdir = ot_gobject_refz (g_hash_table_lookup (self->subdirs, name));
|
||||
@@ -261,7 +260,7 @@ ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree *self,
|
||||
gboolean ret = FALSE;
|
||||
int i;
|
||||
OstreeMutableTree *subdir = self; /* nofree */
|
||||
glnx_unref_object OstreeMutableTree *ret_parent = NULL;
|
||||
g_autoptr(OstreeMutableTree) ret_parent = NULL;
|
||||
|
||||
g_assert (metadata_checksum != NULL);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ checkout_state_clear (CheckoutState *state)
|
||||
if (state->selabel_path_buf)
|
||||
g_string_free (state->selabel_path_buf, TRUE);
|
||||
}
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(CheckoutState, checkout_state_clear);
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(CheckoutState, checkout_state_clear)
|
||||
|
||||
static gboolean
|
||||
checkout_object_for_uncompressed_cache (OstreeRepo *self,
|
||||
@@ -122,7 +122,7 @@ write_regular_file_content (OstreeRepo *self,
|
||||
int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input);
|
||||
guint64 len = g_file_info_get_size (file_info);
|
||||
|
||||
if (glnx_regfile_copy_bytes (infd, outfd, (off_t)len, TRUE) < 0)
|
||||
if (glnx_regfile_copy_bytes (infd, outfd, (off_t)len) < 0)
|
||||
return glnx_throw_errno_prefix (error, "regfile copy");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -27,16 +27,16 @@
|
||||
#include <gio/gfiledescriptorbased.h>
|
||||
#include <gio/gunixinputstream.h>
|
||||
#include <gio/gunixoutputstream.h>
|
||||
#include "otutil.h"
|
||||
#include <sys/xattr.h>
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
#include "otutil.h"
|
||||
#include "ostree.h"
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ostree-repo-file-enumerator.h"
|
||||
#include "ostree-checksum-input-stream.h"
|
||||
#include "ostree-mutable-tree.h"
|
||||
#include "ostree-varint.h"
|
||||
#include <sys/xattr.h>
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
gboolean
|
||||
_ostree_repo_ensure_loose_objdir_at (int dfd,
|
||||
@@ -467,7 +467,7 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
|
||||
if (G_IS_FILE_DESCRIPTOR_BASED (input))
|
||||
{
|
||||
int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input);
|
||||
if (glnx_regfile_copy_bytes (infd, tmpf.fd, (off_t)length, TRUE) < 0)
|
||||
if (glnx_regfile_copy_bytes (infd, tmpf.fd, (off_t)length) < 0)
|
||||
return glnx_throw_errno_prefix (error, "regfile copy");
|
||||
}
|
||||
else
|
||||
@@ -485,10 +485,8 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self,
|
||||
g_input_stream_read (input, buf, MIN (remaining, sizeof (buf)), cancellable, error);
|
||||
if (bytes_read < 0)
|
||||
return FALSE;
|
||||
else if (G_UNLIKELY (bytes_read == 0 && remaining > 0))
|
||||
return glnx_throw (error, "Unexpected EOF with %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " bytes remaining", remaining, length);
|
||||
else if (bytes_read == 0)
|
||||
break;
|
||||
return glnx_throw (error, "Unexpected EOF with %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " bytes remaining", remaining, length);
|
||||
if (glnx_loop_write (tmpf.fd, buf, bytes_read) < 0)
|
||||
return glnx_throw_errno_prefix (error, "write");
|
||||
remaining -= bytes_read;
|
||||
@@ -1448,7 +1446,31 @@ ostree_repo_set_ref_immediate (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
const OstreeCollectionRef _ref = { NULL, (gchar *) ref };
|
||||
return _ostree_repo_write_ref (self, remote, &_ref, checksum,
|
||||
return _ostree_repo_write_ref (self, remote, &_ref, checksum, NULL,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_set_alias_ref_immediate:
|
||||
* @self: An #OstreeRepo
|
||||
* @remote: (allow-none): A remote for the ref
|
||||
* @ref: The ref to write
|
||||
* @target: (allow-none): The ref target to point it to, or %NULL to unset
|
||||
* @cancellable: GCancellable
|
||||
* @error: GError
|
||||
*
|
||||
* Like ostree_repo_set_ref_immediate(), but creates an alias.
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_set_alias_ref_immediate (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char *target,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
const OstreeCollectionRef _ref = { NULL, (gchar *) ref };
|
||||
return _ostree_repo_write_ref (self, remote, &_ref, NULL, target,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
@@ -1480,7 +1502,7 @@ ostree_repo_set_collection_ref_immediate (OstreeRepo *self,
|
||||
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
return _ostree_repo_write_ref (self, NULL, ref, checksum,
|
||||
return _ostree_repo_write_ref (self, NULL, ref, checksum, NULL,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
@@ -2528,7 +2550,7 @@ write_directory_content_to_mtree_internal (OstreeRepo *self,
|
||||
{
|
||||
g_autoptr(GFile) child = NULL;
|
||||
g_autoptr(GFileInfo) modified_info = NULL;
|
||||
glnx_unref_object OstreeMutableTree *child_mtree = NULL;
|
||||
g_autoptr(OstreeMutableTree) child_mtree = NULL;
|
||||
g_autofree char *child_relpath = NULL;
|
||||
const char *name;
|
||||
GFileType file_type;
|
||||
|
||||
@@ -556,7 +556,8 @@ get_refs_and_checksums_from_summary (GBytes *summary_bytes,
|
||||
}
|
||||
|
||||
/* Download the summary file from @remote, and return the bytes of the file in
|
||||
* @out_summary_bytes. */
|
||||
* @out_summary_bytes. This will return %TRUE and set @out_summary_bytes to %NULL
|
||||
* if the summary file does not exist. */
|
||||
static gboolean
|
||||
fetch_summary_from_remote (OstreeRepo *repo,
|
||||
OstreeRemote *remote,
|
||||
@@ -648,6 +649,13 @@ get_checksums (OstreeRepoFinderAvahi *finder,
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
if (summary_bytes == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"No summary file found on server");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return get_refs_and_checksums_from_summary (summary_bytes, supported_ref_to_checksum, error);
|
||||
}
|
||||
|
||||
@@ -816,9 +824,10 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService
|
||||
g_clear_pointer (&remote->keyring, g_free);
|
||||
remote->keyring = g_strdup (repo->keyring);
|
||||
|
||||
/* gpg-verify-summary is false since we use the unsigned summary file support. */
|
||||
g_key_file_set_string (remote->options, remote->group, "url", repo->uri);
|
||||
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE);
|
||||
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", TRUE);
|
||||
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE);
|
||||
|
||||
get_checksums (finder, parent_repo, remote, supported_ref_to_checksum, &error);
|
||||
if (error != NULL)
|
||||
@@ -830,7 +839,7 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService
|
||||
|
||||
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, OSTREE_REPO_FINDER (finder),
|
||||
priority, supported_ref_to_checksum,
|
||||
(summary_timestamp != NULL) ? GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp)) : 0));
|
||||
GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp))));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,9 +111,10 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
|
||||
for (i = 0; i < n_remotes; i++)
|
||||
{
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
g_autoptr(GHashTable) remote_refs = NULL; /* (element-type utf8 utf8) */
|
||||
g_autoptr(GHashTable) remote_refs = NULL; /* (element-type OstreeCollectionRef utf8) */
|
||||
const gchar *checksum;
|
||||
g_autofree gchar *remote_collection_id = NULL;
|
||||
gboolean resolved_a_ref = FALSE;
|
||||
|
||||
remote_name = remotes[i];
|
||||
|
||||
@@ -127,8 +128,9 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ostree_repo_remote_list_refs (parent_repo, remote_name, &remote_refs,
|
||||
cancellable, &local_error))
|
||||
if (!ostree_repo_remote_list_collection_refs (parent_repo, remote_name,
|
||||
&remote_refs, cancellable,
|
||||
&local_error))
|
||||
{
|
||||
g_debug ("Ignoring remote ‘%s’ due to error loading its refs: %s",
|
||||
remote_name, local_error->message);
|
||||
@@ -139,13 +141,14 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
|
||||
for (j = 0; refs[j] != NULL; j++)
|
||||
{
|
||||
if (g_strcmp0 (refs[j]->collection_id, remote_collection_id) == 0 &&
|
||||
g_hash_table_lookup_extended (remote_refs, refs[j]->ref_name, NULL, (gpointer *) &checksum))
|
||||
g_hash_table_lookup_extended (remote_refs, refs[j], NULL, (gpointer *) &checksum))
|
||||
{
|
||||
/* The requested ref is listed in the refs for this remote. Add
|
||||
* the remote to the results, and the ref to its
|
||||
* @supported_ref_to_checksum. */
|
||||
g_debug ("Resolved ref (%s, %s) to remote ‘%s’.",
|
||||
refs[j]->collection_id, refs[j]->ref_name, remote_name);
|
||||
resolved_a_ref = TRUE;
|
||||
|
||||
supported_ref_to_checksum = g_hash_table_lookup (repo_name_to_refs, remote_name);
|
||||
|
||||
@@ -161,6 +164,9 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find
|
||||
(gpointer) refs[j], g_strdup (checksum));
|
||||
}
|
||||
}
|
||||
|
||||
if (!resolved_a_ref)
|
||||
g_debug ("Ignoring remote ‘%s’ due to it not advertising any of the requested refs.", remote_name);
|
||||
}
|
||||
|
||||
/* Aggregate the results. */
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
|
||||
#include "ostree-autocleanups.h"
|
||||
#include "ostree-remote-private.h"
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ostree-repo-finder.h"
|
||||
#include "ostree-repo-finder-mount.h"
|
||||
|
||||
@@ -257,19 +258,16 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||
{
|
||||
struct stat stbuf;
|
||||
g_autofree gchar *collection_and_ref = NULL;
|
||||
g_autofree gchar *repo_dir_path = NULL;
|
||||
g_autofree gchar *resolved_repo_uri = NULL;
|
||||
g_autofree gchar *keyring = NULL;
|
||||
g_autoptr(UriAndKeyring) resolved_repo = NULL;
|
||||
|
||||
collection_and_ref = g_build_filename (refs[i]->collection_id, refs[i]->ref_name, NULL);
|
||||
repo_dir_path = g_build_filename (mount_root_path, ".ostree", "repos",
|
||||
collection_and_ref, NULL);
|
||||
|
||||
if (!glnx_fstatat (repos_dfd, collection_and_ref, &stbuf, AT_NO_AUTOMOUNT, &local_error))
|
||||
{
|
||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as querying info of ‘%s’ failed: %s",
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, repo_dir_path, local_error->message);
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, local_error->message);
|
||||
g_clear_error (&local_error);
|
||||
continue;
|
||||
}
|
||||
@@ -277,7 +275,7 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||
if ((stbuf.st_mode & S_IFMT) != S_IFDIR)
|
||||
{
|
||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as ‘%s’ is of type %u, not a directory.",
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, repo_dir_path, (stbuf.st_mode & S_IFMT));
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, (stbuf.st_mode & S_IFMT));
|
||||
g_clear_error (&local_error);
|
||||
continue;
|
||||
}
|
||||
@@ -294,27 +292,19 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||
}
|
||||
|
||||
/* Exclude repositories which resolve to @parent_repo. */
|
||||
g_autofree char *canonical_repo_dir_path = realpath (repo_dir_path, NULL);
|
||||
g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (parent_repo));
|
||||
g_autofree char *canonical_parent_repo_path = realpath (parent_repo_path, NULL);
|
||||
|
||||
if (g_strcmp0 (canonical_repo_dir_path, canonical_parent_repo_path) == 0)
|
||||
if (stbuf.st_dev == parent_repo->device &&
|
||||
stbuf.st_ino == parent_repo->inode)
|
||||
{
|
||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository was the one we are resolving for: %s",
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, canonical_parent_repo_path);
|
||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as it is the same as the one we are resolving",
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name);
|
||||
g_clear_error (&local_error);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Grab the given ref and a checksum for it from the repo.
|
||||
* FIXME: Ideally, there would be some ostree_repo_open_at() which we
|
||||
* could use to keep the openat() chain going. See
|
||||
* https://github.com/ostreedev/ostree/pull/820. */
|
||||
g_autoptr(OstreeRepo) repo = NULL;
|
||||
g_autoptr(GFile) repo_dir_file = g_file_new_for_path (repo_dir_path);
|
||||
repo = ostree_repo_new (repo_dir_file);
|
||||
|
||||
if (!ostree_repo_open (repo, cancellable, &local_error))
|
||||
/* Grab the given ref and a checksum for it from the repo, if it appears to be a valid repo */
|
||||
g_autoptr(OstreeRepo) repo = ostree_repo_open_at (repos_dfd, collection_and_ref,
|
||||
cancellable, &local_error);
|
||||
if (!repo)
|
||||
{
|
||||
g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository could not be opened: %s",
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message);
|
||||
@@ -358,6 +348,11 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||
* $mount_root/.ostree/repos/$refs[i]->collection_id/$refs[i]->ref_name.
|
||||
* Add it to the results, keyed by the canonicalised repository URI
|
||||
* to deduplicate the results. */
|
||||
|
||||
g_autofree char *repo_abspath = g_build_filename (mount_root_path, ".ostree/repos",
|
||||
collection_and_ref, NULL);
|
||||
/* FIXME - why are we using realpath here? */
|
||||
g_autofree char *canonical_repo_dir_path = realpath (repo_abspath, NULL);
|
||||
resolved_repo_uri = g_strconcat ("file://", canonical_repo_dir_path, NULL);
|
||||
g_debug ("Resolved ref (%s, %s) on mount ‘%s’ to repo URI ‘%s’ with keyring ‘%s’.",
|
||||
refs[i]->collection_id, refs[i]->ref_name, mount_name, resolved_repo_uri, keyring);
|
||||
@@ -392,9 +387,10 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
|
||||
g_clear_pointer (&remote->keyring, g_free);
|
||||
remote->keyring = g_strdup (repo->keyring);
|
||||
|
||||
/* gpg-verify-summary is false since we use the unsigned summary file support. */
|
||||
g_key_file_set_string (remote->options, remote->group, "url", repo->uri);
|
||||
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE);
|
||||
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", TRUE);
|
||||
g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE);
|
||||
|
||||
/* Set the timestamp in the #OstreeRepoFinderResult to 0 because
|
||||
* the code in ostree_repo_pull_from_remotes_async() will be able to
|
||||
|
||||
@@ -550,7 +550,9 @@ ostree_repo_finder_result_free (OstreeRepoFinderResult *result)
|
||||
{
|
||||
g_return_if_fail (result != NULL);
|
||||
|
||||
g_hash_table_unref (result->ref_to_checksum);
|
||||
/* This may be NULL iff the result is freed half-way through find_remotes_cb()
|
||||
* in ostree-repo-pull.c, and at no other time. */
|
||||
g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref);
|
||||
g_object_unref (result->finder);
|
||||
ostree_remote_unref (result->remote);
|
||||
g_free (result);
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "otutil.h"
|
||||
#include "ostree.h"
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ostree-repo-file.h"
|
||||
#include "ostree-mutable-tree.h"
|
||||
|
||||
#ifdef HAVE_LIBARCHIVE
|
||||
#include <archive.h>
|
||||
@@ -185,7 +185,7 @@ mtree_ensure_dir_with_meta (OstreeRepo *repo,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeMutableTree *dir = NULL;
|
||||
g_autoptr(OstreeMutableTree) dir = NULL;
|
||||
g_autofree guchar *csum_raw = NULL;
|
||||
g_autofree char *csum = NULL;
|
||||
|
||||
@@ -374,7 +374,7 @@ aic_create_parent_dirs (OstreeRepoArchiveImportContext *ctx,
|
||||
GError **error)
|
||||
{
|
||||
g_autofree char *fullpath = NULL;
|
||||
glnx_unref_object OstreeMutableTree *dir = NULL;
|
||||
g_autoptr(OstreeMutableTree) dir = NULL;
|
||||
|
||||
/* start with the root itself */
|
||||
if (!aic_ensure_parent_dir (ctx, ctx->root, "/", &dir, cancellable, error))
|
||||
@@ -643,7 +643,7 @@ aic_import_entry (OstreeRepoArchiveImportContext *ctx,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFileInfo) fi = NULL;
|
||||
glnx_unref_object OstreeMutableTree *parent = NULL;
|
||||
g_autoptr(OstreeMutableTree) parent = NULL;
|
||||
g_autofree char *path = aic_get_final_entry_pathname (ctx, error);
|
||||
|
||||
if (path == NULL)
|
||||
@@ -669,7 +669,7 @@ aic_import_from_hardlink (OstreeRepoArchiveImportContext *ctx,
|
||||
const char *name = glnx_basename (target);
|
||||
const char *name_dh = glnx_basename (dh->path);
|
||||
g_autoptr(GPtrArray) components = NULL;
|
||||
glnx_unref_object OstreeMutableTree *parent = NULL;
|
||||
g_autoptr(OstreeMutableTree) parent = NULL;
|
||||
|
||||
if (!ostree_mutable_tree_lookup (dh->parent, name_dh, &csum, NULL, error))
|
||||
return FALSE;
|
||||
@@ -696,8 +696,8 @@ aic_lookup_file_csum (OstreeRepoArchiveImportContext *ctx,
|
||||
{
|
||||
g_autofree char *csum = NULL;
|
||||
const char *name = glnx_basename (target);
|
||||
glnx_unref_object OstreeMutableTree *parent = NULL;
|
||||
glnx_unref_object OstreeMutableTree *subdir = NULL;
|
||||
g_autoptr(OstreeMutableTree) parent = NULL;
|
||||
g_autoptr(OstreeMutableTree) subdir = NULL;
|
||||
g_autoptr(GPtrArray) components = NULL;
|
||||
|
||||
if (!ot_util_path_split_validate (target, &components, error))
|
||||
@@ -900,7 +900,7 @@ ostree_repo_write_archive_to_mtree (OstreeRepo *self,
|
||||
{
|
||||
#ifdef HAVE_LIBARCHIVE
|
||||
gboolean ret = FALSE;
|
||||
ot_cleanup_read_archive struct archive *a = archive_read_new ();
|
||||
g_autoptr(OtAutoArchiveRead) a = archive_read_new ();
|
||||
OstreeRepoImportArchiveOptions opts = { 0, };
|
||||
|
||||
#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
#include "otutil.h"
|
||||
#include "ostree-ref.h"
|
||||
#include "ostree-repo.h"
|
||||
#include "ostree-remote-private.h"
|
||||
#include "otutil.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -96,7 +96,11 @@ struct OstreeRepo {
|
||||
char *commit_stagedir_name;
|
||||
GLnxLockFile commit_stagedir_lock;
|
||||
|
||||
GFile *repodir;
|
||||
/* A cached fd-relative version, distinct from the case where we may have a
|
||||
* user-provided absolute path.
|
||||
*/
|
||||
GFile *repodir_fdrel;
|
||||
GFile *repodir; /* May be %NULL if we were opened via ostree_repo_open_at() */
|
||||
int repo_dir_fd;
|
||||
int tmp_dir_fd;
|
||||
int cache_dir_fd;
|
||||
@@ -132,10 +136,13 @@ struct OstreeRepo {
|
||||
GHashTable *updated_uncompressed_dirs;
|
||||
GHashTable *object_sizes;
|
||||
|
||||
uid_t owner_uid;
|
||||
uid_t target_owner_uid;
|
||||
/* Cache the repo's device/inode to use for comparisons elsewhere */
|
||||
dev_t device;
|
||||
ino_t inode;
|
||||
uid_t owner_uid; /* Cache of repo's owner uid */
|
||||
uid_t target_owner_uid; /* Ensure files are chowned to this uid/gid */
|
||||
gid_t target_owner_gid;
|
||||
guint min_free_space_percent;
|
||||
guint min_free_space_percent; /* See the min-free-space-percent config option */
|
||||
|
||||
guint test_error_flags; /* OstreeRepoTestErrorFlags */
|
||||
|
||||
@@ -173,7 +180,7 @@ _ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state,
|
||||
|
||||
void
|
||||
_ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state);
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy);
|
||||
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-"
|
||||
@@ -265,6 +272,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *rev,
|
||||
const char *alias,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
|
||||
@@ -50,10 +50,21 @@
|
||||
|
||||
#include <gio/gunixinputstream.h>
|
||||
#include <sys/statvfs.h>
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
#include <systemd/sd-journal.h>
|
||||
#endif
|
||||
|
||||
#define OSTREE_MESSAGE_FETCH_COMPLETE_ID SD_ID128_MAKE(75,ba,3d,eb,0a,f0,41,a9,a4,62,72,ff,85,d9,e7,3e)
|
||||
|
||||
#define OSTREE_REPO_PULL_CONTENT_PRIORITY (OSTREE_FETCHER_DEFAULT_PRIORITY)
|
||||
#define OSTREE_REPO_PULL_METADATA_PRIORITY (OSTREE_REPO_PULL_CONTENT_PRIORITY - 100)
|
||||
|
||||
typedef enum {
|
||||
OSTREE_FETCHER_SECURITY_STATE_CA_PINNED,
|
||||
OSTREE_FETCHER_SECURITY_STATE_TLS,
|
||||
OSTREE_FETCHER_SECURITY_STATE_INSECURE,
|
||||
} OstreeFetcherSecurityState;
|
||||
|
||||
typedef struct {
|
||||
OstreeRepo *repo;
|
||||
int tmpdir_dfd;
|
||||
@@ -61,6 +72,8 @@ typedef struct {
|
||||
char *remote_name;
|
||||
OstreeRepoMode remote_mode;
|
||||
OstreeFetcher *fetcher;
|
||||
OstreeFetcherSecurityState fetcher_security_state;
|
||||
|
||||
GPtrArray *meta_mirrorlist; /* List of base URIs for fetching metadata */
|
||||
GPtrArray *content_mirrorlist; /* List of base URIs for fetching content */
|
||||
OstreeRepo *remote_repo_local;
|
||||
@@ -1405,12 +1418,12 @@ gpg_verify_unwritten_commit (OtPullData *pull_data,
|
||||
{
|
||||
if (pull_data->gpg_verify)
|
||||
{
|
||||
glnx_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
g_autoptr(OstreeGpgVerifyResult) result = NULL;
|
||||
g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit);
|
||||
|
||||
if (!detached_metadata)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
|
||||
"Commit %s: no detached metadata found for GPG verification",
|
||||
checksum);
|
||||
return FALSE;
|
||||
@@ -1611,7 +1624,7 @@ scan_commit_object (OtPullData *pull_data,
|
||||
|
||||
if (pull_data->gpg_verify)
|
||||
{
|
||||
glnx_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
g_autoptr(OstreeGpgVerifyResult) result = NULL;
|
||||
|
||||
result = ostree_repo_verify_commit_for_remote (pull_data->repo,
|
||||
checksum,
|
||||
@@ -1777,6 +1790,7 @@ scan_one_metadata_object_c (OtPullData *pull_data,
|
||||
{
|
||||
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
|
||||
{
|
||||
/* mark as partial to ensure we scan the commit below */
|
||||
if (!write_commitpartial_for (pull_data, tmp_checksum, error))
|
||||
return FALSE;
|
||||
}
|
||||
@@ -1806,6 +1820,12 @@ scan_one_metadata_object_c (OtPullData *pull_data,
|
||||
return FALSE;
|
||||
if (!localcache_repo_has_obj)
|
||||
continue;
|
||||
if (objtype == OSTREE_OBJECT_TYPE_COMMIT)
|
||||
{
|
||||
/* mark as partial to ensure we scan the commit below */
|
||||
if (!write_commitpartial_for (pull_data, tmp_checksum, error))
|
||||
return FALSE;
|
||||
}
|
||||
if (!ostree_repo_import_object_from_with_trust (pull_data->repo, refd_repo,
|
||||
objtype, tmp_checksum,
|
||||
!pull_data->is_untrusted,
|
||||
@@ -2450,7 +2470,7 @@ on_superblock_fetched (GObject *src,
|
||||
*/
|
||||
if (pull_data->gpg_verify_summary && !summary_csum)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
|
||||
"GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)");
|
||||
goto out;
|
||||
}
|
||||
@@ -2612,11 +2632,13 @@ static OstreeFetcher *
|
||||
_ostree_repo_remote_new_fetcher (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
gboolean gzip,
|
||||
OstreeFetcherSecurityState *out_state,
|
||||
GError **error)
|
||||
{
|
||||
OstreeFetcher *fetcher = NULL;
|
||||
OstreeFetcherConfigFlags fetcher_flags = 0;
|
||||
gboolean tls_permissive = FALSE;
|
||||
OstreeFetcherSecurityState ret_state = OSTREE_FETCHER_SECURITY_STATE_TLS;
|
||||
gboolean success = FALSE;
|
||||
|
||||
g_return_val_if_fail (OSTREE_IS_REPO (self), NULL);
|
||||
@@ -2628,7 +2650,10 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
|
||||
goto out;
|
||||
|
||||
if (tls_permissive)
|
||||
fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE;
|
||||
{
|
||||
fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE;
|
||||
ret_state = OSTREE_FETCHER_SECURITY_STATE_INSECURE;
|
||||
}
|
||||
|
||||
if (gzip)
|
||||
fetcher_flags |= OSTREE_FETCHER_FLAGS_TRANSFER_GZIP;
|
||||
@@ -2673,6 +2698,10 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
|
||||
if (tls_ca_path != NULL)
|
||||
{
|
||||
_ostree_fetcher_set_tls_database (fetcher, tls_ca_path);
|
||||
|
||||
/* Don't change if it's already _INSECURE */
|
||||
if (ret_state == OSTREE_FETCHER_SECURITY_STATE_TLS)
|
||||
ret_state = OSTREE_FETCHER_SECURITY_STATE_CA_PINNED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2706,6 +2735,8 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
|
||||
out:
|
||||
if (!success)
|
||||
g_clear_object (&fetcher);
|
||||
if (out_state)
|
||||
*out_state = ret_state;
|
||||
|
||||
return fetcher;
|
||||
}
|
||||
@@ -2724,7 +2755,7 @@ _ostree_preload_metadata_file (OstreeRepo *self,
|
||||
|
||||
if (is_metalink)
|
||||
{
|
||||
glnx_unref_object OstreeMetalink *metalink = NULL;
|
||||
g_autoptr(OstreeMetalink) metalink = NULL;
|
||||
GError *local_error = NULL;
|
||||
|
||||
/* the metalink uri is buried in the mirrorlist as the first (and only)
|
||||
@@ -2874,7 +2905,7 @@ repo_remote_fetch_summary (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeFetcher *fetcher = NULL;
|
||||
g_autoptr(OstreeFetcher) fetcher = NULL;
|
||||
g_autoptr(GMainContext) mainctx = NULL;
|
||||
gboolean ret = FALSE;
|
||||
gboolean from_cache = FALSE;
|
||||
@@ -2891,7 +2922,7 @@ repo_remote_fetch_summary (OstreeRepo *self,
|
||||
mainctx = g_main_context_new ();
|
||||
g_main_context_push_thread_default (mainctx);
|
||||
|
||||
fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, error);
|
||||
fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, NULL, error);
|
||||
if (fetcher == NULL)
|
||||
goto out;
|
||||
|
||||
@@ -3001,10 +3032,13 @@ repo_remote_fetch_summary (OstreeRepo *self,
|
||||
* any options specific to this pull (such as extra headers).
|
||||
*/
|
||||
static gboolean
|
||||
reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **error)
|
||||
reinitialize_fetcher (OtPullData *pull_data, const char *remote_name,
|
||||
GError **error)
|
||||
{
|
||||
g_clear_object (&pull_data->fetcher);
|
||||
pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, FALSE, error);
|
||||
pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, FALSE,
|
||||
&pull_data->fetcher_security_state,
|
||||
error);
|
||||
if (pull_data->fetcher == NULL)
|
||||
return FALSE;
|
||||
|
||||
@@ -3186,7 +3220,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
g_autoptr(GHashTable) requested_refs_to_fetch = NULL; /* (element-type OstreeCollectionRef utf8) */
|
||||
g_autoptr(GHashTable) commits_to_fetch = NULL;
|
||||
g_autofree char *remote_mode_str = NULL;
|
||||
glnx_unref_object OstreeMetalink *metalink = NULL;
|
||||
g_autoptr(OstreeMetalink) metalink = NULL;
|
||||
OtPullData pull_data_real = { 0, };
|
||||
OtPullData *pull_data = &pull_data_real;
|
||||
GKeyFile *remote_config = NULL;
|
||||
@@ -3210,6 +3244,10 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
g_autoptr(GHashTable) updated_requested_refs_to_fetch = NULL; /* (element-type OstreeCollectionRef utf8) */
|
||||
int i;
|
||||
g_autofree char **opt_localcache_repos = NULL;
|
||||
/* If refs or collection-refs has exactly one value, this will point to that
|
||||
* value, otherwise NULL. Used for logging.
|
||||
*/
|
||||
const char *the_ref_to_fetch = NULL;
|
||||
|
||||
if (options)
|
||||
{
|
||||
@@ -3239,6 +3277,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
(void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos);
|
||||
}
|
||||
|
||||
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
|
||||
g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE);
|
||||
g_return_val_if_fail (!opt_collection_refs_set ||
|
||||
(refs_to_fetch == NULL && override_commit_ids == NULL), FALSE);
|
||||
@@ -3621,21 +3660,21 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
|
||||
if (!bytes_summary && pull_data->gpg_verify_summary)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"GPG verification enabled, but no summary found (use gpg-verify-summary=false in remote config to disable)");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!bytes_summary && pull_data->require_static_deltas)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"Fetch configured to require static deltas, but no summary found");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!bytes_sig && pull_data->gpg_verify_summary)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
|
||||
"GPG verification enabled, but no summary.sig found (use gpg-verify-summary=false in remote config to disable)");
|
||||
goto out;
|
||||
}
|
||||
@@ -3892,6 +3931,15 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
|
||||
g_hash_table_unref (requested_refs_to_fetch);
|
||||
requested_refs_to_fetch = g_steal_pointer (&updated_requested_refs_to_fetch);
|
||||
if (g_hash_table_size (requested_refs_to_fetch) == 1)
|
||||
{
|
||||
GLNX_HASH_TABLE_FOREACH (requested_refs_to_fetch,
|
||||
const OstreeCollectionRef *, ref)
|
||||
{
|
||||
the_ref_to_fetch = ref->ref_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the state directory here - it's new with the commitpartial code,
|
||||
* and may not exist in older repositories.
|
||||
@@ -4060,6 +4108,69 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
ostree_async_progress_set_status (pull_data->progress, buf->str);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
if (bytes_transferred > 0 && pull_data->remote_name)
|
||||
{
|
||||
g_autoptr(GString) msg = g_string_new ("");
|
||||
if (the_ref_to_fetch)
|
||||
g_string_append_printf (msg, "libostree pull from '%s' for %s complete",
|
||||
pull_data->remote_name, the_ref_to_fetch);
|
||||
else
|
||||
g_string_append_printf (msg, "libostree pull from '%s' for %u refs complete",
|
||||
pull_data->remote_name, g_hash_table_size (requested_refs_to_fetch));
|
||||
|
||||
const char *gpg_verify_state;
|
||||
if (pull_data->gpg_verify_summary)
|
||||
{
|
||||
if (pull_data->gpg_verify)
|
||||
gpg_verify_state = "summary+commit";
|
||||
else
|
||||
gpg_verify_state = "summary-only";
|
||||
}
|
||||
else
|
||||
gpg_verify_state = (pull_data->gpg_verify ? "commit" : "disabled");
|
||||
g_string_append_printf (msg, "\nsecurity: GPG: %s ", gpg_verify_state);
|
||||
OstreeFetcherURI *first_uri = pull_data->meta_mirrorlist->pdata[0];
|
||||
g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri);
|
||||
if (g_str_has_prefix (first_scheme, "http"))
|
||||
{
|
||||
g_string_append (msg, "http: ");
|
||||
switch (pull_data->fetcher_security_state)
|
||||
{
|
||||
case OSTREE_FETCHER_SECURITY_STATE_CA_PINNED:
|
||||
g_string_append (msg, "CA-pinned");
|
||||
break;
|
||||
case OSTREE_FETCHER_SECURITY_STATE_TLS:
|
||||
g_string_append (msg, "TLS");
|
||||
break;
|
||||
case OSTREE_FETCHER_SECURITY_STATE_INSECURE:
|
||||
g_string_append (msg, "insecure");
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_string_append (msg, "\n");
|
||||
|
||||
if (pull_data->n_fetched_deltaparts > 0)
|
||||
g_string_append_printf (msg, "delta: parts: %u loose: %u",
|
||||
pull_data->n_fetched_deltaparts,
|
||||
pull_data->n_fetched_metadata + pull_data->n_fetched_content);
|
||||
else
|
||||
g_string_append_printf (msg, "non-delta: meta: %u content: %u",
|
||||
pull_data->n_fetched_metadata, pull_data->n_fetched_content);
|
||||
const guint n_seconds = (guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC);
|
||||
g_autofree char *formatted_xferred = g_format_size (bytes_transferred);
|
||||
g_string_append_printf (msg, "\ntransfer: secs: %u size: %s", n_seconds, formatted_xferred);
|
||||
|
||||
sd_journal_send ("MESSAGE=%s", msg->str,
|
||||
"MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_MESSAGE_FETCH_COMPLETE_ID),
|
||||
"OSTREE_REMOTE=%s", pull_data->remote_name,
|
||||
"OSTREE_GPG=%s", gpg_verify_state,
|
||||
"OSTREE_SECONDS=%u", n_seconds,
|
||||
"OSTREE_XFER_SIZE=%s", formatted_xferred,
|
||||
NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* iterate over commits fetched and delete any commitpartial files */
|
||||
if (pull_data->dirs == NULL && !pull_data->is_commit_only)
|
||||
{
|
||||
@@ -4730,6 +4841,14 @@ find_remotes_cb (GObject *obj,
|
||||
g_clear_error (&error);
|
||||
continue;
|
||||
}
|
||||
else if (summary_bytes == NULL)
|
||||
{
|
||||
g_debug ("%s: Failed to download summary for result ‘%s’. Ignoring. %s",
|
||||
G_STRFUNC, result->remote->name,
|
||||
"No summary file exists on server");
|
||||
g_clear_pointer (&g_ptr_array_index (results, i), (GDestroyNotify) ostree_repo_finder_result_free);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check the metadata in the summary file, especially whether it contains
|
||||
* all the @refs we are interested in. */
|
||||
@@ -4836,7 +4955,7 @@ find_remotes_cb (GObject *obj,
|
||||
goto error;
|
||||
|
||||
fetcher = _ostree_repo_remote_new_fetcher (self, result->remote->name,
|
||||
TRUE, &error);
|
||||
TRUE, NULL, &error);
|
||||
if (fetcher == NULL)
|
||||
goto error;
|
||||
|
||||
@@ -4857,7 +4976,7 @@ find_remotes_cb (GObject *obj,
|
||||
&error))
|
||||
goto error;
|
||||
|
||||
glnx_unref_object OstreeGpgVerifyResult *verify_result = NULL;
|
||||
g_autoptr(OstreeGpgVerifyResult) verify_result = NULL;
|
||||
|
||||
verify_result = ostree_repo_verify_commit_for_remote (self,
|
||||
commit_metadata->checksum,
|
||||
@@ -4974,7 +5093,7 @@ find_remotes_cb (GObject *obj,
|
||||
{
|
||||
OstreeRepoFinderResult *result = g_ptr_array_index (results, i);
|
||||
g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type utf8 utf8) */
|
||||
gsize j;
|
||||
gsize j, n_latest_refs;
|
||||
|
||||
/* Previous error processing this result? */
|
||||
if (result == NULL)
|
||||
@@ -4986,6 +5105,7 @@ find_remotes_cb (GObject *obj,
|
||||
ostree_collection_ref_equal,
|
||||
(GDestroyNotify) ostree_collection_ref_free,
|
||||
g_free);
|
||||
n_latest_refs = 0;
|
||||
|
||||
for (j = 0; refs[j] != NULL; j++)
|
||||
{
|
||||
@@ -4993,11 +5113,13 @@ find_remotes_cb (GObject *obj,
|
||||
|
||||
if (pointer_table_get (refs_and_remotes_table, j, i) != latest_commit_for_ref)
|
||||
latest_commit_for_ref = NULL;
|
||||
if (latest_commit_for_ref != NULL)
|
||||
n_latest_refs++;
|
||||
|
||||
g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]), g_strdup (latest_commit_for_ref));
|
||||
}
|
||||
|
||||
if (g_hash_table_size (validated_ref_to_checksum) == 0)
|
||||
if (n_latest_refs == 0)
|
||||
{
|
||||
g_debug ("%s: Omitting remote ‘%s’ from results as none of its refs are new enough.",
|
||||
G_STRFUNC, result->remote->name);
|
||||
@@ -5229,7 +5351,7 @@ ostree_repo_pull_from_remotes_async (OstreeRepo *self,
|
||||
g_variant_dict_insert (&local_options_dict, "flags", "i", OSTREE_REPO_PULL_FLAGS_UNTRUSTED | flags);
|
||||
g_variant_dict_insert_value (&local_options_dict, "collection-refs", g_variant_builder_end (&refs_to_pull_builder));
|
||||
g_variant_dict_insert (&local_options_dict, "gpg-verify", "b", TRUE);
|
||||
g_variant_dict_insert (&local_options_dict, "gpg-verify-summary", "b", TRUE);
|
||||
g_variant_dict_insert (&local_options_dict, "gpg-verify-summary", "b", FALSE);
|
||||
g_variant_dict_insert (&local_options_dict, "inherit-transaction", "b", TRUE);
|
||||
copy_option (&options_dict, &local_options_dict, "depth", G_VARIANT_TYPE ("i"));
|
||||
copy_option (&options_dict, &local_options_dict, "disable-static-deltas", G_VARIANT_TYPE ("b"));
|
||||
@@ -5497,7 +5619,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
|
||||
if (gpg_verify_summary && signatures == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
|
||||
"GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)");
|
||||
goto out;
|
||||
}
|
||||
@@ -5505,7 +5627,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
/* Verify any summary signatures. */
|
||||
if (gpg_verify_summary && summary != NULL && signatures != NULL)
|
||||
{
|
||||
glnx_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
g_autoptr(OstreeGpgVerifyResult) result = NULL;
|
||||
|
||||
result = ostree_repo_verify_summary (self,
|
||||
name,
|
||||
@@ -5540,7 +5662,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"This version of ostree was built without libsoup, and cannot fetch over HTTP");
|
||||
"This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -5554,7 +5676,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"This version of ostree was built without libsoup, and cannot fetch over HTTP");
|
||||
"This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@@ -472,6 +472,7 @@ ostree_repo_resolve_rev_ext (OstreeRepo *self,
|
||||
static gboolean
|
||||
enumerate_refs_recurse (OstreeRepo *repo,
|
||||
const char *remote,
|
||||
OstreeRepoListRefsExtFlags flags,
|
||||
const char *collection_id,
|
||||
int base_dfd,
|
||||
GString *base_path,
|
||||
@@ -482,6 +483,7 @@ enumerate_refs_recurse (OstreeRepo *repo,
|
||||
GError **error)
|
||||
{
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
const gboolean aliases_only = (flags & OSTREE_REPO_LIST_REFS_EXT_ALIASES) > 0;
|
||||
|
||||
if (!glnx_dirfd_iterator_init_at (child_dfd, path, FALSE, &dfd_iter, error))
|
||||
return FALSE;
|
||||
@@ -502,16 +504,30 @@ enumerate_refs_recurse (OstreeRepo *repo,
|
||||
{
|
||||
g_string_append_c (base_path, '/');
|
||||
|
||||
if (!enumerate_refs_recurse (repo, remote, collection_id, base_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (repo, remote, flags, collection_id, base_dfd, base_path,
|
||||
dfd_iter.fd, dent->d_name,
|
||||
refs, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (dent->d_type == DT_REG)
|
||||
else
|
||||
{
|
||||
if (!add_ref_to_set (remote, collection_id, base_dfd, base_path->str, refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
if (aliases_only && dent->d_type == DT_LNK)
|
||||
{
|
||||
g_autofree char *target = glnx_readlinkat_malloc (base_dfd, base_path->str,
|
||||
cancellable, error);
|
||||
const char *resolved_target = target;
|
||||
if (!target)
|
||||
return FALSE;
|
||||
while (g_str_has_prefix (resolved_target, "../"))
|
||||
resolved_target += 3;
|
||||
g_hash_table_insert (refs, g_strdup (base_path->str), g_strdup (resolved_target));
|
||||
}
|
||||
else if ((!aliases_only && dent->d_type == DT_REG) || dent->d_type == DT_LNK)
|
||||
{
|
||||
if (!add_ref_to_set (remote, collection_id, base_dfd, base_path->str, refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_string_truncate (base_path, len);
|
||||
@@ -523,6 +539,7 @@ enumerate_refs_recurse (OstreeRepo *repo,
|
||||
static gboolean
|
||||
_ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
gboolean cut_prefix,
|
||||
OstreeRepoListRefsExtFlags flags,
|
||||
const char *refspec_prefix,
|
||||
GHashTable **out_all_refs,
|
||||
GCancellable *cancellable,
|
||||
@@ -571,7 +588,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
if (!glnx_opendirat (self->repo_dir_fd, cut_prefix ? path : prefix_path, TRUE, &base_fd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, remote, NULL, base_fd, base_path,
|
||||
if (!enumerate_refs_recurse (self, remote, flags, NULL, base_fd, base_path,
|
||||
base_fd, cut_prefix ? "." : ref_prefix,
|
||||
ret_all_refs, cancellable, error))
|
||||
return FALSE;
|
||||
@@ -598,7 +615,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, NULL, NULL, refs_heads_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (self, NULL, flags, NULL, refs_heads_dfd, base_path,
|
||||
refs_heads_dfd, ".",
|
||||
ret_all_refs, cancellable, error))
|
||||
return FALSE;
|
||||
@@ -624,7 +641,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, dent->d_name, NULL, remote_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (self, dent->d_name, flags, NULL, remote_dfd, base_path,
|
||||
remote_dfd, ".",
|
||||
ret_all_refs,
|
||||
cancellable, error))
|
||||
@@ -655,7 +672,10 @@ ostree_repo_list_refs (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
return _ostree_repo_list_refs_internal (self, TRUE, refspec_prefix, out_all_refs, cancellable, error);
|
||||
return _ostree_repo_list_refs_internal (self, TRUE,
|
||||
OSTREE_REPO_LIST_REFS_EXT_NONE,
|
||||
refspec_prefix, out_all_refs,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -681,7 +701,9 @@ ostree_repo_list_refs_ext (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
return _ostree_repo_list_refs_internal (self, FALSE, refspec_prefix, out_all_refs, cancellable, error);
|
||||
return _ostree_repo_list_refs_internal (self, FALSE, flags,
|
||||
refspec_prefix, out_all_refs,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -757,17 +779,163 @@ ostree_repo_remote_list_refs (OstreeRepo *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
static gboolean
|
||||
remote_list_collection_refs_process_refs (OstreeRepo *self,
|
||||
const gchar *remote_name,
|
||||
const gchar *summary_collection_id,
|
||||
GVariant *summary_refs,
|
||||
GHashTable *ret_all_refs,
|
||||
GError **error)
|
||||
{
|
||||
gsize j, n;
|
||||
|
||||
for (j = 0, n = g_variant_n_children (summary_refs); j < n; j++)
|
||||
{
|
||||
const guchar *csum_bytes;
|
||||
g_autoptr(GVariant) ref_v = NULL, csum_v = NULL;
|
||||
gchar tmp_checksum[OSTREE_SHA256_STRING_LEN + 1];
|
||||
const gchar *ref_name;
|
||||
|
||||
/* Check the ref name. */
|
||||
ref_v = g_variant_get_child_value (summary_refs, j);
|
||||
g_variant_get_child (ref_v, 0, "&s", &ref_name);
|
||||
|
||||
if (!ostree_validate_rev (ref_name, error))
|
||||
return FALSE;
|
||||
|
||||
/* Check the commit checksum. */
|
||||
g_variant_get_child (ref_v, 1, "(t@ay@a{sv})", NULL, &csum_v, NULL);
|
||||
|
||||
csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, error);
|
||||
if (csum_bytes == NULL)
|
||||
return FALSE;
|
||||
|
||||
ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum);
|
||||
|
||||
g_hash_table_insert (ret_all_refs,
|
||||
ostree_collection_ref_new (summary_collection_id, ref_name),
|
||||
g_strdup (tmp_checksum));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_remote_list_collection_refs:
|
||||
* @self: Repo
|
||||
* @remote_name: Name of the remote.
|
||||
* @out_all_refs: (out) (element-type OstreeCollectionRef utf8): Mapping from collection–ref to checksum
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* List refs advertised by @remote_name, including refs which are part of
|
||||
* collections. If the repository at @remote_name has a collection ID set, its
|
||||
* refs will be returned with that collection ID; otherwise, they will be returned
|
||||
* with a %NULL collection ID in each #OstreeCollectionRef key in @out_all_refs.
|
||||
* Any refs for other collections stored in the repository will also be returned.
|
||||
* No filtering is performed.
|
||||
*
|
||||
* Since: 2017.10
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_remote_list_collection_refs (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
GHashTable **out_all_refs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GBytes) summary_bytes = NULL;
|
||||
g_autoptr(GHashTable) ret_all_refs = NULL; /* (element-type OstreeCollectionRef utf8) */
|
||||
g_autoptr(GVariant) summary_v = NULL;
|
||||
g_autoptr(GVariant) additional_metadata_v = NULL;
|
||||
g_autoptr(GVariant) summary_refs = NULL;
|
||||
const char *summary_collection_id;
|
||||
g_autoptr(GVariantIter) summary_collection_map = NULL;
|
||||
|
||||
if (!ostree_repo_remote_fetch_summary (self, remote_name,
|
||||
&summary_bytes, NULL,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (summary_bytes == NULL)
|
||||
return glnx_throw (error, "Remote refs not available; server has no summary file");
|
||||
|
||||
ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash,
|
||||
ostree_collection_ref_equal,
|
||||
(GDestroyNotify) ostree_collection_ref_free,
|
||||
g_free);
|
||||
|
||||
summary_v = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT,
|
||||
summary_bytes, FALSE);
|
||||
additional_metadata_v = g_variant_get_child_value (summary_v, 1);
|
||||
|
||||
/* List the refs in the main map. */
|
||||
if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_ID, "&s", &summary_collection_id))
|
||||
summary_collection_id = NULL;
|
||||
|
||||
summary_refs = g_variant_get_child_value (summary_v, 0);
|
||||
|
||||
if (!remote_list_collection_refs_process_refs (self, remote_name,
|
||||
summary_collection_id, summary_refs,
|
||||
ret_all_refs, error))
|
||||
return FALSE;
|
||||
|
||||
/* List the refs in the collection map. */
|
||||
if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &summary_collection_map))
|
||||
summary_collection_map = NULL;
|
||||
|
||||
while (summary_collection_map != NULL &&
|
||||
g_variant_iter_loop (summary_collection_map, "{s@a(s(taya{sv}))}", &summary_collection_id, &summary_refs))
|
||||
{
|
||||
if (!remote_list_collection_refs_process_refs (self, remote_name,
|
||||
summary_collection_id, summary_refs,
|
||||
ret_all_refs, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ot_transfer_out_value (out_all_refs, &ret_all_refs);
|
||||
return TRUE;
|
||||
}
|
||||
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
static char *
|
||||
relative_symlink_to (const char *relpath,
|
||||
const char *target)
|
||||
{
|
||||
g_assert (*relpath);
|
||||
g_assert (*target && *target != '/');
|
||||
|
||||
g_autoptr(GString) buf = g_string_new ("");
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
const char *slash = strchr (relpath, '/');
|
||||
if (!slash)
|
||||
break;
|
||||
relpath = slash + 1;
|
||||
g_string_append (buf, "../");
|
||||
}
|
||||
|
||||
g_string_append (buf, target);
|
||||
|
||||
return g_string_free (g_steal_pointer (&buf), FALSE);
|
||||
}
|
||||
|
||||
/* May specify @rev or @alias */
|
||||
gboolean
|
||||
_ostree_repo_write_ref (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *rev,
|
||||
const char *alias,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int dfd = -1;
|
||||
|
||||
g_return_val_if_fail (remote == NULL || ref->collection_id == NULL, FALSE);
|
||||
g_return_val_if_fail (!(rev != NULL && alias != NULL), FALSE);
|
||||
|
||||
if (remote != NULL && !ostree_validate_remote_name (remote, error))
|
||||
return FALSE;
|
||||
@@ -832,7 +1000,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||
return glnx_throw_errno_prefix (error, "Opening remotes/ dir %s", remote);
|
||||
}
|
||||
|
||||
if (rev == NULL)
|
||||
if (rev == NULL && alias == NULL)
|
||||
{
|
||||
if (dfd >= 0)
|
||||
{
|
||||
@@ -843,11 +1011,32 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (rev != NULL)
|
||||
{
|
||||
if (!write_checksum_file_at (self, dfd, ref->ref_name, rev, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (alias != NULL)
|
||||
{
|
||||
const char *lastslash = strrchr (ref->ref_name, '/');
|
||||
|
||||
if (lastslash)
|
||||
{
|
||||
char *parent = strdupa (ref->ref_name);
|
||||
parent[lastslash - ref->ref_name] = '\0';
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (dfd, parent, 0755, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autofree char *reltarget = relative_symlink_to (ref->ref_name, alias);
|
||||
g_autofree char *tmplink = NULL;
|
||||
if (!_ostree_make_temporary_symlink_at (self->tmp_dir_fd, reltarget,
|
||||
&tmplink, cancellable, error))
|
||||
return FALSE;
|
||||
if (!glnx_renameat (self->tmp_dir_fd, tmplink, dfd, ref->ref_name, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!_ostree_repo_update_mtime (self, error))
|
||||
return FALSE;
|
||||
@@ -876,7 +1065,7 @@ _ostree_repo_update_refs (OstreeRepo *self,
|
||||
return FALSE;
|
||||
|
||||
const OstreeCollectionRef ref = { NULL, ref_name };
|
||||
if (!_ostree_repo_write_ref (self, remote, &ref, rev,
|
||||
if (!_ostree_repo_write_ref (self, remote, &ref, rev, NULL,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
@@ -899,7 +1088,7 @@ _ostree_repo_update_collection_refs (OstreeRepo *self,
|
||||
const OstreeCollectionRef *ref = key;
|
||||
const char *rev = value;
|
||||
|
||||
if (!_ostree_repo_write_ref (self, NULL, ref, rev,
|
||||
if (!_ostree_repo_write_ref (self, NULL, ref, rev, NULL,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
@@ -961,7 +1150,8 @@ ostree_repo_list_collection_refs (OstreeRepo *self,
|
||||
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, NULL, main_collection_id, refs_heads_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE,
|
||||
main_collection_id, refs_heads_dfd, base_path,
|
||||
refs_heads_dfd, ".",
|
||||
ret_all_refs, cancellable, error))
|
||||
return FALSE;
|
||||
@@ -993,7 +1183,8 @@ ostree_repo_list_collection_refs (OstreeRepo *self,
|
||||
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &collection_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, NULL, dent->d_name, collection_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE,
|
||||
dent->d_name, collection_dfd, base_path,
|
||||
collection_dfd, ".",
|
||||
ret_all_refs,
|
||||
cancellable, error))
|
||||
|
||||
@@ -649,7 +649,7 @@ _ostree_delta_get_endianness (GVariant *superblock,
|
||||
* deltas, period. Past the gigabyte scale you really want
|
||||
* bittorrent or something.
|
||||
*/
|
||||
if ((total_size / total_objects) > G_MAXUINT32)
|
||||
if (total_objects > 0 && (total_size / total_objects) > G_MAXUINT32)
|
||||
{
|
||||
is_byteswapped = TRUE;
|
||||
}
|
||||
|
||||
+275
-114
@@ -456,6 +456,7 @@ ostree_repo_finalize (GObject *object)
|
||||
g_clear_object (&self->parent_repo);
|
||||
|
||||
g_free (self->stagedir_prefix);
|
||||
g_clear_object (&self->repodir_fdrel);
|
||||
g_clear_object (&self->repodir);
|
||||
if (self->repo_dir_fd != -1)
|
||||
(void) close (self->repo_dir_fd);
|
||||
@@ -546,22 +547,11 @@ ostree_repo_get_property(GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_repo_constructed (GObject *object)
|
||||
{
|
||||
OstreeRepo *self = OSTREE_REPO (object);
|
||||
|
||||
g_assert (self->repodir != NULL);
|
||||
|
||||
G_OBJECT_CLASS (ostree_repo_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
static void
|
||||
ostree_repo_class_init (OstreeRepoClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = ostree_repo_constructed;
|
||||
object_class->get_property = ostree_repo_get_property;
|
||||
object_class->set_property = ostree_repo_set_property;
|
||||
object_class->finalize = ostree_repo_finalize;
|
||||
@@ -581,6 +571,7 @@ ostree_repo_class_init (OstreeRepoClass *klass)
|
||||
"",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_REMOTES_CONFIG_DIR,
|
||||
g_param_spec_string ("remotes-config-dir",
|
||||
@@ -662,6 +653,43 @@ ostree_repo_new (GFile *path)
|
||||
return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL);
|
||||
}
|
||||
|
||||
static OstreeRepo *
|
||||
repo_open_at_take_fd (int *dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(OstreeRepo) repo = g_object_new (OSTREE_TYPE_REPO, NULL);
|
||||
repo->repo_dir_fd = glnx_steal_fd (dfd);
|
||||
|
||||
if (!ostree_repo_open (repo, cancellable, error))
|
||||
return NULL;
|
||||
return g_steal_pointer (&repo);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_open_at:
|
||||
* @dfd: Directory fd
|
||||
* @path: Path
|
||||
*
|
||||
* This combines ostree_repo_new() (but using fd-relative access) with
|
||||
* ostree_repo_open(). Use this when you know you should be operating on an
|
||||
* already extant repository. If you want to create one, use ostree_repo_create_at().
|
||||
*
|
||||
* Returns: (transfer full): An accessor object for an OSTree repository located at @dfd + @path
|
||||
*/
|
||||
OstreeRepo*
|
||||
ostree_repo_open_at (int dfd,
|
||||
const char *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int repo_dfd = -1;
|
||||
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
|
||||
return NULL;
|
||||
|
||||
return repo_open_at_take_fd (&repo_dfd, cancellable, error);
|
||||
}
|
||||
|
||||
static GFile *
|
||||
get_default_repo_path (GFile *sysroot_path)
|
||||
{
|
||||
@@ -744,8 +772,16 @@ ostree_repo_is_system (OstreeRepo *repo)
|
||||
if (!repo->sysroot_dir)
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir);
|
||||
return g_file_equal (repo->repodir, default_repo_path);
|
||||
/* If we created via ostree_repo_new(), we'll have a repo path. Compare
|
||||
* it to the sysroot path in that case.
|
||||
*/
|
||||
if (repo->repodir)
|
||||
{
|
||||
g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir);
|
||||
return g_file_equal (repo->repodir, default_repo_path);
|
||||
}
|
||||
/* Otherwise, not a system repo */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1331,9 +1367,9 @@ ostree_repo_remote_gpg_import (OstreeRepo *self,
|
||||
GError **error)
|
||||
{
|
||||
OstreeRemote *remote;
|
||||
ot_auto_gpgme_ctx gpgme_ctx_t source_context = NULL;
|
||||
ot_auto_gpgme_ctx gpgme_ctx_t target_context = NULL;
|
||||
ot_auto_gpgme_data gpgme_data_t data_buffer = NULL;
|
||||
g_auto(gpgme_ctx_t) source_context = NULL;
|
||||
g_auto(gpgme_ctx_t) target_context = NULL;
|
||||
g_auto(gpgme_data_t) data_buffer = NULL;
|
||||
gpgme_import_result_t import_result;
|
||||
gpgme_import_status_t import_status;
|
||||
g_autofree char *source_tmp_dir = NULL;
|
||||
@@ -1670,6 +1706,104 @@ ostree_repo_mode_from_string (const char *mode,
|
||||
#define DEFAULT_CONFIG_CONTENTS ("[core]\n" \
|
||||
"repo_version=1\n")
|
||||
|
||||
/* Just write the dirs to disk, return a dfd */
|
||||
static gboolean
|
||||
repo_create_at_internal (int dfd,
|
||||
const char *path,
|
||||
OstreeRepoMode mode,
|
||||
GVariant *options,
|
||||
int *out_dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
struct stat stbuf;
|
||||
/* We do objects/ last - if it exists we do nothing and exit successfully */
|
||||
const char *state_dirs[] = { "tmp", "extensions", "state",
|
||||
"refs", "refs/heads", "refs/mirrors",
|
||||
"refs/remotes", "objects" };
|
||||
|
||||
/* Early return if we have an existing repo */
|
||||
{ g_autofree char *objects_path = g_build_filename (path, "objects", NULL);
|
||||
|
||||
if (fstatat (dfd, objects_path, &stbuf, 0) == 0)
|
||||
{
|
||||
glnx_fd_close int repo_dfd = -1;
|
||||
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
/* Note early return */
|
||||
*out_dfd = glnx_steal_fd (&repo_dfd);
|
||||
return TRUE;
|
||||
}
|
||||
else if (errno != ENOENT)
|
||||
return glnx_throw_errno_prefix (error, "fstatat");
|
||||
}
|
||||
|
||||
if (mkdirat (dfd, path, 0755) != 0)
|
||||
{
|
||||
if (G_UNLIKELY (errno != EEXIST))
|
||||
return glnx_throw_errno_prefix (error, "mkdirat");
|
||||
}
|
||||
|
||||
glnx_fd_close int repo_dfd = -1;
|
||||
if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (fstatat (repo_dfd, "config", &stbuf, 0) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
const char *mode_str = NULL;
|
||||
g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
|
||||
|
||||
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
|
||||
return FALSE;
|
||||
g_assert (mode_str);
|
||||
|
||||
g_string_append_printf (config_data, "mode=%s\n", mode_str);
|
||||
|
||||
const char *collection_id = NULL;
|
||||
if (options)
|
||||
g_variant_lookup (options, "collection-id", "&s", &collection_id);
|
||||
if (collection_id != NULL)
|
||||
g_string_append_printf (config_data, "collection-id=%s\n", collection_id);
|
||||
|
||||
if (!glnx_file_replace_contents_at (repo_dfd, "config",
|
||||
(guint8*)config_data->str, config_data->len,
|
||||
0, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return glnx_throw_errno_prefix (error, "fstatat");
|
||||
}
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++)
|
||||
{
|
||||
const char *elt = state_dirs[i];
|
||||
if (mkdirat (repo_dfd, elt, 0755) == -1)
|
||||
{
|
||||
if (G_UNLIKELY (errno != EEXIST))
|
||||
return glnx_throw_errno_prefix (error, "mkdirat");
|
||||
}
|
||||
}
|
||||
|
||||
/* Test that the fs supports user xattrs now, so we get an error early rather
|
||||
* than during an object write later.
|
||||
*/
|
||||
if (mode == OSTREE_REPO_MODE_BARE_USER)
|
||||
{
|
||||
g_auto(GLnxTmpfile) tmpf = { 0, };
|
||||
|
||||
if (!glnx_open_tmpfile_linkable_at (repo_dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error))
|
||||
return FALSE;
|
||||
if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*out_dfd = glnx_steal_fd (&repo_dfd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_create:
|
||||
* @self: An #OstreeRepo
|
||||
@@ -1686,6 +1820,11 @@ ostree_repo_mode_from_string (const char *mode,
|
||||
* of an existing repository, and will silently ignore an attempt to
|
||||
* do so.
|
||||
*
|
||||
* Since 2017.9, "existing repository" is defined by the existence of an
|
||||
* `objects` subdirectory.
|
||||
*
|
||||
* This function predates ostree_repo_create_at(). It is an error to call
|
||||
* this function on a repository initialized via ostree_repo_open_at().
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_create (OstreeRepo *self,
|
||||
@@ -1693,76 +1832,64 @@ ostree_repo_create (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (self->repodir, FALSE);
|
||||
const char *repopath = gs_file_get_path_cached (self->repodir);
|
||||
glnx_fd_close int dfd = -1;
|
||||
struct stat stbuf;
|
||||
const char *state_dirs[] = { "objects", "tmp", "extensions", "state",
|
||||
"refs", "refs/heads", "refs/mirrors",
|
||||
"refs/remotes" };
|
||||
g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
||||
if (self->collection_id)
|
||||
g_variant_builder_add (builder, "{s@v}", "collection-id",
|
||||
g_variant_new_variant (g_variant_new_string (self->collection_id)));
|
||||
|
||||
if (mkdir (repopath, 0755) != 0)
|
||||
{
|
||||
if (G_UNLIKELY (errno != EEXIST))
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
|
||||
if (!glnx_opendirat (AT_FDCWD, repopath, TRUE, &dfd, error))
|
||||
glnx_fd_close int repo_dir_fd = -1;
|
||||
if (!repo_create_at_internal (AT_FDCWD, repopath, mode,
|
||||
g_variant_builder_end (builder),
|
||||
&repo_dir_fd,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (fstatat (dfd, "config", &stbuf, 0) < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
const char *mode_str = NULL;
|
||||
g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
|
||||
|
||||
if (!ostree_repo_mode_to_string (mode, &mode_str, error))
|
||||
return FALSE;
|
||||
g_assert (mode_str);
|
||||
|
||||
g_string_append_printf (config_data, "mode=%s\n", mode_str);
|
||||
|
||||
if (self->collection_id != NULL)
|
||||
g_string_append_printf (config_data, "collection-id=%s\n", self->collection_id);
|
||||
|
||||
if (!glnx_file_replace_contents_at (dfd, "config",
|
||||
(guint8*)config_data->str, config_data->len,
|
||||
0, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
|
||||
for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++)
|
||||
{
|
||||
const char *elt = state_dirs[i];
|
||||
if (mkdirat (dfd, elt, 0755) == -1)
|
||||
{
|
||||
if (G_UNLIKELY (errno != EEXIST))
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
}
|
||||
|
||||
/* Test that the fs supports user xattrs now, so we get an error early rather
|
||||
* than during an object write later.
|
||||
*/
|
||||
if (mode == OSTREE_REPO_MODE_BARE_USER)
|
||||
{
|
||||
g_auto(GLnxTmpfile) tmpf = { 0, };
|
||||
|
||||
if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error))
|
||||
return FALSE;
|
||||
if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
self->repo_dir_fd = glnx_steal_fd (&repo_dir_fd);
|
||||
if (!ostree_repo_open (self, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_create_at:
|
||||
* @dfd: Directory fd
|
||||
* @path: Path
|
||||
* @mode: The mode to store the repository in
|
||||
* @options: a{sv}: See below for accepted keys
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* This is a file-descriptor relative version of ostree_repo_create().
|
||||
* Create the underlying structure on disk for the repository, and call
|
||||
* ostree_repo_open_at() on the result, preparing it for use.
|
||||
*
|
||||
* If a repository already exists at @dfd + @path (defined by an `objects/`
|
||||
* subdirectory existing), then this function will simply call
|
||||
* ostree_repo_open_at(). In other words, this function cannot be used to change
|
||||
* the mode or configuration (`repo/config`) of an existing repo.
|
||||
*
|
||||
* The @options dict may contain:
|
||||
*
|
||||
* - collection-id: s: Set as collection ID in repo/config (Since 2017.9)
|
||||
*
|
||||
* Returns: (transfer full): A new OSTree repository reference
|
||||
*/
|
||||
OstreeRepo *
|
||||
ostree_repo_create_at (int dfd,
|
||||
const char *path,
|
||||
OstreeRepoMode mode,
|
||||
GVariant *options,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int repo_dfd = -1;
|
||||
if (!repo_create_at_internal (dfd, path, mode, options, &repo_dfd,
|
||||
cancellable, error))
|
||||
return NULL;
|
||||
return repo_open_at_take_fd (&repo_dfd, cancellable, error);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
enumerate_directory_allow_noent (GFile *dirpath,
|
||||
const char *queryargs,
|
||||
@@ -2132,7 +2259,6 @@ ostree_repo_open (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
struct stat self_stbuf;
|
||||
struct stat stbuf;
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
@@ -2162,22 +2288,25 @@ ostree_repo_open (OstreeRepo *self,
|
||||
self->stagedir_prefix = g_strconcat (OSTREE_REPO_TMPDIR_STAGING, boot_id, "-", NULL);
|
||||
}
|
||||
|
||||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE,
|
||||
&self->repo_dir_fd, error))
|
||||
if (self->repo_dir_fd == -1)
|
||||
{
|
||||
g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir));
|
||||
return FALSE;
|
||||
g_assert (self->repodir);
|
||||
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE,
|
||||
&self->repo_dir_fd, error))
|
||||
{
|
||||
g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!glnx_fstat (self->repo_dir_fd, &self_stbuf, error))
|
||||
if (!glnx_fstat (self->repo_dir_fd, &stbuf, error))
|
||||
return FALSE;
|
||||
self->device = stbuf.st_dev;
|
||||
self->inode = stbuf.st_ino;
|
||||
|
||||
if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE,
|
||||
&self->objects_dir_fd, error))
|
||||
{
|
||||
g_prefix_error (error, "Opening objects/ directory: ");
|
||||
return FALSE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
self->writable = faccessat (self->objects_dir_fd, ".", W_OK, 0) == 0;
|
||||
if (!self->writable)
|
||||
@@ -2238,8 +2367,8 @@ ostree_repo_open (OstreeRepo *self,
|
||||
if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0)
|
||||
{
|
||||
/* Are we the same as /ostree/repo? */
|
||||
if (self_stbuf.st_dev == system_stbuf.st_dev &&
|
||||
self_stbuf.st_ino == system_stbuf.st_ino)
|
||||
if (self->device == system_stbuf.st_dev &&
|
||||
self->inode == system_stbuf.st_ino)
|
||||
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE;
|
||||
else
|
||||
self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO;
|
||||
@@ -2349,14 +2478,24 @@ _ostree_repo_file_replace_contents (OstreeRepo *self,
|
||||
|
||||
/**
|
||||
* ostree_repo_get_path:
|
||||
* @self:
|
||||
* @self: Repo
|
||||
*
|
||||
* Note that since the introduction of ostree_repo_open_at(), this function may
|
||||
* return a process-specific path in `/proc` if the repository was created using
|
||||
* that API. In general, you should avoid use of this API.
|
||||
*
|
||||
* Returns: (transfer none): Path to repo
|
||||
*/
|
||||
GFile *
|
||||
ostree_repo_get_path (OstreeRepo *self)
|
||||
{
|
||||
return self->repodir;
|
||||
/* Did we have an abspath? Return it */
|
||||
if (self->repodir)
|
||||
return self->repodir;
|
||||
/* Lazily create a fd-relative path */
|
||||
if (!self->repodir_fdrel)
|
||||
self->repodir_fdrel = ot_fdrel_to_gfile (self->repo_dir_fd, ".");
|
||||
return self->repodir_fdrel;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4082,14 +4221,14 @@ ostree_repo_sign_commit (OstreeRepo *self,
|
||||
* check if the commit has already been signed with the given key ID.
|
||||
* We want to avoid storing duplicate signatures in the metadata. */
|
||||
g_autoptr(GError) local_error = NULL;
|
||||
glnx_unref_object OstreeGpgVerifyResult *result
|
||||
g_autoptr(OstreeGpgVerifyResult) result
|
||||
=_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata,
|
||||
NULL, NULL, NULL,
|
||||
cancellable, &local_error);
|
||||
if (!result)
|
||||
{
|
||||
/* "Not found" just means the commit is not yet signed. That's okay. */
|
||||
if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
|
||||
if (g_error_matches (local_error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE))
|
||||
{
|
||||
g_clear_error (&local_error);
|
||||
}
|
||||
@@ -4202,31 +4341,52 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
|
||||
/* Special remote for _ostree_repo_gpg_verify_with_metadata() */
|
||||
static const char *OSTREE_ALL_REMOTES = "__OSTREE_ALL_REMOTES__";
|
||||
|
||||
static GFile *
|
||||
/* Look for a keyring for @remote in the repo itself, or in
|
||||
* /etc/ostree/remotes.d.
|
||||
*/
|
||||
static gboolean
|
||||
find_keyring (OstreeRepo *self,
|
||||
OstreeRemote *remote,
|
||||
GCancellable *cancellable)
|
||||
GBytes **ret_bytes,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GFile) file = g_file_get_child (self->repodir, remote->keyring);
|
||||
glnx_fd_close int fd = -1;
|
||||
if (!ot_openat_ignore_enoent (self->repo_dir_fd, remote->keyring, &fd, error))
|
||||
return FALSE;
|
||||
|
||||
if (g_file_query_exists (file, cancellable))
|
||||
if (fd != -1)
|
||||
{
|
||||
return g_steal_pointer (&file);
|
||||
GBytes *ret = glnx_fd_readall_bytes (fd, cancellable, error);
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
*ret_bytes = ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL);
|
||||
if (remotes_d)
|
||||
{
|
||||
g_autoptr(GFile) file2 = g_file_get_child (remotes_d, remote->keyring);
|
||||
g_autoptr(GFile) child = g_file_get_child (remotes_d, remote->keyring);
|
||||
|
||||
if (g_file_query_exists (file2, cancellable))
|
||||
return g_steal_pointer (&file2);
|
||||
if (!ot_openat_ignore_enoent (AT_FDCWD, gs_file_get_path_cached (child), &fd, error))
|
||||
return FALSE;
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
GBytes *ret = glnx_fd_readall_bytes (fd, cancellable, error);
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
*ret_bytes = ret;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->parent_repo)
|
||||
return find_keyring (self->parent_repo, remote, cancellable);
|
||||
return find_keyring (self->parent_repo, remote, ret_bytes, cancellable, error);
|
||||
|
||||
return NULL;
|
||||
*ret_bytes = NULL;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static OstreeGpgVerifyResult *
|
||||
@@ -4239,7 +4399,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeGpgVerifier *verifier = NULL;
|
||||
g_autoptr(OstreeGpgVerifier) verifier = NULL;
|
||||
gboolean add_global_keyring_dir = TRUE;
|
||||
|
||||
verifier = _ostree_gpg_verifier_new ();
|
||||
@@ -4248,8 +4408,8 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
|
||||
{
|
||||
/* Add all available remote keyring files. */
|
||||
|
||||
if (!_ostree_gpg_verifier_add_keyring_dir (verifier, self->repodir,
|
||||
cancellable, error))
|
||||
if (!_ostree_gpg_verifier_add_keyring_dir_at (verifier, self->repo_dir_fd, ".",
|
||||
cancellable, error))
|
||||
return NULL;
|
||||
}
|
||||
else if (remote_name != NULL)
|
||||
@@ -4258,17 +4418,18 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
|
||||
/* Add the remote's keyring file if it exists. */
|
||||
|
||||
OstreeRemote *remote;
|
||||
g_autoptr(GFile) file = NULL;
|
||||
|
||||
remote = _ostree_repo_get_remote_inherited (self, remote_name, error);
|
||||
if (remote == NULL)
|
||||
return NULL;
|
||||
|
||||
file = find_keyring (self, remote, cancellable);
|
||||
g_autoptr(GBytes) keyring_data = NULL;
|
||||
if (!find_keyring (self, remote, &keyring_data, cancellable, error))
|
||||
return NULL;
|
||||
|
||||
if (file != NULL)
|
||||
if (keyring_data != NULL)
|
||||
{
|
||||
_ostree_gpg_verifier_add_keyring (verifier, file);
|
||||
_ostree_gpg_verifier_add_keyring_data (verifier, keyring_data);
|
||||
add_global_keyring_dir = FALSE;
|
||||
}
|
||||
|
||||
@@ -4297,7 +4458,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self,
|
||||
}
|
||||
if (extra_keyring != NULL)
|
||||
{
|
||||
_ostree_gpg_verifier_add_keyring (verifier, extra_keyring);
|
||||
_ostree_gpg_verifier_add_keyring_file (verifier, extra_keyring);
|
||||
}
|
||||
|
||||
return _ostree_gpg_verifier_check_signature (verifier,
|
||||
@@ -4329,7 +4490,7 @@ _ostree_repo_gpg_verify_with_metadata (OstreeRepo *self,
|
||||
_OSTREE_METADATA_GPGSIGS_TYPE);
|
||||
if (!signaturedata)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
g_set_error_literal (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE,
|
||||
"GPG verification enabled, but no signatures found (use gpg-verify=false in remote config to disable)");
|
||||
return NULL;
|
||||
}
|
||||
@@ -4441,7 +4602,7 @@ ostree_repo_verify_commit (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeGpgVerifyResult *result = NULL;
|
||||
g_autoptr(OstreeGpgVerifyResult) result = NULL;
|
||||
|
||||
result = ostree_repo_verify_commit_ext (self, commit_checksum,
|
||||
keyringdir, extra_keyring,
|
||||
|
||||
@@ -63,6 +63,13 @@ gboolean ostree_repo_open (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
OstreeRepo*
|
||||
ostree_repo_open_at (int dfd,
|
||||
const char *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_set_disable_fsync (OstreeRepo *self,
|
||||
gboolean disable_fsync);
|
||||
@@ -89,6 +96,13 @@ gboolean ostree_repo_create (OstreeRepo *self,
|
||||
OstreeRepoMode mode,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
_OSTREE_PUBLIC
|
||||
OstreeRepo * ostree_repo_create_at (int dfd,
|
||||
const char *path,
|
||||
OstreeRepoMode mode,
|
||||
GVariant *options,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
@@ -327,6 +341,14 @@ gboolean ostree_repo_set_ref_immediate (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_set_alias_ref_immediate (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char *target,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
@@ -452,9 +474,11 @@ gboolean ostree_repo_list_refs (OstreeRepo *self,
|
||||
/**
|
||||
* OstreeRepoListRefsExtFlags:
|
||||
* @OSTREE_REPO_LIST_REFS_EXT_NONE: No flags.
|
||||
* @OSTREE_REPO_LIST_REFS_EXT_ALIASES: Only list aliases. Since: 2017.10
|
||||
*/
|
||||
typedef enum {
|
||||
OSTREE_REPO_LIST_REFS_EXT_NONE = 0,
|
||||
OSTREE_REPO_LIST_REFS_EXT_ALIASES = 1,
|
||||
} OstreeRepoListRefsExtFlags;
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
@@ -472,6 +496,15 @@ gboolean ostree_repo_remote_list_refs (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_remote_list_collection_refs (OstreeRepo *self,
|
||||
const char *remote_name,
|
||||
GHashTable **out_all_refs,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_load_variant (OstreeRepo *self,
|
||||
OstreeObjectType objtype,
|
||||
|
||||
@@ -328,7 +328,7 @@ initable_init (GInitable *initable,
|
||||
g_autoptr(GFile) policy_root = NULL;
|
||||
if (g_file_query_exists (policy_config_path, NULL))
|
||||
{
|
||||
g_autoptr(GFileInputStream) filein = filein = g_file_read (policy_config_path, cancellable, error);
|
||||
g_autoptr(GFileInputStream) filein = g_file_read (policy_config_path, cancellable, error);
|
||||
|
||||
if (!filein)
|
||||
return FALSE;
|
||||
|
||||
@@ -22,24 +22,36 @@
|
||||
|
||||
#include <gio/gunixinputstream.h>
|
||||
#include <gio/gunixoutputstream.h>
|
||||
#include <glib-unix.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <linux/fs.h>
|
||||
#include <err.h>
|
||||
|
||||
#ifdef HAVE_LIBMOUNT
|
||||
#include <libmount.h>
|
||||
#endif
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
#include <systemd/sd-journal.h>
|
||||
#endif
|
||||
|
||||
#include "otutil.h"
|
||||
#include "ostree.h"
|
||||
#include "ostree-sysroot-private.h"
|
||||
#include "ostree-sepolicy-private.h"
|
||||
#include "ostree-deployment-private.h"
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-linuxfsutil.h"
|
||||
#include "otutil.h"
|
||||
#include "libglnx.h"
|
||||
|
||||
#define OSTREE_VARRELABEL_ID "da679b08acd34504b789d96f818ea781"
|
||||
#define OSTREE_CONFIGMERGE_ID "d3863baec13e4449ab0384684a8af3a7"
|
||||
#define OSTREE_DEPLOYMENT_COMPLETE_ID "dd440e3e549083b63d0efc7dc15255f1"
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
#define OSTREE_VARRELABEL_ID SD_ID128_MAKE(da,67,9b,08,ac,d3,45,04,b7,89,d9,6f,81,8e,a7,81)
|
||||
#define OSTREE_CONFIGMERGE_ID SD_ID128_MAKE(d3,86,3b,ae,c1,3e,44,49,ab,03,84,68,4a,8a,f3,a7)
|
||||
#define OSTREE_DEPLOYMENT_COMPLETE_ID SD_ID128_MAKE(dd,44,0e,3e,54,90,83,b6,3d,0e,fc,7d,c1,52,55,f1)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Like symlinkat() but overwrites (atomically) an existing
|
||||
@@ -101,7 +113,7 @@ hardlink_or_copy_at (int src_dfd,
|
||||
sysroot_flags_to_copy_flags (0, flags),
|
||||
cancellable, error);
|
||||
else
|
||||
return glnx_throw_errno_prefix (error, "linkat");
|
||||
return glnx_throw_errno_prefix (error, "linkat(%s)", dest_subpath);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -417,11 +429,19 @@ merge_configuration_from (OstreeSysroot *sysroot,
|
||||
cancellable, error))
|
||||
return glnx_prefix_error (error, "While computing configuration diff");
|
||||
|
||||
ot_log_structured_print_id_v (OSTREE_CONFIGMERGE_ID,
|
||||
"Copying /etc changes: %u modified, %u removed, %u added",
|
||||
modified->len,
|
||||
removed->len,
|
||||
added->len);
|
||||
{ g_autofree char *msg =
|
||||
g_strdup_printf ("Copying /etc changes: %u modified, %u removed, %u added",
|
||||
modified->len, removed->len, added->len);
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
sd_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_CONFIGMERGE_ID),
|
||||
"MESSAGE=%s", msg,
|
||||
"ETC_N_MODIFIED=%u", modified->len,
|
||||
"ETC_N_REMOVED=%u", removed->len,
|
||||
"ETC_N_ADDED=%u", added->len,
|
||||
NULL);
|
||||
#endif
|
||||
_ostree_sysroot_emit_journal_msg (sysroot, msg);
|
||||
}
|
||||
|
||||
glnx_fd_close int orig_etc_fd = -1;
|
||||
if (!glnx_opendirat (merge_deployment_dfd, "usr/etc", TRUE, &orig_etc_fd, error))
|
||||
@@ -676,9 +696,15 @@ selinux_relabel_var_if_needed (OstreeSysroot *sysroot,
|
||||
|
||||
if (!deployment_var_labeled)
|
||||
{
|
||||
ot_log_structured_print_id_v (OSTREE_VARRELABEL_ID,
|
||||
"Relabeling /var (no stamp file '%s' found)",
|
||||
selabeled);
|
||||
{ g_autofree char *msg =
|
||||
g_strdup_printf ("Relabeling /var (no stamp file '%s' found)", selabeled);
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
sd_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_VARRELABEL_ID),
|
||||
"MESSAGE=%s", msg,
|
||||
NULL);
|
||||
#endif
|
||||
_ostree_sysroot_emit_journal_msg (sysroot, msg);
|
||||
}
|
||||
|
||||
g_autoptr(GFile) deployment_var_path = ot_fdrel_to_gfile (os_deploy_dfd, "var");
|
||||
if (!selinux_relabel_dir (sysroot, sepolicy,
|
||||
@@ -717,7 +743,7 @@ merge_configuration (OstreeSysroot *sysroot,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_unref_object OstreeSePolicy *sepolicy = NULL;
|
||||
g_autoptr(OstreeSePolicy) sepolicy = NULL;
|
||||
|
||||
if (previous_deployment)
|
||||
{
|
||||
@@ -856,131 +882,253 @@ ostree_sysroot_write_origin_file (OstreeSysroot *sysroot,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
/* Originally OSTree defined kernels to be found underneath /boot
|
||||
* in the tree. But that means when mounting /boot at runtime
|
||||
* we end up masking the content underneath, triggering a warning.
|
||||
*
|
||||
* For that reason, and also consistency with the "/usr defines the OS" model we
|
||||
* later switched to defining the in-tree kernels to be found under
|
||||
* /usr/lib/ostree-boot.
|
||||
*/
|
||||
static gboolean
|
||||
get_kernel_from_tree (int deployment_dfd,
|
||||
int *out_boot_dfd,
|
||||
char **out_kernel_name,
|
||||
char **out_initramfs_name,
|
||||
char **out_kernel_srcpath,
|
||||
char **out_kernel_namever,
|
||||
char **out_initramfs_srcpath,
|
||||
char **out_initramfs_namever,
|
||||
char **out_bootcsum,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
glnx_fd_close int ret_boot_dfd = -1;
|
||||
g_auto(GLnxDirFdIterator) dfditer = { 0, };
|
||||
g_autofree char *ret_kernel_name = NULL;
|
||||
g_autofree char *ret_initramfs_name = NULL;
|
||||
g_autofree char *ret_kernel_srcpath = NULL;
|
||||
g_autofree char *ret_kernel_namever = NULL;
|
||||
g_autofree char *ret_initramfs_srcpath = NULL;
|
||||
g_autofree char *ret_initramfs_namever = NULL;
|
||||
g_autofree char *kernel_checksum = NULL;
|
||||
g_autofree char *initramfs_checksum = NULL;
|
||||
|
||||
ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE);
|
||||
glnx_fd_close int ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE);
|
||||
if (ret_boot_dfd == -1)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "%s", "openat");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "%s", "openat(usr/lib/ostree-boot)");
|
||||
else
|
||||
{
|
||||
if (!glnx_opendirat (deployment_dfd, "boot", TRUE, &ret_boot_dfd, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_auto(GLnxDirFdIterator) dfditer = { 0, };
|
||||
if (!glnx_dirfd_iterator_init_at (ret_boot_dfd, ".", FALSE, &dfditer, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
struct dirent *dent;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (dent == NULL)
|
||||
break;
|
||||
|
||||
if (ret_kernel_name == NULL && g_str_has_prefix (dent->d_name, "vmlinuz-"))
|
||||
const char *name = dent->d_name;
|
||||
if (ret_kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-"))
|
||||
{
|
||||
const char *dash = strrchr (dent->d_name, '-');
|
||||
const char *dash = strrchr (name, '-');
|
||||
g_assert (dash);
|
||||
if (ostree_validate_structureof_checksum_string (dash + 1, NULL))
|
||||
{
|
||||
kernel_checksum = g_strdup (dash + 1);
|
||||
ret_kernel_name = g_strdup (dent->d_name);
|
||||
ret_kernel_srcpath = g_strdup (name);
|
||||
ret_kernel_namever = g_strndup (name, dash - name);
|
||||
}
|
||||
}
|
||||
else if (ret_initramfs_name == NULL && g_str_has_prefix (dent->d_name, "initramfs-"))
|
||||
else if (ret_initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-"))
|
||||
{
|
||||
const char *dash = strrchr (dent->d_name, '-');
|
||||
const char *dash = strrchr (name, '-');
|
||||
g_assert (dash);
|
||||
if (ostree_validate_structureof_checksum_string (dash + 1, NULL))
|
||||
{
|
||||
initramfs_checksum = g_strdup (dash + 1);
|
||||
ret_initramfs_name = g_strdup (dent->d_name);
|
||||
ret_initramfs_srcpath = g_strdup (name);
|
||||
ret_initramfs_namever = g_strndup (name, dash - name);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_kernel_name != NULL && ret_initramfs_name != NULL)
|
||||
if (ret_kernel_srcpath != NULL && ret_initramfs_srcpath != NULL)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret_kernel_name == NULL)
|
||||
if (ret_kernel_srcpath == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"Failed to find boot/vmlinuz-<CHECKSUM> in tree");
|
||||
goto out;
|
||||
"Failed to find kernel in /usr/lib/ostree-boot or /boot");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ret_initramfs_name != NULL)
|
||||
if (ret_initramfs_srcpath != NULL)
|
||||
{
|
||||
if (strcmp (kernel_checksum, initramfs_checksum) != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
|
||||
"Mismatched kernel checksum vs initrd in tree");
|
||||
goto out;
|
||||
"Mismatched kernel checksum vs initrd");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
*out_boot_dfd = ret_boot_dfd;
|
||||
ret_boot_dfd = -1;
|
||||
*out_kernel_name = g_steal_pointer (&ret_kernel_name);
|
||||
*out_initramfs_name = g_steal_pointer (&ret_initramfs_name);
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
*out_boot_dfd = glnx_steal_fd (&ret_boot_dfd);
|
||||
*out_kernel_srcpath = g_steal_pointer (&ret_kernel_srcpath);
|
||||
*out_kernel_namever = g_steal_pointer (&ret_kernel_namever);
|
||||
*out_initramfs_srcpath = g_steal_pointer (&ret_initramfs_srcpath);
|
||||
*out_initramfs_namever = g_steal_pointer (&ret_initramfs_namever);
|
||||
*out_bootcsum = g_steal_pointer (&kernel_checksum);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* We used to syncfs(), but that doesn't flush the journal on XFS,
|
||||
* and since GRUB2 can't read the XFS journal, the system
|
||||
* could fail to boot.
|
||||
*
|
||||
* http://marc.info/?l=linux-fsdevel&m=149520244919284&w=2
|
||||
* https://github.com/ostreedev/ostree/pull/1049
|
||||
*/
|
||||
static gboolean
|
||||
checksum_from_kernel_src (const char *name,
|
||||
char **out_checksum,
|
||||
GError **error)
|
||||
fsfreeze_thaw_cycle (OstreeSysroot *self,
|
||||
int rootfs_dfd,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
const char *last_dash = strrchr (name, '-');
|
||||
if (!last_dash)
|
||||
GLNX_AUTO_PREFIX_ERROR ("During fsfreeze-thaw", error);
|
||||
|
||||
int sockpair[2];
|
||||
if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockpair) < 0)
|
||||
return glnx_throw_errno_prefix (error, "socketpair");
|
||||
glnx_fd_close int sock_parent = sockpair[0];
|
||||
glnx_fd_close int sock_watchdog = sockpair[1];
|
||||
|
||||
pid_t pid = fork ();
|
||||
if (pid < 0)
|
||||
return glnx_throw_errno_prefix (error, "fork");
|
||||
|
||||
const gboolean debug_fifreeze = (self->debug_flags & OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE)>0;
|
||||
char c = '!';
|
||||
if (pid == 0) /* Child watchdog/unfreezer process. */
|
||||
{
|
||||
return glnx_throw (error,
|
||||
"Malformed kernel/initramfs name '%s', missing '-'",
|
||||
name);
|
||||
(void) close (glnx_steal_fd (&sock_parent));
|
||||
/* Daemonize, and mask SIGINT/SIGTERM, so we're likely to survive e.g.
|
||||
* someone doing a `systemctl restart rpm-ostreed` or a Ctrl-C of
|
||||
* `ostree admin upgrade`. We don't daemonize though if testing so
|
||||
* that we can waitpid().
|
||||
*/
|
||||
if (!debug_fifreeze)
|
||||
{
|
||||
if (daemon (0, 0) < 0)
|
||||
err (1, "daemon");
|
||||
}
|
||||
int sigs[] = { SIGINT, SIGTERM };
|
||||
for (guint i = 0; i < G_N_ELEMENTS (sigs); i++)
|
||||
{
|
||||
if (signal (sigs[i], SIG_IGN) == SIG_ERR)
|
||||
err (1, "signal");
|
||||
}
|
||||
/* Tell the parent we're ready */
|
||||
if (write (sock_watchdog, &c, sizeof (c)) != 1)
|
||||
err (1, "write");
|
||||
/* Wait for the parent to say it's going to freeze. */
|
||||
ssize_t bytes_read = TEMP_FAILURE_RETRY (read (sock_watchdog, &c, sizeof (c)));
|
||||
if (bytes_read < 0)
|
||||
err (1, "read");
|
||||
if (bytes_read != 1)
|
||||
errx (1, "failed to read from parent");
|
||||
/* Now we wait for the second message from the parent saying the freeze is
|
||||
* complete. We have a 30 second timeout; if somehow the parent hasn't
|
||||
* signaled completion, go ahead and unfreeze. But for debugging, just 1
|
||||
* second to avoid exessively lengthining the test suite.
|
||||
*/
|
||||
const int timeout_ms = debug_fifreeze ? 1000 : 30000;
|
||||
struct pollfd pfds[1];
|
||||
pfds[0].fd = sock_watchdog;
|
||||
pfds[0].events = POLLIN | POLLHUP;
|
||||
int r = TEMP_FAILURE_RETRY (poll (pfds, 1, timeout_ms));
|
||||
/* Do a thaw if we hit an error, or if the poll timed out */
|
||||
if (r <= 0)
|
||||
{
|
||||
/* Ignore errors:
|
||||
* EINVAL: Not frozen
|
||||
* EPERM: For running the test suite as non-root
|
||||
* EOPNOTSUPP: If the filesystem doesn't support it
|
||||
*/
|
||||
int saved_errno = errno;
|
||||
(void) TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0));
|
||||
errno = saved_errno;
|
||||
/* But if we got an error from poll, let's log it */
|
||||
if (r < 0)
|
||||
err (1, "poll");
|
||||
}
|
||||
if (debug_fifreeze)
|
||||
g_printerr ("fifreeze watchdog was run\n");
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
else /* Parent process. */
|
||||
{
|
||||
(void) close (glnx_steal_fd (&sock_watchdog));
|
||||
/* Wait for the watchdog to say it's set up; mainly that it's
|
||||
* masked SIGTERM successfully.
|
||||
*/
|
||||
ssize_t bytes_read = TEMP_FAILURE_RETRY (read (sock_parent, &c, sizeof (c)));
|
||||
if (bytes_read < 0)
|
||||
return glnx_throw_errno_prefix (error, "read(watchdog init)");
|
||||
if (bytes_read != 1)
|
||||
return glnx_throw (error, "read(watchdog init)");
|
||||
/* And tell the watchdog that we're ready to start */
|
||||
if (write (sock_parent, &c, sizeof (c)) != sizeof (c))
|
||||
return glnx_throw_errno_prefix (error, "write(watchdog start)");
|
||||
/* Testing infrastructure */
|
||||
if (debug_fifreeze)
|
||||
{
|
||||
int wstatus;
|
||||
/* Ensure the child has written its data */
|
||||
if (TEMP_FAILURE_RETRY (waitpid (pid, &wstatus, 0)) < 0)
|
||||
return glnx_throw_errno_prefix (error, "waitpid(test-fifreeze)");
|
||||
if (!g_spawn_check_exit_status (wstatus, error))
|
||||
return glnx_prefix_error (error, "test-fifreeze: ");
|
||||
return glnx_throw (error, "aborting due to test-fifreeze");
|
||||
}
|
||||
/* Do a freeze/thaw cycle; TODO add a FIFREEZETHAW ioctl */
|
||||
if (ioctl (rootfs_dfd, FIFREEZE, 0) != 0)
|
||||
{
|
||||
/* Not supported, or we're running in the unit tests (as non-root)?
|
||||
* OK, let's just do a syncfs.
|
||||
*/
|
||||
if (G_IN_SET (errno, EOPNOTSUPP, EPERM))
|
||||
{
|
||||
if (TEMP_FAILURE_RETRY (syncfs (rootfs_dfd)) != 0)
|
||||
return glnx_throw_errno_prefix (error, "syncfs");
|
||||
/* Write the completion, and return */
|
||||
if (write (sock_parent, &c, sizeof (c)) != sizeof (c))
|
||||
return glnx_throw_errno_prefix (error, "write(watchdog syncfs complete)");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return glnx_throw_errno_prefix (error, "ioctl(FIFREEZE)");
|
||||
}
|
||||
/* And finally thaw, then signal our completion to the watchdog */
|
||||
if (TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0)) != 0)
|
||||
return glnx_throw_errno_prefix (error, "ioctl(FITHAW)");
|
||||
if (write (sock_parent, &c, sizeof (c)) != sizeof (c))
|
||||
return glnx_throw_errno_prefix (error, "write(watchdog FITHAW complete)");
|
||||
}
|
||||
*out_checksum = g_strdup (last_dash + 1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
syncfs_dir_at (int dfd,
|
||||
const char *path,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int child_dfd = -1;
|
||||
if (!glnx_opendirat (dfd, path, TRUE, &child_dfd, error))
|
||||
return FALSE;
|
||||
if (syncfs (child_dfd) != 0)
|
||||
return glnx_throw_errno (error);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
typedef struct {
|
||||
guint64 root_syncfs_msec;
|
||||
guint64 boot_syncfs_msec;
|
||||
guint64 extra_syncfs_msec;
|
||||
} SyncStats;
|
||||
|
||||
/* First, sync the root directory as well as /var and /boot which may
|
||||
* be separate mount points. Then *in addition*, do a global
|
||||
@@ -988,14 +1136,25 @@ syncfs_dir_at (int dfd,
|
||||
*/
|
||||
static gboolean
|
||||
full_system_sync (OstreeSysroot *self,
|
||||
SyncStats *out_stats,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
guint64 start_msec = g_get_monotonic_time () / 1000;
|
||||
if (syncfs (self->sysroot_fd) != 0)
|
||||
return glnx_throw_errno (error);
|
||||
return glnx_throw_errno_prefix (error, "syncfs(sysroot)");
|
||||
guint64 end_msec = g_get_monotonic_time () / 1000;
|
||||
|
||||
if (!syncfs_dir_at (self->sysroot_fd, "boot", cancellable, error))
|
||||
out_stats->root_syncfs_msec = (end_msec - start_msec);
|
||||
|
||||
start_msec = g_get_monotonic_time () / 1000;
|
||||
glnx_fd_close int boot_dfd = -1;
|
||||
if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, &boot_dfd, error))
|
||||
return FALSE;
|
||||
if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error))
|
||||
return FALSE;
|
||||
end_msec = g_get_monotonic_time () / 1000;
|
||||
out_stats->boot_syncfs_msec = (end_msec - start_msec);
|
||||
|
||||
/* And now out of an excess of conservativism, we still invoke
|
||||
* sync(). The advantage of still using `syncfs()` above is that we
|
||||
@@ -1003,7 +1162,10 @@ full_system_sync (OstreeSysroot *self,
|
||||
* delineate what we actually want to sync in the future when this
|
||||
* global sync call is removed.
|
||||
*/
|
||||
start_msec = g_get_monotonic_time () / 1000;
|
||||
sync ();
|
||||
end_msec = g_get_monotonic_time () / 1000;
|
||||
out_stats->extra_syncfs_msec = (end_msec - start_msec);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1099,15 +1261,6 @@ swap_bootlinks (OstreeSysroot *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *
|
||||
remove_checksum_from_kernel_name (const char *name,
|
||||
const char *csum)
|
||||
{
|
||||
const char *p = strrchr (name, '-');
|
||||
g_assert_cmpstr (p+1, ==, csum);
|
||||
return g_strndup (name, p-name);
|
||||
}
|
||||
|
||||
static GHashTable *
|
||||
parse_os_release (const char *contents,
|
||||
const char *split)
|
||||
@@ -1161,11 +1314,19 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
&deployment_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
/* Find the kernel/initramfs in the tree */
|
||||
glnx_fd_close int tree_boot_dfd = -1;
|
||||
g_autofree char *tree_kernel_name = NULL;
|
||||
g_autofree char *tree_initramfs_name = NULL;
|
||||
g_autofree char *tree_kernel_srcpath = NULL;
|
||||
g_autofree char *tree_kernel_namever = NULL;
|
||||
g_autofree char *tree_initramfs_srcpath = NULL;
|
||||
g_autofree char *tree_initramfs_namever = NULL;
|
||||
g_autofree char *tree_bootcsum = NULL;
|
||||
if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd,
|
||||
&tree_kernel_name, &tree_initramfs_name,
|
||||
&tree_kernel_srcpath,
|
||||
&tree_kernel_namever,
|
||||
&tree_initramfs_srcpath,
|
||||
&tree_initramfs_namever,
|
||||
&tree_bootcsum,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
@@ -1175,6 +1336,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
|
||||
const char *osname = ostree_deployment_get_osname (deployment);
|
||||
const char *bootcsum = ostree_deployment_get_bootcsum (deployment);
|
||||
g_assert_cmpstr (bootcsum, ==, tree_bootcsum);
|
||||
g_autofree char *bootcsumdir = g_strdup_printf ("ostree/%s-%s", osname, bootcsum);
|
||||
g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", new_bootversion);
|
||||
g_autofree char *bootconf_name = g_strdup_printf ("ostree-%s-%d.conf", osname,
|
||||
@@ -1189,30 +1351,33 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
if (!glnx_shutil_mkdir_p_at (boot_dfd, bootconfdir, 0775, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_autofree char *dest_kernel_name = remove_checksum_from_kernel_name (tree_kernel_name, bootcsum);
|
||||
/* Install (hardlink/copy) the kernel into /boot/ostree/osname-${bootcsum} if
|
||||
* it doesn't exist already.
|
||||
*/
|
||||
struct stat stbuf;
|
||||
if (fstatat (bootcsum_dfd, dest_kernel_name, &stbuf, 0) != 0)
|
||||
if (fstatat (bootcsum_dfd, tree_kernel_namever, &stbuf, 0) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return glnx_throw_errno_prefix (error, "fstat %s", dest_kernel_name);
|
||||
if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_name,
|
||||
bootcsum_dfd, dest_kernel_name,
|
||||
return glnx_throw_errno_prefix (error, "fstat %s", tree_kernel_namever);
|
||||
if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_srcpath,
|
||||
bootcsum_dfd, tree_kernel_namever,
|
||||
sysroot->debug_flags,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_autofree char *dest_initramfs_name = NULL;
|
||||
if (tree_initramfs_name)
|
||||
/* If we have an initramfs, then install it into
|
||||
* /boot/ostree/osname-${bootcsum} if it doesn't exist already.
|
||||
*/
|
||||
if (tree_initramfs_srcpath)
|
||||
{
|
||||
dest_initramfs_name = remove_checksum_from_kernel_name (tree_initramfs_name, bootcsum);
|
||||
|
||||
if (fstatat (bootcsum_dfd, dest_initramfs_name, &stbuf, 0) != 0)
|
||||
g_assert (tree_initramfs_namever);
|
||||
if (fstatat (bootcsum_dfd, tree_initramfs_namever, &stbuf, 0) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return glnx_throw_errno_prefix (error, "fstat %s", dest_initramfs_name);
|
||||
if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_name,
|
||||
bootcsum_dfd, dest_initramfs_name,
|
||||
return glnx_throw_errno_prefix (error, "fstat %s", tree_initramfs_namever);
|
||||
if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_srcpath,
|
||||
bootcsum_dfd, tree_initramfs_namever,
|
||||
sysroot->debug_flags,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
@@ -1293,12 +1458,12 @@ install_deployment_kernel (OstreeSysroot *sysroot,
|
||||
|
||||
g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment));
|
||||
ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key);
|
||||
g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", dest_kernel_name, NULL);
|
||||
g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_kernel_namever, NULL);
|
||||
ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath);
|
||||
|
||||
if (dest_initramfs_name)
|
||||
if (tree_initramfs_namever)
|
||||
{
|
||||
g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", dest_initramfs_name, NULL);
|
||||
g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_initramfs_namever, NULL);
|
||||
ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath);
|
||||
}
|
||||
|
||||
@@ -1379,7 +1544,7 @@ swap_bootloader (OstreeSysroot *sysroot,
|
||||
* admin by going back to the previous session.
|
||||
*/
|
||||
if (fsync (boot_dfd) != 0)
|
||||
return glnx_throw_errno (error);
|
||||
return glnx_throw_errno_prefix (error, "fsync(boot)");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1452,10 +1617,9 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
guint i;
|
||||
g_autoptr(GString) buf = g_string_new ("");
|
||||
|
||||
for (i = 0; i < self->deployments->len; i++)
|
||||
for (guint i = 0; i < self->deployments->len; i++)
|
||||
{
|
||||
OstreeDeployment *deployment = self->deployments->pdata[i];
|
||||
const char *osname = ostree_deployment_get_osname (deployment);
|
||||
@@ -1463,11 +1627,8 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self,
|
||||
g_string_truncate (buf, 0);
|
||||
g_string_append_printf (buf, "ostree/deploy/%s/current", osname);
|
||||
|
||||
if (unlinkat (self->sysroot_fd, buf->str, 0) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return glnx_throw_errno (error);
|
||||
}
|
||||
if (!ot_ensure_unlinked_at (self->sysroot_fd, buf->str, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -1568,6 +1729,8 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
|
||||
gboolean found_booted_deployment = FALSE;
|
||||
gboolean bootloader_is_atomic = FALSE;
|
||||
gboolean boot_was_ro_mount = FALSE;
|
||||
SyncStats syncstats = { 0, };
|
||||
g_autoptr(OstreeBootloader) bootloader = NULL;
|
||||
|
||||
g_assert (self->loaded);
|
||||
|
||||
@@ -1631,7 +1794,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!full_system_sync (self, cancellable, error))
|
||||
if (!full_system_sync (self, &syncstats, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Full sync: ");
|
||||
goto out;
|
||||
@@ -1650,9 +1813,8 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
|
||||
else
|
||||
{
|
||||
int new_bootversion = self->bootversion ? 0 : 1;
|
||||
glnx_unref_object OstreeBootloader *bootloader = NULL;
|
||||
g_autofree char* new_loader_entries_dir = NULL;
|
||||
glnx_unref_object OstreeRepo *repo = NULL;
|
||||
g_autoptr(OstreeRepo) repo = NULL;
|
||||
gboolean show_osname = FALSE;
|
||||
|
||||
if (self->booted_deployment)
|
||||
@@ -1751,7 +1913,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!full_system_sync (self, cancellable, error))
|
||||
if (!full_system_sync (self, &syncstats, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Full sync: ");
|
||||
goto out;
|
||||
@@ -1765,11 +1927,25 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
|
||||
}
|
||||
}
|
||||
|
||||
ot_log_structured_print_id_v (OSTREE_DEPLOYMENT_COMPLETE_ID,
|
||||
"%s; bootconfig swap: %s deployment count change: %i",
|
||||
(bootloader_is_atomic ? "Transaction complete" : "Bootloader updated"),
|
||||
requires_new_bootversion ? "yes" : "no",
|
||||
new_deployments->len - self->deployments->len);
|
||||
{ g_autofree char *msg =
|
||||
g_strdup_printf ("%s; bootconfig swap: %s deployment count change: %i",
|
||||
(bootloader_is_atomic ? "Transaction complete" : "Bootloader updated"),
|
||||
requires_new_bootversion ? "yes" : "no",
|
||||
new_deployments->len - self->deployments->len);
|
||||
#ifdef HAVE_LIBSYSTEMD
|
||||
sd_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_DEPLOYMENT_COMPLETE_ID),
|
||||
"MESSAGE=%s", msg,
|
||||
"OSTREE_BOOTLOADER=%s", bootloader ? _ostree_bootloader_get_name (bootloader) : "none",
|
||||
"OSTREE_BOOTLOADER_ATOMIC=%s", bootloader_is_atomic ? "yes" : "no",
|
||||
"OSTREE_DID_BOOTSWAP=%s", requires_new_bootversion ? "yes" : "no",
|
||||
"OSTREE_N_DEPLOYMENTS=%u", new_deployments->len,
|
||||
"OSTREE_SYNCFS_ROOT_MSEC=%" G_GUINT64_FORMAT, syncstats.root_syncfs_msec,
|
||||
"OSTREE_SYNCFS_BOOT_MSEC=%" G_GUINT64_FORMAT, syncstats.boot_syncfs_msec,
|
||||
"OSTREE_SYNCFS_EXTRA_MSEC=%" G_GUINT64_FORMAT, syncstats.extra_syncfs_msec,
|
||||
NULL);
|
||||
#endif
|
||||
_ostree_sysroot_emit_journal_msg (self, msg);
|
||||
}
|
||||
|
||||
if (!_ostree_sysroot_bump_mtime (self, error))
|
||||
goto out;
|
||||
@@ -1884,7 +2060,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
||||
return FALSE;
|
||||
|
||||
OstreeRepo *repo = ostree_sysroot_repo (self);
|
||||
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
|
||||
g_autoptr(OstreeDeployment) merge_deployment = NULL;
|
||||
if (provided_merge_deployment != NULL)
|
||||
merge_deployment = g_object_ref (provided_merge_deployment);
|
||||
|
||||
@@ -1894,7 +2070,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
||||
return FALSE;
|
||||
|
||||
g_autofree char *new_bootcsum = NULL;
|
||||
glnx_unref_object OstreeDeployment *new_deployment =
|
||||
g_autoptr(OstreeDeployment) new_deployment =
|
||||
ostree_deployment_new (0, osname, revision, new_deployserial,
|
||||
new_bootcsum, -1);
|
||||
ostree_deployment_set_origin (new_deployment, origin);
|
||||
@@ -1909,33 +2085,29 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
|
||||
}
|
||||
|
||||
glnx_fd_close int tree_boot_dfd = -1;
|
||||
g_autofree char *tree_kernel_path = NULL;
|
||||
g_autofree char *tree_initramfs_path = NULL;
|
||||
g_autofree char *tree_kernel_srcpath = NULL;
|
||||
g_autofree char *tree_kernel_namever = NULL;
|
||||
g_autofree char *tree_initramfs_srcpath = NULL;
|
||||
g_autofree char *tree_initramfs_namever = NULL;
|
||||
g_autofree char *tree_bootcsum = NULL;
|
||||
if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd,
|
||||
&tree_kernel_path, &tree_initramfs_path,
|
||||
&tree_kernel_srcpath,
|
||||
&tree_kernel_namever,
|
||||
&tree_initramfs_srcpath,
|
||||
&tree_initramfs_namever,
|
||||
&new_bootcsum,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
if (tree_initramfs_path != NULL)
|
||||
{
|
||||
if (!checksum_from_kernel_src (tree_initramfs_path, &new_bootcsum, error))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!checksum_from_kernel_src (tree_kernel_path, &new_bootcsum, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
_ostree_deployment_set_bootcsum (new_deployment, new_bootcsum);
|
||||
|
||||
/* Create an empty boot configuration; we will merge things into
|
||||
* it as we go.
|
||||
*/
|
||||
glnx_unref_object OstreeBootconfigParser *bootconfig = ostree_bootconfig_parser_new ();
|
||||
g_autoptr(OstreeBootconfigParser) bootconfig = ostree_bootconfig_parser_new ();
|
||||
ostree_deployment_set_bootconfig (new_deployment, bootconfig);
|
||||
|
||||
glnx_unref_object OstreeSePolicy *sepolicy = NULL;
|
||||
g_autoptr(OstreeSePolicy) sepolicy = NULL;
|
||||
if (!merge_configuration (self, repo, merge_deployment, new_deployment,
|
||||
deployment_dfd,
|
||||
&sepolicy,
|
||||
@@ -2013,7 +2185,7 @@ ostree_sysroot_deployment_set_kargs (OstreeSysroot *self,
|
||||
{
|
||||
guint i;
|
||||
g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
glnx_unref_object OstreeDeployment *new_deployment = NULL;
|
||||
g_autoptr(OstreeDeployment) new_deployment = NULL;
|
||||
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
|
||||
g_autofree char *new_options = NULL;
|
||||
OstreeBootconfigParser *new_bootconfig;
|
||||
|
||||
@@ -33,7 +33,8 @@ typedef enum {
|
||||
OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS = 1 << 0,
|
||||
/* See https://github.com/ostreedev/ostree/pull/759 */
|
||||
OSTREE_SYSROOT_DEBUG_NO_XATTRS = 1 << 1,
|
||||
|
||||
/* https://github.com/ostreedev/ostree/pull/1049 */
|
||||
OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE = 1 << 2,
|
||||
} OstreeSysrootDebugFlags;
|
||||
|
||||
/**
|
||||
@@ -56,9 +57,8 @@ struct OstreeSysroot {
|
||||
OstreeDeployment *booted_deployment;
|
||||
struct timespec loaded_ts;
|
||||
|
||||
/* Only access through ostree_sysroot_get_repo() */
|
||||
/* Only access through ostree_sysroot_[_get]repo() */
|
||||
OstreeRepo *repo;
|
||||
gboolean repo_opened;
|
||||
|
||||
OstreeSysrootDebugFlags debug_flags;
|
||||
};
|
||||
@@ -68,6 +68,10 @@ struct OstreeSysroot {
|
||||
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/"
|
||||
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development"
|
||||
|
||||
void
|
||||
_ostree_sysroot_emit_journal_msg (OstreeSysroot *self,
|
||||
const char *msg);
|
||||
|
||||
gboolean
|
||||
_ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
|
||||
int bootversion,
|
||||
|
||||
+120
-127
@@ -25,6 +25,7 @@
|
||||
#include <sys/mount.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "ostree.h"
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-repo-private.h"
|
||||
#include "ostree-sepolicy-private.h"
|
||||
@@ -57,8 +58,18 @@ find_booted_deployment (OstreeSysroot *self,
|
||||
*/
|
||||
typedef struct {
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* Signals */
|
||||
void (*journal_msg) (OstreeSysroot *sysroot,
|
||||
const char *msg);
|
||||
} OstreeSysrootClass;
|
||||
|
||||
enum {
|
||||
JOURNAL_MSG_SIGNAL,
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
@@ -126,18 +137,11 @@ static void
|
||||
ostree_sysroot_constructed (GObject *object)
|
||||
{
|
||||
OstreeSysroot *self = OSTREE_SYSROOT (object);
|
||||
g_autoptr(GFile) repo_path = NULL;
|
||||
|
||||
/* Ensure the system root path is set. */
|
||||
if (self->path == NULL)
|
||||
self->path = g_object_ref (_ostree_get_default_sysroot_path ());
|
||||
|
||||
repo_path = g_file_resolve_relative_path (self->path, "ostree/repo");
|
||||
self->repo = ostree_repo_new_for_sysroot_path (repo_path, self->path);
|
||||
self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT;
|
||||
/* Hold a weak ref for the remote-add handling */
|
||||
g_weak_ref_init (&self->repo->sysroot, object);
|
||||
|
||||
G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object);
|
||||
}
|
||||
|
||||
@@ -158,6 +162,27 @@ ostree_sysroot_class_init (OstreeSysrootClass *klass)
|
||||
"",
|
||||
G_TYPE_FILE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
/**
|
||||
* OstreeSysroot::journal-msg:
|
||||
* @self: Self
|
||||
* @msg: Human-readable string (should not contain newlines)
|
||||
*
|
||||
* libostree will log to the journal various events, such as the /etc merge
|
||||
* status, and transaction completion. Connect to this signal to also
|
||||
* synchronously receive the text for those messages. This is intended to be
|
||||
* used by command line tools which link to libostree as a library.
|
||||
*
|
||||
* Currently, the structured data is only available via the systemd journal.
|
||||
*
|
||||
* Since: 2017.10
|
||||
*/
|
||||
signals[JOURNAL_MSG_SIGNAL] =
|
||||
g_signal_new ("journal-msg",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (OstreeSysrootClass, journal_msg),
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -165,6 +190,7 @@ ostree_sysroot_init (OstreeSysroot *self)
|
||||
{
|
||||
const GDebugKey keys[] = {
|
||||
{ "mutable-deployments", OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS },
|
||||
{ "test-fifreeze", OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE },
|
||||
{ "no-xattrs", OSTREE_SYSROOT_DEBUG_NO_XATTRS },
|
||||
};
|
||||
|
||||
@@ -299,24 +325,22 @@ ostree_sysroot_ensure_initialized (OstreeSysroot *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
struct stat stbuf;
|
||||
if (fstatat (self->sysroot_fd, "ostree/repo/objects", &stbuf, 0) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
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))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_autoptr(OstreeRepo) repo =
|
||||
ostree_repo_create_at (self->sysroot_fd, "ostree/repo",
|
||||
OSTREE_REPO_MODE_BARE, NULL,
|
||||
cancellable, error);
|
||||
if (!repo)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_ostree_sysroot_emit_journal_msg (OstreeSysroot *self,
|
||||
const char *msg)
|
||||
{
|
||||
g_signal_emit (self, signals[JOURNAL_MSG_SIGNAL], 0, msg);
|
||||
}
|
||||
|
||||
gboolean
|
||||
_ostree_sysroot_parse_deploy_path_name (const char *name,
|
||||
char **out_csum,
|
||||
@@ -454,7 +478,7 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
|
||||
g_str_has_suffix (dent->d_name, ".conf") &&
|
||||
S_ISREG (stbuf.st_mode))
|
||||
{
|
||||
glnx_unref_object OstreeBootconfigParser *config = ostree_bootconfig_parser_new ();
|
||||
g_autoptr(OstreeBootconfigParser) config = ostree_bootconfig_parser_new ();
|
||||
|
||||
if (!ostree_bootconfig_parser_parse_at (config, dfd_iter.fd, dent->d_name, cancellable, error))
|
||||
return glnx_prefix_error (error, "Parsing %s", dent->d_name);
|
||||
@@ -624,7 +648,7 @@ parse_deployment (OstreeSysroot *self,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
glnx_unref_object OstreeDeployment *ret_deployment
|
||||
g_autoptr(OstreeDeployment) ret_deployment
|
||||
= ostree_deployment_new (-1, osname, treecsum, deployserial,
|
||||
bootcsum, treebootserial);
|
||||
if (origin)
|
||||
@@ -691,7 +715,7 @@ list_deployments_process_one_boot_entry (OstreeSysroot *self,
|
||||
if (ostree_arg == NULL)
|
||||
return glnx_throw (error, "No ostree= kernel argument found");
|
||||
|
||||
glnx_unref_object OstreeDeployment *deployment = NULL;
|
||||
g_autoptr(OstreeDeployment) deployment = NULL;
|
||||
if (!parse_deployment (self, ostree_arg, &deployment,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
@@ -732,14 +756,22 @@ ostree_sysroot_load (OstreeSysroot *self,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ensure_repo_opened (OstreeSysroot *self,
|
||||
GError **error)
|
||||
ensure_repo (OstreeSysroot *self,
|
||||
GError **error)
|
||||
{
|
||||
if (self->repo_opened)
|
||||
if (self->repo != NULL)
|
||||
return TRUE;
|
||||
if (!ostree_repo_open (self->repo, NULL, error))
|
||||
if (!ensure_sysroot_fd (self, error))
|
||||
return FALSE;
|
||||
self->repo_opened = TRUE;
|
||||
self->repo = ostree_repo_open_at (self->sysroot_fd, "ostree/repo", NULL, error);
|
||||
if (!self->repo)
|
||||
return FALSE;
|
||||
|
||||
/* Flag it as having been created via ostree_sysroot_get_repo(), and hold a
|
||||
* weak ref for the remote-add handling.
|
||||
*/
|
||||
g_weak_ref_init (&self->repo->sysroot, self);
|
||||
self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -756,7 +788,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self,
|
||||
* previous to v2017.6, but we do now to support the error-free
|
||||
* ostree_sysroot_repo() API.
|
||||
*/
|
||||
if (!ensure_repo_opened (self, error))
|
||||
if (!ensure_repo (self, error))
|
||||
return FALSE;
|
||||
|
||||
int bootversion = 0;
|
||||
@@ -959,9 +991,8 @@ ostree_sysroot_get_repo (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
if (!ensure_repo_opened (self, error))
|
||||
if (!ensure_repo (self, error))
|
||||
return FALSE;
|
||||
|
||||
if (out_repo != NULL)
|
||||
*out_repo = g_object_ref (self->repo);
|
||||
return TRUE;
|
||||
@@ -999,7 +1030,7 @@ _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
|
||||
GError **error)
|
||||
{
|
||||
gboolean is_active;
|
||||
glnx_unref_object OstreeBootloader *ret_loader =
|
||||
g_autoptr(OstreeBootloader) ret_loader =
|
||||
(OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot);
|
||||
if (!_ostree_bootloader_query (ret_loader, &is_active,
|
||||
cancellable, error))
|
||||
@@ -1078,7 +1109,7 @@ find_booted_deployment (OstreeSysroot *self,
|
||||
{
|
||||
struct stat root_stbuf;
|
||||
struct stat self_stbuf;
|
||||
glnx_unref_object OstreeDeployment *ret_deployment = NULL;
|
||||
g_autoptr(OstreeDeployment) ret_deployment = NULL;
|
||||
|
||||
if (stat ("/", &root_stbuf) != 0)
|
||||
return glnx_throw_errno_prefix (error, "stat /");
|
||||
@@ -1540,6 +1571,7 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Deploy a copy of @target_deployment */
|
||||
static gboolean
|
||||
clone_deployment (OstreeSysroot *sysroot,
|
||||
OstreeDeployment *target_deployment,
|
||||
@@ -1547,38 +1579,26 @@ clone_deployment (OstreeSysroot *sysroot,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
|
||||
glnx_unref_object OstreeDeployment *new_deployment = NULL;
|
||||
|
||||
/* Ensure we have a clean slate */
|
||||
if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Performing initial cleanup: ");
|
||||
goto out;
|
||||
}
|
||||
return glnx_prefix_error (error, "Performing initial cleanup");
|
||||
|
||||
kargs = _ostree_kernel_args_new ();
|
||||
/* Copy the bootloader config options */
|
||||
OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
|
||||
g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);
|
||||
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = _ostree_kernel_args_new ();
|
||||
_ostree_kernel_args_append_argv (kargs, previous_args);
|
||||
|
||||
{ OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
|
||||
g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);
|
||||
|
||||
_ostree_kernel_args_append_argv (kargs, previous_args);
|
||||
}
|
||||
|
||||
{
|
||||
g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs);
|
||||
|
||||
if (!ostree_sysroot_deploy_tree (sysroot,
|
||||
ostree_deployment_get_osname (target_deployment),
|
||||
ostree_deployment_get_csum (target_deployment),
|
||||
ostree_deployment_get_origin (target_deployment),
|
||||
merge_deployment,
|
||||
kargs_strv,
|
||||
&new_deployment,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
/* Deploy the copy */
|
||||
g_autoptr(OstreeDeployment) new_deployment = NULL;
|
||||
g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs);
|
||||
if (!ostree_sysroot_deploy_tree (sysroot,
|
||||
ostree_deployment_get_osname (target_deployment),
|
||||
ostree_deployment_get_csum (target_deployment),
|
||||
ostree_deployment_get_origin (target_deployment),
|
||||
merge_deployment, kargs_strv, &new_deployment,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
/* Hotfixes push the deployment as rollback target, so it shouldn't
|
||||
* be the default.
|
||||
@@ -1587,11 +1607,9 @@ clone_deployment (OstreeSysroot *sysroot,
|
||||
new_deployment, merge_deployment,
|
||||
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1616,59 +1634,41 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
glnx_unref_object OstreeSePolicy *sepolicy = NULL;
|
||||
OstreeDeploymentUnlockedState current_unlocked =
|
||||
ostree_deployment_get_unlocked (deployment);
|
||||
glnx_unref_object OstreeDeployment *deployment_clone =
|
||||
ostree_deployment_clone (deployment);
|
||||
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
|
||||
GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone);
|
||||
const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
|
||||
const char *ovl_options = NULL;
|
||||
g_autofree char *deployment_path = NULL;
|
||||
glnx_fd_close int deployment_dfd = -1;
|
||||
pid_t mount_child;
|
||||
|
||||
/* This function cannot re-lock */
|
||||
g_return_val_if_fail (unlocked_state != OSTREE_DEPLOYMENT_UNLOCKED_NONE, FALSE);
|
||||
|
||||
OstreeDeploymentUnlockedState current_unlocked = ostree_deployment_get_unlocked (deployment);
|
||||
if (current_unlocked != OSTREE_DEPLOYMENT_UNLOCKED_NONE)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Deployment is already in unlocked state: %s",
|
||||
ostree_deployment_unlocked_state_to_string (current_unlocked));
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "Deployment is already in unlocked state: %s",
|
||||
ostree_deployment_unlocked_state_to_string (current_unlocked));
|
||||
|
||||
merge_deployment = ostree_sysroot_get_merge_deployment (self, ostree_deployment_get_osname (deployment));
|
||||
g_autoptr(OstreeDeployment) merge_deployment =
|
||||
ostree_sysroot_get_merge_deployment (self, ostree_deployment_get_osname (deployment));
|
||||
if (!merge_deployment)
|
||||
{
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No previous deployment to duplicate");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw (error, "No previous deployment to duplicate");
|
||||
|
||||
/* For hotfixes, we push a rollback target */
|
||||
if (unlocked_state == OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX)
|
||||
{
|
||||
if (!clone_deployment (self, deployment, merge_deployment, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Crack it open */
|
||||
if (!ostree_sysroot_deployment_set_mutable (self, deployment, TRUE,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
||||
return FALSE;
|
||||
|
||||
g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
|
||||
glnx_fd_close int deployment_dfd = -1;
|
||||
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error);
|
||||
g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error);
|
||||
if (!sepolicy)
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
const char *ovl_options = NULL;
|
||||
switch (unlocked_state)
|
||||
{
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
|
||||
@@ -1676,14 +1676,15 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
break;
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX:
|
||||
{
|
||||
const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
|
||||
/* Create the overlayfs directories in the deployment root
|
||||
* directly for hotfixes. The ostree-prepare-root.c helper
|
||||
* is also set up to detect and mount these.
|
||||
*/
|
||||
if (!glnx_shutil_mkdir_p_at (deployment_dfd, ".usr-ovl-upper", 0755, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
if (!glnx_shutil_mkdir_p_at (deployment_dfd, ".usr-ovl-work", 0755, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
ovl_options = hotfix_ovl_options;
|
||||
}
|
||||
break;
|
||||
@@ -1701,18 +1702,18 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
|
||||
if (!_ostree_sepolicy_preparefscreatecon (&con, sepolicy,
|
||||
"/usr", 0755, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
if (!glnx_mkdtempat (AT_FDCWD, development_ovldir, 0755, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
development_ovl_upper = glnx_strjoina (development_ovldir, "/upper");
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, development_ovl_upper, 0755, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
development_ovl_work = glnx_strjoina (development_ovldir, "/work");
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, development_ovl_work, 0755, cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
ovl_options = glnx_strjoina ("lowerdir=usr,upperdir=", development_ovl_upper,
|
||||
",workdir=", development_ovl_work);
|
||||
}
|
||||
@@ -1728,12 +1729,9 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
* threads, etc.
|
||||
*/
|
||||
{
|
||||
mount_child = fork ();
|
||||
pid_t mount_child = fork ();
|
||||
if (mount_child < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "%s", "fork");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "fork");
|
||||
else if (mount_child == 0)
|
||||
{
|
||||
/* Child process. Do NOT use any GLib API here. */
|
||||
@@ -1749,18 +1747,15 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
int estatus;
|
||||
|
||||
if (TEMP_FAILURE_RETRY (waitpid (mount_child, &estatus, 0)) < 0)
|
||||
{
|
||||
glnx_set_prefix_error_from_errno (error, "%s", "waitpid() on mount helper");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "waitpid() on mount helper");
|
||||
if (!g_spawn_check_exit_status (estatus, error))
|
||||
{
|
||||
g_prefix_error (error, "overlayfs mount helper: ");
|
||||
goto out;
|
||||
}
|
||||
return glnx_throw_errno_prefix (error, "overlayfs mount helper");
|
||||
}
|
||||
}
|
||||
|
||||
g_autoptr(OstreeDeployment) deployment_clone = ostree_deployment_clone (deployment);
|
||||
GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone);
|
||||
|
||||
/* Now, write out the flag saying what we did */
|
||||
switch (unlocked_state)
|
||||
{
|
||||
@@ -1772,7 +1767,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
ostree_deployment_unlocked_state_to_string (unlocked_state));
|
||||
if (!ostree_sysroot_write_origin_file (self, deployment, origin_clone,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
break;
|
||||
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
|
||||
{
|
||||
@@ -1780,10 +1775,10 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
g_autofree char *devpath_parent = dirname (g_strdup (devpath));
|
||||
|
||||
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error))
|
||||
goto out;
|
||||
|
||||
return FALSE;
|
||||
|
||||
if (!g_file_set_contents (devpath, "", 0, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1793,9 +1788,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
|
||||
* regardless.
|
||||
*/
|
||||
if (!_ostree_sysroot_bump_mtime (self, error))
|
||||
goto out;
|
||||
return FALSE;
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
return ret;
|
||||
return TRUE;
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "otutil.h"
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@@ -31,6 +32,7 @@ G_BEGIN_DECLS
|
||||
|
||||
typedef struct _OstreeTlsCertInteraction OstreeTlsCertInteraction;
|
||||
typedef struct _OstreeTlsCertInteractionClass OstreeTlsCertInteractionClass;
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeTlsCertInteraction, g_object_unref)
|
||||
|
||||
GType _ostree_tls_cert_interaction_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_RELEASE_VERSION (9)
|
||||
#define OSTREE_RELEASE_VERSION (10)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION
|
||||
@@ -53,7 +53,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION (2017.9)
|
||||
#define OSTREE_VERSION (2017.10)
|
||||
|
||||
/**
|
||||
* OSTREE_VERSION_S:
|
||||
@@ -63,7 +63,7 @@
|
||||
*
|
||||
* Since: 2017.4
|
||||
*/
|
||||
#define OSTREE_VERSION_S "2017.9"
|
||||
#define OSTREE_VERSION_S "2017.10"
|
||||
|
||||
#define OSTREE_ENCODE_VERSION(year,release) \
|
||||
((year) << 16 | (release))
|
||||
|
||||
Reference in new issue
Block a user