diff --git a/Makefile-tests.am b/Makefile-tests.am index 5498fd43..f5a65278 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -126,6 +126,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-create-usb.sh \ tests/test-find-remotes.sh \ tests/test-fsck-collections.sh \ + tests/test-fsck-delete.sh \ tests/test-init-collections.sh \ tests/test-prune-collections.sh \ tests/test-refs-collections.sh \ diff --git a/Makefile.in b/Makefile.in index ce89b39d..356f5589 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1999,8 +1999,8 @@ am__EXEEXT_25 = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-summary-update.sh tests/test-summary-view.sh \ tests/test-no-initramfs.sh tests/test-create-usb.sh \ tests/test-find-remotes.sh tests/test-fsck-collections.sh \ - tests/test-init-collections.sh tests/test-prune-collections.sh \ - tests/test-refs-collections.sh \ + tests/test-fsck-delete.sh tests/test-init-collections.sh \ + tests/test-prune-collections.sh tests/test-refs-collections.sh \ tests/test-remote-add-collections.sh \ tests/test-repo-finder-mount-integration.sh \ tests/test-summary-collections.sh \ @@ -2842,8 +2842,8 @@ _installed_or_uninstalled_test_scripts = tests/test-basic.sh \ tests/test-summary-update.sh tests/test-summary-view.sh \ tests/test-no-initramfs.sh tests/test-create-usb.sh \ tests/test-find-remotes.sh tests/test-fsck-collections.sh \ - tests/test-init-collections.sh tests/test-prune-collections.sh \ - tests/test-refs-collections.sh \ + tests/test-fsck-delete.sh tests/test-init-collections.sh \ + tests/test-prune-collections.sh tests/test-refs-collections.sh \ tests/test-remote-add-collections.sh \ tests/test-repo-finder-mount-integration.sh \ tests/test-summary-collections.sh \ @@ -8205,6 +8205,13 @@ tests/test-fsck-collections.sh.log: tests/test-fsck-collections.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-fsck-delete.sh.log: tests/test-fsck-delete.sh + @p='tests/test-fsck-delete.sh'; \ + b='tests/test-fsck-delete.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) tests/test-init-collections.sh.log: tests/test-init-collections.sh @p='tests/test-init-collections.sh'; \ b='tests/test-init-collections.sh'; \ diff --git a/apidoc/html/index.html b/apidoc/html/index.html index 98f7ed38..bb689ad8 100644 --- a/apidoc/html/index.html +++ b/apidoc/html/index.html @@ -14,7 +14,7 @@
-

for OSTree 2019.3

+

for OSTree 2019.4


diff --git a/apidoc/html/ostree-OstreeRepo.html b/apidoc/html/ostree-OstreeRepo.html index 490f498b..91b9bc83 100644 --- a/apidoc/html/ostree-OstreeRepo.html +++ b/apidoc/html/ostree-OstreeRepo.html @@ -442,6 +442,14 @@ gboolean +ostree_repo_mark_commit_partial_reason () + + + + +gboolean + + ostree_repo_write_metadata () @@ -3435,9 +3443,10 @@ ostree_repo_mark_commit_partial (const char *checksum, gboolean is_partial, GError **error); -

Commits in "partial" state do not have all their child objects written. This -occurs in various situations, such as during a pull, but also if a "subpath" -pull is used, as well as "commit only" pulls.

+

Commits in the "partial" state do not have all their child objects +written. This occurs in various situations, such as during a pull, +but also if a "subpath" pull is used, as well as "commit only" +pulls.

This function is used by ostree_repo_pull_with_options(); you should use this if you are implementing a different type of transport.

@@ -3476,6 +3485,62 @@ should use this if you are implementing a different type of transport.


+

ostree_repo_mark_commit_partial_reason ()

+
gboolean
+ostree_repo_mark_commit_partial_reason
+                               (OstreeRepo *self,
+                                const char *checksum,
+                                gboolean is_partial,
+                                OstreeRepoCommitState in_state,
+                                GError **error);
+

Allows the setting of a reason code for a partial commit. Presently +it only supports setting reason bitmask to +OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL, or +OSTREE_REPO_COMMIT_STATE_NORMAL. This will allow successive ostree +fsck operations to exit properly with an error code if the +repository has been truncated as a result of fsck trying to repair +it.

+
+

Parameters

+
+++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + +

self

Repo

 

checksum

Commit SHA-256

 

is_partial

Whether or not this commit is partial

 

in_state

Reason bitmask for partial commit

 

error

Error

 
+
+

Since: 2019.4

+
+
+

ostree_repo_write_metadata ()

gboolean
 ostree_repo_write_metadata (OstreeRepo *self,
@@ -8291,6 +8356,14 @@ by  
 
+
+

OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL

+ +

One or more objects are missing from the + local copy of the commit, due to an fsck --delete. (Since: 2019.4.)

+ +  +
diff --git a/apidoc/html/ostree.devhelp2 b/apidoc/html/ostree.devhelp2 index 6804d47e..00931091 100644 --- a/apidoc/html/ostree.devhelp2 +++ b/apidoc/html/ostree.devhelp2 @@ -134,6 +134,7 @@ + @@ -433,6 +434,7 @@ + diff --git a/apidoc/html/reference.html b/apidoc/html/reference.html index b2b92571..ef4b30be 100644 --- a/apidoc/html/reference.html +++ b/apidoc/html/reference.html @@ -1235,6 +1235,10 @@ ostree_repo_list_collection_refs, function in ostree-misc-experimental
+ostree_repo_mark_commit_partial_reason, function in OstreeRepo +
+
+
OSTREE_REPO_METADATA_REF, macro in ostree-repo-experimental
diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index e8faeb10..252a563a 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -333,6 +333,7 @@ ostree_repo_set_cache_dir ostree_repo_sign_delta ostree_repo_has_object ostree_repo_mark_commit_partial +ostree_repo_mark_commit_partial_reason ostree_repo_write_metadata ostree_repo_write_metadata_async ostree_repo_write_metadata_finish diff --git a/apidoc/version.xml b/apidoc/version.xml index 506ed987..b428e33c 100644 --- a/apidoc/version.xml +++ b/apidoc/version.xml @@ -1 +1 @@ -2019.3 \ No newline at end of file +2019.4 \ No newline at end of file diff --git a/build-aux/compile b/build-aux/compile index 99e50524..b89c278e 100755 --- a/build-aux/compile +++ b/build-aux/compile @@ -1,4 +1,4 @@ -#! /bin/sh +#!/usr/bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC diff --git a/build-aux/config.guess b/build-aux/config.guess index b33c9e89..b5d7a0f3 100755 --- a/build-aux/config.guess +++ b/build-aux/config.guess @@ -1,4 +1,4 @@ -#! /bin/sh +#!/usr/bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2018 Free Software Foundation, Inc. diff --git a/build-aux/config.sub b/build-aux/config.sub index b51fb8cd..be4dc6e5 100755 --- a/build-aux/config.sub +++ b/build-aux/config.sub @@ -1,4 +1,4 @@ -#! /bin/sh +#!/usr/bin/sh # Configuration validation subroutine script. # Copyright 1992-2018 Free Software Foundation, Inc. diff --git a/build-aux/depcomp b/build-aux/depcomp index 65cbf709..4e0ae31b 100755 --- a/build-aux/depcomp +++ b/build-aux/depcomp @@ -1,4 +1,4 @@ -#! /bin/sh +#!/usr/bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2018-03-07.03; # UTC diff --git a/build-aux/install-sh b/build-aux/install-sh index 8175c640..defb86ae 100755 --- a/build-aux/install-sh +++ b/build-aux/install-sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/usr/bin/sh # install - install a program, script, or datafile scriptversion=2018-03-11.20; # UTC diff --git a/build-aux/missing b/build-aux/missing index 625aeb11..ab658ed5 100755 --- a/build-aux/missing +++ b/build-aux/missing @@ -1,4 +1,4 @@ -#! /bin/sh +#!/usr/bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC diff --git a/build-aux/test-driver b/build-aux/test-driver index b8521a48..d1ef0647 100755 --- a/build-aux/test-driver +++ b/build-aux/test-driver @@ -1,4 +1,4 @@ -#! /bin/sh +#!/usr/bin/sh # test-driver - basic testsuite driver script. scriptversion=2018-03-07.03; # UTC diff --git a/configure b/configure index 83fd8af5..a1de30db 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libostree 2019.3. +# Generated by GNU Autoconf 2.69 for libostree 2019.4. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libostree' PACKAGE_TARNAME='libostree' -PACKAGE_VERSION='2019.3' -PACKAGE_STRING='libostree 2019.3' +PACKAGE_VERSION='2019.4' +PACKAGE_STRING='libostree 2019.4' PACKAGE_BUGREPORT='walters@verbum.org' PACKAGE_URL='' @@ -1556,7 +1556,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libostree 2019.3 to adapt to many kinds of systems. +\`configure' configures libostree 2019.4 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1626,7 +1626,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libostree 2019.3:";; + short | recursive ) echo "Configuration of libostree 2019.4:";; esac cat <<\_ACEOF @@ -1885,7 +1885,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libostree configure 2019.3 +libostree configure 2019.4 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2357,7 +2357,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libostree $as_me 2019.3, which was +It was created by libostree $as_me 2019.4, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3225,7 +3225,7 @@ fi # Define the identity of the package. PACKAGE='libostree' - VERSION='2019.3' + VERSION='2019.4' # Some tools Automake needs. @@ -5959,9 +5959,9 @@ test -n "$YACC" || YACC="yacc" YEAR_VERSION=2019 -RELEASE_VERSION=3 +RELEASE_VERSION=4 -PACKAGE_VERSION=2019.3 +PACKAGE_VERSION=2019.4 if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then : @@ -18833,7 +18833,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libostree $as_me 2019.3, which was +This file was extended by libostree $as_me 2019.4, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -18899,7 +18899,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -libostree config.status 2019.3 +libostree config.status 2019.4 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 15c60bb4..cd3cfd10 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl update libostree-released.sym from libostree-devel.sym, and update the check dnl in test-symbols.sh, and also set is_release_build=yes below. Then make dnl another post-release commit to bump the version, and set is_release_build=no. m4_define([year_version], [2019]) -m4_define([release_version], [3]) +m4_define([release_version], [4]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) is_release_build=yes diff --git a/src/boot/ostree-finalize-staged.service b/src/boot/ostree-finalize-staged.service index e112bc0c..9c4706e8 100644 --- a/src/boot/ostree-finalize-staged.service +++ b/src/boot/ostree-finalize-staged.service @@ -26,6 +26,9 @@ DefaultDependencies=no RequiresMountsFor=/sysroot After=local-fs.target Before=basic.target final.target +# We want to make sure the transaction logs are persisted to disk: +# https://bugzilla.redhat.com/show_bug.cgi?id=1751272 +After=systemd-journal-flush.service Conflicts=final.target [Service] diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym index fbcb2d56..ec9eec66 100644 --- a/src/libostree/libostree-released.sym +++ b/src/libostree/libostree-released.sym @@ -571,6 +571,10 @@ global: ostree_kernel_args_to_string; } LIBOSTREE_2018.9; +LIBOSTREE_2019.4 { + ostree_repo_mark_commit_partial_reason; +} LIBOSTREE_2019.3; + /* NOTE: Only add more content here in release commits! See the * comments at the top of this file. */ diff --git a/src/libostree/ostree-bootconfig-parser.c b/src/libostree/ostree-bootconfig-parser.c index 25da6657..67f9fb58 100644 --- a/src/libostree/ostree-bootconfig-parser.c +++ b/src/libostree/ostree-bootconfig-parser.c @@ -30,7 +30,6 @@ struct _OstreeBootconfigParser const char *separators; GHashTable *options; - GPtrArray *lines; }; typedef GObjectClass OstreeBootconfigParserClass; @@ -48,9 +47,6 @@ ostree_bootconfig_parser_clone (OstreeBootconfigParser *self) { OstreeBootconfigParser *parser = ostree_bootconfig_parser_new (); - for (guint i = 0; i < self->lines->len; i++) - g_ptr_array_add (parser->lines, g_variant_ref (self->lines->pdata[i])); - GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v) g_hash_table_replace (parser->options, g_strdup (k), g_strdup (v)); @@ -84,7 +80,6 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, for (char **iter = lines; *iter; iter++) { const char *line = *iter; - char *keyname = ""; if (g_ascii_isalpha (*line)) { @@ -92,7 +87,6 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, items = g_strsplit_set (line, self->separators, 2); if (g_strv_length (items) == 2 && items[0][0] != '\0') { - keyname = items[0]; g_hash_table_insert (self->options, items[0], items[1]); g_free (items); /* Transfer ownership */ } @@ -101,7 +95,6 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, g_strfreev (items); } } - g_ptr_array_add (self->lines, g_variant_new ("(ss)", keyname, line)); } self->parsed = TRUE; @@ -153,34 +146,29 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self, GCancellable *cancellable, GError **error) { + /* Write the fields in a deterministic order, following what is used + * in the bootconfig example of the BootLoaderspec document: + * https://systemd.io/BOOT_LOADER_SPECIFICATION + */ + const char *fields[] = { "title", "version", "options", "devicetree", "linux", "initrd" }; + g_autoptr(GHashTable) keys_written = g_hash_table_new (g_str_hash, g_str_equal); g_autoptr(GString) buf = g_string_new (""); - g_autoptr(GHashTable) written_overrides = g_hash_table_new (g_str_hash, g_str_equal); - for (guint i = 0; i < self->lines->len; i++) + for (guint i = 0; i < G_N_ELEMENTS (fields); i++) { - GVariant *linedata = self->lines->pdata[i]; - const char *key; - const char *value; - const char *line; - - g_variant_get (linedata, "(&s&s)", &key, &line); - - value = g_hash_table_lookup (self->options, key); - if (value == NULL) - { - g_string_append (buf, line); - g_string_append_c (buf, '\n'); - } - else + const char *key = fields[i]; + const char *value = g_hash_table_lookup (self->options, key); + if (value != NULL) { write_key (self, buf, key, value); - g_hash_table_add (written_overrides, (gpointer)key); + g_hash_table_add (keys_written, (gpointer)key); } } + /* Write unknown fields */ GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v) { - if (g_hash_table_lookup (written_overrides, k)) + if (g_hash_table_lookup (keys_written, k)) continue; write_key (self, buf, k, v); } @@ -210,7 +198,6 @@ ostree_bootconfig_parser_finalize (GObject *object) OstreeBootconfigParser *self = OSTREE_BOOTCONFIG_PARSER (object); g_hash_table_unref (self->options); - g_ptr_array_unref (self->lines); G_OBJECT_CLASS (ostree_bootconfig_parser_parent_class)->finalize (object); } @@ -219,7 +206,6 @@ static void ostree_bootconfig_parser_init (OstreeBootconfigParser *self) { self->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - self->lines = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); } void diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index e7bc9820..0aaebbdb 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -1873,6 +1873,57 @@ ensure_txn_refs (OstreeRepo *self) g_free); } +/** + * ostree_repo_mark_commit_partial_reason: + * @self: Repo + * @checksum: Commit SHA-256 + * @is_partial: Whether or not this commit is partial + * @in_state: Reason bitmask for partial commit + * @error: Error + * + * Allows the setting of a reason code for a partial commit. Presently + * it only supports setting reason bitmask to + * OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL, or + * OSTREE_REPO_COMMIT_STATE_NORMAL. This will allow successive ostree + * fsck operations to exit properly with an error code if the + * repository has been truncated as a result of fsck trying to repair + * it. + * + * Since: 2019.4 + */ +gboolean +ostree_repo_mark_commit_partial_reason (OstreeRepo *self, + const char *checksum, + gboolean is_partial, + OstreeRepoCommitState in_state, + GError **error) +{ + g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum); + if (is_partial) + { + glnx_autofd int fd = openat (self->repo_dir_fd, commitpartial_path, + O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644); + if (fd == -1) + { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "open(%s)", commitpartial_path); + } + else + { + if (in_state & OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL) + if (glnx_loop_write (fd, "f", 1) < 0) + return glnx_throw_errno_prefix (error, "write(%s)", commitpartial_path); + } + } + else + { + if (!ot_ensure_unlinked_at (self->repo_dir_fd, commitpartial_path, 0)) + return FALSE; + } + + return TRUE; +} + /** * ostree_repo_mark_commit_partial: * @self: Repo @@ -1880,9 +1931,10 @@ ensure_txn_refs (OstreeRepo *self) * @is_partial: Whether or not this commit is partial * @error: Error * - * Commits in "partial" state do not have all their child objects written. This - * occurs in various situations, such as during a pull, but also if a "subpath" - * pull is used, as well as "commit only" pulls. + * Commits in the "partial" state do not have all their child objects + * written. This occurs in various situations, such as during a pull, + * but also if a "subpath" pull is used, as well as "commit only" + * pulls. * * This function is used by ostree_repo_pull_with_options(); you * should use this if you are implementing a different type of transport. @@ -1895,24 +1947,9 @@ ostree_repo_mark_commit_partial (OstreeRepo *self, gboolean is_partial, GError **error) { - g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum); - if (is_partial) - { - glnx_autofd int fd = openat (self->repo_dir_fd, commitpartial_path, - O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644); - if (fd == -1) - { - if (errno != EEXIST) - return glnx_throw_errno_prefix (error, "open(%s)", commitpartial_path); - } - } - else - { - if (!ot_ensure_unlinked_at (self->repo_dir_fd, commitpartial_path, 0)) - return FALSE; - } - - return TRUE; + return ostree_repo_mark_commit_partial_reason (self, checksum, is_partial, + OSTREE_REPO_COMMIT_STATE_NORMAL, + error); } /** diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 3adaa477..ba6e7289 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -385,6 +385,8 @@ check_outstanding_requests_handle_error (OtPullData *pull_data, GError *error = *errorp; if (error) { + g_debug ("Request caught error: %s", error->message); + if (!pull_data->caught_error) { pull_data->caught_error = TRUE; diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index eb652bef..b654aff2 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -3768,10 +3768,19 @@ load_metadata_internal (OstreeRepo *self, g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (sha256); *out_state = 0; - if (!glnx_fstatat_allow_noent (self->repo_dir_fd, commitpartial_path, NULL, 0, error)) + glnx_autofd int fd = -1; + if (!ot_openat_ignore_enoent (self->repo_dir_fd, commitpartial_path, &fd, error)) return FALSE; - if (errno == 0) - *out_state |= OSTREE_REPO_COMMIT_STATE_PARTIAL; + if (fd != -1) + { + *out_state |= OSTREE_REPO_COMMIT_STATE_PARTIAL; + char reason; + if (read (fd, &reason, 1) == 1) + { + if (reason == 'f') + *out_state |= OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL; + } + } } } else if (self->parent_repo) diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 038bbd41..40d3f773 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -248,6 +248,26 @@ gboolean ostree_repo_write_config (OstreeRepo *self, GKeyFile *new_config, GError **error); +/** + * OstreeRepoCommitState: + * @OSTREE_REPO_COMMIT_STATE_NORMAL: Commit is complete. This is the default. + * (Since: 2017.14.) + * @OSTREE_REPO_COMMIT_STATE_PARTIAL: One or more objects are missing from the + * local copy of the commit, but metadata is present. (Since: 2015.7.) + * @OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL: One or more objects are missing from the + * local copy of the commit, due to an fsck --delete. (Since: 2019.4.) + * + * Flags representing the state of a commit in the local repository, as returned + * by ostree_repo_load_commit(). + * + * Since: 2015.7 + */ +typedef enum { + OSTREE_REPO_COMMIT_STATE_NORMAL = 0, + OSTREE_REPO_COMMIT_STATE_PARTIAL = (1 << 0), + OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL = (1 << 1), +} OstreeRepoCommitState; + /** * OstreeRepoTransactionStats: * @metadata_objects_total: The total number of metadata objects @@ -315,6 +335,13 @@ gboolean ostree_repo_mark_commit_partial (OstreeRepo *self, gboolean is_partial, GError **error); +_OSTREE_PUBLIC +gboolean ostree_repo_mark_commit_partial_reason (OstreeRepo *self, + const char *checksum, + gboolean is_partial, + OstreeRepoCommitState in_state, + GError **error); + _OSTREE_PUBLIC void ostree_repo_transaction_set_refspec (OstreeRepo *self, const char *refspec, @@ -526,23 +553,6 @@ gboolean ostree_repo_load_variant_if_exists (OstreeRepo *self, GVariant **out_variant, GError **error); -/** - * OstreeRepoCommitState: - * @OSTREE_REPO_COMMIT_STATE_NORMAL: Commit is complete. This is the default. - * (Since: 2017.14.) - * @OSTREE_REPO_COMMIT_STATE_PARTIAL: One or more objects are missing from the - * local copy of the commit, but metadata is present. (Since: 2015.7.) - * - * Flags representing the state of a commit in the local repository, as returned - * by ostree_repo_load_commit(). - * - * Since: 2015.7 - */ -typedef enum { - OSTREE_REPO_COMMIT_STATE_NORMAL = 0, - OSTREE_REPO_COMMIT_STATE_PARTIAL = (1 << 0), -} OstreeRepoCommitState; - _OSTREE_PUBLIC gboolean ostree_repo_load_commit (OstreeRepo *self, const char *checksum, diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 9de5464a..c342d7e0 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -1746,10 +1746,9 @@ install_deployment_kernel (OstreeSysroot *sysroot, g_string_append_c (title_key, ':'); g_string_append (title_key, osname); } - if (!(deployment_version && *deployment_version)) - { - g_string_append_printf (title_key, ":%d", ostree_deployment_get_index (deployment)); - } + + g_string_append_printf (title_key, ":%d", ostree_deployment_get_index (deployment)); + g_string_append_c (title_key, ')'); ostree_bootconfig_parser_set (bootconfig, "title", title_key->str); diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index b3ad2498..2c0c0546 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -959,7 +959,18 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, } if (self->root_is_ostree_booted && !self->booted_deployment) - return glnx_throw (error, "Unexpected state: /run/ostree-booted found and in / sysroot but not in a booted deployment"); + { + if (!glnx_fstatat_allow_noent (self->sysroot_fd, "boot/loader", NULL, AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (errno == ENOENT) + { + return glnx_throw (error, "Unexpected state: /run/ostree-booted found, but no /boot/loader directory"); + } + else + { + return glnx_throw (error, "Unexpected state: /run/ostree-booted found and in / sysroot, but bootloader entry not found"); + } + } if (!_ostree_sysroot_reload_staged (self, error)) return FALSE; diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h index 82a50373..ebb38d0e 100644 --- a/src/libostree/ostree-version.h +++ b/src/libostree/ostree-version.h @@ -43,7 +43,7 @@ * * Since: 2017.4 */ -#define OSTREE_RELEASE_VERSION (3) +#define OSTREE_RELEASE_VERSION (4) /** * OSTREE_VERSION @@ -52,7 +52,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION (2019.3) +#define OSTREE_VERSION (2019.4) /** * OSTREE_VERSION_S: @@ -62,7 +62,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION_S "2019.3" +#define OSTREE_VERSION_S "2019.4" #define OSTREE_ENCODE_VERSION(year,release) \ ((year) << 16 | (release)) diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c index cf5ce3ea..743d941e 100644 --- a/src/libotutil/ot-gpg-utils.c +++ b/src/libotutil/ot-gpg-utils.c @@ -25,6 +25,7 @@ #include +#include #include "libglnx.h" /* Like glnx_throw_errno_prefix, but takes @gpg_error */ @@ -438,28 +439,102 @@ ot_gpgme_new_ctx (const char *homedir, return g_steal_pointer (&context); } +static gboolean +get_gnupg_version (guint *major, + guint *minor, + guint *patch) +{ + g_return_val_if_fail (major != NULL, FALSE); + g_return_val_if_fail (minor != NULL, FALSE); + g_return_val_if_fail (patch != NULL, FALSE); + + gpgme_engine_info_t info; + gpgme_error_t err = gpgme_get_engine_info (&info); + if (err != GPG_ERR_NO_ERROR) + { + g_debug ("Failed to get GPGME engine info: %s: %s", + gpgme_strsource (err), gpgme_strerror (err)); + return FALSE; + } + + const char *gnupg_version = NULL; + for (; info != NULL; info = info->next) + { + if (info->protocol == GPGME_PROTOCOL_OpenPGP) + { + gnupg_version = info->version; + break; + } + } + + if (gnupg_version == NULL) + { + g_debug ("Could not determine GnuPG version"); + return FALSE; + } + + g_auto(GStrv) parts = g_strsplit (gnupg_version, ".", 4); + if (g_strv_length (parts) < 3) + { + g_debug ("Less than 3 components in GnuPG version \"%s\"", gnupg_version); + return FALSE; + } + + *major = g_ascii_strtoull (parts[0], NULL, 10); + *minor = g_ascii_strtoull (parts[1], NULL, 10); + *patch = g_ascii_strtoull (parts[2], NULL, 10); + + return TRUE; +} + void ot_gpgme_kill_agent (const char *homedir) { g_return_if_fail (homedir != NULL); + /* If gnupg is at least 2.1.17, gpg-agent will exit when the homedir + * is deleted. + */ + guint gnupg_major = 0, gnupg_minor = 0, gnupg_patch = 0; + if (get_gnupg_version (&gnupg_major, &gnupg_minor, &gnupg_patch)) + { + if ((gnupg_major > 2) || + (gnupg_major == 2 && gnupg_minor > 1) || + (gnupg_major == 2 && gnupg_minor == 1 && gnupg_patch >= 17)) + { + /* Note early return */ + g_debug ("GnuPG >= 2.1.17, skipping gpg-agent cleanup in %s", homedir); + return; + } + } + /* Run gpg-connect-agent killagent /bye */ + g_autoptr(GPtrArray) argv = g_ptr_array_new (); + g_ptr_array_add (argv, "gpg-connect-agent"); + g_ptr_array_add (argv, "--homedir"); + g_ptr_array_add (argv, (gpointer)homedir); + g_ptr_array_add (argv, "killagent"); + g_ptr_array_add (argv, "/bye"); + g_ptr_array_add (argv, NULL); + g_autoptr(GError) local_error = NULL; - g_autoptr(GSubprocess) proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_SILENCE, - &local_error, - "gpg-connect-agent", - "--homedir", - homedir, - "killagent", - "/bye", - NULL); - if (proc == NULL) { - g_debug ("Spawning gpg-connect-agent failed: %s", local_error->message); - return; - } - if (!g_subprocess_wait_check (proc, NULL, &local_error)) { - g_debug ("Killing GPG agent with gpg-connect-agent failed: %s", - local_error->message); - return; - } + GSpawnFlags flags = G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL; + gint proc_status = 0; + g_autofree gchar *proc_stderr = NULL; + g_debug ("Killing gpg-agent in %s", homedir); + if (!g_spawn_sync (NULL, (char **)argv->pdata, NULL, flags, NULL, NULL, + NULL, &proc_stderr, &proc_status, &local_error)) + { + g_debug ("Spawning gpg-connect-agent failed: %s", local_error->message); + return; + } + if (!g_spawn_check_exit_status (proc_status, &local_error)) + { + /* Dump out stderr on failures */ + g_printerr ("%s", proc_stderr); + + g_debug ("Killing GPG agent with gpg-connect-agent failed: %s", + local_error->message); + return; + } } diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c index a7ecd3d0..5ad3bf38 100644 --- a/src/ostree/ot-builtin-fsck.c +++ b/src/ostree/ot-builtin-fsck.c @@ -127,7 +127,7 @@ fsck_one_object (OstreeRepo *repo, if ((state & OSTREE_REPO_COMMIT_STATE_PARTIAL) == 0) { g_printerr ("Marking commit as partial: %s\n", parent_commit); - if (!ostree_repo_mark_commit_partial (repo, parent_commit, TRUE, error)) + if (!ostree_repo_mark_commit_partial_reason (repo, parent_commit, TRUE, OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL, error)) return FALSE; } } @@ -302,6 +302,7 @@ ostree_builtin_fsck (int argc, char **argv, OstreeCommandInvocation *invocation, opt_verify_bindings = TRUE; guint n_partial = 0; + guint n_fsck_partial = 0; g_hash_table_iter_init (&hash_iter, objects); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { @@ -410,7 +411,11 @@ ostree_builtin_fsck (int argc, char **argv, OstreeCommandInvocation *invocation, } if (commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) - n_partial++; + { + n_partial++; + if (commitstate & OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL) + n_fsck_partial++; + } else g_hash_table_add (commits, g_variant_ref (serialized_key)); } @@ -450,5 +455,8 @@ ostree_builtin_fsck (int argc, char **argv, OstreeCommandInvocation *invocation, if (found_corruption) return glnx_throw (error, "Repository corruption encountered"); + if (n_fsck_partial > 0) + return glnx_throw (error, "%u partial commits from fsck-detected corruption", n_partial); + return TRUE; } diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index 3d6e7833..33c46ff4 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -273,6 +273,9 @@ main(int argc, char *argv[]) if (mount (".", root_mountpoint, NULL, MS_MOVE, NULL) < 0) err (EXIT_FAILURE, "failed to MS_MOVE %s to %s", deploy_path, root_mountpoint); + + if (rmdir ("/sysroot.tmp") < 0) + err (EXIT_FAILURE, "couldn't remove temporary sysroot /sysroot.tmp"); } /* The /sysroot mount needs to be private to avoid having a mount for e.g. /var/cache diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 0defebc0..11b9ea14 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -290,10 +290,10 @@ echo "ok upgrade with multiple kernel args" os_repository_new_commit ${CMD_PREFIX} ostree admin upgrade --os=testos -assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf "^title TestOS 42 ${version} (ostree:testos)$" +assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf "^title TestOS 42 ${version} (ostree:testos:0)$" os_repository_new_commit 0 0 testos/buildmaster/x86_64-runtime 42 ${CMD_PREFIX} ostree admin upgrade --os=testos -assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf "^title TestOS 42 (ostree:testos)$" +assert_file_has_content sysroot/boot/loader/entries/ostree-4-testos.conf "^title TestOS 42 (ostree:testos:0)$" echo "ok no duplicate version strings in title" diff --git a/tests/test-fsck-delete.sh b/tests/test-fsck-delete.sh new file mode 100755 index 00000000..3e7347bb --- /dev/null +++ b/tests/test-fsck-delete.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Copyright © 2019 Wind River Systems, Inc. +# +# SPDX-License-Identifier: LGPL-2.0+ +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo '1..6' + +cd ${test_tmpdir} + +rm -rf ./f1 +mkdir -p ./f1 +${CMD_PREFIX} ostree --repo=./f1 init --mode=archive-z2 +rm -rf ./trial +mkdir -p ./trial +echo test > ./trial/test +${CMD_PREFIX} ostree --repo=./f1 commit --tree=dir=./trial --skip-if-unchanged --branch=exp1 --subject="test Commit" + +rm -rf ./f2 +mkdir -p ./f2 +${CMD_PREFIX} ostree --repo=./f2 init --mode=archive-z2 +${CMD_PREFIX} ostree --repo=./f2 pull-local ./f1 +echo "ok 1 fsck-pre-commit" + +file=`find ./f2 |grep objects |grep \\.file |tail -1 ` +rm $file +echo whoops > $file + +# First check for corruption +if ${CMD_PREFIX} ostree fsck --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck did not fail" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck-error "^error: In commits" + +echo "ok 2 fsck-fail-check" + +# Fix the corruption +if ${CMD_PREFIX} ostree fsck --delete --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck did not fail" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck-error "^In commits" + +echo "ok 3 fsck-delete-check" + +# Check that fsck still exits with non-zero after corruption fix +if ${CMD_PREFIX} ostree fsck --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck did not fail" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_has_content fsck-error "^error: 1" + +echo "ok 4 fsck-post-delete-check" + +${CMD_PREFIX} ostree --repo=./f2 pull-local ./f1 > /dev/null +echo "ok 5 fsck-repair" + +if ! ${CMD_PREFIX} ostree fsck --repo=./f2 > fsck 2> fsck-error; then + assert_not_reached "fsck failed when it should have passed" +fi +assert_file_has_content fsck "^Validating refs\.\.\.$" +assert_file_empty fsck-error +echo "ok 6 fsck-good" diff --git a/tests/test-symbols.sh b/tests/test-symbols.sh index 5ec06d72..32285bdc 100755 --- a/tests/test-symbols.sh +++ b/tests/test-symbols.sh @@ -54,7 +54,7 @@ echo 'ok documented symbols' # ONLY update this checksum in release commits! cat > released-sha256.txt <