diff --git a/Makefile-tests.am b/Makefile-tests.am
index a417937..3fbc94b 100644
--- a/Makefile-tests.am
+++ b/Makefile-tests.am
@@ -105,6 +105,7 @@ _installed_or_uninstalled_test_scripts = \
tests/test-admin-deploy-nomerge.sh \
tests/test-admin-deploy-none.sh \
tests/test-admin-deploy-bootid-gc.sh \
+ tests/test-osupdate-dtb.sh \
tests/test-admin-instutil-set-kargs.sh \
tests/test-admin-upgrade-not-backwards.sh \
tests/test-admin-pull-deploy-commit.sh \
@@ -114,6 +115,8 @@ _installed_or_uninstalled_test_scripts = \
tests/test-reset-nonlinear.sh \
tests/test-oldstyle-partial.sh \
tests/test-delta.sh \
+ tests/test-delta-sign.sh \
+ tests/test-delta-ed25519.sh \
tests/test-xattrs.sh \
tests/test-auto-summary.sh \
tests/test-prune.sh \
diff --git a/Makefile.am b/Makefile.am
index cd04a05..87a705c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -43,6 +43,9 @@ AM_DISTCHECK_CONFIGURE_FLAGS += \
GITIGNOREFILES = aclocal.m4 build-aux/ buildutil/*.m4 config.h.in gtk-doc.make
+# Generated by coreos-assembler build-fast and kola
+GITIGNOREFILES += fastbuild-*.qcow2 _kola_temp/
+
SUBDIRS += .
if ENABLE_GTK_DOC
diff --git a/Makefile.in b/Makefile.in
index 541e5d4..e90c219 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -2056,13 +2056,15 @@ am__EXEEXT_25 = tests/test-basic.sh tests/test-basic-user.sh \
tests/test-admin-deploy-nomerge.sh \
tests/test-admin-deploy-none.sh \
tests/test-admin-deploy-bootid-gc.sh \
+ tests/test-osupdate-dtb.sh \
tests/test-admin-instutil-set-kargs.sh \
tests/test-admin-upgrade-not-backwards.sh \
tests/test-admin-pull-deploy-commit.sh \
tests/test-admin-pull-deploy-split.sh \
tests/test-admin-locking.sh tests/test-admin-deploy-clean.sh \
tests/test-reset-nonlinear.sh tests/test-oldstyle-partial.sh \
- tests/test-delta.sh tests/test-xattrs.sh \
+ tests/test-delta.sh tests/test-delta-sign.sh \
+ tests/test-delta-ed25519.sh tests/test-xattrs.sh \
tests/test-auto-summary.sh tests/test-prune.sh \
tests/test-concurrency.py tests/test-refs.sh \
tests/test-demo-buildsystem.sh tests/test-switchroot.sh \
@@ -2504,8 +2506,10 @@ ALL_LOCAL_RULES = tests/libreaddir-rand.so
shortened_sysconfdir = $$(echo "$(sysconfdir)" | sed -e 's|^$(prefix)||' -e 's|^/||')
OSTREE_GITREV = $(shell cd $(srcdir) && if command -v git >/dev/null 2>&1 && test -d .git; then git describe --abbrev=42 --tags --always HEAD; fi)
ACLOCAL_AMFLAGS = -I buildutil -I libglnx ${ACLOCAL_FLAGS}
+
+# Generated by coreos-assembler build-fast and kola
GITIGNOREFILES = aclocal.m4 build-aux/ buildutil/*.m4 config.h.in \
- gtk-doc.make $(am__append_72)
+ gtk-doc.make fastbuild-*.qcow2 _kola_temp/ $(am__append_72)
OT_INTERNAL_GIO_UNIX_CFLAGS = $(OT_DEP_GIO_UNIX_CFLAGS)
OT_INTERNAL_GIO_UNIX_LIBS = $(OT_DEP_GIO_UNIX_LIBS)
OT_INTERNAL_SOUP_CFLAGS = $(OT_DEP_SOUP_CFLAGS)
@@ -2909,13 +2913,15 @@ _installed_or_uninstalled_test_scripts = tests/test-basic.sh \
tests/test-admin-deploy-nomerge.sh \
tests/test-admin-deploy-none.sh \
tests/test-admin-deploy-bootid-gc.sh \
+ tests/test-osupdate-dtb.sh \
tests/test-admin-instutil-set-kargs.sh \
tests/test-admin-upgrade-not-backwards.sh \
tests/test-admin-pull-deploy-commit.sh \
tests/test-admin-pull-deploy-split.sh \
tests/test-admin-locking.sh tests/test-admin-deploy-clean.sh \
tests/test-reset-nonlinear.sh tests/test-oldstyle-partial.sh \
- tests/test-delta.sh tests/test-xattrs.sh \
+ tests/test-delta.sh tests/test-delta-sign.sh \
+ tests/test-delta-ed25519.sh tests/test-xattrs.sh \
tests/test-auto-summary.sh tests/test-prune.sh \
tests/test-concurrency.py tests/test-refs.sh \
tests/test-demo-buildsystem.sh tests/test-switchroot.sh \
@@ -8357,6 +8363,13 @@ tests/test-admin-deploy-bootid-gc.sh.log: tests/test-admin-deploy-bootid-gc.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-osupdate-dtb.sh.log: tests/test-osupdate-dtb.sh
+ @p='tests/test-osupdate-dtb.sh'; \
+ b='tests/test-osupdate-dtb.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-admin-instutil-set-kargs.sh.log: tests/test-admin-instutil-set-kargs.sh
@p='tests/test-admin-instutil-set-kargs.sh'; \
b='tests/test-admin-instutil-set-kargs.sh'; \
@@ -8420,6 +8433,20 @@ tests/test-delta.sh.log: tests/test-delta.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-delta-sign.sh.log: tests/test-delta-sign.sh
+ @p='tests/test-delta-sign.sh'; \
+ b='tests/test-delta-sign.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-delta-ed25519.sh.log: tests/test-delta-ed25519.sh
+ @p='tests/test-delta-ed25519.sh'; \
+ b='tests/test-delta-ed25519.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-xattrs.sh.log: tests/test-xattrs.sh
@p='tests/test-xattrs.sh'; \
b='tests/test-xattrs.sh'; \
diff --git a/README.md b/README.md
index 1ef8e30..be6f645 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,4 @@
-libostree
----------
-
-New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs.org/en/latest/ )
-
------
+# libostree
This project is now known as "libostree", though it is still appropriate to use
the previous name: "OSTree" (or "ostree"). The focus is on projects which use
@@ -36,8 +31,12 @@ version of
projects like [flatpak](https://github.com/flatpak/flatpak) which
use libostree for applications, rather than hosts.
-Operating systems and distributions using OSTree
----------------------
+## Documentation
+
+For more information, see the [project documentation](docs/index.md) or the
+[project documentation website](https://ostreedev.github.io/ostree).
+
+## Operating systems and distributions using OSTree
[Endless OS](https://endlessos.com/) uses libostree for their host system as
well as flatpak. See
@@ -63,8 +62,7 @@ system for GNOME.
[Liri OS](https://liri.io/download/silverblue/) has the option to install
their distribution using ostree.
-Distribution build tools
-------------------------
+## Distribution build tools
[meta-updater](https://github.com/advancedtelematic/meta-updater) is
a layer available for [OpenEmbedded](http://www.openembedded.org/wiki/Main_Page)
@@ -79,8 +77,7 @@ integration tool supports importing and exporting from libostree repos.
Fedora [coreos-assembler](https://github.com/coreos/coreos-assembler) is
the build tool used to generate Fedora CoreOS derivatives.
-Projects linking to libostree
------------------------------
+## Projects linking to libostree
[rpm-ostree](https://github.com/projectatomic/rpm-ostree) is used by the
Fedora-derived operating systems listed above. It is a full hybrid
@@ -98,8 +95,7 @@ use the "libostree host system" aspects (e.g. bootloader management), just the
"git-like hardlink dedup". For example, flatpak supports a per-user OSTree
repository.
-Language bindings
-----
+## Language bindings
libostree is accessible via [GObject Introspection](https://gi.readthedocs.io/en/latest/);
any language which has implemented the GI binding model should work.
@@ -114,8 +110,7 @@ for statically compiled languages. Here's a list of such bindings:
- [ostree-go](https://github.com/ostreedev/ostree-go/)
- [ostree-rs](https://gitlab.com/fkrull/ostree-rs/)
-Building
---------
+## Building
Releases are available as GPG signed git tags, and most recent
versions support extended validation using
@@ -139,19 +134,11 @@ make
make install DESTDIR=/path/to/dest
```
-More documentation
-------------------
-
-New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs.org/en/latest/ )
-
-Contributing
-------------
+## Contributing
See [Contributing](docs/CONTRIBUTING.md).
-
-Licensing
--------
+## Licensing
The licensing for the *code* of libostree can be canonically found in the individual files;
and the overall status in the [COPYING](https://github.com/ostreedev/ostree/blob/master/COPYING)
diff --git a/apidoc/html/ostree-OstreeRepo.html b/apidoc/html/ostree-OstreeRepo.html
index c9a2783..efccacd 100644
--- a/apidoc/html/ostree-OstreeRepo.html
+++ b/apidoc/html/ostree-OstreeRepo.html
@@ -914,11 +914,27 @@
gboolean
+ostree_repo_static_delta_execute_offline_with_signature ()
+
+
+
+
+gboolean
+
+
ostree_repo_static_delta_execute_offline ()
+gboolean
+
+
+ostree_repo_static_delta_verify_signature ()
+
+
+
+
GHashTable *
@@ -5279,6 +5295,7 @@ one to easily set up SELinux labeling from a base commit.
+Since: 2020.4
@@ -6471,6 +6488,8 @@ for input files
verbose: b: Print diagnostic messages. Default FALSE.
endianness: b: Deltas use host byte order by default; this option allows choosing (G_BIG_ENDIAN or G_LITTLE_ENDIAN)
filename: ay: Save delta superblock to this filename, and parts in the same directory. Default saves to repository.
+
sign-name: ay: Signature type to use.
+
sign-key-ids: as: Array of keys used to sign delta superblock.
Parameters
@@ -6527,6 +6546,69 @@ for input files
+
ostree_repo_static_delta_execute_offline_with_signature ()
+
gboolean
+ostree_repo_static_delta_execute_offline_with_signature
+ (OstreeRepo *self
,
+ GFile *dir_or_file
,
+ OstreeSign *sign
,
+ gboolean skip_validation
,
+ GCancellable *cancellable
,
+ GError **error
);
+
Given a directory representing an already-downloaded static delta
+on disk, apply it, generating a new commit.
+If sign is passed, the static delta signature is verified.
+If sign-verify-deltas configuration option is set and static delta is signed,
+signature verification will be mandatory before apply the static delta.
+The directory must be named with the form "FROM-TO", where both are
+checksums, and it must contain a file named "superblock", along with at least
+one part.
+
+
Since: 2020.7
+
+
+
ostree_repo_static_delta_execute_offline ()
gboolean
ostree_repo_static_delta_execute_offline
@@ -6579,6 +6661,61 @@ must contain a file named "superblock", along with at least one part.
+
ostree_repo_static_delta_verify_signature ()
+
gboolean
+ostree_repo_static_delta_verify_signature
+ (OstreeRepo *self
,
+ const char *delta_id
,
+ OstreeSign *sign
,
+ char **out_success_message
,
+ GError **error
);
+
Verify static delta file signature.
+
+
+
Returns
+
TRUE if the signature of static delta file is valid using the
+signature engine provided, FALSE otherwise.
+
+
Since: 2020.7
+
+
+
ostree_repo_traverse_new_reachable ()
GHashTable *
ostree_repo_traverse_new_reachable (void
);
@@ -7455,37 +7592,37 @@ ostree_repo_pull_with_options (
Like ostree_repo_pull()
, but supports an extensible set of flags.
The following are currently defined:
-refs (as): Array of string refs
-collection-refs (a(sss)): Array of (collection ID, ref name, checksum) tuples to pull;
+
refs
(as
): Array of string refs
+collection-refs
(a(sss)
): Array of (collection ID, ref name, checksum) tuples to pull;
mutually exclusive with refs
and override-commit-ids
. Checksums may be the empty
string to pull the latest commit for that ref
-flags (i): An instance of OstreeRepoPullFlags
-subdir (s): Pull just this subdirectory
-subdirs (as): Pull just these subdirectories
-override-remote-name (s): If local, add this remote to refspec
-gpg-verify (b): GPG verify commits
-gpg-verify-summary (b): GPG verify summary
-disable-sign-verify (b): Disable signapi verification of commits
-disable-sign-verify-summary (b): Disable signapi verification of the summary
-depth (i): How far in the history to traverse; default is 0, -1 means infinite
-per-object-fsync (b): Perform disk writes more slowly, avoiding a single large I/O sync
-disable-static-deltas (b): Do not use static deltas
-require-static-deltas (b): Require static deltas
-override-commit-ids (as): Array of specific commit IDs to fetch for refs
-timestamp-check (b): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11
-timestamp-check-from-rev (s): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4
-metadata-size-restriction (t): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9
-dry-run (b): Only print information on what will be downloaded (requires static deltas)
-override-url (s): Fetch objects from this URL if remote specifies no metalink in options
-inherit-transaction (b): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction.
-http-headers (a(ss)): Additional headers to add to all HTTP requests
-update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid
-localcache-repos (as): File paths for local repos to use as caches when doing remote fetches
-append-user-agent (s): Additional string to append to the user agent
-n-network-retries (u): Number of times to retry each download on receiving
+
flags
(i
): An instance of OstreeRepoPullFlags
+subdir
(s
): Pull just this subdirectory
+subdirs
(as
): Pull just these subdirectories
+override-remote-name
(s
): If local, add this remote to refspec
+gpg-verify
(b
): GPG verify commits
+gpg-verify-summary
(b
): GPG verify summary
+disable-sign-verify
(b
): Disable signapi verification of commits
+disable-sign-verify-summary
(b
): Disable signapi verification of the summary
+depth
(i
): How far in the history to traverse; default is 0, -1 means infinite
+per-object-fsync
(b
): Perform disk writes more slowly, avoiding a single large I/O sync
+disable-static-deltas
(b
): Do not use static deltas
+require-static-deltas
(b
): Require static deltas
+override-commit-ids
(as
): Array of specific commit IDs to fetch for refs
+timestamp-check
(b
): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11
+timestamp-check-from-rev
(s
): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4
+metadata-size-restriction
(t
): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9
+dry-run
(b
): Only print information on what will be downloaded (requires static deltas)
+override-url
(s
): Fetch objects from this URL if remote specifies no metalink in options
+inherit-transaction
(b
): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction.
+http-headers
(a(ss)
): Additional headers to add to all HTTP requests
+update-frequency
(u
): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid
+localcache-repos
(as
): File paths for local repos to use as caches when doing remote fetches
+append-user-agent
(s
): Additional string to append to the user agent
+n-network-retries
(u
): Number of times to retry each download on receiving
a transient network error, such as a socket timeout; default is 5, 0
means return errors without retrying. Since: 2018.6
-ref-keyring-map (a(sss)): Array of (collection ID, ref name, keyring
+
ref-keyring-map
(a(sss)
): Array of (collection ID, ref name, keyring
remote name) tuples specifying which remote's keyring should be used when
doing GPG verification of each collection-ref. This is useful to prevent a
remote from serving malicious updates to refs which did not originate from
diff --git a/apidoc/html/ostree-Root-partition-mount-point.html b/apidoc/html/ostree-Root-partition-mount-point.html
index 3b1b106..91c0d6b 100644
--- a/apidoc/html/ostree-Root-partition-mount-point.html
+++ b/apidoc/html/ostree-Root-partition-mount-point.html
@@ -348,11 +348,35 @@
gboolean
+ostree_sysroot_stage_tree_with_options ()
+
+
+
+
+gboolean
+
+
+ostree_sysroot_stage_overlay_initrd ()
+
+
+
+
+gboolean
+
+
ostree_sysroot_deploy_tree ()
+gboolean
+
+
+ostree_sysroot_deploy_tree_with_options ()
+
+
+
+
OstreeDeployment *
@@ -1728,8 +1752,7 @@ ostree_sysroot_stage_tree (OstreeDeployment **out_new_deployment
,
GCancellable *cancellable
,
GError **error
);
-Like ostree_sysroot_deploy_tree()
, but "finalization" only occurs at OS
-shutdown time.
+Older version of ostree_sysroot_stage_tree_with_options()
.
@@ -246,6 +262,69 @@ ostree_bootconfig_parser_set (OstreeBootconfigParser *self
,
const char *key
);
+
+
+
ostree_bootconfig_parser_set_overlay_initrds ()
+
void
+ostree_bootconfig_parser_set_overlay_initrds
+ (OstreeBootconfigParser *self
,
+ char **initrds
);
+
These are rendered as additional initrd
keys in the final bootloader configs. The
+base initrd is part of the primary keys.
+
+
Since: 2020.7
+
+
+
+
ostree_bootconfig_parser_get_overlay_initrds ()
+
char **
+ostree_bootconfig_parser_get_overlay_initrds
+ (OstreeBootconfigParser *self
);
+
+
+
Since: 2020.7
+
Types and Values
diff --git a/apidoc/html/ostree-ostree-deployment.html b/apidoc/html/ostree-ostree-deployment.html
index bcac84d..a206f46 100644
--- a/apidoc/html/ostree-ostree-deployment.html
+++ b/apidoc/html/ostree-ostree-deployment.html
@@ -574,6 +574,8 @@ ostree_deployment_unlocked_state_to_string
GKeyFile *origin;
OstreeDeploymentUnlockedState unlocked;
gboolean staged;
+ char **overlay_initrds;
+ char *overlay_initrds_id;
} OstreeDeployment;
@@ -635,6 +637,16 @@ ostree_deployment_unlocked_state_to_string
TRUE iff this deployment is staged
+
+char ** overlay_initrds
;
+Checksums of staged additional initrds for this deployment
+
+
+
+char * overlay_initrds_id
;
+Unique ID generated from initrd checksums; used to compare deployments
+
+
diff --git a/apidoc/html/ostree.devhelp2 b/apidoc/html/ostree.devhelp2
index ad15fe0..89cd25b 100644
--- a/apidoc/html/ostree.devhelp2
+++ b/apidoc/html/ostree.devhelp2
@@ -172,7 +172,7 @@
-
+
@@ -199,7 +199,9 @@
+
+
@@ -305,7 +307,10 @@
-
+
+
+
+
@@ -378,7 +383,7 @@
-
+
@@ -388,6 +393,8 @@
+
+
@@ -559,5 +566,7 @@
+
+
diff --git a/apidoc/html/reference.html b/apidoc/html/reference.html
index 272075d..0bf7c27 100644
--- a/apidoc/html/reference.html
+++ b/apidoc/html/reference.html
@@ -148,6 +148,10 @@
+ostree_bootconfig_parser_get_overlay_initrds , function in ostree-bootconfig-parser
+
+
+
ostree_bootconfig_parser_new , function in ostree-bootconfig-parser
@@ -164,6 +168,10 @@
+ostree_bootconfig_parser_set_overlay_initrds , function in ostree-bootconfig-parser
+
+
+
ostree_bootconfig_parser_write , function in ostree-bootconfig-parser
@@ -1462,10 +1470,18 @@ ostree_repo_set_collection_ref_immediate, function in ostree-misc-experimental
+ostree_repo_static_delta_execute_offline_with_signature , function in OstreeRepo
+
+
+
ostree_repo_static_delta_generate , function in OstreeRepo
+ostree_repo_static_delta_verify_signature , function in OstreeRepo
+
+
+
ostree_repo_transaction_set_collection_ref, function in ostree-misc-experimental
@@ -1763,6 +1779,10 @@ ostree_repo_transaction_set_collection_ref, function in ostree-misc-experimental
+ostree_sysroot_deploy_tree_with_options , function in Root partition mount point
+
+
+
ostree_sysroot_ensure_initialized , function in Root partition mount point
@@ -1879,10 +1899,18 @@ ostree_repo_transaction_set_collection_ref, function in ostree-misc-experimental
+ostree_sysroot_stage_overlay_initrd , function in Root partition mount point
+
+
+
ostree_sysroot_stage_tree , function in Root partition mount point
+ostree_sysroot_stage_tree_with_options , function in Root partition mount point
+
+
+
ostree_sysroot_try_lock , function in Root partition mount point
diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt
index 979c8e9..c1d6b35 100644
--- a/apidoc/ostree-sections.txt
+++ b/apidoc/ostree-sections.txt
@@ -37,6 +37,8 @@ ostree_bootconfig_parser_write
ostree_bootconfig_parser_write_at
ostree_bootconfig_parser_set
ostree_bootconfig_parser_get
+ostree_bootconfig_parser_set_overlay_initrds
+ostree_bootconfig_parser_get_overlay_initrds
OSTREE_BOOTCONFIG_PARSER
OSTREE_IS_BOOTCONFIG_PARSER
@@ -412,7 +414,9 @@ ostree_repo_list_commit_objects_starting_with
ostree_repo_list_static_delta_names
OstreeStaticDeltaGenerateOpt
ostree_repo_static_delta_generate
+ostree_repo_static_delta_execute_offline_with_signature
ostree_repo_static_delta_execute_offline
+ostree_repo_static_delta_verify_signature
ostree_repo_traverse_new_reachable
ostree_repo_traverse_new_parents
ostree_repo_traverse_parents_get_commits
@@ -543,7 +547,10 @@ ostree_sysroot_write_deployments
ostree_sysroot_write_deployments_with_options
ostree_sysroot_write_origin_file
ostree_sysroot_stage_tree
+ostree_sysroot_stage_tree_with_options
+ostree_sysroot_stage_overlay_initrd
ostree_sysroot_deploy_tree
+ostree_sysroot_deploy_tree_with_options
ostree_sysroot_get_merge_deployment
ostree_sysroot_query_deployments_for
ostree_sysroot_origin_new_from_refspec
diff --git a/bash/ostree b/bash/ostree
index 7256e40..d00695e 100644
--- a/bash/ostree
+++ b/bash/ostree
@@ -1532,6 +1532,9 @@ _ostree_static_delta_apply_offline() {
"
local options_with_args="
+ --sign-type
+ --keys-file
+ --keys-dir
--repo
"
@@ -1613,6 +1616,8 @@ _ostree_static_delta_generate() {
--repo
--set-endianness
--to
+ --sign
+ --sign-type
"
local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" )
@@ -1630,6 +1635,9 @@ _ostree_static_delta_generate() {
COMPREPLY=( $( compgen -W "l B" -- "$cur" ) )
return 0
;;
+ $options_with_args_glob )
+ return 0
+ ;;
esac
case "$cur" in
@@ -1704,6 +1712,40 @@ _ostree_static_delta_show() {
return 0
}
+_ostree_static_delta_verify() {
+ local boolean_options="
+ $main_boolean_options
+ "
+
+ local options_with_args="
+ --sign-type
+ --keys-file
+ --keys-dir
+ --repo
+ "
+
+ local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" )
+
+ case "$prev" in
+ --keys-file|--keys-dir|--repo)
+ __ostree_compreply_dirs_only
+ return 0
+ ;;
+ $options_with_args_glob )
+ return 0
+ ;;
+ esac
+
+ case "$cur" in
+ -*)
+ local all_options="$boolean_options $options_with_args"
+ __ostree_compreply_all_options
+ ;;
+ esac
+
+ return 0
+}
+
_ostree_static_delta() {
local subcommands="
apply-offline
diff --git a/configure b/configure
index 127efaa..6f5d091 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 2020.4.
+# Generated by GNU Autoconf 2.69 for libostree 2020.7.
#
# Report bugs to .
#
@@ -590,8 +590,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='libostree'
PACKAGE_TARNAME='libostree'
-PACKAGE_VERSION='2020.4'
-PACKAGE_STRING='libostree 2020.4'
+PACKAGE_VERSION='2020.7'
+PACKAGE_STRING='libostree 2020.7'
PACKAGE_BUGREPORT='walters@verbum.org'
PACKAGE_URL=''
@@ -1561,7 +1561,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 2020.4 to adapt to many kinds of systems.
+\`configure' configures libostree 2020.7 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1631,7 +1631,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of libostree 2020.4:";;
+ short | recursive ) echo "Configuration of libostree 2020.7:";;
esac
cat <<\_ACEOF
@@ -1896,7 +1896,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-libostree configure 2020.4
+libostree configure 2020.7
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2368,7 +2368,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 2020.4, which was
+It was created by libostree $as_me 2020.7, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3236,7 +3236,7 @@ fi
# Define the identity of the package.
PACKAGE='libostree'
- VERSION='2020.4'
+ VERSION='2020.7'
# Some tools Automake needs.
@@ -5970,9 +5970,9 @@ test -n "$YACC" || YACC="yacc"
YEAR_VERSION=2020
-RELEASE_VERSION=4
+RELEASE_VERSION=7
-PACKAGE_VERSION=2020.4
+PACKAGE_VERSION=2020.7
if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then :
@@ -5983,6 +5983,7 @@ else
for flag in \
-pipe \
-Wall \
+ -Werror=shadow \
-Werror=empty-body \
-Werror=strict-prototypes \
-Werror=missing-prototypes \
@@ -19025,7 +19026,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 2020.4, which was
+This file was extended by libostree $as_me 2020.7, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -19091,7 +19092,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 2020.4
+libostree config.status 2020.7
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 855528c..13f5bef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ dnl Seed the release notes with `git-shortlog-with-prs ..`. Th
dnl `git-evtag` to create the tag and push it. Finally, create a GitHub release and attach
dnl the tarball from `make dist`.
m4_define([year_version], [2020])
-m4_define([release_version], [4])
+m4_define([release_version], [7])
m4_define([package_version], [year_version.release_version])
AC_INIT([libostree], [package_version], [walters@verbum.org])
is_release_build=yes
@@ -35,6 +35,7 @@ AS_IF([echo "$CFLAGS" | grep -q -E -e '-Werror($| )'], [], [
CC_CHECK_FLAGS_APPEND([WARN_CFLAGS], [CFLAGS], [\
-pipe \
-Wall \
+ -Werror=shadow \
-Werror=empty-body \
-Werror=strict-prototypes \
-Werror=missing-prototypes \
diff --git a/libglnx/glnx-fdio.c b/libglnx/glnx-fdio.c
index e537a9b..422bc2d 100644
--- a/libglnx/glnx-fdio.c
+++ b/libglnx/glnx-fdio.c
@@ -303,8 +303,8 @@ glnx_open_anonymous_tmpfile_full (int flags,
}
/* A variant of `glnx_open_tmpfile_linkable_at()` which doesn't support linking.
- * Useful for true temporary storage. The fd will be allocated in /var/tmp to
- * ensure maximum storage space.
+ * Useful for true temporary storage. The fd will be allocated in `$TMPDIR` if
+ * set or `/var/tmp` otherwise.
*
* If you need the file on a specific filesystem use glnx_open_anonymous_tmpfile_full()
* which lets you pass a directory.
@@ -314,7 +314,10 @@ glnx_open_anonymous_tmpfile (int flags,
GLnxTmpfile *out_tmpf,
GError **error)
{
- return glnx_open_anonymous_tmpfile_full (flags, "/var/tmp", out_tmpf, error);
+ return glnx_open_anonymous_tmpfile_full (flags,
+ getenv("TMPDIR") ?: "/var/tmp",
+ out_tmpf,
+ error);
}
/* Use this after calling glnx_open_tmpfile_linkable_at() to give
diff --git a/libglnx/glnx-xattrs.c b/libglnx/glnx-xattrs.c
index 79a14cd..892d534 100644
--- a/libglnx/glnx-xattrs.c
+++ b/libglnx/glnx-xattrs.c
@@ -283,7 +283,7 @@ set_all_xattrs_for_path (const char *path,
const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1);
if (lsetxattr (path, (char*)name, (char*)value_data, value_len, 0) < 0)
- return glnx_throw_errno_prefix (error, "lsetxattr");
+ return glnx_throw_errno_prefix (error, "lsetxattr(%s)", name);
}
return TRUE;
@@ -351,7 +351,7 @@ glnx_fd_set_all_xattrs (int fd,
const guint8* value_data = g_variant_get_fixed_array (value, &value_len, 1);
if (TEMP_FAILURE_RETRY (fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0)) < 0)
- return glnx_throw_errno_prefix (error, "fsetxattr");
+ return glnx_throw_errno_prefix (error, "Setting xattrs: fsetxattr(%s)", name);
}
return TRUE;
@@ -378,11 +378,11 @@ glnx_lgetxattrat (int dfd,
ssize_t bytes_read, real_size;
if (TEMP_FAILURE_RETRY (bytes_read = lgetxattr (pathbuf, attribute, NULL, 0)) < 0)
- return glnx_null_throw_errno_prefix (error, "lgetxattr");
+ return glnx_null_throw_errno_prefix (error, "lgetxattr(%s)", attribute);
g_autofree guint8 *buf = g_malloc (bytes_read);
if (TEMP_FAILURE_RETRY (real_size = lgetxattr (pathbuf, attribute, buf, bytes_read)) < 0)
- return glnx_null_throw_errno_prefix (error, "lgetxattr");
+ return glnx_null_throw_errno_prefix (error, "lgetxattr(%s)", attribute);
return g_bytes_new_take (g_steal_pointer (&buf), real_size);
}
@@ -403,11 +403,11 @@ glnx_fgetxattr_bytes (int fd,
ssize_t bytes_read, real_size;
if (TEMP_FAILURE_RETRY (bytes_read = fgetxattr (fd, attribute, NULL, 0)) < 0)
- return glnx_null_throw_errno_prefix (error, "fgetxattr");
+ return glnx_null_throw_errno_prefix (error, "fgetxattr(%s)", attribute);
g_autofree guint8 *buf = g_malloc (bytes_read);
if (TEMP_FAILURE_RETRY (real_size = fgetxattr (fd, attribute, buf, bytes_read)) < 0)
- return glnx_null_throw_errno_prefix (error, "fgetxattr");
+ return glnx_null_throw_errno_prefix (error, "fgetxattr(%s)", attribute);
return g_bytes_new_take (g_steal_pointer (&buf), real_size);
}
@@ -437,7 +437,7 @@ glnx_lsetxattrat (int dfd,
snprintf (pathbuf, sizeof (pathbuf), "/proc/self/fd/%d/%s", dfd, subpath);
if (TEMP_FAILURE_RETRY (lsetxattr (subpath, attribute, value, len, flags)) < 0)
- return glnx_throw_errno_prefix (error, "lsetxattr");
+ return glnx_throw_errno_prefix (error, "lsetxattr(%s)", attribute);
return TRUE;
}
diff --git a/man/ostree-checkout.xml b/man/ostree-checkout.xml
index 3956e34..dfa2ce1 100644
--- a/man/ostree-checkout.xml
+++ b/man/ostree-checkout.xml
@@ -163,7 +163,7 @@ Boston, MA 02111-1307, USA.
-z
- Do not hardlink zero-sized files.
+ This option does nothing; the functionality is now always on by default.
diff --git a/man/ostree-commit.xml b/man/ostree-commit.xml
index b0c5b33..ab5d341 100644
--- a/man/ostree-commit.xml
+++ b/man/ostree-commit.xml
@@ -83,6 +83,14 @@ Boston, MA 02111-1307, USA.
+ --body-file , -F ="FILE"
+
+
+ Full commit description from a file. (optional)
+
+
+
+
--editor , -e
@@ -99,6 +107,14 @@ Boston, MA 02111-1307, USA.
+ --parent ="COMMIT"
+
+
+ Parent checksum or "none" to explicitly use no parent. If not specified, BRANCH is used as parent (no parent in case BRANCH does not exist).
+
+
+
+
--tree ="dir=PATH" or "tar=TARFILE" or "ref=COMMIT"
@@ -119,7 +135,23 @@ Boston, MA 02111-1307, USA.
--add-metadata-string ="KEY=VALUE"
- Add a key/value pair to metadata.
+ Add a key/value pair to metadata. Can be specified multiple times.
+
+
+
+
+ --add-metadata ="KEY=VALUE"
+
+
+ Add a key/value pair to metadata, where the KEY is a string, and VALUE is g_variant_parse() formatted. Can be specified multiple times.
+
+
+
+
+ --keep-metadata ="KEY"
+
+
+ Keep metadata KEY and its associated VALUE from parent. Can be specified multiple times.
diff --git a/man/ostree-static-delta.xml b/man/ostree-static-delta.xml
index dfeef28..440ada4 100644
--- a/man/ostree-static-delta.xml
+++ b/man/ostree-static-delta.xml
@@ -63,7 +63,10 @@ Boston, MA 02111-1307, USA.
ostree static-delta generate --to=REV OPTIONS
- ostree static-delta apply-offline PATH
+ ostree static-delta apply-offline OPTIONS PATH KEY-ID
+
+
+ ostree static-delta verify OPTIONS STATIC-DELTA KEY-ID
@@ -113,6 +116,159 @@ Boston, MA 02111-1307, USA.
+
+ --sign-type =ENGINE
+
+
+ Use particular signature engine. Currently
+ available ed25519 and dummy
+ signature types.
+
+ The default is ed25519 .
+
+
+
+
+ --sign ="KEY-ID"
+
+ There KEY-ID is:
+
+
+ for ed25519:
+
+ base64 -encoded secret key for signing.
+
+
+
+
+ for dummy:
+
+ ASCII-string used as secret key.
+
+
+
+
+
+
+
+
+
+ 'Apply-offline' Options
+
+
+
+ KEY-ID
+
+
+
+
+ for ed25519:
+
+ base64 -encoded public key for verifying.
+
+
+
+
+ for dummy:
+
+ ASCII-string used as public key.
+
+
+
+
+
+
+
+ --sign-type =ENGINE
+
+
+ Use particular signature engine. Currently
+ available ed25519 and dummy
+ signature types.
+
+
+
+
+ --keys-file
+
+ Read key(s) from file filename .
+
+
+
+ Valid for ed25519 signature type.
+ For ed25519 this file must contain base64 -encoded
+ public key(s) per line for verifying.
+
+
+
+
+ --keys-dir
+
+ Redefine the system path, where to search files and subdirectories with
+ well-known and revoked keys.
+
+
+
+
+
+
+ 'Verify' Options
+
+
+
+ KEY-ID
+
+
+
+
+ for ed25519:
+
+ base64 -encoded public key for verifying.
+
+
+
+
+ for dummy:
+
+ ASCII-string used as public key.
+
+
+
+
+
+
+
+ --sign-type =ENGINE
+
+
+ Use particular signature engine. Currently
+ available ed25519 and dummy
+ signature types.
+
+ The default is ed25519 .
+
+
+
+
+ --keys-file
+
+ Read key(s) from file filename .
+
+
+
+ Valid for ed25519 signature type.
+ For ed25519 this file must contain base64 -encoded
+ public key(s) per line for verifying.
+
+
+
+
+ --keys-dir
+
+ Redefine the system path, where to search files and subdirectories with
+ well-known and revoked keys.
+
+
diff --git a/man/ostree.xml b/man/ostree.xml
index 8c08bae..e280a02 100644
--- a/man/ostree.xml
+++ b/man/ostree.xml
@@ -484,6 +484,70 @@ Boston, MA 02111-1307, USA.
+ Terminology
+
+ The following terms are commonly used throughout the man pages. Terms in upper case letters
+ are literals used in command line arguments.
+
+
+ BRANCH
+
+
+ Branch name. Part of a REF .
+
+
+
+ CHECKSUM
+
+
+ A SHA256 hash of a object stored in the OSTree repository. This can be a content,
+ a dirtree, a dirmeta or a commit object. If the SHA256 hash of a commit object is
+ meant, the term COMMIT is used.
+
+
+
+ COMMIT
+
+
+ A SHA256 hash of a commit object.
+
+
+
+ REF
+
+
+ A reference to a particular commit. References are text files stored in
+ refs/ that name (refer to) a particular commit. A
+ reference can only be the branch name part, in which case a local reference
+ is used (e.g. mybranch/stable ). If a remote branch
+ is referred to, the remote name followed by a colon and the branch name
+ needs to be used (e.g. myremote:mybranch/stable ).
+
+
+
+ REV REFSPEC
+
+
+ A specific revision, a commit. This can be anything which can be resolved to a
+ commit, e.g. a REF or a
+ COMMIT .
+
+
+
+ SHA256
+
+
+ A cryptographic hash function used to store objects in the OSTree
+ repository. The hashes have a length of 256 bites and are typically
+ shown and passed to ostree in its 64 ASCII character long hexadecimal
+ representation
+ (e.g. 0fc70ed33cfd7d26fe99ae29afb7682ddd0e2157a4898bd8cfcdc8a03565b870).
+
+
+
+
+
+
See Also
ostree.repo 5
diff --git a/src/boot/dracut/ostree.conf b/src/boot/dracut/ostree.conf
index 612bb43..ac70494 100755
--- a/src/boot/dracut/ostree.conf
+++ b/src/boot/dracut/ostree.conf
@@ -16,3 +16,4 @@
# Boston, MA 02111-1307, USA.
add_dracutmodules+=" ostree systemd "
+reproducible=yes
diff --git a/src/boot/mkinitcpio/ostree b/src/boot/mkinitcpio/ostree
index 7f21cac..3aa0659 100644
--- a/src/boot/mkinitcpio/ostree
+++ b/src/boot/mkinitcpio/ostree
@@ -5,6 +5,6 @@ build() {
add_binary /usr/lib/ostree/ostree-remount
add_file /usr/lib/systemd/system/ostree-prepare-root.service
- add_symlink /usr/lib/systemd/system/initrd-switch-root.target.wants/ostree-prepare-root.service \
+ add_symlink /usr/lib/systemd/system/initrd-root-fs.target.wants/ostree-prepare-root.service \
/usr/lib/systemd/system/ostree-prepare-root.service
}
diff --git a/src/boot/ostree-prepare-root.service b/src/boot/ostree-prepare-root.service
index 9169220..250ffe7 100644
--- a/src/boot/ostree-prepare-root.service
+++ b/src/boot/ostree-prepare-root.service
@@ -30,6 +30,6 @@ Before=initrd-root-fs.target
Type=oneshot
ExecStart=/usr/lib/ostree/ostree-prepare-root /sysroot
StandardInput=null
-StandardOutput=syslog
-StandardError=syslog+console
+StandardOutput=journal
+StandardError=journal+console
RemainAfterExit=yes
diff --git a/src/boot/ostree-remount.service b/src/boot/ostree-remount.service
index 4c3ed94..af40453 100644
--- a/src/boot/ostree-remount.service
+++ b/src/boot/ostree-remount.service
@@ -35,8 +35,8 @@ Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/lib/ostree/ostree-remount
StandardInput=null
-StandardOutput=syslog
-StandardError=syslog+console
+StandardOutput=journal
+StandardError=journal+console
[Install]
WantedBy=local-fs.target
diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym
index 5c63f78..c154d8c 100644
--- a/src/libostree/libostree-released.sym
+++ b/src/libostree/libostree-released.sym
@@ -593,6 +593,9 @@ global:
ostree_sysroot_set_mount_namespace_in_use;
} LIBOSTREE_2019.6;
+/* No new symbols in 2020.2 */
+/* No new symbols in 2020.3 */
+
/* Add new symbols here. Release commits should copy this section into -released.sym. */
LIBOSTREE_2020.4 {
global:
@@ -615,7 +618,23 @@ global:
ostree_sign_summary;
} LIBOSTREE_2020.1;
-/* No new symbols in 2020.2 */
+/* No new symbols in 2020.5 */
+
+/* No new symbols in 2020.6 */
+
+LIBOSTREE_2020.7 {
+global:
+ /* Add symbols here, and uncomment the bits in
+ * Makefile-libostree.am to enable this too.
+ */
+ ostree_repo_static_delta_execute_offline_with_signature;
+ ostree_repo_static_delta_verify_signature;
+ ostree_bootconfig_parser_get_overlay_initrds;
+ ostree_bootconfig_parser_set_overlay_initrds;
+ ostree_sysroot_deploy_tree_with_options;
+ ostree_sysroot_stage_tree_with_options;
+ ostree_sysroot_stage_overlay_initrd;
+} LIBOSTREE_2020.4;
/* 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 67f9fb5..a36a411 100644
--- a/src/libostree/ostree-bootconfig-parser.c
+++ b/src/libostree/ostree-bootconfig-parser.c
@@ -30,6 +30,9 @@ struct _OstreeBootconfigParser
const char *separators;
GHashTable *options;
+
+ /* Additional initrds; the primary initrd is in options. */
+ char **overlay_initrds;
};
typedef GObjectClass OstreeBootconfigParserClass;
@@ -50,6 +53,8 @@ ostree_bootconfig_parser_clone (OstreeBootconfigParser *self)
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));
+ parser->overlay_initrds = g_strdupv (self->overlay_initrds);
+
return parser;
}
@@ -76,6 +81,8 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
if (!contents)
return FALSE;
+ g_autoptr(GPtrArray) overlay_initrds = NULL;
+
g_auto(GStrv) lines = g_strsplit (contents, "\n", -1);
for (char **iter = lines; *iter; iter++)
{
@@ -87,8 +94,19 @@ 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')
{
- g_hash_table_insert (self->options, items[0], items[1]);
- g_free (items); /* Transfer ownership */
+ if (g_str_equal (items[0], "initrd") &&
+ g_hash_table_contains (self->options, "initrd"))
+ {
+ if (!overlay_initrds)
+ overlay_initrds = g_ptr_array_new_with_free_func (g_free);
+ g_ptr_array_add (overlay_initrds, items[1]);
+ g_free (items[0]);
+ }
+ else
+ {
+ g_hash_table_insert (self->options, items[0], items[1]);
+ }
+ g_free (items); /* Free container; we stole the elements */
}
else
{
@@ -97,6 +115,12 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
}
}
+ if (overlay_initrds)
+ {
+ g_ptr_array_add (overlay_initrds, NULL);
+ self->overlay_initrds = (char**)g_ptr_array_free (g_steal_pointer (&overlay_initrds), FALSE);
+ }
+
self->parsed = TRUE;
return TRUE;
@@ -127,6 +151,41 @@ ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
return g_hash_table_lookup (self->options, key);
}
+/**
+ * ostree_bootconfig_parser_set_overlay_initrds:
+ * @self: Parser
+ * @initrds: (array zero-terminated=1) (transfer none) (allow-none): Array of overlay
+ * initrds or %NULL to unset.
+ *
+ * These are rendered as additional `initrd` keys in the final bootloader configs. The
+ * base initrd is part of the primary keys.
+ *
+ * Since: 2020.7
+ */
+void
+ostree_bootconfig_parser_set_overlay_initrds (OstreeBootconfigParser *self,
+ char **initrds)
+{
+ g_assert (g_hash_table_contains (self->options, "initrd"));
+ g_strfreev (self->overlay_initrds);
+ self->overlay_initrds = g_strdupv (initrds);
+}
+
+/**
+ * ostree_bootconfig_parser_get_overlay_initrds:
+ * @self: Parser
+ *
+ * Returns: (array zero-terminated=1) (transfer none) (nullable): Array of initrds or %NULL
+ * if none are set.
+ *
+ * Since: 2020.7
+ */
+char**
+ostree_bootconfig_parser_get_overlay_initrds (OstreeBootconfigParser *self)
+{
+ return self->overlay_initrds;
+}
+
static void
write_key (OstreeBootconfigParser *self,
GString *buf,
@@ -165,6 +224,15 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
}
}
+ /* Write overlay initrds */
+ if (self->overlay_initrds && (g_strv_length (self->overlay_initrds) > 0))
+ {
+ /* we should've written the primary initrd already */
+ g_assert (g_hash_table_contains (keys_written, "initrd"));
+ for (char **it = self->overlay_initrds; it && *it; it++)
+ write_key (self, buf, "initrd", *it);
+ }
+
/* Write unknown fields */
GLNX_HASH_TABLE_FOREACH_KV (self->options, const char*, k, const char*, v)
{
@@ -197,6 +265,7 @@ ostree_bootconfig_parser_finalize (GObject *object)
{
OstreeBootconfigParser *self = OSTREE_BOOTCONFIG_PARSER (object);
+ g_strfreev (self->overlay_initrds);
g_hash_table_unref (self->options);
G_OBJECT_CLASS (ostree_bootconfig_parser_parent_class)->finalize (object);
diff --git a/src/libostree/ostree-bootconfig-parser.h b/src/libostree/ostree-bootconfig-parser.h
index aec0753..d03c931 100644
--- a/src/libostree/ostree-bootconfig-parser.h
+++ b/src/libostree/ostree-bootconfig-parser.h
@@ -73,5 +73,11 @@ _OSTREE_PUBLIC
const char *ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
const char *key);
+_OSTREE_PUBLIC
+void ostree_bootconfig_parser_set_overlay_initrds (OstreeBootconfigParser *self,
+ char **initrds);
+
+_OSTREE_PUBLIC
+char** ostree_bootconfig_parser_get_overlay_initrds (OstreeBootconfigParser *self);
G_END_DECLS
diff --git a/src/libostree/ostree-bootloader-syslinux.c b/src/libostree/ostree-bootloader-syslinux.c
index 5fb8a1d..0055896 100644
--- a/src/libostree/ostree-bootloader-syslinux.c
+++ b/src/libostree/ostree-bootloader-syslinux.c
@@ -89,15 +89,15 @@ append_config_from_loader_entries (OstreeBootloaderSyslinux *self,
val = ostree_bootconfig_parser_get (config, "linux");
if (!val)
return glnx_throw (error, "No \"linux\" key in bootloader config");
- g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL %s", val));
+ g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL /boot%s", val));
val = ostree_bootconfig_parser_get (config, "initrd");
if (val)
- g_ptr_array_add (new_lines, g_strdup_printf ("\tINITRD %s", val));
+ g_ptr_array_add (new_lines, g_strdup_printf ("\tINITRD /boot%s", val));
val = ostree_bootconfig_parser_get (config, "devicetree");
if (val)
- g_ptr_array_add (new_lines, g_strdup_printf ("\tDEVICETREE %s", val));
+ g_ptr_array_add (new_lines, g_strdup_printf ("\tDEVICETREE /boot%s", val));
val = ostree_bootconfig_parser_get (config, "options");
if (val)
@@ -150,10 +150,13 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader,
if (kernel_arg == NULL)
return glnx_throw (error, "No KERNEL argument found after LABEL");
- /* If this is a non-ostree kernel, just emit the lines
- * we saw.
+ /* If this is a non-ostree kernel, just emit the lines we saw.
+ *
+ * We check for /ostree (without /boot prefix) as well to support
+ * upgrading ostree from len; i++)
{
diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c
index 1e1f037..7e23001 100644
--- a/src/libostree/ostree-bootloader-uboot.c
+++ b/src/libostree/ostree-bootloader-uboot.c
@@ -134,19 +134,19 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot *self,
"No \"linux\" key in bootloader config");
return FALSE;
}
- g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=%s", index_suffix, val));
+ g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=/boot%s", index_suffix, val));
val = ostree_bootconfig_parser_get (config, "initrd");
if (val)
- g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=%s", index_suffix, val));
+ g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image%s=/boot%s", index_suffix, val));
val = ostree_bootconfig_parser_get (config, "devicetree");
if (val)
- g_ptr_array_add (new_lines, g_strdup_printf ("fdt_file%s=%s", index_suffix, val));
+ g_ptr_array_add (new_lines, g_strdup_printf ("fdt_file%s=/boot%s", index_suffix, val));
val = ostree_bootconfig_parser_get (config, "fdtdir");
if (val)
- g_ptr_array_add (new_lines, g_strdup_printf ("fdtdir%s=%s", index_suffix, val));
+ g_ptr_array_add (new_lines, g_strdup_printf ("fdtdir%s=/boot%s", index_suffix, val));
val = ostree_bootconfig_parser_get (config, "options");
if (val)
diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c
index 523f57c..29528fa 100644
--- a/src/libostree/ostree-core.c
+++ b/src/libostree/ostree-core.c
@@ -2675,7 +2675,7 @@ _ostree_detached_metadata_append_gpg_sig (GVariant *existing_metadata,
_OSTREE_METADATA_GPGSIGS_NAME,
g_variant_builder_end (signature_builder));
- return g_variant_dict_end (&metadata_dict);
+ return g_variant_ref_sink (g_variant_dict_end (&metadata_dict));
}
#endif /* OSTREE_DISABLE_GPGME */
diff --git a/src/libostree/ostree-deployment-private.h b/src/libostree/ostree-deployment-private.h
index ad77317..b339ae2 100644
--- a/src/libostree/ostree-deployment-private.h
+++ b/src/libostree/ostree-deployment-private.h
@@ -37,6 +37,8 @@ G_BEGIN_DECLS
* @origin: How to construct an upgraded version of this tree
* @unlocked: The unlocked state
* @staged: TRUE iff this deployment is staged
+ * @overlay_initrds: Checksums of staged additional initrds for this deployment
+ * @overlay_initrds_id: Unique ID generated from initrd checksums; used to compare deployments
*/
struct _OstreeDeployment
{
@@ -52,8 +54,15 @@ struct _OstreeDeployment
GKeyFile *origin;
OstreeDeploymentUnlockedState unlocked;
gboolean staged;
+ char **overlay_initrds;
+ char *overlay_initrds_id;
};
void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum);
+void _ostree_deployment_set_overlay_initrds (OstreeDeployment *self,
+ char **overlay_initrds);
+
+char** _ostree_deployment_get_overlay_initrds (OstreeDeployment *self);
+
G_END_DECLS
diff --git a/src/libostree/ostree-deployment.c b/src/libostree/ostree-deployment.c
index 6532a97..182bcee 100644
--- a/src/libostree/ostree-deployment.c
+++ b/src/libostree/ostree-deployment.c
@@ -158,6 +158,34 @@ _ostree_deployment_set_bootcsum (OstreeDeployment *self,
self->bootcsum = g_strdup (bootcsum);
}
+void
+_ostree_deployment_set_overlay_initrds (OstreeDeployment *self,
+ char **overlay_initrds)
+{
+ g_clear_pointer (&self->overlay_initrds, g_strfreev);
+ g_clear_pointer (&self->overlay_initrds_id, g_free);
+
+ if (!overlay_initrds || g_strv_length (overlay_initrds) == 0)
+ return;
+
+ /* Generate a unique ID representing this combination of overlay initrds. This is so that
+ * ostree_sysroot_write_deployments_with_options() can easily compare initrds when
+ * comparing deployments for whether a bootswap is necessary. We could be fancier here but
+ * meh... this works. */
+ g_autoptr(GString) id = g_string_new (NULL);
+ for (char **it = overlay_initrds; it && *it; it++)
+ g_string_append (id, *it);
+
+ self->overlay_initrds = g_strdupv (overlay_initrds);
+ self->overlay_initrds_id = g_string_free (g_steal_pointer (&id), FALSE);
+}
+
+char**
+_ostree_deployment_get_overlay_initrds (OstreeDeployment *self)
+{
+ return self->overlay_initrds;
+}
+
/**
* ostree_deployment_clone:
* @self: Deployment
@@ -175,6 +203,8 @@ ostree_deployment_clone (OstreeDeployment *self)
new_bootconfig = ostree_bootconfig_parser_clone (self->bootconfig);
ostree_deployment_set_bootconfig (ret, new_bootconfig);
+ _ostree_deployment_set_overlay_initrds (ret, self->overlay_initrds);
+
if (self->origin)
{
g_autoptr(GKeyFile) new_origin = NULL;
@@ -238,6 +268,8 @@ ostree_deployment_finalize (GObject *object)
g_free (self->bootcsum);
g_clear_object (&self->bootconfig);
g_clear_pointer (&self->origin, g_key_file_unref);
+ g_strfreev (self->overlay_initrds);
+ g_free (self->overlay_initrds_id);
G_OBJECT_CLASS (ostree_deployment_parent_class)->finalize (object);
}
@@ -318,6 +350,8 @@ ostree_deployment_unlocked_state_to_string (OstreeDeploymentUnlockedState state)
return "hotfix";
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
return "development";
+ case OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT:
+ return "transient";
}
g_assert_not_reached ();
}
diff --git a/src/libostree/ostree-deployment.h b/src/libostree/ostree-deployment.h
index 756e39d..dcfa25e 100644
--- a/src/libostree/ostree-deployment.h
+++ b/src/libostree/ostree-deployment.h
@@ -99,7 +99,8 @@ char *ostree_deployment_get_origin_relpath (OstreeDeployment *self);
typedef enum {
OSTREE_DEPLOYMENT_UNLOCKED_NONE,
OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT,
- OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX
+ OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX,
+ OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT,
} OstreeDeploymentUnlockedState;
_OSTREE_PUBLIC
diff --git a/src/libostree/ostree-fetcher-curl.c b/src/libostree/ostree-fetcher-curl.c
index fdf8a2e..0ce3ff0 100644
--- a/src/libostree/ostree-fetcher-curl.c
+++ b/src/libostree/ostree-fetcher-curl.c
@@ -341,14 +341,14 @@ check_multi_info (OstreeFetcher *fetcher)
if (req->idx + 1 == req->mirrorlist->len)
{
- g_autofree char *msg = g_strdup_printf ("Server returned HTTP %lu", response);
+ g_autofree char *response_msg = g_strdup_printf ("Server returned HTTP %lu", response);
g_task_return_new_error (task, G_IO_ERROR, giocode,
- "%s", msg);
+ "%s", response_msg);
if (req->fetcher->remote_name &&
!((req->flags & OSTREE_FETCHER_REQUEST_OPTIONAL_CONTENT) > 0 &&
giocode == G_IO_ERROR_NOT_FOUND))
_ostree_fetcher_journal_failure (req->fetcher->remote_name,
- eff_url, msg);
+ eff_url, response_msg);
}
else
diff --git a/src/libostree/ostree-linuxfsutil.c b/src/libostree/ostree-linuxfsutil.c
index 231ecf7..cb778de 100644
--- a/src/libostree/ostree-linuxfsutil.c
+++ b/src/libostree/ostree-linuxfsutil.c
@@ -55,7 +55,7 @@ _ostree_linuxfs_fd_alter_immutable_flag (int fd,
if (g_atomic_int_get (&no_alter_immutable))
return TRUE;
- unsigned long flags;
+ int flags = 0;
int r = ioctl (fd, EXT2_IOC_GETFLAGS, &flags);
if (r == -1)
{
diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c
index dc36370..00c6a77 100644
--- a/src/libostree/ostree-repo-checkout.c
+++ b/src/libostree/ostree-repo-checkout.c
@@ -613,9 +613,12 @@ checkout_one_file_at (OstreeRepo *repo,
}
const gboolean is_symlink = (g_file_info_get_file_type (source_info) == G_FILE_TYPE_SYMBOLIC_LINK);
+ const guint32 source_mode = g_file_info_get_attribute_uint32 (source_info, "unix::mode");
+ const gboolean is_unreadable = (!is_symlink && (source_mode & S_IRUSR) == 0);
const gboolean is_whiteout = (!is_symlink && options->process_whiteouts &&
g_str_has_prefix (destination_name, WHITEOUT_PREFIX));
const gboolean is_reg_zerosized = (!is_symlink && g_file_info_get_size (source_info) == 0);
+ const gboolean override_user_unreadable = (options->mode == OSTREE_REPO_CHECKOUT_MODE_USER && is_unreadable);
/* First, see if it's a Docker whiteout,
* https://github.com/docker/docker/blob/1a714e76a2cb9008cd19609059e9988ff1660b78/pkg/archive/whiteouts.go
@@ -634,8 +637,12 @@ checkout_one_file_at (OstreeRepo *repo,
need_copy = FALSE;
}
- else if (options->force_copy_zerosized && is_reg_zerosized)
+ else if (is_reg_zerosized || override_user_unreadable)
{
+ /* In https://github.com/ostreedev/ostree/commit/673cacd633f9d6b653cdea530657d3e780a41bbd we
+ * made this an option, but in order to avoid hitting EMLINK, we now force copy zerosized
+ * files unconditionally.
+ */
need_copy = TRUE;
}
else if (!options->force_copy)
@@ -735,7 +742,7 @@ checkout_one_file_at (OstreeRepo *repo,
if (can_cache
&& !is_whiteout
&& !is_symlink
- && !is_reg_zerosized
+ && !(is_reg_zerosized || override_user_unreadable)
&& need_copy
&& repo->mode == OSTREE_REPO_MODE_ARCHIVE
&& options->mode == OSTREE_REPO_CHECKOUT_MODE_USER)
@@ -799,12 +806,21 @@ checkout_one_file_at (OstreeRepo *repo,
* succeeded at hardlinking above.
*/
if (options->no_copy_fallback)
- g_assert (is_bare_user_symlink || is_reg_zerosized);
+ g_assert (is_bare_user_symlink || is_reg_zerosized || override_user_unreadable);
if (!ostree_repo_load_file (repo, checksum, &input, NULL, &xattrs,
cancellable, error))
return FALSE;
- if (!create_file_copy_from_input_at (repo, options, state, checksum, source_info, xattrs, input,
+ GFileInfo *copy_source_info = source_info;
+ g_autoptr(GFileInfo) modified_info = NULL;
+ if (override_user_unreadable)
+ {
+ modified_info = g_file_info_dup (source_info);
+ g_file_info_set_attribute_uint32 (modified_info, "unix::mode", (source_mode | S_IRUSR));
+ copy_source_info = modified_info;
+ }
+
+ if (!create_file_copy_from_input_at (repo, options, state, checksum, copy_source_info, xattrs, input,
destination_dfd, destination_name,
cancellable, error))
return glnx_prefix_error (error, "Copy checkout of %s to %s", checksum, destination_name);
diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c
index 0c9de23..690075e 100644
--- a/src/libostree/ostree-repo-commit.c
+++ b/src/libostree/ostree-repo-commit.c
@@ -3943,11 +3943,9 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
- g_autoptr(GFileInfo) child_info = NULL;
g_autoptr(GFileInfo) modified_info = NULL;
g_autoptr(GVariant) xattrs = NULL;
g_autofree guchar *child_file_csum = NULL;
- g_autofree char *tmp_checksum = NULL;
g_autofree char *relpath = NULL;
OstreeRepoCommitFilterResult filter_result;
struct stat dir_stbuf;
@@ -3955,19 +3953,19 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
if (!glnx_fstat (src_dfd_iter->fd, &dir_stbuf, error))
return FALSE;
- child_info = _ostree_stbuf_to_gfileinfo (&dir_stbuf);
-
- if (modifier != NULL)
- {
- relpath = ptrarray_path_join (path);
-
- filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info);
- }
- else
- {
- filter_result = OSTREE_REPO_COMMIT_FILTER_ALLOW;
- modified_info = g_object_ref (child_info);
- }
+ {
+ g_autoptr(GFileInfo) child_info = _ostree_stbuf_to_gfileinfo (&dir_stbuf);
+ if (modifier != NULL)
+ {
+ relpath = ptrarray_path_join (path);
+ filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info);
+ }
+ else
+ {
+ filter_result = OSTREE_REPO_COMMIT_FILTER_ALLOW;
+ modified_info = g_object_ref (child_info);
+ }
+ }
if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW)
{
@@ -3979,8 +3977,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
cancellable, error))
return FALSE;
- g_free (tmp_checksum);
- tmp_checksum = ostree_checksum_from_bytes (child_file_csum);
+ g_autofree char *tmp_checksum = ostree_checksum_from_bytes (child_file_csum);
ostree_mutable_tree_set_metadata_checksum (mtree, tmp_checksum);
}
@@ -4332,6 +4329,8 @@ ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier
* In many cases, one wants to create a "derived" commit from base commit.
* SELinux policy labels are part of that base commit. This API allows
* one to easily set up SELinux labeling from a base commit.
+ *
+ * Since: 2020.4
*/
gboolean
ostree_repo_commit_modifier_set_sepolicy_from_commit (OstreeRepoCommitModifier *modifier,
diff --git a/src/libostree/ostree-repo-finder-avahi-parser.c b/src/libostree/ostree-repo-finder-avahi-parser.c
index afc9790..1cf4a11 100644
--- a/src/libostree/ostree-repo-finder-avahi-parser.c
+++ b/src/libostree/ostree-repo-finder-avahi-parser.c
@@ -91,14 +91,14 @@ parse_txt_record (const guint8 *txt,
/* TODO: Docs. Return value is only valid as long as @txt is. Reference: RFC 6763, §6. */
GHashTable *
-_ostree_txt_records_parse (AvahiStringList *txt)
+_ostree_txt_records_parse (AvahiStringList *txt_list)
{
AvahiStringList *l;
g_autoptr(GHashTable) out = NULL;
out = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_bytes_unref);
- for (l = txt; l != NULL; l = avahi_string_list_get_next (l))
+ for (l = txt_list; l != NULL; l = avahi_string_list_get_next (l))
{
const guint8 *txt;
gsize txt_len;
diff --git a/src/libostree/ostree-repo-finder-mount.c b/src/libostree/ostree-repo-finder-mount.c
index c259f3e..5c8ab1f 100644
--- a/src/libostree/ostree-repo-finder-mount.c
+++ b/src/libostree/ostree-repo-finder-mount.c
@@ -336,7 +336,6 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde
g_autoptr(GHashTable) repo_to_refs = NULL; /* (element-type UriAndKeyring GHashTable) */
GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */
GHashTableIter iter;
- UriAndKeyring *repo;
g_autoptr(GError) local_error = NULL;
mount_name = g_mount_get_name (mount);
@@ -525,6 +524,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/* Aggregate the results. */
g_hash_table_iter_init (&iter, repo_to_refs);
+ UriAndKeyring *repo;
while (g_hash_table_iter_next (&iter, (gpointer *) &repo, (gpointer *) &supported_ref_to_checksum))
{
g_autoptr(OstreeRemote) remote = NULL;
diff --git a/src/libostree/ostree-repo-finder-override.c b/src/libostree/ostree-repo-finder-override.c
index 3219954..d6fb5a9 100644
--- a/src/libostree/ostree-repo-finder-override.c
+++ b/src/libostree/ostree-repo-finder-override.c
@@ -151,7 +151,6 @@ ostree_repo_finder_override_resolve_async (OstreeRepoFinder *fi
GHashTable *supported_ref_to_checksum; /* (element-type OstreeCollectionRef utf8) */
GHashTableIter iter;
const gchar *remote_uri;
- OstreeRemote *remote;
task = g_task_new (finder, cancellable, callback, user_data);
g_task_set_source_tag (task, ostree_repo_finder_override_resolve_async);
@@ -242,6 +241,7 @@ ostree_repo_finder_override_resolve_async (OstreeRepoFinder *fi
/* Aggregate the results. */
g_hash_table_iter_init (&iter, repo_remote_to_refs);
+ OstreeRemote *remote;
while (g_hash_table_iter_next (&iter, (gpointer *) &remote, (gpointer *) &supported_ref_to_checksum))
g_ptr_array_add (results, ostree_repo_finder_result_new (remote, finder, priority, supported_ref_to_checksum, NULL, 0));
diff --git a/src/libostree/ostree-repo-libarchive.c b/src/libostree/ostree-repo-libarchive.c
index d55459f..ef7252e 100644
--- a/src/libostree/ostree-repo-libarchive.c
+++ b/src/libostree/ostree-repo-libarchive.c
@@ -1161,16 +1161,16 @@ write_directory_to_libarchive_recurse (OstreeRepo *self,
{
guint8 buf[8192];
g_autoptr(GInputStream) file_in = NULL;
- g_autoptr(GFileInfo) file_info = NULL;
+ g_autoptr(GFileInfo) regular_file_info = NULL;
const char *checksum;
checksum = ostree_repo_file_get_checksum ((OstreeRepoFile*)path);
- if (!ostree_repo_load_file (self, checksum, &file_in, &file_info, NULL,
+ if (!ostree_repo_load_file (self, checksum, &file_in, ®ular_file_info, NULL,
cancellable, error))
goto out;
- archive_entry_set_size (entry, g_file_info_get_size (file_info));
+ archive_entry_set_size (entry, g_file_info_get_size (regular_file_info));
if (archive_write_header (a, entry) != ARCHIVE_OK)
{
diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h
index 8c1f507..a48feca 100644
--- a/src/libostree/ostree-repo-private.h
+++ b/src/libostree/ostree-repo-private.h
@@ -55,6 +55,8 @@ G_BEGIN_DECLS
#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires"
#define OSTREE_SUMMARY_COLLECTION_ID "ostree.summary.collection-id"
#define OSTREE_SUMMARY_COLLECTION_MAP "ostree.summary.collection-map"
+#define OSTREE_SUMMARY_MODE "ostree.summary.mode"
+#define OSTREE_SUMMARY_TOMBSTONE_COMMITS "ostree.summary.tombstone-commits"
#define _OSTREE_PAYLOAD_LINK_PREFIX "../"
#define _OSTREE_PAYLOAD_LINK_PREFIX_LEN (sizeof (_OSTREE_PAYLOAD_LINK_PREFIX) - 1)
diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c
index 5fdbeab..58c8054 100644
--- a/src/libostree/ostree-repo-pull.c
+++ b/src/libostree/ostree-repo-pull.c
@@ -436,8 +436,9 @@ ensure_idle_queued (OtPullData *pull_data)
idle_src = g_idle_source_new ();
g_source_set_callback (idle_src, idle_worker, pull_data, NULL);
g_source_attach (idle_src, pull_data->main_context);
- g_source_unref (idle_src);
pull_data->idle_src = idle_src;
+ /* Ownership is transferred to pull_data */
+ g_source_unref (idle_src);
}
typedef struct {
@@ -1624,13 +1625,13 @@ scan_commit_object (OtPullData *pull_data,
}
if (pull_data->timestamp_check_from_rev)
{
- g_autoptr(GVariant) commit = NULL;
+ g_autoptr(GVariant) timestamp_commit = NULL;
if (!ostree_repo_load_commit (pull_data->repo, pull_data->timestamp_check_from_rev,
- &commit, NULL, error))
+ ×tamp_commit, NULL, error))
return glnx_prefix_error (error, "Reading %s for timestamp-check-from-rev",
pull_data->timestamp_check_from_rev);
- guint64 ts = ostree_commit_get_timestamp (commit);
+ guint64 ts = ostree_commit_get_timestamp (timestamp_commit);
if (!_ostree_compare_timestamps (pull_data->timestamp_check_from_rev, ts, checksum, new_ts, error))
return FALSE;
}
@@ -2000,6 +2001,8 @@ start_fetch (OtPullData *pull_data,
is_meta ? meta_fetch_on_complete : content_fetch_on_complete, fetch);
}
+/* Deprecated: code should load options from the `summary` file rather than
+ * downloading the remote’s `config` file, to save on network round trips. */
static gboolean
load_remote_repo_config (OtPullData *pull_data,
GKeyFile **out_keyfile,
@@ -2512,10 +2515,7 @@ on_superblock_fetched (GObject *src,
const guchar *expected_summary_digest = g_hash_table_lookup (pull_data->summary_deltas_checksums, delta);
guint8 actual_summary_digest[OSTREE_SHA256_DIGEST_LEN];
- g_auto(OtChecksum) hasher = { 0, };
- ot_checksum_init (&hasher);
- ot_checksum_update_bytes (&hasher, delta_superblock_data);
- ot_checksum_get_digest (&hasher, actual_summary_digest, sizeof (actual_summary_digest));
+ ot_checksum_bytes (delta_superblock_data, actual_summary_digest);
#ifndef OSTREE_DISABLE_GPGME
/* At this point we've GPG verified the data, so in theory
@@ -2625,88 +2625,198 @@ validate_variant_is_csum (GVariant *csum,
return ostree_validate_structureof_csum_v (csum, error);
}
+static gboolean
+_ostree_repo_verify_summary (OstreeRepo *self,
+ const char *name,
+ gboolean gpg_verify_summary,
+ GPtrArray *signapi_summary_verifiers,
+ GBytes *summary,
+ GBytes *signatures,
+ GCancellable *cancellable,
+ GError **error)
+{
+ if (gpg_verify_summary)
+ {
+ if (summary == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ "GPG verification enabled, but no summary found (check that the configured URL in remote config is correct)");
+ return FALSE;
+ }
+
+ if (signatures == NULL)
+ {
+ 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)");
+ return FALSE;
+ }
+
+ /* Verify any summary signatures. */
+ if (summary != NULL && signatures != NULL)
+ {
+ g_autoptr(OstreeGpgVerifyResult) result = NULL;
+
+ result = ostree_repo_verify_summary (self,
+ name,
+ summary,
+ signatures,
+ cancellable,
+ error);
+ if (!ostree_gpg_verify_result_require_valid_signature (result, error))
+ return FALSE;
+ }
+ }
+
+ if (signapi_summary_verifiers)
+ {
+ if (summary == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ "Signature verification enabled, but no summary found (check that the configured URL in remote config is correct)");
+ return FALSE;
+ }
+
+ if (signatures == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+ "Signature verification enabled, but no summary signatures found (use sign-verify-summary=false in remote config to disable)");
+ return FALSE;
+ }
+
+ /* Verify any summary signatures. */
+ if (summary != NULL && signatures != NULL)
+ {
+ g_autoptr(GVariant) sig_variant = NULL;
+
+ sig_variant = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT,
+ signatures, FALSE);
+
+ if (!_sign_verify_for_remote (signapi_summary_verifiers, summary, sig_variant, NULL, error))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+_ostree_repo_load_cache_summary_file (OstreeRepo *self,
+ const char *filename,
+ const char *extension,
+ GBytes **out_data,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const char *file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", filename, extension);
+ glnx_autofd int fd = -1;
+ g_autoptr(GBytes) data = NULL;
+
+ *out_data = NULL;
+
+ if (self->cache_dir_fd == -1)
+ return TRUE;
+
+ fd = openat (self->cache_dir_fd, file, O_CLOEXEC | O_RDONLY);
+ if (fd < 0)
+ {
+ if (errno == ENOENT)
+ return TRUE;
+ return glnx_throw_errno_prefix (error, "openat(%s)", file);
+ }
+
+ data = ot_fd_readall_or_mmap (fd, 0, error);
+ if (!data)
+ return FALSE;
+
+ *out_data =g_steal_pointer (&data);
+ return TRUE;
+}
+
/* Load the summary from the cache if the provided .sig file is the same as the
cached version. */
static gboolean
_ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
const char *remote,
GBytes *summary_sig,
- GBytes **summary,
+ GBytes **out_summary,
GCancellable *cancellable,
GError **error)
{
- if (self->cache_dir_fd == -1)
- return TRUE;
+ g_autoptr(GBytes) old_sig_contents = NULL;
- const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig");
- glnx_autofd int prev_fd = -1;
- if (!ot_openat_ignore_enoent (self->cache_dir_fd, summary_cache_sig_file, &prev_fd, error))
- return FALSE;
- if (prev_fd < 0)
- return TRUE; /* Note early return */
+ *out_summary = NULL;
- g_autoptr(GBytes) old_sig_contents = ot_fd_readall_or_mmap (prev_fd, 0, error);
- if (!old_sig_contents)
+ if (!_ostree_repo_load_cache_summary_file (self, remote, ".sig",
+ &old_sig_contents,
+ cancellable, error))
return FALSE;
- if (g_bytes_compare (old_sig_contents, summary_sig) == 0)
+ if (old_sig_contents != NULL &&
+ g_bytes_compare (old_sig_contents, summary_sig) == 0)
{
- const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote);
- glnx_autofd int summary_fd = -1;
- GBytes *summary_data;
+ g_autoptr(GBytes) summary_data = NULL;
+ if (!_ostree_repo_load_cache_summary_file (self, remote, NULL,
+ &summary_data,
+ cancellable, error))
+ return FALSE;
- summary_fd = openat (self->cache_dir_fd, summary_cache_file, O_CLOEXEC | O_RDONLY);
- if (summary_fd < 0)
+ if (summary_data == NULL)
{
- if (errno == ENOENT)
- {
- (void) unlinkat (self->cache_dir_fd, summary_cache_sig_file, 0);
- return TRUE; /* Note early return */
- }
-
- return glnx_throw_errno_prefix (error, "openat(%s)", summary_cache_file);
+ /* Cached signature without cached summary, remove the signature */
+ const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig");
+ (void) unlinkat (self->cache_dir_fd, summary_cache_sig_file, 0);
}
-
- summary_data = glnx_fd_readall_bytes (summary_fd, cancellable, error);
- if (!summary_data)
- return FALSE;
- *summary = summary_data;
+ else
+ *out_summary = g_steal_pointer (&summary_data);
}
+
return TRUE;
}
-/* Replace the current summary+signature with new versions */
static gboolean
-_ostree_repo_cache_summary (OstreeRepo *self,
- const char *remote,
- GBytes *summary,
- GBytes *summary_sig,
- GCancellable *cancellable,
- GError **error)
+_ostree_repo_save_cache_summary_file (OstreeRepo *self,
+ const char *filename,
+ const char *extension,
+ GBytes *data,
+ GCancellable *cancellable,
+ GError **error)
{
+ const char *file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", filename, extension);
+ glnx_autofd int fd = -1;
+
if (self->cache_dir_fd == -1)
return TRUE;
if (!glnx_shutil_mkdir_p_at (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, DEFAULT_DIRECTORY_MODE, cancellable, error))
return FALSE;
- const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote);
if (!glnx_file_replace_contents_at (self->cache_dir_fd,
- summary_cache_file,
- g_bytes_get_data (summary, NULL),
- g_bytes_get_size (summary),
+ file,
+ g_bytes_get_data (data, NULL),
+ g_bytes_get_size (data),
self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW,
cancellable, error))
return FALSE;
- const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig");
- if (!glnx_file_replace_contents_at (self->cache_dir_fd,
- summary_cache_sig_file,
- g_bytes_get_data (summary_sig, NULL),
- g_bytes_get_size (summary_sig),
- self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW,
- cancellable, error))
+ return TRUE;
+}
+
+/* Replace the current summary+signature with new versions */
+static gboolean
+_ostree_repo_cache_summary (OstreeRepo *self,
+ const char *remote,
+ GBytes *summary,
+ GBytes *summary_sig,
+ GCancellable *cancellable,
+ GError **error)
+{
+ if (!_ostree_repo_save_cache_summary_file (self, remote, NULL,
+ summary, cancellable, error))
+ return FALSE;
+
+ if (!_ostree_repo_save_cache_summary_file (self, remote, ".sig",
+ summary_sig, cancellable, error))
return FALSE;
return TRUE;
@@ -2716,6 +2826,8 @@ static OstreeFetcher *
_ostree_repo_remote_new_fetcher (OstreeRepo *self,
const char *remote_name,
gboolean gzip,
+ GVariant *extra_headers,
+ const char *append_user_agent,
OstreeFetcherSecurityState *out_state,
GError **error)
{
@@ -2829,6 +2941,12 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self,
_ostree_fetcher_set_cookie_jar (fetcher, jar_path);
}
+ if (extra_headers)
+ _ostree_fetcher_set_extra_headers (fetcher, extra_headers);
+
+ if (append_user_agent)
+ _ostree_fetcher_set_extra_user_agent (fetcher, append_user_agent);
+
success = TRUE;
out:
@@ -2976,127 +3094,43 @@ fetch_mirrorlist (OstreeFetcher *fetcher,
}
static gboolean
-repo_remote_fetch_summary (OstreeRepo *self,
- const char *name,
- const char *metalink_url_string,
- GVariant *options,
- GBytes **out_summary,
- GBytes **out_signatures,
- gboolean *out_from_cache,
- GCancellable *cancellable,
- GError **error)
+compute_effective_mirrorlist (OstreeRepo *self,
+ const char *remote_name_or_baseurl,
+ const char *url_override,
+ OstreeFetcher *fetcher,
+ guint n_network_retries,
+ GPtrArray **out_mirrorlist,
+ GCancellable *cancellable,
+ GError **error)
{
- g_autoptr(OstreeFetcher) fetcher = NULL;
- g_autoptr(GMainContext) mainctx = NULL;
- gboolean ret = FALSE;
- gboolean from_cache = FALSE;
- const char *url_override = NULL;
- g_autoptr(GVariant) extra_headers = NULL;
- g_autoptr(GPtrArray) mirrorlist = NULL;
- const char *append_user_agent = NULL;
- guint n_network_retries = DEFAULT_N_NETWORK_RETRIES;
-
- if (options)
- {
- (void) g_variant_lookup (options, "override-url", "&s", &url_override);
- (void) g_variant_lookup (options, "http-headers", "@a(ss)", &extra_headers);
- (void) g_variant_lookup (options, "append-user-agent", "&s", &append_user_agent);
- (void) g_variant_lookup (options, "n-network-retries", "&u", &n_network_retries);
- }
-
- mainctx = g_main_context_new ();
- g_main_context_push_thread_default (mainctx);
-
- fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, NULL, error);
- if (fetcher == NULL)
- goto out;
-
- if (extra_headers)
- _ostree_fetcher_set_extra_headers (fetcher, extra_headers);
-
- if (append_user_agent)
- _ostree_fetcher_set_extra_user_agent (fetcher, append_user_agent);
-
- {
- g_autofree char *url_string = NULL;
- if (metalink_url_string)
- url_string = g_strdup (metalink_url_string);
- else if (url_override)
- url_string = g_strdup (url_override);
- else if (!ostree_repo_remote_get_url (self, name, &url_string, error))
- goto out;
-
- if (metalink_url_string == NULL &&
- g_str_has_prefix (url_string, "mirrorlist="))
- {
- if (!fetch_mirrorlist (fetcher, url_string + strlen ("mirrorlist="),
- n_network_retries, &mirrorlist, cancellable, error))
- goto out;
- }
- else
- {
- g_autoptr(OstreeFetcherURI) uri = _ostree_fetcher_uri_parse (url_string, error);
-
- if (!uri)
- goto out;
-
- mirrorlist =
- g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free);
- g_ptr_array_add (mirrorlist, g_steal_pointer (&uri));
- }
- }
+ g_autofree char *baseurl = NULL;
- /* FIXME: Send the ETag from the cache with the request for summary.sig to
- * avoid downloading summary.sig unnecessarily. This won’t normally provide
- * any benefits (but won’t do any harm) since summary.sig is typically 500B
- * in size. But if a repository has multiple keys, the signature file will
- * grow and this optimisation may be useful. */
- if (!_ostree_preload_metadata_file (self,
- fetcher,
- mirrorlist,
- "summary.sig",
- metalink_url_string ? TRUE : FALSE,
- n_network_retries,
- out_signatures,
- cancellable,
- error))
- goto out;
+ if (url_override != NULL)
+ baseurl = g_strdup (url_override);
+ else if (!ostree_repo_remote_get_url (self, remote_name_or_baseurl, &baseurl, error))
+ return FALSE;
- if (*out_signatures)
+ if (g_str_has_prefix (baseurl, "mirrorlist="))
{
- if (!_ostree_repo_load_cache_summary_if_same_sig (self,
- name,
- *out_signatures,
- out_summary,
- cancellable,
- error))
- goto out;
+ if (!fetch_mirrorlist (fetcher,
+ baseurl + strlen ("mirrorlist="),
+ n_network_retries,
+ out_mirrorlist,
+ cancellable, error))
+ return FALSE;
}
-
- if (*out_summary)
- from_cache = TRUE;
else
{
- if (!_ostree_preload_metadata_file (self,
- fetcher,
- mirrorlist,
- "summary",
- metalink_url_string ? TRUE : FALSE,
- n_network_retries,
- out_summary,
- cancellable,
- error))
- goto out;
- }
-
- ret = TRUE;
+ g_autoptr(OstreeFetcherURI) baseuri = _ostree_fetcher_uri_parse (baseurl, error);
- out:
- if (mainctx)
- g_main_context_pop_thread_default (mainctx);
+ if (!baseuri)
+ return FALSE;
- *out_from_cache = from_cache;
- return ret;
+ *out_mirrorlist =
+ g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free);
+ g_ptr_array_add (*out_mirrorlist, g_steal_pointer (&baseuri));
+ }
+ return TRUE;
}
/* Create the fetcher by unioning options from the remote config, plus
@@ -3108,17 +3142,13 @@ reinitialize_fetcher (OtPullData *pull_data, const char *remote_name,
{
g_clear_object (&pull_data->fetcher);
pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, FALSE,
+ pull_data->extra_headers,
+ pull_data->append_user_agent,
&pull_data->fetcher_security_state,
error);
if (pull_data->fetcher == NULL)
return FALSE;
- if (pull_data->extra_headers)
- _ostree_fetcher_set_extra_headers (pull_data->fetcher, pull_data->extra_headers);
-
- if (pull_data->append_user_agent)
- _ostree_fetcher_set_extra_user_agent (pull_data->fetcher, pull_data->append_user_agent);
-
return TRUE;
}
@@ -3273,37 +3303,37 @@ initiate_request (OtPullData *pull_data,
* Like ostree_repo_pull(), but supports an extensible set of flags.
* The following are currently defined:
*
- * * refs (as): Array of string refs
- * * collection-refs (a(sss)): Array of (collection ID, ref name, checksum) tuples to pull;
+ * * `refs` (`as`): Array of string refs
+ * * `collection-refs` (`a(sss)`): Array of (collection ID, ref name, checksum) tuples to pull;
* mutually exclusive with `refs` and `override-commit-ids`. Checksums may be the empty
* string to pull the latest commit for that ref
- * * flags (i): An instance of #OstreeRepoPullFlags
- * * subdir (s): Pull just this subdirectory
- * * subdirs (as): Pull just these subdirectories
- * * override-remote-name (s): If local, add this remote to refspec
- * * gpg-verify (b): GPG verify commits
- * * gpg-verify-summary (b): GPG verify summary
- * * disable-sign-verify (b): Disable signapi verification of commits
- * * disable-sign-verify-summary (b): Disable signapi verification of the summary
- * * depth (i): How far in the history to traverse; default is 0, -1 means infinite
- * * per-object-fsync (b): Perform disk writes more slowly, avoiding a single large I/O sync
- * * disable-static-deltas (b): Do not use static deltas
- * * require-static-deltas (b): Require static deltas
- * * override-commit-ids (as): Array of specific commit IDs to fetch for refs
- * * timestamp-check (b): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11
- * * timestamp-check-from-rev (s): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4
- * * metadata-size-restriction (t): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9
- * * dry-run (b): Only print information on what will be downloaded (requires static deltas)
- * * override-url (s): Fetch objects from this URL if remote specifies no metalink in options
- * * inherit-transaction (b): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction.
- * * http-headers (a(ss)): Additional headers to add to all HTTP requests
- * * update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid
- * * localcache-repos (as): File paths for local repos to use as caches when doing remote fetches
- * * append-user-agent (s): Additional string to append to the user agent
- * * n-network-retries (u): Number of times to retry each download on receiving
+ * * `flags` (`i`): An instance of #OstreeRepoPullFlags
+ * * `subdir` (`s`): Pull just this subdirectory
+ * * `subdirs` (`as`): Pull just these subdirectories
+ * * `override-remote-name` (`s`): If local, add this remote to refspec
+ * * `gpg-verify` (`b`): GPG verify commits
+ * * `gpg-verify-summary` (`b`): GPG verify summary
+ * * `disable-sign-verify` (`b`): Disable signapi verification of commits
+ * * `disable-sign-verify-summary` (`b`): Disable signapi verification of the summary
+ * * `depth` (`i`): How far in the history to traverse; default is 0, -1 means infinite
+ * * `per-object-fsync` (`b`): Perform disk writes more slowly, avoiding a single large I/O sync
+ * * `disable-static-deltas` (`b`): Do not use static deltas
+ * * `require-static-deltas` (`b`): Require static deltas
+ * * `override-commit-ids` (`as`): Array of specific commit IDs to fetch for refs
+ * * `timestamp-check` (`b`): Verify commit timestamps are newer than current (when pulling via ref); Since: 2017.11
+ * * `timestamp-check-from-rev` (`s`): Verify that all fetched commit timestamps are newer than timestamp of given rev; Since: 2020.4
+ * * `metadata-size-restriction` (`t`): Restrict metadata objects to a maximum number of bytes; 0 to disable. Since: 2018.9
+ * * `dry-run` (`b`): Only print information on what will be downloaded (requires static deltas)
+ * * `override-url` (`s`): Fetch objects from this URL if remote specifies no metalink in options
+ * * `inherit-transaction` (`b`): Don't initiate, finish or abort a transaction, useful to do multiple pulls in one transaction.
+ * * `http-headers` (`a(ss)`): Additional headers to add to all HTTP requests
+ * * `update-frequency` (`u`): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid
+ * * `localcache-repos` (`as`): File paths for local repos to use as caches when doing remote fetches
+ * * `append-user-agent` (`s`): Additional string to append to the user agent
+ * * `n-network-retries` (`u`): Number of times to retry each download on receiving
* a transient network error, such as a socket timeout; default is 5, 0
* means return errors without retrying. Since: 2018.6
- * * ref-keyring-map (a(sss)): Array of (collection ID, ref name, keyring
+ * * `ref-keyring-map` (`a(sss)`): Array of (collection ID, ref name, keyring
* remote name) tuples specifying which remote's keyring should be used when
* doing GPG verification of each collection-ref. This is useful to prevent a
* remote from serving malicious updates to refs which did not originate from
@@ -3311,6 +3341,14 @@ initiate_request (OtPullData *pull_data,
* not being pulled will be ignored and any ref without a keyring remote
* will be verified with the keyring of the remote being pulled from.
* Since: 2019.2
+ * * `summary-bytes` (`ay'): Contents of the `summary` file to use. If this is
+ * specified, `summary-sig-bytes` must also be specified. This is
+ * useful if doing multiple pull operations in a transaction, using
+ * ostree_repo_remote_fetch_summary_with_options() beforehand to download
+ * the `summary` and `summary.sig` once for the entire transaction. If not
+ * specified, the `summary` will be downloaded from the remote. Since: 2020.5
+ * * `summary-sig-bytes` (`ay`): Contents of the `summary.sig` file. If this
+ * is specified, `summary-bytes` must also be specified. Since: 2020.5
*/
gboolean
ostree_repo_pull_with_options (OstreeRepo *self,
@@ -3353,9 +3391,11 @@ ostree_repo_pull_with_options (OstreeRepo *self,
const char *url_override = NULL;
gboolean inherit_transaction = FALSE;
g_autoptr(GHashTable) updated_requested_refs_to_fetch = NULL; /* (element-type OstreeCollectionRef utf8) */
- int i;
+ gsize i;
g_autofree char **opt_localcache_repos = NULL;
g_autoptr(GVariantIter) ref_keyring_map_iter = NULL;
+ g_autoptr(GVariant) summary_bytes_v = NULL;
+ g_autoptr(GVariant) summary_sig_bytes_v = NULL;
/* If refs or collection-refs has exactly one value, this will point to that
* value, otherwise NULL. Used for logging.
*/
@@ -3402,6 +3442,8 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_variant_lookup (options, "n-network-retries", "u", &pull_data->n_network_retries);
opt_ref_keyring_map_set =
g_variant_lookup (options, "ref-keyring-map", "a(sss)", &ref_keyring_map_iter);
+ (void) g_variant_lookup (options, "summary-bytes", "@ay", &summary_bytes_v);
+ (void) g_variant_lookup (options, "summary-sig-bytes", "@ay", &summary_sig_bytes_v);
if (pull_data->remote_refspec_name != NULL)
pull_data->remote_name = g_strdup (pull_data->remote_refspec_name);
@@ -3439,6 +3481,10 @@ ostree_repo_pull_with_options (OstreeRepo *self,
*/
g_return_val_if_fail (!pull_data->dry_run || pull_data->require_static_deltas, FALSE);
+ /* summary-bytes and summary-sig-bytes must both be specified, or neither be
+ * specified, so we know they’re consistent */
+ g_return_val_if_fail ((summary_bytes_v == NULL) == (summary_sig_bytes_v == NULL), FALSE);
+
pull_data->is_mirror = (flags & OSTREE_REPO_PULL_FLAGS_MIRROR) > 0;
pull_data->is_commit_only = (flags & OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY) > 0;
/* See our processing of OSTREE_REPO_PULL_FLAGS_UNTRUSTED below */
@@ -3614,33 +3660,13 @@ ostree_repo_pull_with_options (OstreeRepo *self,
if (!metalink_url_str)
{
- g_autofree char *baseurl = NULL;
-
- if (url_override != NULL)
- baseurl = g_strdup (url_override);
- else if (!ostree_repo_remote_get_url (self, remote_name_or_baseurl, &baseurl, error))
+ if (!compute_effective_mirrorlist (self, remote_name_or_baseurl,
+ url_override,
+ pull_data->fetcher,
+ pull_data->n_network_retries,
+ &pull_data->meta_mirrorlist,
+ cancellable, error))
goto out;
-
- if (g_str_has_prefix (baseurl, "mirrorlist="))
- {
- if (!fetch_mirrorlist (pull_data->fetcher,
- baseurl + strlen ("mirrorlist="),
- pull_data->n_network_retries,
- &pull_data->meta_mirrorlist,
- cancellable, error))
- goto out;
- }
- else
- {
- g_autoptr(OstreeFetcherURI) baseuri = _ostree_fetcher_uri_parse (baseurl, error);
-
- if (!baseuri)
- goto out;
-
- pull_data->meta_mirrorlist =
- g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free);
- g_ptr_array_add (pull_data->meta_mirrorlist, g_steal_pointer (&baseuri));
- }
}
else
{
@@ -3651,6 +3677,10 @@ ostree_repo_pull_with_options (OstreeRepo *self,
if (!metalink_uri)
goto out;
+ /* FIXME: Use summary_bytes_v/summary_sig_bytes_v to avoid unnecessary
+ * re-downloads here. Would require additional support for caching the
+ * metalink file or mirror list. */
+
metalink = _ostree_metalink_new (pull_data->fetcher, "summary",
OSTREE_MAX_METADATA_SIZE, metalink_uri,
pull_data->n_network_retries);
@@ -3695,27 +3725,13 @@ ostree_repo_pull_with_options (OstreeRepo *self,
}
else
{
- if (g_str_has_prefix (contenturl, "mirrorlist="))
- {
- if (!fetch_mirrorlist (pull_data->fetcher,
- contenturl + strlen ("mirrorlist="),
- pull_data->n_network_retries,
- &pull_data->content_mirrorlist,
- cancellable, error))
- goto out;
- }
- else
- {
- g_autoptr(OstreeFetcherURI) contenturi = _ostree_fetcher_uri_parse (contenturl, error);
-
- if (!contenturi)
- goto out;
-
- pull_data->content_mirrorlist =
- g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free);
- g_ptr_array_add (pull_data->content_mirrorlist,
- g_steal_pointer (&contenturi));
- }
+ if (!compute_effective_mirrorlist (self, remote_name_or_baseurl,
+ contenturl,
+ pull_data->fetcher,
+ pull_data->n_network_retries,
+ &pull_data->content_mirrorlist,
+ cancellable, error))
+ goto out;
}
}
@@ -3743,30 +3759,6 @@ ostree_repo_pull_with_options (OstreeRepo *self,
if (!ostree_repo_open (pull_data->remote_repo_local, cancellable, error))
goto out;
}
- else
- {
- if (!load_remote_repo_config (pull_data, &remote_config, cancellable, error))
- goto out;
-
- if (!ot_keyfile_get_value_with_default (remote_config, "core", "mode", "bare",
- &remote_mode_str, error))
- goto out;
-
- if (!ostree_repo_mode_from_string (remote_mode_str, &pull_data->remote_mode, error))
- goto out;
-
- if (!ot_keyfile_get_boolean_with_default (remote_config, "core", "tombstone-commits", FALSE,
- &pull_data->has_tombstone_commits, error))
- goto out;
-
- if (pull_data->remote_mode != OSTREE_REPO_MODE_ARCHIVE)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Can't pull from archives with mode \"%s\"",
- remote_mode_str);
- goto out;
- }
- }
}
/* Change some option defaults if we're actually pulling from a local
@@ -3835,13 +3827,33 @@ ostree_repo_pull_with_options (OstreeRepo *self,
{
g_autoptr(GBytes) bytes_sig = NULL;
- gsize i, n;
+ gsize n;
g_autoptr(GVariant) refs = NULL;
g_autoptr(GVariant) deltas = NULL;
g_autoptr(GVariant) additional_metadata = NULL;
gboolean summary_from_cache = FALSE;
+ gboolean remote_mode_loaded = FALSE;
+ gboolean tombstone_commits = FALSE;
- if (!pull_data->summary_data_sig)
+ if (summary_sig_bytes_v)
+ {
+ /* Must both be specified */
+ g_assert (summary_bytes_v);
+
+ bytes_sig = g_variant_get_data_as_bytes (summary_sig_bytes_v);
+ bytes_summary = g_variant_get_data_as_bytes (summary_bytes_v);
+
+ if (!bytes_sig || !bytes_summary)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "summary-bytes or summary-sig-bytes set to invalid value");
+ goto out;
+ }
+
+ g_debug ("Loaded %s summary from options", remote_name_or_baseurl);
+ }
+
+ if (!bytes_sig)
{
if (!_ostree_fetcher_mirrored_request_to_membuf (pull_data->fetcher,
pull_data->meta_mirrorlist,
@@ -3854,6 +3866,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
}
if (bytes_sig &&
+ !bytes_summary &&
!pull_data->remote_repo_local &&
!_ostree_repo_load_cache_summary_if_same_sig (self,
remote_name_or_baseurl,
@@ -3863,7 +3876,7 @@ ostree_repo_pull_with_options (OstreeRepo *self,
error))
goto out;
- if (bytes_summary)
+ if (bytes_summary && !summary_bytes_v)
{
g_debug ("Loaded %s summary from cache", remote_name_or_baseurl);
summary_from_cache = TRUE;
@@ -4134,6 +4147,46 @@ ostree_repo_pull_with_options (OstreeRepo *self,
csum_data);
}
}
+
+ if (pull_data->summary &&
+ g_variant_lookup (additional_metadata, OSTREE_SUMMARY_MODE, "s", &remote_mode_str) &&
+ g_variant_lookup (additional_metadata, OSTREE_SUMMARY_TOMBSTONE_COMMITS, "b", &tombstone_commits))
+ {
+ if (!ostree_repo_mode_from_string (remote_mode_str, &pull_data->remote_mode, error))
+ goto out;
+ pull_data->has_tombstone_commits = tombstone_commits;
+ remote_mode_loaded = TRUE;
+ }
+ else if (pull_data->remote_repo_local == NULL)
+ {
+ /* Fall-back path which loads the necessary config from the remote’s
+ * `config` file. Doing so is deprecated since it means an
+ * additional round trip to the remote for each pull. No need to do
+ * it for local pulls. */
+ if (!load_remote_repo_config (pull_data, &remote_config, cancellable, error))
+ goto out;
+
+ if (!ot_keyfile_get_value_with_default (remote_config, "core", "mode", "bare",
+ &remote_mode_str, error))
+ goto out;
+
+ if (!ostree_repo_mode_from_string (remote_mode_str, &pull_data->remote_mode, error))
+ goto out;
+
+ if (!ot_keyfile_get_boolean_with_default (remote_config, "core", "tombstone-commits", FALSE,
+ &pull_data->has_tombstone_commits, error))
+ goto out;
+
+ remote_mode_loaded = TRUE;
+ }
+
+ if (remote_mode_loaded && pull_data->remote_repo_local == NULL && pull_data->remote_mode != OSTREE_REPO_MODE_ARCHIVE)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Can't pull from archives with mode \"%s\"",
+ remote_mode_str);
+ goto out;
+ }
}
if (pull_data->is_mirror && !refs_to_fetch && !opt_collection_refs_set && !configured_branches)
@@ -5194,7 +5247,7 @@ find_remotes_process_refs (OstreeRepo *self,
static void
find_remotes_cb (GObject *obj,
- GAsyncResult *result,
+ GAsyncResult *async_result,
gpointer user_data)
{
OstreeRepo *self;
@@ -5226,7 +5279,7 @@ find_remotes_cb (GObject *obj,
/* progress = data->progress; */
/* Finish finding the remotes. */
- results = ostree_repo_finder_resolve_all_finish (result, &error);
+ results = ostree_repo_finder_resolve_all_finish (async_result, &error);
if (results == NULL)
{
@@ -5319,8 +5372,8 @@ find_remotes_cb (GObject *obj,
/* Check the metadata in the summary file, especially whether it contains
* all the @refs we are interested in. */
- summary_v = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT,
- summary_bytes, FALSE);
+ summary_v = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT,
+ summary_bytes, FALSE));
/* Check the summary’s additional metadata and set up @commit_metadata
* and @refs_and_remotes_table with the refs listed in the summary file,
@@ -5431,7 +5484,7 @@ find_remotes_cb (GObject *obj,
goto error;
fetcher = _ostree_repo_remote_new_fetcher (self, result->remote->name,
- TRUE, NULL, &error);
+ TRUE, NULL, NULL, NULL, &error);
if (fetcher == NULL)
goto error;
@@ -6053,96 +6106,108 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
g_autoptr(GBytes) signatures = NULL;
gboolean gpg_verify_summary;
g_autoptr(GPtrArray) signapi_summary_verifiers = NULL;
- gboolean ret = FALSE;
- gboolean summary_is_from_cache;
+ gboolean summary_is_from_cache = FALSE;
+ g_autoptr(OstreeFetcher) fetcher = NULL;
+ g_autoptr(GMainContextPopDefault) mainctx = NULL;
+ const char *url_override = NULL;
+ g_autoptr(GVariant) extra_headers = NULL;
+ g_autoptr(GPtrArray) mirrorlist = NULL;
+ const char *append_user_agent = NULL;
+ guint n_network_retries = DEFAULT_N_NETWORK_RETRIES;
g_return_val_if_fail (OSTREE_REPO (self), FALSE);
g_return_val_if_fail (name != NULL, FALSE);
if (!ostree_repo_get_remote_option (self, name, "metalink", NULL,
&metalink_url_string, error))
- goto out;
-
- if (!repo_remote_fetch_summary (self,
- name,
- metalink_url_string,
- options,
- &summary,
- &signatures,
- &summary_is_from_cache,
- cancellable,
- error))
- goto out;
-
- if (!ostree_repo_remote_get_gpg_verify_summary (self, name, &gpg_verify_summary, error))
- goto out;
+ return FALSE;
- if (gpg_verify_summary)
+ if (options)
{
- if (summary == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- "GPG verification enabled, but no summary found (check that the configured URL in remote config is correct)");
- goto out;
- }
-
- if (signatures == NULL)
- {
- 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;
- }
-
- /* Verify any summary signatures. */
- if (summary != NULL && signatures != NULL)
- {
- g_autoptr(OstreeGpgVerifyResult) result = NULL;
-
- result = ostree_repo_verify_summary (self,
- name,
- summary,
- signatures,
- cancellable,
- error);
- if (!ostree_gpg_verify_result_require_valid_signature (result, error))
- goto out;
- }
+ (void) g_variant_lookup (options, "override-url", "&s", &url_override);
+ (void) g_variant_lookup (options, "http-headers", "@a(ss)", &extra_headers);
+ (void) g_variant_lookup (options, "append-user-agent", "&s", &append_user_agent);
+ (void) g_variant_lookup (options, "n-network-retries", "u", &n_network_retries);
}
+ if (!ostree_repo_remote_get_gpg_verify_summary (self, name, &gpg_verify_summary, error))
+ return FALSE;
+
if (!_signapi_init_for_remote (self, name, NULL,
&signapi_summary_verifiers,
error))
- goto out;
+ return FALSE;
- if (signapi_summary_verifiers)
+ mainctx = _ostree_main_context_new_default ();
+
+ fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, extra_headers, append_user_agent, NULL, error);
+ if (fetcher == NULL)
+ return FALSE;
+
+ if (metalink_url_string)
{
- if (summary == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- "Signature verification enabled, but no summary found (check that the configured URL in remote config is correct)");
- goto out;
- }
+ g_autoptr(OstreeFetcherURI) uri = _ostree_fetcher_uri_parse (metalink_url_string, error);
+ if (!uri)
+ return FALSE;
- if (signatures == NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
- "Signature verification enabled, but no summary signatures found (use sign-verify-summary=false in remote config to disable)");
- goto out;
- }
+ mirrorlist =
+ g_ptr_array_new_with_free_func ((GDestroyNotify) _ostree_fetcher_uri_free);
+ g_ptr_array_add (mirrorlist, g_steal_pointer (&uri));
+ }
+ else if (!compute_effective_mirrorlist (self, name, url_override,
+ fetcher, n_network_retries,
+ &mirrorlist, cancellable, error))
+ return FALSE;
- /* Verify any summary signatures. */
- if (summary != NULL && signatures != NULL)
- {
- g_autoptr(GVariant) sig_variant = NULL;
+ /* FIXME: Send the ETag from the cache with the request for summary.sig to
+ * avoid downloading summary.sig unnecessarily. This won’t normally provide
+ * any benefits (but won’t do any harm) since summary.sig is typically 500B
+ * in size. But if a repository has multiple keys, the signature file will
+ * grow and this optimisation may be useful. */
+ if (!_ostree_preload_metadata_file (self,
+ fetcher,
+ mirrorlist,
+ "summary.sig",
+ metalink_url_string ? TRUE : FALSE,
+ n_network_retries,
+ &signatures,
+ cancellable,
+ error))
+ return FALSE;
- sig_variant = g_variant_new_from_bytes (OSTREE_SUMMARY_SIG_GVARIANT_FORMAT,
- signatures, FALSE);
+ if (signatures)
+ {
+ if (!_ostree_repo_load_cache_summary_if_same_sig (self,
+ name,
+ signatures,
+ &summary,
+ cancellable,
+ error))
+ return FALSE;
+ }
- if (!_sign_verify_for_remote (signapi_summary_verifiers, summary, sig_variant, NULL, error))
- goto out;
- }
+ if (summary)
+ summary_is_from_cache = TRUE;
+ else
+ {
+ if (!_ostree_preload_metadata_file (self,
+ fetcher,
+ mirrorlist,
+ "summary",
+ metalink_url_string ? TRUE : FALSE,
+ n_network_retries,
+ &summary,
+ cancellable,
+ error))
+ return FALSE;
}
+ if (!_ostree_repo_verify_summary (self, name,
+ gpg_verify_summary, signapi_summary_verifiers,
+ summary, signatures,
+ cancellable, error))
+ return FALSE;
+
if (!summary_is_from_cache && summary && signatures)
{
g_autoptr(GError) temp_error = NULL;
@@ -6159,7 +6224,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
else
{
g_propagate_error (error, g_steal_pointer (&temp_error));
- goto out;
+ return FALSE;
}
}
}
@@ -6170,10 +6235,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self,
if (out_signatures != NULL)
*out_signatures = g_steal_pointer (&signatures);
- ret = TRUE;
-
-out:
- return ret;
+ return TRUE;
}
#else /* HAVE_LIBCURL_OR_LIBSOUP */
diff --git a/src/libostree/ostree-repo-static-delta-compilation.c b/src/libostree/ostree-repo-static-delta-compilation.c
index 3e9a8e3..753f8ae 100644
--- a/src/libostree/ostree-repo-static-delta-compilation.c
+++ b/src/libostree/ostree-repo-static-delta-compilation.c
@@ -36,6 +36,8 @@
#include "libglnx.h"
#include "ostree-varint.h"
#include "bsdiff/bsdiff.h"
+#include "ostree-autocleanups.h"
+#include "ostree-sign.h"
#define CONTENT_SIZE_SIMILARITY_THRESHOLD_PERCENT (30)
@@ -1335,6 +1337,8 @@ get_fallback_headers (OstreeRepo *self,
* - verbose: b: Print diagnostic messages. Default FALSE.
* - endianness: b: Deltas use host byte order by default; this option allows choosing (G_BIG_ENDIAN or G_LITTLE_ENDIAN)
* - filename: ay: Save delta superblock to this filename, and parts in the same directory. Default saves to repository.
+ * - sign-name: ay: Signature type to use.
+ * - sign-key-ids: as: Array of keys used to sign delta superblock.
*/
gboolean
ostree_repo_static_delta_generate (OstreeRepo *self,
@@ -1368,6 +1372,8 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
g_autoptr(GPtrArray) builder_fallback_objects = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref);
g_auto(GLnxTmpfile) descriptor_tmpf = { 0, };
g_autoptr(OtVariantBuilder) descriptor_builder = NULL;
+ const char *opt_sign_name;
+ const char **opt_key_ids;
if (!g_variant_lookup (params, "min-fallback-size", "u", &min_fallback_size))
min_fallback_size = 4;
@@ -1407,6 +1413,12 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
if (!g_variant_lookup (params, "filename", "^&ay", &opt_filename))
opt_filename = NULL;
+ if (!g_variant_lookup (params, "sign-name", "^&ay", &opt_sign_name))
+ opt_sign_name = NULL;
+
+ if (!g_variant_lookup (params, "sign-key-ids", "^a&s", &opt_key_ids))
+ opt_key_ids = NULL;
+
if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, to,
&to_commit, error))
return FALSE;
@@ -1442,7 +1454,7 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
cancellable, error))
return FALSE;
- if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_WRONLY | O_CLOEXEC,
+ if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_RDWR | O_CLOEXEC,
&descriptor_tmpf, error))
return FALSE;
@@ -1586,12 +1598,85 @@ ostree_repo_static_delta_generate (OstreeRepo *self,
g_printerr ("bsdiff=%u objects\n", builder.n_bsdiff);
}
- if (fchmod (descriptor_tmpf.fd, 0644) < 0)
- return glnx_throw_errno_prefix (error, "fchmod");
+ if (opt_sign_name != NULL && opt_key_ids != NULL)
+ {
+ g_autoptr(GBytes) tmpdata = NULL;
+ g_autoptr(OstreeSign) sign = NULL;
+ const gchar *signature_key = NULL;
+ g_autoptr(GVariantBuilder) signature_builder = NULL;
+ g_auto(GLnxTmpfile) descriptor_sign_tmpf = { 0, };
+ g_autoptr(OtVariantBuilder) descriptor_sign_builder = NULL;
+
+ lseek (descriptor_tmpf.fd, 0, SEEK_SET);
+ tmpdata = glnx_fd_readall_bytes (descriptor_tmpf.fd, cancellable, error);
+ if (!tmpdata)
+ return FALSE;
- if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE,
- descriptor_dfd, descriptor_name, error))
- return FALSE;
+ sign = ostree_sign_get_by_name (opt_sign_name, error);
+ if (sign == NULL)
+ return FALSE;
+
+ signature_key = ostree_sign_metadata_key (sign);
+ const gchar *signature_format = ostree_sign_metadata_format (sign);
+
+ signature_builder = g_variant_builder_new (G_VARIANT_TYPE (signature_format));
+
+ for (const char **iter = opt_key_ids; iter && *iter; iter++)
+ {
+ const char *keyid = *iter;
+ g_autoptr(GVariant) secret_key = NULL;
+ g_autoptr(GBytes) signature_bytes = NULL;
+
+ secret_key = g_variant_new_string (keyid);
+ if (!ostree_sign_set_sk (sign, secret_key, error))
+ return FALSE;
+
+ if (!ostree_sign_data (sign, tmpdata, &signature_bytes,
+ NULL, error))
+ return FALSE;
+
+ g_variant_builder_add (signature_builder, "@ay", ot_gvariant_new_ay_bytes (signature_bytes));
+ }
+
+ if (!glnx_open_tmpfile_linkable_at (descriptor_dfd, ".", O_WRONLY | O_CLOEXEC,
+ &descriptor_sign_tmpf, error))
+ return FALSE;
+
+ descriptor_sign_builder = ot_variant_builder_new (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SIGNED_FORMAT),
+ descriptor_sign_tmpf.fd);
+
+ if (!ot_variant_builder_add (descriptor_sign_builder, error, "t",
+ GUINT64_TO_BE (OSTREE_STATIC_DELTA_SIGNED_MAGIC)))
+ return FALSE;
+ if (!ot_variant_builder_add (descriptor_sign_builder, error, "@ay", ot_gvariant_new_ay_bytes (tmpdata)))
+ return FALSE;
+ if (!ot_variant_builder_open (descriptor_sign_builder, G_VARIANT_TYPE ("a{sv}"), error))
+ return FALSE;
+ if (!ot_variant_builder_add (descriptor_sign_builder, error, "{sv}",
+ signature_key, g_variant_builder_end(signature_builder)))
+ return FALSE;
+ if (!ot_variant_builder_close (descriptor_sign_builder, error))
+ return FALSE;
+
+ if (!ot_variant_builder_end (descriptor_sign_builder, error))
+ return FALSE;
+
+ if (fchmod (descriptor_sign_tmpf.fd, 0644) < 0)
+ return glnx_throw_errno_prefix (error, "fchmod");
+
+ if (!glnx_link_tmpfile_at (&descriptor_sign_tmpf, GLNX_LINK_TMPFILE_REPLACE,
+ descriptor_dfd, descriptor_name, error))
+ return FALSE;
+ }
+ else
+ {
+ if (fchmod (descriptor_tmpf.fd, 0644) < 0)
+ return glnx_throw_errno_prefix (error, "fchmod");
+
+ if (!glnx_link_tmpfile_at (&descriptor_tmpf, GLNX_LINK_TMPFILE_REPLACE,
+ descriptor_dfd, descriptor_name, error))
+ return FALSE;
+ }
return TRUE;
}
diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c
index ade4e9d..d83ec8c 100644
--- a/src/libostree/ostree-repo-static-delta-core.c
+++ b/src/libostree/ostree-repo-static-delta-core.c
@@ -54,6 +54,28 @@ _ostree_static_delta_parse_checksum_array (GVariant *array,
return TRUE;
}
+GVariant *
+_ostree_repo_static_delta_superblock_digest (OstreeRepo *repo,
+ const char *from,
+ const char *to,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autofree char *superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to);
+ glnx_autofd int superblock_file_fd = -1;
+ guint8 digest[OSTREE_SHA256_DIGEST_LEN];
+
+ if (!glnx_openat_rdonly (repo->repo_dir_fd, superblock, TRUE, &superblock_file_fd, error))
+ return NULL;
+
+ g_autoptr(GBytes) superblock_content = ot_fd_readall_or_mmap (superblock_file_fd, 0, error);
+ if (!superblock_content)
+ return NULL;
+
+ ot_checksum_bytes (superblock_content, digest);
+
+ return ot_gvariant_new_bytearray (digest, sizeof (digest));
+}
/**
* ostree_repo_list_static_delta_names:
@@ -109,7 +131,7 @@ ostree_repo_list_static_delta_names (OstreeRepo *self,
return FALSE;
if (sub_dent == NULL)
break;
- if (dent->d_type != DT_DIR)
+ if (sub_dent->d_type != DT_DIR)
continue;
const char *name1 = dent->d_name;
@@ -188,27 +210,126 @@ _ostree_repo_static_delta_part_have_all_objects (OstreeRepo *repo,
return TRUE;
}
+static gboolean
+_ostree_repo_static_delta_is_signed (OstreeRepo *self,
+ int fd,
+ GPtrArray **out_value,
+ GError **error)
+{
+ g_autoptr(GVariant) delta = NULL;
+ g_autoptr(GVariant) delta_sign_magic = NULL;
+ g_autoptr(GVariant) delta_sign = NULL;
+ GVariantIter iter;
+ GVariant *item;
+ g_autoptr(GPtrArray) signatures = NULL;
+ gboolean ret = FALSE;
+
+ if (out_value)
+ *out_value = NULL;
+
+ if (!ot_variant_read_fd (fd, 0, (GVariantType*)OSTREE_STATIC_DELTA_SIGNED_FORMAT, TRUE, &delta, error))
+ return FALSE;
+
+ delta_sign_magic = g_variant_get_child_value (delta, 0);
+ if (delta_sign_magic == NULL)
+ return glnx_throw (error, "no signatures in static-delta");
+
+ if (GUINT64_FROM_BE (g_variant_get_uint64 (delta_sign_magic)) != OSTREE_STATIC_DELTA_SIGNED_MAGIC)
+ return glnx_throw (error, "no signatures in static-delta");
+
+ delta_sign = g_variant_get_child_value (delta, 2);
+ if (delta_sign == NULL)
+ return glnx_throw (error, "no signatures in static-delta");
+
+ if (out_value)
+ signatures = g_ptr_array_new_with_free_func (g_free);
+
+ /* Check if there are signatures in the superblock */
+ g_variant_iter_init (&iter, delta_sign);
+ while ((item = g_variant_iter_next_value (&iter)))
+ {
+ g_autoptr(GVariant) key_v = g_variant_get_child_value (item, 0);
+ const char *str = g_variant_get_string (key_v, NULL);
+ if (g_str_has_prefix (str, "ostree.sign."))
+ {
+ ret = TRUE;
+ if (signatures)
+ g_ptr_array_add (signatures, g_strdup (str + strlen ("ostree.sign.")));
+ }
+ g_variant_unref (item);
+ }
+
+ if (out_value && ret)
+ ot_transfer_out_value (out_value, &signatures);
+
+ return ret;
+}
+
+static gboolean
+_ostree_repo_static_delta_verify_signature (OstreeRepo *self,
+ int fd,
+ OstreeSign *sign,
+ char **out_success_message,
+ GError **error)
+{
+ g_autoptr(GVariant) delta = NULL;
+
+ if (!ot_variant_read_fd (fd, 0,
+ (GVariantType*)OSTREE_STATIC_DELTA_SIGNED_FORMAT,
+ TRUE, &delta, error))
+ return FALSE;
+
+ /* Check if there are signatures for signature engine */
+ const gchar *signature_key = ostree_sign_metadata_key(sign);
+ GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format(sign);
+ g_autoptr(GVariant) delta_meta = g_variant_get_child_value (delta, 2);
+ if (delta_meta == NULL)
+ return glnx_throw (error, "no metadata in static-delta superblock");
+ g_autoptr(GVariant) signatures = g_variant_lookup_value (delta_meta,
+ signature_key,
+ signature_format);
+ if (!signatures)
+ return glnx_throw (error, "no signature for '%s' in static-delta superblock", signature_key);
+
+ /* Get static delta superblock */
+ g_autoptr(GVariant) child = g_variant_get_child_value (delta, 1);
+ if (child == NULL)
+ return glnx_throw (error, "no metadata in static-delta superblock");
+ g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes(child);
+
+ return ostree_sign_data_verify (sign, signed_data, signatures, out_success_message, error);
+}
+
/**
- * ostree_repo_static_delta_execute_offline:
+ * ostree_repo_static_delta_execute_offline_with_signature:
* @self: Repo
* @dir_or_file: Path to a directory containing static delta data, or directly to the superblock
+ * @sign: Signature engine used to check superblock
* @skip_validation: If %TRUE, assume data integrity
* @cancellable: Cancellable
* @error: Error
*
* Given a directory representing an already-downloaded static delta
- * on disk, apply it, generating a new commit. The directory must be
- * named with the form "FROM-TO", where both are checksums, and it
- * must contain a file named "superblock", along with at least one part.
+ * on disk, apply it, generating a new commit.
+ * If sign is passed, the static delta signature is verified.
+ * If sign-verify-deltas configuration option is set and static delta is signed,
+ * signature verification will be mandatory before apply the static delta.
+ * The directory must be named with the form "FROM-TO", where both are
+ * checksums, and it must contain a file named "superblock", along with at least
+ * one part.
+ *
+ * Since: 2020.7
*/
gboolean
-ostree_repo_static_delta_execute_offline (OstreeRepo *self,
- GFile *dir_or_file,
- gboolean skip_validation,
- GCancellable *cancellable,
- GError **error)
+ostree_repo_static_delta_execute_offline_with_signature (OstreeRepo *self,
+ GFile *dir_or_file,
+ OstreeSign *sign,
+ gboolean skip_validation,
+ GCancellable *cancellable,
+ GError **error)
{
g_autofree char *basename = NULL;
+ g_autoptr(GVariant) meta = NULL;
const char *dir_or_file_path = gs_file_get_path_cached (dir_or_file);
@@ -234,10 +355,44 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
if (meta_fd < 0)
return glnx_throw_errno_prefix (error, "openat(%s)", basename);
- g_autoptr(GVariant) meta = NULL;
- if (!ot_variant_read_fd (meta_fd, 0, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT),
- FALSE, &meta, error))
- return FALSE;
+ gboolean is_signed = _ostree_repo_static_delta_is_signed (self, meta_fd, NULL, NULL);
+ if (is_signed)
+ {
+ gboolean verify_deltas;
+ gboolean verified;
+
+ if (!ot_keyfile_get_boolean_with_default (self->config, "core", "sign-verify-deltas",
+ FALSE, &verify_deltas, error))
+ return FALSE;
+
+ if (verify_deltas && !sign)
+ return glnx_throw (error, "Key is mandatory to check delta signature");
+
+ if (sign)
+ {
+ verified = _ostree_repo_static_delta_verify_signature (self, meta_fd, sign, NULL, error);
+ if (*error)
+ return FALSE;
+ if (!verified)
+ return glnx_throw (error, "Delta signature verification failed");
+ }
+
+ g_autoptr(GVariant) delta = NULL;
+ if (!ot_variant_read_fd (meta_fd, 0, (GVariantType*)OSTREE_STATIC_DELTA_SIGNED_FORMAT,
+ TRUE, &delta, error))
+ return FALSE;
+
+ g_autoptr(GVariant) child = g_variant_get_child_value (delta, 1);
+ g_autoptr(GBytes) bytes = g_variant_get_data_as_bytes (child);
+ meta = g_variant_new_from_bytes ((GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
+ bytes, FALSE);
+ }
+ else
+ {
+ if (!ot_variant_read_fd (meta_fd, 0, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT),
+ FALSE, &meta, error))
+ return FALSE;
+ }
/* Parsing OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT */
@@ -280,9 +435,8 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
if (!have_to_commit)
{
g_autofree char *detached_path = _ostree_get_relative_static_delta_path (from_checksum, to_checksum, "commitmeta");
- g_autoptr(GVariant) detached_data = NULL;
-
- detached_data = g_variant_lookup_value (metadata, detached_path, G_VARIANT_TYPE("a{sv}"));
+ g_autoptr(GVariant) detached_data =
+ g_variant_lookup_value (metadata, detached_path, G_VARIANT_TYPE("a{sv}"));
if (detached_data && !ostree_repo_write_commit_detached_metadata (self,
to_checksum,
detached_data,
@@ -386,6 +540,32 @@ ostree_repo_static_delta_execute_offline (OstreeRepo *self,
return TRUE;
}
+/**
+ * ostree_repo_static_delta_execute_offline:
+ * @self: Repo
+ * @dir_or_file: Path to a directory containing static delta data, or directly to the superblock
+ * @skip_validation: If %TRUE, assume data integrity
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Given a directory representing an already-downloaded static delta
+ * on disk, apply it, generating a new commit. The directory must be
+ * named with the form "FROM-TO", where both are checksums, and it
+ * must contain a file named "superblock", along with at least one part.
+ */
+gboolean
+ostree_repo_static_delta_execute_offline (OstreeRepo *self,
+ GFile *dir_or_file,
+ gboolean skip_validation,
+ GCancellable *cancellable,
+ GError **error)
+{
+ return ostree_repo_static_delta_execute_offline_with_signature(self, dir_or_file, NULL,
+ skip_validation,
+ cancellable,
+ error);
+}
+
gboolean
_ostree_static_delta_part_open (GInputStream *part_in,
GBytes *inline_part_bytes,
@@ -726,6 +906,8 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
GError **error)
{
glnx_autofd int superblock_fd = -1;
+ g_autoptr(GVariant) delta = NULL;
+ g_autoptr(GVariant) delta_superblock = NULL;
if (strchr (delta_id, '/'))
{
@@ -744,13 +926,28 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
return FALSE;
}
- g_autoptr(GVariant) delta_superblock = NULL;
- if (!ot_variant_read_fd (superblock_fd, 0,
- (GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
- TRUE, &delta_superblock, error))
- return FALSE;
+ gboolean is_signed = _ostree_repo_static_delta_is_signed(self, superblock_fd, NULL, NULL);
+ if (is_signed)
+ {
+ if (!ot_variant_read_fd (superblock_fd, 0, (GVariantType*)OSTREE_STATIC_DELTA_SIGNED_FORMAT,
+ TRUE, &delta, error))
+ return FALSE;
+
+ g_autoptr(GVariant) child = g_variant_get_child_value (delta, 1);
+ g_autoptr(GBytes) bytes = g_variant_get_data_as_bytes(child);
+ delta_superblock = g_variant_new_from_bytes ((GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
+ bytes, FALSE);
+ }
+ else
+ {
+ if (!ot_variant_read_fd (superblock_fd, 0,
+ (GVariantType*)OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT,
+ TRUE, &delta_superblock, error))
+ return FALSE;
+ }
g_print ("Delta: %s\n", delta_id);
+ g_print ("Signed: %s\n", is_signed ? "yes" : "no");
g_autoptr(GVariant) from_commit_v = NULL;
g_variant_get_child (delta_superblock, 2, "@ay", &from_commit_v);
g_autofree char *from_commit = NULL;
@@ -873,3 +1070,51 @@ _ostree_repo_static_delta_dump (OstreeRepo *self,
return TRUE;
}
+
+/**
+ * ostree_repo_static_delta_verify_signature:
+ * @self: Repo
+ * @delta_id: delta path
+ * @sign: Signature engine used to check superblock
+ * @out_success_message: success message
+ * @error: Error
+ *
+ * Verify static delta file signature.
+ *
+ * Returns: TRUE if the signature of static delta file is valid using the
+ * signature engine provided, FALSE otherwise.
+ *
+ * Since: 2020.7
+ */
+gboolean
+ostree_repo_static_delta_verify_signature (OstreeRepo *self,
+ const char *delta_id,
+ OstreeSign *sign,
+ char **out_success_message,
+ GError **error)
+{
+ g_autoptr(GVariant) delta_meta = NULL;
+ glnx_autofd int delta_fd = -1;
+
+ if (strchr (delta_id, '/'))
+ {
+ if (!glnx_openat_rdonly (AT_FDCWD, delta_id, TRUE, &delta_fd, error))
+ return FALSE;
+ }
+ else
+ {
+ g_autofree char *from = NULL;
+ g_autofree char *to = NULL;
+ if (!_ostree_parse_delta_name (delta_id, &from, &to, error))
+ return FALSE;
+
+ g_autofree char *delta_path = _ostree_get_relative_static_delta_superblock_path (from, to);
+ if (!glnx_openat_rdonly (self->repo_dir_fd, delta_path, TRUE, &delta_fd, error))
+ return FALSE;
+ }
+
+ if (!_ostree_repo_static_delta_is_signed (self, delta_fd, NULL, error))
+ return FALSE;
+
+ return _ostree_repo_static_delta_verify_signature (self, delta_fd, sign, out_success_message, error);
+}
diff --git a/src/libostree/ostree-repo-static-delta-private.h b/src/libostree/ostree-repo-static-delta-private.h
index 155acd5..5a2e687 100644
--- a/src/libostree/ostree-repo-static-delta-private.h
+++ b/src/libostree/ostree-repo-static-delta-private.h
@@ -104,6 +104,25 @@ G_BEGIN_DECLS
*/
#define OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT "(a{sv}tayay" OSTREE_COMMIT_GVARIANT_STRING "aya" OSTREE_STATIC_DELTA_META_ENTRY_FORMAT "a" OSTREE_STATIC_DELTA_FALLBACK_FORMAT ")"
+/**
+ * OSTREE_STATIC_DELTA_SIGNED_FORMAT
+ *
+ * magic: t magic number, 8 bytes for alignment
+ * superblock: ay delta supeblock variant
+ * signatures: a{sv}
+ *
+ * The signed static delta starts with the 'OSTSGNDT' magic number followed by
+ * the array of bytes containing the superblock used for the signature.
+ *
+ * Then, the signatures array contains the signatures of the superblock. A
+ * signature has the following form:
+ * type: signature key
+ * signature: variant depending on type used
+ */
+#define OSTREE_STATIC_DELTA_SIGNED_FORMAT "(taya{sv})"
+
+#define OSTREE_STATIC_DELTA_SIGNED_MAGIC 0x4F535453474E4454 /* OSTSGNDT */
+
typedef enum {
OSTREE_STATIC_DELTA_OPEN_FLAGS_NONE = 0,
OSTREE_STATIC_DELTA_OPEN_FLAGS_SKIP_CHECKSUM = (1 << 0),
@@ -190,6 +209,12 @@ _ostree_repo_static_delta_query_exists (OstreeRepo *repo,
gboolean *out_exists,
GCancellable *cancellable,
GError **error);
+GVariant *
+_ostree_repo_static_delta_superblock_digest (OstreeRepo *repo,
+ const char *from,
+ const char *to,
+ GCancellable *cancellable,
+ GError **error);
gboolean
_ostree_repo_static_delta_dump (OstreeRepo *repo,
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 95eb0ef..ba3e877 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -3782,14 +3782,14 @@ load_metadata_internal (OstreeRepo *self,
g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (sha256);
*out_state = 0;
- glnx_autofd int fd = -1;
- if (!ot_openat_ignore_enoent (self->repo_dir_fd, commitpartial_path, &fd, error))
+ glnx_autofd int commitpartial_fd = -1;
+ if (!ot_openat_ignore_enoent (self->repo_dir_fd, commitpartial_path, &commitpartial_fd, error))
return FALSE;
- if (fd != -1)
+ if (commitpartial_fd != -1)
{
*out_state |= OSTREE_REPO_COMMIT_STATE_PARTIAL;
char reason;
- if (read (fd, &reason, 1) == 1)
+ if (read (commitpartial_fd, &reason, 1) == 1)
{
if (reason == 'f')
*out_state |= OSTREE_REPO_COMMIT_STATE_FSCK_PARTIAL;
@@ -5793,25 +5793,18 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
{
g_autofree char *from = NULL;
g_autofree char *to = NULL;
- if (!_ostree_parse_delta_name (delta_names->pdata[i], &from, &to, error))
- return FALSE;
-
- g_autofree char *superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to);
- glnx_autofd int superblock_file_fd = -1;
+ GVariant *digest;
- if (!glnx_openat_rdonly (self->repo_dir_fd, superblock, TRUE, &superblock_file_fd, error))
+ if (!_ostree_parse_delta_name (delta_names->pdata[i], &from, &to, error))
return FALSE;
- g_autoptr(GBytes) superblock_content = ot_fd_readall_or_mmap (superblock_file_fd, 0, error);
- if (!superblock_content)
+ digest = _ostree_repo_static_delta_superblock_digest (self,
+ (from && from[0]) ? from : NULL,
+ to, cancellable, error);
+ if (digest == NULL)
return FALSE;
- g_auto(OtChecksum) hasher = { 0, };
- ot_checksum_init (&hasher);
- ot_checksum_update_bytes (&hasher, superblock_content);
- guint8 digest[OSTREE_SHA256_DIGEST_LEN];
- ot_checksum_get_digest (&hasher, digest, sizeof (digest));
- g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], ot_gvariant_new_bytearray (digest, sizeof (digest)));
+ g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], digest);
}
if (delta_names->len > 0)
@@ -5823,6 +5816,24 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC)));
}
+ {
+ g_autofree char *remote_mode_str = NULL;
+ if (!ot_keyfile_get_value_with_default (self->config, "core", "mode", "bare",
+ &remote_mode_str, error))
+ return FALSE;
+ g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_MODE,
+ g_variant_new_string (remote_mode_str));
+ }
+
+ {
+ gboolean tombstone_commits = FALSE;
+ if (!ot_keyfile_get_boolean_with_default (self->config, "core", "tombstone-commits", FALSE,
+ &tombstone_commits, error))
+ return FALSE;
+ g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_TOMBSTONE_COMMITS,
+ g_variant_new_boolean (tombstone_commits));
+ }
+
/* Add refs which have a collection specified, which could be in refs/mirrors,
* refs/heads, and/or refs/remotes. */
{
@@ -5838,19 +5849,19 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
collection_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
(GDestroyNotify) g_hash_table_unref);
- const OstreeCollectionRef *ref;
+ const OstreeCollectionRef *c_ref;
const char *checksum;
- while (g_hash_table_iter_next (&iter, (gpointer *) &ref, (gpointer *) &checksum))
+ while (g_hash_table_iter_next (&iter, (gpointer *) &c_ref, (gpointer *) &checksum))
{
- GHashTable *ref_map = g_hash_table_lookup (collection_map, ref->collection_id);
+ GHashTable *ref_map = g_hash_table_lookup (collection_map, c_ref->collection_id);
if (ref_map == NULL)
{
ref_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
- g_hash_table_insert (collection_map, ref->collection_id, ref_map);
+ g_hash_table_insert (collection_map, c_ref->collection_id, ref_map);
}
- g_hash_table_insert (ref_map, ref->ref_name, (gpointer) checksum);
+ g_hash_table_insert (ref_map, c_ref->ref_name, (gpointer) checksum);
}
g_autoptr(GVariantBuilder) collection_refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sa(s(taya{sv}))}"));
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index e28af29..d52fc9c 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -32,6 +32,7 @@
#include "ostree-repo-finder.h"
#include "ostree-sepolicy.h"
#include "ostree-gpg-verify-result.h"
+#include "ostree-sign.h"
G_BEGIN_DECLS
@@ -1068,6 +1069,14 @@ gboolean ostree_repo_static_delta_generate (OstreeRepo *self,
GError **error);
_OSTREE_PUBLIC
+gboolean ostree_repo_static_delta_execute_offline_with_signature (OstreeRepo *self,
+ GFile *dir_or_file,
+ OstreeSign *sign,
+ gboolean skip_validation,
+ GCancellable *cancellable,
+ GError **error);
+
+_OSTREE_PUBLIC
gboolean ostree_repo_static_delta_execute_offline (OstreeRepo *self,
GFile *dir_or_file,
gboolean skip_validation,
@@ -1075,6 +1084,13 @@ gboolean ostree_repo_static_delta_execute_offline (OstreeRepo
GError **error);
_OSTREE_PUBLIC
+gboolean ostree_repo_static_delta_verify_signature (OstreeRepo *self,
+ const char *delta_id,
+ OstreeSign *sign,
+ char **out_success_message,
+ GError **error);
+
+_OSTREE_PUBLIC
GHashTable *ostree_repo_traverse_new_reachable (void);
_OSTREE_PUBLIC
diff --git a/src/libostree/ostree-sign.c b/src/libostree/ostree-sign.c
index bcb5d0a..eeef96d 100644
--- a/src/libostree/ostree-sign.c
+++ b/src/libostree/ostree-sign.c
@@ -271,7 +271,7 @@ ostree_sign_load_pk (OstreeSign *self,
* ostree_sign_data:
* @self: an #OstreeSign object
* @data: the raw data to be signed with pre-loaded secret key
- * @signature: in case of success will contain signature
+ * @signature: (out): in case of success will contain signature
* @cancellable: A #GCancellable
* @error: a #GError
*
@@ -305,6 +305,7 @@ ostree_sign_data (OstreeSign *self,
* @self: an #OstreeSign object
* @data: the raw data to check
* @signatures: the signatures to be checked
+ * @out_success_message: (out) (nullable) (optional): success message returned by the signing engine
* @error: a #GError
*
* Verify given data against signatures with pre-loaded public keys.
@@ -364,7 +365,7 @@ _sign_detached_metadata_append (OstreeSign *self,
signature_key,
g_variant_builder_end (signature_builder));
- return g_variant_dict_end (&metadata_dict);
+ return g_variant_ref_sink (g_variant_dict_end (&metadata_dict));
}
/**
@@ -372,6 +373,7 @@ _sign_detached_metadata_append (OstreeSign *self,
* @self: an #OstreeSign object
* @repo: an #OsreeRepo object
* @commit_checksum: SHA256 of given commit to verify
+ * @out_success_message: (out) (nullable) (optional): success message returned by the signing engine
* @cancellable: A #GCancellable
* @error: a #GError
*
@@ -593,6 +595,8 @@ ostree_sign_get_by_name (const gchar *name, GError **error)
* Based on ostree_repo_add_gpg_signature_summary implementation.
*
* Returns: @TRUE if summary file has been signed with all provided keys
+ *
+ * Since: 2020.2
*/
gboolean
ostree_sign_summary (OstreeSign *self,
diff --git a/src/libostree/ostree-sign.h b/src/libostree/ostree-sign.h
index 0d06905..75dd483 100644
--- a/src/libostree/ostree-sign.h
+++ b/src/libostree/ostree-sign.h
@@ -52,6 +52,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/**
* OSTREE_SIGN_NAME_ED25519:
* The name of the default ed25519 signing type.
+ *
+ * Since: 2020.4
*/
#define OSTREE_SIGN_NAME_ED25519 "ed25519"
diff --git a/src/libostree/ostree-soup-uri.c b/src/libostree/ostree-soup-uri.c
index a3fa2ac..ba14e5c 100644
--- a/src/libostree/ostree-soup-uri.c
+++ b/src/libostree/ostree-soup-uri.c
@@ -348,7 +348,7 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string)
{
SoupURI *uri, fixed_base;
const char *end, *hash, *colon, *at, *path, *question;
- const char *p, *hostend;
+ const char *c, *hostend;
gboolean remove_dot_segments = TRUE;
int len;
@@ -402,17 +402,17 @@ soup_uri_new_with_base (SoupURI *base, const char *uri_string)
}
/* Find scheme */
- p = uri_string;
- while (p < end && (g_ascii_isalpha (*p) ||
- (p > uri_string && (g_ascii_isdigit (*p) ||
- *p == '.' ||
- *p == '+' ||
- *p == '-'))))
- p++;
-
- if (p > uri_string && *p == ':') {
- uri->scheme = soup_uri_parse_scheme (uri_string, p - uri_string);
- uri_string = p + 1;
+ c = uri_string;
+ while (c < end && (g_ascii_isalpha (*c) ||
+ (c > uri_string && (g_ascii_isdigit (*c) ||
+ *c == '.' ||
+ *c == '+' ||
+ *c == '-'))))
+ c++;
+
+ if (c > uri_string && *c == ':') {
+ uri->scheme = soup_uri_parse_scheme (uri_string, c - uri_string);
+ uri_string = c + 1;
}
if (uri_string == end && !base && !uri->fragment) {
diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c
index 71d978e..2712283 100644
--- a/src/libostree/ostree-sysroot-cleanup.c
+++ b/src/libostree/ostree-sysroot-cleanup.c
@@ -295,9 +295,11 @@ cleanup_old_deployments (OstreeSysroot *self,
/* Load all active deployments referenced by bootloader configuration. */
g_autoptr(GHashTable) active_deployment_dirs =
- g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL);
+ g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_autoptr(GHashTable) active_boot_checksums =
- g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL);
+ g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ g_autoptr(GHashTable) active_overlay_initrds =
+ g_hash_table_new (g_str_hash, g_str_equal); /* borrows from deployment's bootconfig */
for (guint i = 0; i < self->deployments->len; i++)
{
OstreeDeployment *deployment = self->deployments->pdata[i];
@@ -306,6 +308,11 @@ cleanup_old_deployments (OstreeSysroot *self,
/* Transfer ownership */
g_hash_table_replace (active_deployment_dirs, deployment_path, deployment_path);
g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum);
+
+ OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
+ char **initrds = ostree_bootconfig_parser_get_overlay_initrds (bootconfig);
+ for (char **it = initrds; it && *it; it++)
+ g_hash_table_add (active_overlay_initrds, (char*)glnx_basename (*it));
}
/* Find all deployment directories, both active and inactive */
@@ -349,6 +356,42 @@ cleanup_old_deployments (OstreeSysroot *self,
return FALSE;
}
+ /* Clean up overlay initrds */
+ glnx_autofd int overlays_dfd =
+ glnx_opendirat_with_errno (self->sysroot_fd, _OSTREE_SYSROOT_INITRAMFS_OVERLAYS, FALSE);
+ if (overlays_dfd < 0)
+ {
+ if (errno != ENOENT)
+ return glnx_throw_errno_prefix (error, "open(initrd_overlays)");
+ }
+ else
+ {
+ g_autoptr(GPtrArray) initrds_to_delete = g_ptr_array_new_with_free_func (g_free);
+ g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
+ if (!glnx_dirfd_iterator_init_at (overlays_dfd, ".", TRUE, &dfd_iter, error))
+ return FALSE;
+ while (TRUE)
+ {
+ struct dirent *dent;
+ if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
+ return FALSE;
+ if (dent == NULL)
+ break;
+
+ /* there shouldn't be other file types there, but let's be conservative */
+ if (dent->d_type != DT_REG)
+ continue;
+
+ if (!g_hash_table_lookup (active_overlay_initrds, dent->d_name))
+ g_ptr_array_add (initrds_to_delete, g_strdup (dent->d_name));
+ }
+ for (guint i = 0; i < initrds_to_delete->len; i++)
+ {
+ if (!ot_ensure_unlinked_at (overlays_dfd, initrds_to_delete->pdata[i], error))
+ return FALSE;
+ }
+ }
+
return TRUE;
}
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index cb59302..7b7ba5e 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -111,7 +111,6 @@ install_into_boot (OstreeRepo *repo,
const char *src_subpath,
int dest_dfd,
const char *dest_subpath,
- OstreeSysrootDebugFlags flags,
GCancellable *cancellable,
GError **error)
{
@@ -273,13 +272,13 @@ checksum_dir_recurse (int dfd,
}
else
{
- int fd;
+ glnx_autofd int fd = -1;
if (!ot_openat_ignore_enoent (dfditer.fd, d_name, &fd, error))
return FALSE;
if (fd != -1)
{
- g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE);
+ g_autoptr(GInputStream) in = g_unix_input_stream_new (glnx_steal_fd (&fd), TRUE);
if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error))
return FALSE;
}
@@ -314,7 +313,7 @@ copy_dir_recurse (int src_parent_dfd,
if (!dirfd_copy_attributes_and_xattrs (src_parent_dfd, name, src_dfd_iter.fd, dest_dfd,
flags, cancellable, error))
- return FALSE;
+ return glnx_prefix_error (error, "Copying attributes of %s", name);
while (TRUE)
{
@@ -341,7 +340,7 @@ copy_dir_recurse (int src_parent_dfd,
dest_dfd, dent->d_name,
sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags),
cancellable, error))
- return FALSE;
+ return glnx_prefix_error (error, "Copying %s", dent->d_name);
}
}
@@ -489,7 +488,7 @@ copy_modified_config_file (int orig_etc_fd,
new_etc_fd, path,
sysroot_flags_to_copy_flags (GLNX_FILE_COPY_OVERWRITE, flags),
cancellable, error))
- return FALSE;
+ return glnx_prefix_error (error, "Copying %s", path);
}
else
{
@@ -1029,7 +1028,8 @@ _ostree_kernel_layout_new (void)
/* See get_kernel_from_tree() below */
static gboolean
-get_kernel_from_tree_usrlib_modules (int deployment_dfd,
+get_kernel_from_tree_usrlib_modules (OstreeSysroot *sysroot,
+ int deployment_dfd,
OstreeKernelLayout **out_layout,
GCancellable *cancellable,
GError **error)
@@ -1138,37 +1138,41 @@ get_kernel_from_tree_usrlib_modules (int deployment_dfd,
g_clear_object (&in);
glnx_close_fd (&fd);
- /* Check for /usr/lib/modules/$kver/devicetree first, if it does not
- * exist check for /usr/lib/modules/$kver/dtb/ directory.
- */
- if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "devicetree", &fd, error))
- return FALSE;
- if (fd != -1)
- {
- ret_layout->devicetree_srcpath = g_strdup ("devicetree");
- ret_layout->devicetree_namever = g_strdup_printf ("devicetree-%s", kver);
- in = g_unix_input_stream_new (fd, FALSE);
- if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
- return FALSE;
- }
- else
+ /* Testing aid for https://github.com/ostreedev/ostree/issues/2154 */
+ const gboolean no_dtb = (sysroot->debug_flags & OSTREE_SYSROOT_DEBUG_TEST_NO_DTB) > 0;
+ if (!no_dtb)
{
- struct stat stbuf;
- /* Check for dtb directory */
- if (!glnx_fstatat_allow_noent (ret_layout->boot_dfd, "dtb", &stbuf, 0, error))
+ /* Check for /usr/lib/modules/$kver/devicetree first, if it does not
+ * exist check for /usr/lib/modules/$kver/dtb/ directory.
+ */
+ if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, "devicetree", &fd, error))
return FALSE;
-
- if (errno == 0 && S_ISDIR (stbuf.st_mode))
+ if (fd != -1)
{
- /* devicetree_namever set to NULL indicates a complete directory */
- ret_layout->devicetree_srcpath = g_strdup ("dtb");
- ret_layout->devicetree_namever = NULL;
-
- if (!checksum_dir_recurse(ret_layout->boot_dfd, "dtb", &checksum, cancellable, error))
+ ret_layout->devicetree_srcpath = g_strdup ("devicetree");
+ ret_layout->devicetree_namever = g_strdup_printf ("devicetree-%s", kver);
+ in = g_unix_input_stream_new (fd, FALSE);
+ if (!ot_gio_splice_update_checksum (NULL, in, &checksum, cancellable, error))
return FALSE;
}
- }
+ else
+ {
+ struct stat stbuf;
+ /* Check for dtb directory */
+ if (!glnx_fstatat_allow_noent (ret_layout->boot_dfd, "dtb", &stbuf, 0, error))
+ return FALSE;
+ if (errno == 0 && S_ISDIR (stbuf.st_mode))
+ {
+ /* devicetree_namever set to NULL indicates a complete directory */
+ ret_layout->devicetree_srcpath = g_strdup ("dtb");
+ ret_layout->devicetree_namever = NULL;
+
+ if (!checksum_dir_recurse(ret_layout->boot_dfd, "dtb", &checksum, cancellable, error))
+ return FALSE;
+ }
+ }
+ }
g_clear_object (&in);
glnx_close_fd (&fd);
@@ -1337,7 +1341,8 @@ get_kernel_from_tree_legacy_layouts (int deployment_dfd,
* initramfs there, so we need to look in /usr/lib/ostree-boot first.
*/
static gboolean
-get_kernel_from_tree (int deployment_dfd,
+get_kernel_from_tree (OstreeSysroot *sysroot,
+ int deployment_dfd,
OstreeKernelLayout **out_layout,
GCancellable *cancellable,
GError **error)
@@ -1346,7 +1351,7 @@ get_kernel_from_tree (int deployment_dfd,
g_autoptr(OstreeKernelLayout) legacy_layout = NULL;
/* First, gather from usr/lib/modules/$kver if it exists */
- if (!get_kernel_from_tree_usrlib_modules (deployment_dfd, &usrlib_modules_layout, cancellable, error))
+ if (!get_kernel_from_tree_usrlib_modules (sysroot, deployment_dfd, &usrlib_modules_layout, cancellable, error))
return FALSE;
/* Gather the legacy layout */
@@ -1762,7 +1767,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
/* Find the kernel/initramfs/devicetree in the tree */
g_autoptr(OstreeKernelLayout) kernel_layout = NULL;
- if (!get_kernel_from_tree (deployment_dfd, &kernel_layout,
+ if (!get_kernel_from_tree (sysroot, deployment_dfd, &kernel_layout,
cancellable, error))
return FALSE;
@@ -1772,7 +1777,6 @@ install_deployment_kernel (OstreeSysroot *sysroot,
const char *osname = ostree_deployment_get_osname (deployment);
const char *bootcsum = ostree_deployment_get_bootcsum (deployment);
- g_assert_cmpstr (kernel_layout->bootcsum, ==, 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-%d-%s.conf",
@@ -1798,7 +1802,6 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{
if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->kernel_srcpath,
bootcsum_dfd, kernel_layout->kernel_namever,
- sysroot->debug_flags,
cancellable, error))
return FALSE;
}
@@ -1815,7 +1818,6 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{
if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->initramfs_srcpath,
bootcsum_dfd, kernel_layout->initramfs_namever,
- sysroot->debug_flags,
cancellable, error))
return FALSE;
}
@@ -1832,7 +1834,6 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{
if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->devicetree_srcpath,
bootcsum_dfd, kernel_layout->devicetree_namever,
- sysroot->debug_flags,
cancellable, error))
return FALSE;
}
@@ -1853,12 +1854,52 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{
if (!install_into_boot (repo, sepolicy, kernel_layout->boot_dfd, kernel_layout->kernel_hmac_srcpath,
bootcsum_dfd, kernel_layout->kernel_hmac_namever,
- sysroot->debug_flags,
cancellable, error))
return FALSE;
}
}
+ g_autoptr(GPtrArray) overlay_initrds = NULL;
+ for (char **it = _ostree_deployment_get_overlay_initrds (deployment); it && *it; it++)
+ {
+ char *checksum = *it;
+
+ /* Overlay initrds are not part of the bootcsum dir; they're not part of the tree
+ * proper. Instead they're in /boot/ostree/initramfs-overlays/ named by their csum.
+ * Doing it this way allows sharing the same bootcsum dir for multiple deployments
+ * with the only change being in overlay initrds (or conversely, the same overlay
+ * across different boocsums). Eventually, it'd be nice to have an OSTree repo in
+ * /boot itself and drop the boocsum dir concept entirely. */
+
+ g_autofree char *destpath =
+ g_strdup_printf ("/" _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS "/%s.img", checksum);
+ const char *rel_destpath = destpath + 1;
+
+ /* lazily allocate array and create dir so we don't pollute /boot if not needed */
+ if (overlay_initrds == NULL)
+ {
+ overlay_initrds = g_ptr_array_new_with_free_func (g_free);
+
+ if (!glnx_shutil_mkdir_p_at (boot_dfd, _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS,
+ 0755, cancellable, error))
+ return FALSE;
+ }
+
+ if (!glnx_fstatat_allow_noent (boot_dfd, rel_destpath, NULL, 0, error))
+ return FALSE;
+ if (errno == ENOENT)
+ {
+ g_autofree char *srcpath =
+ g_strdup_printf (_OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR "/%s", checksum);
+ if (!install_into_boot (repo, sepolicy, AT_FDCWD, srcpath, boot_dfd, rel_destpath,
+ cancellable, error))
+ return FALSE;
+ }
+
+ /* these are used lower down to populate the bootconfig */
+ g_ptr_array_add (overlay_initrds, g_steal_pointer (&destpath));
+ }
+
g_autofree char *contents = NULL;
if (!glnx_fstatat_allow_noent (deployment_dfd, "usr/lib/os-release", &stbuf, 0, error))
return FALSE;
@@ -1935,8 +1976,15 @@ install_deployment_kernel (OstreeSysroot *sysroot,
if (kernel_layout->initramfs_namever)
{
- g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL);
- ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath);
+ g_autofree char * initrd_boot_relpath =
+ g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL);
+ ostree_bootconfig_parser_set (bootconfig, "initrd", initrd_boot_relpath);
+
+ if (overlay_initrds)
+ {
+ g_ptr_array_add (overlay_initrds, NULL);
+ ostree_bootconfig_parser_set_overlay_initrds (bootconfig, (char**)overlay_initrds->pdata);
+ }
}
else
{
@@ -1949,8 +1997,8 @@ install_deployment_kernel (OstreeSysroot *sysroot,
if (kernel_layout->devicetree_namever)
{
- g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_namever, NULL);
- ostree_bootconfig_parser_set (bootconfig, "devicetree", boot_relpath);
+ g_autofree char * dt_boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_namever, NULL);
+ ostree_bootconfig_parser_set (bootconfig, "devicetree", dt_boot_relpath);
}
else if (kernel_layout->devicetree_srcpath)
{
@@ -1958,8 +2006,8 @@ install_deployment_kernel (OstreeSysroot *sysroot,
* want to point to a whole directory of device trees.
* See: https://github.com/ostreedev/ostree/issues/1900
*/
- g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_srcpath, NULL);
- ostree_bootconfig_parser_set (bootconfig, "fdtdir", boot_relpath);
+ g_autofree char * dt_boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->devicetree_srcpath, NULL);
+ ostree_bootconfig_parser_set (bootconfig, "fdtdir", dt_boot_relpath);
}
/* Note this is parsed in ostree-impl-system-generator.c */
@@ -1998,6 +2046,12 @@ prepare_new_bootloader_link (OstreeSysroot *sysroot,
g_assert ((current_bootversion == 0 && new_bootversion == 1) ||
(current_bootversion == 1 && new_bootversion == 0));
+ /* This allows us to support both /boot on a seperate filesystem to / as well
+ * as on the same filesystem. */
+ if (TEMP_FAILURE_RETRY (symlinkat (".", sysroot->sysroot_fd, "boot/boot")) < 0)
+ if (errno != EEXIST)
+ return glnx_throw_errno_prefix (error, "symlinkat");
+
g_autofree char *new_target = g_strdup_printf ("loader.%d", new_bootversion);
/* We shouldn't actually need to replace but it's easier to reuse
@@ -2128,6 +2182,10 @@ deployment_bootconfigs_equal (OstreeRepo *repo,
if (strcmp (a_bootcsum, b_bootcsum) != 0)
return FALSE;
+ /* same initrd overlays? */
+ if (g_strcmp0 (a->overlay_initrds_id, b->overlay_initrds_id) != 0)
+ return FALSE;
+
/* same kargs? */
g_autofree char *a_boot_options_without_ostree = get_deployment_nonostree_kargs (a);
g_autofree char *b_boot_options_without_ostree = get_deployment_nonostree_kargs (b);
@@ -2681,7 +2739,7 @@ sysroot_initialize_deployment (OstreeSysroot *self,
const char *osname,
const char *revision,
GKeyFile *origin,
- char **override_kernel_argv,
+ OstreeSysrootDeployTreeOpts *opts,
OstreeDeployment **out_new_deployment,
GCancellable *cancellable,
GError **error)
@@ -2698,10 +2756,8 @@ sysroot_initialize_deployment (OstreeSysroot *self,
cancellable, error))
return FALSE;
- g_autofree char *new_bootcsum = NULL;
g_autoptr(OstreeDeployment) new_deployment =
- ostree_deployment_new (0, osname, revision, new_deployserial,
- new_bootcsum, -1);
+ ostree_deployment_new (0, osname, revision, new_deployserial, NULL, -1);
ostree_deployment_set_origin (new_deployment, origin);
/* Check out the userspace tree onto the filesystem */
@@ -2711,12 +2767,13 @@ sysroot_initialize_deployment (OstreeSysroot *self,
return FALSE;
g_autoptr(OstreeKernelLayout) kernel_layout = NULL;
- if (!get_kernel_from_tree (deployment_dfd, &kernel_layout,
+ if (!get_kernel_from_tree (self, deployment_dfd, &kernel_layout,
cancellable, error))
return FALSE;
_ostree_deployment_set_bootcsum (new_deployment, kernel_layout->bootcsum);
- _ostree_deployment_set_bootconfig_from_kargs (new_deployment, override_kernel_argv);
+ _ostree_deployment_set_bootconfig_from_kargs (new_deployment, opts ? opts->override_kernel_argv : NULL);
+ _ostree_deployment_set_overlay_initrds (new_deployment, opts ? opts->overlay_initrds : NULL);
if (!prepare_deployment_etc (self, repo, new_deployment, deployment_dfd,
cancellable, error))
@@ -2770,7 +2827,6 @@ get_var_dfd (OstreeSysroot *self,
static gboolean
sysroot_finalize_deployment (OstreeSysroot *self,
OstreeDeployment *deployment,
- char **override_kernel_argv,
OstreeDeployment *merge_deployment,
GCancellable *cancellable,
GError **error)
@@ -2780,15 +2836,18 @@ sysroot_finalize_deployment (OstreeSysroot *self,
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error))
return FALSE;
- /* Only use the merge if we didn't get an override */
- if (!override_kernel_argv && merge_deployment)
+ OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (deployment);
+
+ /* If the kargs weren't set yet, then just pick it up from the merge deployment. In the
+ * deploy path, overrides are set as part of sysroot_initialize_deployment(). In the
+ * finalize-staged path, they're set by OstreeSysroot when reading the staged GVariant. */
+ if (merge_deployment && ostree_bootconfig_parser_get (bootconfig, "options") == NULL)
{
- /* Override the bootloader arguments */
OstreeBootconfigParser *merge_bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
if (merge_bootconfig)
{
- const char *opts = ostree_bootconfig_parser_get (merge_bootconfig, "options");
- ostree_bootconfig_parser_set (ostree_deployment_get_bootconfig (deployment), "options", opts);
+ const char *kargs = ostree_bootconfig_parser_get (merge_bootconfig, "options");
+ ostree_bootconfig_parser_set (bootconfig, "options", kargs);
}
}
@@ -2846,13 +2905,13 @@ sysroot_finalize_deployment (OstreeSysroot *self,
}
/**
- * ostree_sysroot_deploy_tree:
+ * ostree_sysroot_deploy_tree_with_options:
* @self: Sysroot
* @osname: (allow-none): osname to use for merge deployment
* @revision: Checksum to add
* @origin: (allow-none): Origin to use for upgrades
* @provided_merge_deployment: (allow-none): Use this deployment for merge path
- * @override_kernel_argv: (allow-none) (array zero-terminated=1) (element-type utf8): Use these as kernel arguments; if %NULL, inherit options from provided_merge_deployment
+ * @opts: (allow-none): Options
* @out_new_deployment: (out): The new deployment path
* @cancellable: Cancellable
* @error: Error
@@ -2860,30 +2919,31 @@ sysroot_finalize_deployment (OstreeSysroot *self,
* Check out deployment tree with revision @revision, performing a 3
* way merge with @provided_merge_deployment for configuration.
*
- * While this API is not deprecated, you most likely want to use the
- * ostree_sysroot_stage_tree() API.
+ * When booted into the sysroot, you should use the
+ * ostree_sysroot_stage_tree() API instead.
+ *
+ * Since: 2020.7
*/
gboolean
-ostree_sysroot_deploy_tree (OstreeSysroot *self,
- const char *osname,
- const char *revision,
- GKeyFile *origin,
- OstreeDeployment *provided_merge_deployment,
- char **override_kernel_argv,
- OstreeDeployment **out_new_deployment,
- GCancellable *cancellable,
- GError **error)
+ostree_sysroot_deploy_tree_with_options (OstreeSysroot *self,
+ const char *osname,
+ const char *revision,
+ GKeyFile *origin,
+ OstreeDeployment *provided_merge_deployment,
+ OstreeSysrootDeployTreeOpts *opts,
+ OstreeDeployment **out_new_deployment,
+ GCancellable *cancellable,
+ GError **error)
{
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;
g_autoptr(OstreeDeployment) deployment = NULL;
- if (!sysroot_initialize_deployment (self, osname, revision, origin, override_kernel_argv,
+ if (!sysroot_initialize_deployment (self, osname, revision, origin, opts,
&deployment, cancellable, error))
return FALSE;
- if (!sysroot_finalize_deployment (self, deployment, override_kernel_argv,
- provided_merge_deployment,
+ if (!sysroot_finalize_deployment (self, deployment, provided_merge_deployment,
cancellable, error))
return FALSE;
@@ -2891,6 +2951,39 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self,
return TRUE;
}
+/**
+ * ostree_sysroot_deploy_tree:
+ * @self: Sysroot
+ * @osname: (allow-none): osname to use for merge deployment
+ * @revision: Checksum to add
+ * @origin: (allow-none): Origin to use for upgrades
+ * @provided_merge_deployment: (allow-none): Use this deployment for merge path
+ * @override_kernel_argv: (allow-none) (array zero-terminated=1) (element-type utf8): Use these as kernel arguments; if %NULL, inherit options from provided_merge_deployment
+ * @out_new_deployment: (out): The new deployment path
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Older version of ostree_sysroot_stage_tree_with_options().
+ *
+ * Since: 2018.5
+ */
+gboolean
+ostree_sysroot_deploy_tree (OstreeSysroot *self,
+ const char *osname,
+ const char *revision,
+ GKeyFile *origin,
+ OstreeDeployment *provided_merge_deployment,
+ char **override_kernel_argv,
+ OstreeDeployment **out_new_deployment,
+ GCancellable *cancellable,
+ GError **error)
+{
+ OstreeSysrootDeployTreeOpts opts = { .override_kernel_argv = override_kernel_argv };
+ return ostree_sysroot_deploy_tree_with_options (self, osname, revision, origin,
+ provided_merge_deployment, &opts,
+ out_new_deployment, cancellable, error);
+}
+
/* Serialize information about a deployment to a variant, used by the staging
* code.
*/
@@ -2951,6 +3044,63 @@ _ostree_sysroot_deserialize_deployment_from_variant (GVariant *v,
/**
+ * ostree_sysroot_stage_overlay_initrd:
+ * @self: Sysroot
+ * @fd: (transfer none): File descriptor to overlay initrd
+ * @out_checksum: (out) (transfer full): Overlay initrd checksum
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Stage an overlay initrd to be used in an upcoming deployment. Returns a checksum which
+ * can be passed to ostree_sysroot_deploy_tree_with_options() or
+ * ostree_sysroot_stage_tree_with_options() via the `overlay_initrds` array option.
+ *
+ * Since: 2020.7
+ */
+gboolean
+ostree_sysroot_stage_overlay_initrd (OstreeSysroot *self,
+ int fd,
+ char **out_checksum,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (fd != -1, FALSE);
+ g_return_val_if_fail (out_checksum != NULL, FALSE);
+
+ if (!glnx_shutil_mkdir_p_at (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR,
+ 0755, cancellable, error))
+ return FALSE;
+
+ glnx_autofd int staged_initrds_dfd = -1;
+ if (!glnx_opendirat (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR, FALSE,
+ &staged_initrds_dfd, error))
+ return FALSE;
+
+ g_auto(GLnxTmpfile) overlay_initrd = { 0, };
+ if (!glnx_open_tmpfile_linkable_at (staged_initrds_dfd, ".", O_WRONLY | O_CLOEXEC,
+ &overlay_initrd, error))
+ return FALSE;
+
+ char checksum[_OSTREE_SHA256_STRING_LEN+1];
+ {
+ g_autoptr(GOutputStream) output = g_unix_output_stream_new (overlay_initrd.fd, FALSE);
+ g_autoptr(GInputStream) input = g_unix_input_stream_new (fd, FALSE);
+ g_autofree guchar *digest = NULL;
+ if (!ot_gio_splice_get_checksum (output, input, &digest, cancellable, error))
+ return FALSE;
+ ot_bin2hex (checksum, (guint8*)digest, _OSTREE_SHA256_DIGEST_LEN);
+ }
+
+ if (!glnx_link_tmpfile_at (&overlay_initrd, GLNX_LINK_TMPFILE_REPLACE,
+ staged_initrds_dfd, checksum, error))
+ return FALSE;
+
+ *out_checksum = g_strdup (checksum);
+ return TRUE;
+}
+
+
+/**
* ostree_sysroot_stage_tree:
* @self: Sysroot
* @osname: (allow-none): osname to use for merge deployment
@@ -2962,8 +3112,7 @@ _ostree_sysroot_deserialize_deployment_from_variant (GVariant *v,
* @cancellable: Cancellable
* @error: Error
*
- * Like ostree_sysroot_deploy_tree(), but "finalization" only occurs at OS
- * shutdown time.
+ * Older version of ostree_sysroot_stage_tree_with_options().
*
* Since: 2018.5
*/
@@ -2978,6 +3127,41 @@ ostree_sysroot_stage_tree (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
+ OstreeSysrootDeployTreeOpts opts = { .override_kernel_argv = override_kernel_argv };
+ return ostree_sysroot_stage_tree_with_options (self, osname, revision, origin,
+ merge_deployment, &opts,
+ out_new_deployment, cancellable, error);
+}
+
+
+/**
+ * ostree_sysroot_stage_tree_with_options:
+ * @self: Sysroot
+ * @osname: (allow-none): osname to use for merge deployment
+ * @revision: Checksum to add
+ * @origin: (allow-none): Origin to use for upgrades
+ * @merge_deployment: (allow-none): Use this deployment for merge path
+ * @opts: Options
+ * @out_new_deployment: (out): The new deployment path
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Like ostree_sysroot_deploy_tree(), but "finalization" only occurs at OS
+ * shutdown time.
+ *
+ * Since: 2020.7
+ */
+gboolean
+ostree_sysroot_stage_tree_with_options (OstreeSysroot *self,
+ const char *osname,
+ const char *revision,
+ GKeyFile *origin,
+ OstreeDeployment *merge_deployment,
+ OstreeSysrootDeployTreeOpts *opts,
+ OstreeDeployment **out_new_deployment,
+ GCancellable *cancellable,
+ GError **error)
+{
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;
@@ -3008,8 +3192,8 @@ ostree_sysroot_stage_tree (OstreeSysroot *self,
} /* OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH */
g_autoptr(OstreeDeployment) deployment = NULL;
- if (!sysroot_initialize_deployment (self, osname, revision, origin, override_kernel_argv,
- &deployment, cancellable, error))
+ if (!sysroot_initialize_deployment (self, osname, revision, origin, opts, &deployment,
+ cancellable, error))
return FALSE;
/* Write out the origin file using the sepolicy from the non-merged root for
@@ -3044,9 +3228,12 @@ ostree_sysroot_stage_tree (OstreeSysroot *self,
g_variant_builder_add (builder, "{sv}", "merge-deployment",
serialize_deployment_to_variant (merge_deployment));
- if (override_kernel_argv)
+ if (opts && opts->override_kernel_argv)
g_variant_builder_add (builder, "{sv}", "kargs",
- g_variant_new_strv ((const char *const*)override_kernel_argv, -1));
+ g_variant_new_strv ((const char *const*)opts->override_kernel_argv, -1));
+ if (opts && opts->overlay_initrds)
+ g_variant_builder_add (builder, "{sv}", "overlay-initrds",
+ g_variant_new_strv ((const char *const*)opts->overlay_initrds, -1));
const char *parent = dirname (strdupa (_OSTREE_SYSROOT_RUNSTATE_STAGED));
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, parent, 0755, cancellable, error))
@@ -3149,8 +3336,6 @@ _ostree_sysroot_finalize_staged (OstreeSysroot *self,
ostree_deployment_get_csum (merge_deployment_stub),
ostree_deployment_get_deployserial (merge_deployment_stub));
}
- g_autofree char **kargs = NULL;
- g_variant_lookup (self->staged_deployment_data, "kargs", "^a&s", &kargs);
/* Unlink the staged state now; if we're interrupted in the middle,
* we don't want e.g. deal with the partially written /etc merge.
@@ -3158,7 +3343,7 @@ _ostree_sysroot_finalize_staged (OstreeSysroot *self,
if (!glnx_unlinkat (AT_FDCWD, _OSTREE_SYSROOT_RUNSTATE_STAGED, 0, error))
return FALSE;
- if (!sysroot_finalize_deployment (self, self->staged_deployment, kargs, merge_deployment,
+ if (!sysroot_finalize_deployment (self, self->staged_deployment, merge_deployment,
cancellable, error))
return FALSE;
diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h
index 96670b1..318b0b1 100644
--- a/src/libostree/ostree-sysroot-private.h
+++ b/src/libostree/ostree-sysroot-private.h
@@ -38,6 +38,7 @@ typedef enum {
/* This is a temporary flag until we fully drop the explicit `systemctl start
* ostree-finalize-staged.service` so that tests can exercise the new path unit. */
OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH = 1 << 3,
+ OSTREE_SYSROOT_DEBUG_TEST_NO_DTB = 1 << 4, /* https://github.com/ostreedev/ostree/issues/2154 */
} OstreeSysrootDebugFlags;
typedef enum {
@@ -83,8 +84,13 @@ struct OstreeSysroot {
/* We keep some transient state in /run */
#define _OSTREE_SYSROOT_RUNSTATE_STAGED "/run/ostree/staged-deployment"
#define _OSTREE_SYSROOT_RUNSTATE_STAGED_LOCKED "/run/ostree/staged-deployment-locked"
+#define _OSTREE_SYSROOT_RUNSTATE_STAGED_INITRDS_DIR "/run/ostree/staged-initrds/"
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/"
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development"
+#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_TRANSIENT "unlocked-transient"
+
+#define _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS "ostree/initramfs-overlays"
+#define _OSTREE_SYSROOT_INITRAMFS_OVERLAYS "boot/" _OSTREE_SYSROOT_BOOT_INITRAMFS_OVERLAYS
gboolean
_ostree_sysroot_ensure_writable (OstreeSysroot *self,
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c
index 0dc7a39..e0813b5 100644
--- a/src/libostree/ostree-sysroot.c
+++ b/src/libostree/ostree-sysroot.c
@@ -190,6 +190,7 @@ ostree_sysroot_init (OstreeSysroot *self)
{ "test-fifreeze", OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE },
{ "no-xattrs", OSTREE_SYSROOT_DEBUG_NO_XATTRS },
{ "test-staged-path", OSTREE_SYSROOT_DEBUG_TEST_STAGED_PATH },
+ { "no-dtb", OSTREE_SYSROOT_DEBUG_TEST_NO_DTB },
};
self->debug_flags = g_parse_debug_string (g_getenv ("OSTREE_SYSROOT_DEBUG"),
@@ -747,9 +748,13 @@ parse_deployment (OstreeSysroot *self,
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE;
g_autofree char *unlocked_development_path =
_ostree_sysroot_get_runstate_path (ret_deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
+ g_autofree char *unlocked_transient_path =
+ _ostree_sysroot_get_runstate_path (ret_deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_TRANSIENT);
struct stat stbuf;
if (lstat (unlocked_development_path, &stbuf) == 0)
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
+ else if (lstat (unlocked_transient_path, &stbuf) == 0)
+ ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT;
else
{
GKeyFile *origin = ostree_deployment_get_origin (ret_deployment);
@@ -810,6 +815,24 @@ list_deployments_process_one_boot_entry (OstreeSysroot *self,
return FALSE;
ostree_deployment_set_bootconfig (deployment, config);
+ char **overlay_initrds = ostree_bootconfig_parser_get_overlay_initrds (config);
+ g_autoptr(GPtrArray) initrds_chksums = NULL;
+ for (char **it = overlay_initrds; it && *it; it++)
+ {
+ const char *basename = glnx_basename (*it);
+ if (strlen (basename) != (_OSTREE_SHA256_STRING_LEN + strlen (".img")))
+ return glnx_throw (error, "Malformed overlay initrd filename: %s", basename);
+
+ if (!initrds_chksums) /* lazy init */
+ initrds_chksums = g_ptr_array_new_full (g_strv_length (overlay_initrds), g_free);
+ g_ptr_array_add (initrds_chksums, g_strndup (basename, _OSTREE_SHA256_STRING_LEN));
+ }
+
+ if (initrds_chksums)
+ {
+ g_ptr_array_add (initrds_chksums, NULL);
+ _ostree_deployment_set_overlay_initrds (deployment, (char**)initrds_chksums->pdata);
+ }
g_ptr_array_add (inout_deployments, g_object_ref (deployment));
return TRUE;
@@ -962,8 +985,10 @@ _ostree_sysroot_reload_staged (OstreeSysroot *self,
/* Parse it */
g_autoptr(GVariant) target = NULL;
g_autofree char **kargs = NULL;
+ g_autofree char **overlay_initrds = NULL;
g_variant_dict_lookup (staged_deployment_dict, "target", "@a{sv}", &target);
g_variant_dict_lookup (staged_deployment_dict, "kargs", "^a&s", &kargs);
+ g_variant_dict_lookup (staged_deployment_dict, "overlay-initrds", "^a&s", &overlay_initrds);
if (target)
{
g_autoptr(OstreeDeployment) staged =
@@ -975,6 +1000,8 @@ _ostree_sysroot_reload_staged (OstreeSysroot *self,
if (!load_origin (self, staged, NULL, error))
return FALSE;
+ _ostree_deployment_set_overlay_initrds (staged, overlay_initrds);
+
self->staged_deployment = g_steal_pointer (&staged);
self->staged_deployment_data = g_steal_pointer (&staged_deployment_data);
/* We set this flag for ostree_deployment_is_staged() because that API
@@ -1932,6 +1959,8 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
const char *ovl_options = NULL;
static const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
+ g_autofree char *unlock_ovldir = NULL;
+
switch (unlocked_state)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
@@ -1951,11 +1980,12 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
}
break;
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
+ case OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT:
{
+ unlock_ovldir = g_strdup ("/var/tmp/ostree-unlock-ovl.XXXXXX");
/* We're just doing transient development/hacking? Okay,
* stick the overlayfs bits in /var/tmp.
*/
- char *development_ovldir = strdupa ("/var/tmp/ostree-unlock-ovl.XXXXXX");
const char *development_ovl_upper;
const char *development_ovl_work;
@@ -1966,14 +1996,14 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
"/usr", usr_mode, error))
return FALSE;
- if (g_mkdtemp_full (development_ovldir, 0755) == NULL)
+ if (g_mkdtemp_full (unlock_ovldir, 0755) == NULL)
return glnx_throw_errno_prefix (error, "mkdtemp");
}
- development_ovl_upper = glnx_strjoina (development_ovldir, "/upper");
+ development_ovl_upper = glnx_strjoina (unlock_ovldir, "/upper");
if (!mkdir_unmasked (AT_FDCWD, development_ovl_upper, usr_mode, cancellable, error))
return FALSE;
- development_ovl_work = glnx_strjoina (development_ovldir, "/work");
+ development_ovl_work = glnx_strjoina (unlock_ovldir, "/work");
if (!mkdir_unmasked (AT_FDCWD, development_ovl_work, usr_mode, cancellable, error))
return FALSE;
ovl_options = glnx_strjoina ("lowerdir=usr,upperdir=", development_ovl_upper,
@@ -1996,6 +2026,9 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return glnx_throw_errno_prefix (error, "fork");
else if (mount_child == 0)
{
+ int mountflags = 0;
+ if (unlocked_state == OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT)
+ mountflags |= MS_RDONLY;
/* Child process. Do NOT use any GLib API here; it's not generally fork() safe.
*
* TODO: report errors across a pipe (or use the journal?) rather than
@@ -2003,7 +2036,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
*/
if (fchdir (deployment_dfd) < 0)
err (1, "fchdir");
- if (mount ("overlay", "/usr", "overlay", 0, ovl_options) < 0)
+ if (mount ("overlay", "/usr", "overlay", mountflags, ovl_options) < 0)
err (1, "mount");
exit (EXIT_SUCCESS);
}
@@ -2036,15 +2069,19 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self,
return FALSE;
break;
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
+ case OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT:
{
g_autofree char *devpath =
- _ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
+ unlocked_state == OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT ?
+ _ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT)
+ :
+ _ostree_sysroot_get_runstate_path (deployment, _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_TRANSIENT);
g_autofree char *devpath_parent = dirname (g_strdup (devpath));
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error))
return FALSE;
- if (!g_file_set_contents (devpath, "", 0, error))
+ if (!g_file_set_contents (devpath, unlock_ovldir, -1, error))
return FALSE;
}
}
diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h
index d9f5a54..3a3b6a7 100644
--- a/src/libostree/ostree-sysroot.h
+++ b/src/libostree/ostree-sysroot.h
@@ -187,6 +187,21 @@ gboolean ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
GError **error);
_OSTREE_PUBLIC
+gboolean ostree_sysroot_stage_overlay_initrd (OstreeSysroot *self,
+ int fd,
+ char **out_checksum,
+ GCancellable *cancellable,
+ GError **error);
+
+typedef struct {
+ gboolean unused_bools[8];
+ int unused_ints[8];
+ char **override_kernel_argv;
+ char **overlay_initrds;
+ gpointer unused_ptrs[6];
+} OstreeSysrootDeployTreeOpts;
+
+_OSTREE_PUBLIC
gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self,
const char *osname,
const char *revision,
@@ -198,6 +213,17 @@ gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self,
GError **error);
_OSTREE_PUBLIC
+gboolean ostree_sysroot_deploy_tree_with_options (OstreeSysroot *self,
+ const char *osname,
+ const char *revision,
+ GKeyFile *origin,
+ OstreeDeployment *provided_merge_deployment,
+ OstreeSysrootDeployTreeOpts *opts,
+ OstreeDeployment **out_new_deployment,
+ GCancellable *cancellable,
+ GError **error);
+
+_OSTREE_PUBLIC
gboolean ostree_sysroot_stage_tree (OstreeSysroot *self,
const char *osname,
const char *revision,
@@ -209,6 +235,18 @@ gboolean ostree_sysroot_stage_tree (OstreeSysroot *self,
GError **error);
_OSTREE_PUBLIC
+gboolean ostree_sysroot_stage_tree_with_options (OstreeSysroot *self,
+ const char *osname,
+ const char *revision,
+ GKeyFile *origin,
+ OstreeDeployment *merge_deployment,
+ OstreeSysrootDeployTreeOpts *opts,
+ OstreeDeployment **out_new_deployment,
+ GCancellable *cancellable,
+ GError **error);
+
+
+_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
OstreeDeployment *deployment,
gboolean is_mutable,
diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h
index f9c398e..90e96ea 100644
--- a/src/libostree/ostree-version.h
+++ b/src/libostree/ostree-version.h
@@ -43,7 +43,7 @@
*
* Since: 2017.4
*/
-#define OSTREE_RELEASE_VERSION (4)
+#define OSTREE_RELEASE_VERSION (7)
/**
* OSTREE_VERSION
@@ -52,7 +52,7 @@
*
* Since: 2017.4
*/
-#define OSTREE_VERSION (2020.4)
+#define OSTREE_VERSION (2020.7)
/**
* OSTREE_VERSION_S:
@@ -62,7 +62,7 @@
*
* Since: 2017.4
*/
-#define OSTREE_VERSION_S "2020.4"
+#define OSTREE_VERSION_S "2020.7"
#define OSTREE_ENCODE_VERSION(year,release) \
((year) << 16 | (release))
diff --git a/src/libotutil/ot-checksum-utils.c b/src/libotutil/ot-checksum-utils.c
index 6676736..26e0280 100644
--- a/src/libotutil/ot-checksum-utils.c
+++ b/src/libotutil/ot-checksum-utils.c
@@ -275,3 +275,13 @@ ot_checksum_file_at (int dfd,
ot_checksum_get_hexdigest (&checksum, hexdigest, sizeof (hexdigest));
return g_strdup (hexdigest);
}
+
+void
+ot_checksum_bytes (GBytes *data,
+ guint8 out_digest[_OSTREE_SHA256_DIGEST_LEN])
+{
+ g_auto(OtChecksum) hasher = { 0, };
+ ot_checksum_init (&hasher);
+ ot_checksum_update_bytes (&hasher, data);
+ ot_checksum_get_digest (&hasher, out_digest, _OSTREE_SHA256_DIGEST_LEN);
+}
diff --git a/src/libotutil/ot-checksum-utils.h b/src/libotutil/ot-checksum-utils.h
index 411ef25..5432c81 100644
--- a/src/libotutil/ot-checksum-utils.h
+++ b/src/libotutil/ot-checksum-utils.h
@@ -96,4 +96,7 @@ char * ot_checksum_file_at (int dfd,
GCancellable *cancellable,
GError **error);
+void ot_checksum_bytes (GBytes *data,
+ guint8 out_digest[_OSTREE_SHA256_DIGEST_LEN]);
+
G_END_DECLS
diff --git a/src/libotutil/otutil.h b/src/libotutil/otutil.h
index cd31236..7db7270 100644
--- a/src/libotutil/otutil.h
+++ b/src/libotutil/otutil.h
@@ -52,6 +52,31 @@
#define ot_journal_print(...) {}
#endif
+typedef GMainContext GMainContextPopDefault;
+static inline void
+_ostree_main_context_pop_default_destroy (void *p)
+{
+ GMainContext *main_context = p;
+
+ if (main_context)
+ {
+ g_main_context_pop_thread_default (main_context);
+ g_main_context_unref (main_context);
+ }
+}
+
+static inline GMainContextPopDefault *
+_ostree_main_context_new_default (void)
+{
+ GMainContext *main_context = g_main_context_new ();
+
+ g_main_context_push_thread_default (main_context);
+ return main_context;
+}
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GMainContextPopDefault, _ostree_main_context_pop_default_destroy)
+
+
#include
#include
#include
diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c
index bcece3f..8156cc1 100644
--- a/src/ostree/ot-admin-builtin-deploy.c
+++ b/src/ostree/ot-admin-builtin-deploy.c
@@ -44,6 +44,7 @@ static gboolean opt_kernel_proc_cmdline;
static char *opt_osname;
static char *opt_origin_path;
static gboolean opt_kernel_arg_none;
+static char **opt_overlay_initrds;
static GOptionEntry options[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" },
@@ -59,6 +60,7 @@ static GOptionEntry options[] = {
{ "karg", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv, "Set kernel argument, like root=/dev/sda1; this overrides any earlier argument with the same name", "NAME=VALUE" },
{ "karg-append", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv_append, "Append kernel argument; useful with e.g. console= that can be used multiple times", "NAME=VALUE" },
{ "karg-none", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_arg_none, "Do not import kernel arguments", NULL },
+ { "overlay-initrd", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_overlay_initrds, "Overlay iniramfs file", "FILE" },
{ NULL }
};
@@ -167,24 +169,76 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocat
ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append);
}
- g_autoptr(OstreeDeployment) new_deployment = NULL;
+ g_autoptr(GPtrArray) overlay_initrd_chksums = NULL;
+ for (char **it = opt_overlay_initrds; it && *it; it++)
+ {
+ const char *path = *it;
+
+ glnx_autofd int fd = -1;
+ if (!glnx_openat_rdonly (AT_FDCWD, path, TRUE, &fd, error))
+ return FALSE;
+
+ g_autofree char *chksum = NULL;
+ if (!ostree_sysroot_stage_overlay_initrd (sysroot, fd, &chksum, cancellable, error))
+ return FALSE;
+
+ if (!overlay_initrd_chksums)
+ overlay_initrd_chksums = g_ptr_array_new_full (g_strv_length (opt_overlay_initrds), g_free);
+ g_ptr_array_add (overlay_initrd_chksums, g_steal_pointer (&chksum));
+ }
+
+ if (overlay_initrd_chksums)
+ g_ptr_array_add (overlay_initrd_chksums, NULL);
+
g_auto(GStrv) kargs_strv = kargs ? ostree_kernel_args_to_strv (kargs) : NULL;
+
+ OstreeSysrootDeployTreeOpts opts = {
+ .override_kernel_argv = kargs_strv,
+ .overlay_initrds = overlay_initrd_chksums ? (char**)overlay_initrd_chksums->pdata : NULL,
+ };
+
+ g_autoptr(OstreeDeployment) new_deployment = NULL;
if (opt_stage)
{
if (opt_retain_pending || opt_retain_rollback)
return glnx_throw (error, "--stage cannot currently be combined with --retain arguments");
if (opt_not_as_default)
return glnx_throw (error, "--stage cannot currently be combined with --not-as-default");
- if (!ostree_sysroot_stage_tree (sysroot, opt_osname, revision, origin, merge_deployment,
- kargs_strv, &new_deployment, cancellable, error))
- return FALSE;
+ /* use old API if we can to exercise it in CI */
+ if (!overlay_initrd_chksums)
+ {
+ if (!ostree_sysroot_stage_tree (sysroot, opt_osname, revision, origin,
+ merge_deployment, kargs_strv, &new_deployment,
+ cancellable, error))
+ return FALSE;
+ }
+ else
+ {
+ if (!ostree_sysroot_stage_tree_with_options (sysroot, opt_osname, revision,
+ origin, merge_deployment, &opts,
+ &new_deployment, cancellable, error))
+ return FALSE;
+ }
g_assert (new_deployment);
}
else
{
- if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment,
- kargs_strv, &new_deployment, cancellable, error))
- return FALSE;
+ /* use old API if we can to exercise it in CI */
+ if (!overlay_initrd_chksums)
+ {
+ if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin,
+ merge_deployment, kargs_strv, &new_deployment,
+ cancellable, error))
+ return FALSE;
+ }
+ else
+ {
+ if (!ostree_sysroot_deploy_tree_with_options (sysroot, opt_osname, revision,
+ origin, merge_deployment, &opts,
+ &new_deployment, cancellable,
+ error))
+ return FALSE;
+ }
g_assert (new_deployment);
OstreeSysrootSimpleWriteDeploymentFlags flags = OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN;
diff --git a/src/ostree/ot-admin-builtin-pin.c b/src/ostree/ot-admin-builtin-pin.c
index d4337e3..5269dd8 100644
--- a/src/ostree/ot-admin-builtin-pin.c
+++ b/src/ostree/ot-admin-builtin-pin.c
@@ -55,7 +55,14 @@ ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation
for (unsigned int i = 1; i < argc; i++)
{
const char *deploy_index_str = argv[i];
- const int deploy_index = atoi (deploy_index_str);
+ char *endptr = NULL;
+
+ errno = 0;
+ const guint64 deploy_index = g_ascii_strtoull (deploy_index_str, &endptr, 10);
+ if (*endptr != '\0')
+ return glnx_throw (error, "Invalid index: %s", deploy_index_str);
+ if (errno == ERANGE)
+ return glnx_throw (error, "Index too large: %s", deploy_index_str);
g_autoptr(OstreeDeployment) target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error);
if (!target_deployment)
diff --git a/src/ostree/ot-admin-builtin-set-origin.c b/src/ostree/ot-admin-builtin-set-origin.c
index 9d96512..4dc68a0 100644
--- a/src/ostree/ot-admin-builtin-set-origin.c
+++ b/src/ostree/ot-admin-builtin-set-origin.c
@@ -95,7 +95,7 @@ ot_admin_builtin_set_origin (int argc, char **argv, OstreeCommandInvocation *inv
{ char **iter;
g_autoptr(GVariantBuilder) optbuilder =
g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
- g_autoptr(GVariant) options = NULL;
+ g_autoptr(GVariant) remote_options = NULL;
for (iter = opt_set; iter && *iter; iter++)
{
@@ -110,12 +110,12 @@ ot_admin_builtin_set_origin (int argc, char **argv, OstreeCommandInvocation *inv
subkey, g_variant_new_variant (g_variant_new_string (subvalue)));
}
- options = g_variant_ref_sink (g_variant_builder_end (optbuilder));
+ remote_options = g_variant_ref_sink (g_variant_builder_end (optbuilder));
if (!ostree_repo_remote_change (repo, NULL,
OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS,
remotename, url,
- options,
+ remote_options,
cancellable, error))
goto out;
}
diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c
index 2f12ef1..b94be76 100644
--- a/src/ostree/ot-admin-builtin-switch.c
+++ b/src/ostree/ot-admin-builtin-switch.c
@@ -44,7 +44,7 @@ gboolean
ot_admin_builtin_switch (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
g_autoptr(GOptionContext) context =
- g_option_context_new ("REF");
+ g_option_context_new ("REFSPEC");
g_autoptr(OstreeSysroot) sysroot = NULL;
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
@@ -53,7 +53,7 @@ ot_admin_builtin_switch (int argc, char **argv, OstreeCommandInvocation *invocat
if (argc < 2)
{
- ot_util_usage_error (context, "REF must be specified", error);
+ ot_util_usage_error (context, "REFSPEC must be specified", error);
return FALSE;
}
diff --git a/src/ostree/ot-admin-builtin-unlock.c b/src/ostree/ot-admin-builtin-unlock.c
index cd46618..6c265f5 100644
--- a/src/ostree/ot-admin-builtin-unlock.c
+++ b/src/ostree/ot-admin-builtin-unlock.c
@@ -31,9 +31,11 @@
#include
static gboolean opt_hotfix;
+static gboolean opt_transient;
static GOptionEntry options[] = {
{ "hotfix", 0, 0, G_OPTION_ARG_NONE, &opt_hotfix, "Retain changes across reboots", NULL },
+ { "transient", 0, 0, G_OPTION_ARG_NONE, &opt_transient, "Mount overlayfs read-only by default", NULL },
{ NULL }
};
@@ -67,7 +69,17 @@ ot_admin_builtin_unlock (int argc, char **argv, OstreeCommandInvocation *invocat
goto out;
}
- target_state = opt_hotfix ? OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX : OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
+ if (opt_hotfix && opt_transient)
+ {
+ glnx_throw (error, "Cannot specify both --hotfix and --transient");
+ goto out;
+ }
+ else if (opt_hotfix)
+ target_state = OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX;
+ else if (opt_transient)
+ target_state = OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT;
+ else
+ target_state = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
if (!ostree_sysroot_deployment_unlock (sysroot, booted_deployment,
target_state, cancellable, error))
@@ -87,6 +99,10 @@ ot_admin_builtin_unlock (int argc, char **argv, OstreeCommandInvocation *invocat
g_print ("Development mode enabled. A writable overlayfs is now mounted on /usr.\n"
"All changes there will be discarded on reboot.\n");
break;
+ case OSTREE_DEPLOYMENT_UNLOCKED_TRANSIENT:
+ g_print ("A writable overlayfs is prepared for /usr, but is mounted read-only by default.\n"
+ "All changes there will be discarded on reboot.\n");
+ break;
}
ret = TRUE;
diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c
index 9f1a615..834a271 100644
--- a/src/ostree/ot-builtin-admin.c
+++ b/src/ostree/ot-builtin-admin.c
@@ -65,7 +65,7 @@ static OstreeCommand admin_subcommands[] = {
"List deployments" },
{ "switch", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_switch,
- "Construct new tree from REF and deploy it" },
+ "Construct new tree from REFSPEC and deploy it" },
{ "undeploy", OSTREE_BUILTIN_FLAG_NO_REPO,
ot_admin_builtin_undeploy,
"Delete deployment INDEX" },
diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c
index 813dbb9..fe9558c 100644
--- a/src/ostree/ot-builtin-checkout.c
+++ b/src/ostree/ot-builtin-checkout.c
@@ -84,7 +84,7 @@ static GOptionEntry options[] = {
{ "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" },
{ "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" },
{ "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL },
- { "force-copy-zerosized", 'z', 0, G_OPTION_ARG_NONE, &opt_force_copy_zerosized, "Do not hardlink zero-sized files", NULL },
+ { "force-copy-zerosized", 'z', G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_force_copy_zerosized, "Do not hardlink zero-sized files", NULL },
{ "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL },
{ "bareuseronly-dirs", 'M', 0, G_OPTION_ARG_NONE, &opt_bareuseronly_dirs, "Suppress mode bits outside of 0775 for directories (suid, world writable, etc.)", NULL },
{ "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "FILE" },
@@ -135,14 +135,14 @@ process_one_checkout (OstreeRepo *repo,
opt_bareuseronly_dirs || opt_union_identical ||
opt_skiplist_file || opt_selinux_policy || opt_selinux_prefix)
{
- OstreeRepoCheckoutAtOptions options = { 0, };
+ OstreeRepoCheckoutAtOptions checkout_options = { 0, };
/* do this early so option checking also catches force copy conflicts */
if (opt_selinux_policy)
opt_force_copy = TRUE;
if (opt_user_mode)
- options.mode = OSTREE_REPO_CHECKOUT_MODE_USER;
+ checkout_options.mode = OSTREE_REPO_CHECKOUT_MODE_USER;
/* Can't union these */
if (opt_union && opt_union_add)
{
@@ -173,9 +173,9 @@ process_one_checkout (OstreeRepo *repo,
goto out;
}
else if (opt_union)
- options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
+ checkout_options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
else if (opt_union_add)
- options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES;
+ checkout_options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES;
else if (opt_union_identical)
{
if (!opt_require_hardlinks)
@@ -184,12 +184,12 @@ process_one_checkout (OstreeRepo *repo,
"--union-identical requires --require-hardlinks");
goto out;
}
- options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL;
+ checkout_options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL;
}
if (opt_whiteouts)
- options.process_whiteouts = TRUE;
+ checkout_options.process_whiteouts = TRUE;
if (subpath)
- options.subpath = subpath;
+ checkout_options.subpath = subpath;
g_autoptr(OstreeSePolicy) policy = NULL;
if (opt_selinux_policy)
@@ -203,8 +203,8 @@ process_one_checkout (OstreeRepo *repo,
policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error);
if (!policy)
goto out;
- options.sepolicy = policy;
- options.sepolicy_prefix = opt_selinux_prefix;
+ checkout_options.sepolicy = policy;
+ checkout_options.sepolicy_prefix = opt_selinux_prefix;
}
g_autoptr(GHashTable) skip_list =
@@ -214,16 +214,16 @@ process_one_checkout (OstreeRepo *repo,
if (!ot_parse_file_by_line (opt_skiplist_file, handle_skiplist_line, skip_list,
cancellable, error))
goto out;
- options.filter = checkout_filter;
- options.filter_user_data = skip_list;
+ checkout_options.filter = checkout_filter;
+ checkout_options.filter_user_data = skip_list;
}
- options.no_copy_fallback = opt_require_hardlinks;
- options.force_copy = opt_force_copy;
- options.force_copy_zerosized = opt_force_copy_zerosized;
- options.bareuseronly_dirs = opt_bareuseronly_dirs;
+ checkout_options.no_copy_fallback = opt_require_hardlinks;
+ checkout_options.force_copy = opt_force_copy;
+ checkout_options.force_copy_zerosized = opt_force_copy_zerosized;
+ checkout_options.bareuseronly_dirs = opt_bareuseronly_dirs;
- if (!ostree_repo_checkout_at (repo, &options,
+ if (!ostree_repo_checkout_at (repo, &checkout_options,
AT_FDCWD, destination,
resolved_commit,
cancellable, error))
diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c
index 20409fc..48fa292 100644
--- a/src/ostree/ot-builtin-commit.c
+++ b/src/ostree/ot-builtin-commit.c
@@ -94,7 +94,7 @@ parse_fsync_cb (const char *option_name,
*/
static GOptionEntry options[] = {
- { "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent ref, or \"none\"", "REF" },
+ { "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent commit checksum, or \"none\"", "COMMIT" },
{ "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject", "SUBJECT" },
{ "body", 'm', 0, G_OPTION_ARG_STRING, &opt_body, "Full description", "BODY" },
{ "body-file", 'F', 0, G_OPTION_ARG_FILENAME, &opt_body_file, "Commit message from FILE path", "FILE" },
@@ -103,7 +103,7 @@ static GOptionEntry options[] = {
{ "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL },
{ "no-bindings", 0, 0, G_OPTION_ARG_NONE, &opt_no_bindings, "Do not write any ref bindings", NULL },
{ "bind-ref", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_bind_refs, "Add a ref to ref binding commit metadata", "BRANCH" },
- { "base", 0, 0, G_OPTION_ARG_STRING, &opt_base, "Start from the given commit as a base (no modifiers apply)", "REF" },
+ { "base", 0, 0, G_OPTION_ARG_STRING, &opt_base, "Start from the given commit as a base (no modifiers apply)", "REV" },
{ "tree", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_trees, "Overlay the given argument as a tree", "dir=PATH or tar=TARFILE or ref=COMMIT" },
{ "add-metadata-string", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_strings, "Add a key/value pair to metadata", "KEY=VALUE" },
{ "add-metadata", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_metadata_variants, "Add a key/value pair to metadata, where the KEY is a string, an VALUE is g_variant_parse() formatted", "KEY=VALUE" },
@@ -614,10 +614,10 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
if (opt_base)
{
g_autofree char *base_commit = NULL;
- g_autoptr(GFile) root = NULL;
- if (!ostree_repo_read_commit (repo, opt_base, &root, &base_commit, cancellable, error))
+ g_autoptr(GFile) base_root = NULL;
+ if (!ostree_repo_read_commit (repo, opt_base, &base_root, &base_commit, cancellable, error))
goto out;
- OstreeRepoFile *rootf = (OstreeRepoFile*) root;
+ OstreeRepoFile *rootf = (OstreeRepoFile*) base_root;
mtree = ostree_mutable_tree_new_from_checksum (repo,
ostree_repo_file_tree_get_contents_checksum (rootf),
diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c
index 811a838..64e434a 100644
--- a/src/ostree/ot-builtin-config.c
+++ b/src/ostree/ot-builtin-config.c
@@ -134,7 +134,7 @@ ostree_builtin_config (int argc, char **argv, OstreeCommandInvocation *invocatio
else if (!strcmp (op, "get"))
{
GKeyFile *readonly_config = NULL;
- g_autofree char *value = NULL;
+ g_autofree char *read_value = NULL;
if (opt_group)
{
if (argc < 3)
@@ -160,11 +160,11 @@ ostree_builtin_config (int argc, char **argv, OstreeCommandInvocation *invocatio
}
readonly_config = ostree_repo_get_config (repo);
- value = g_key_file_get_string (readonly_config, section, key, error);
- if (value == NULL)
+ read_value = g_key_file_get_string (readonly_config, section, key, error);
+ if (read_value == NULL)
return FALSE;
- g_print ("%s\n", value);
+ g_print ("%s\n", read_value);
}
else if (!strcmp (op, "unset"))
{
diff --git a/src/ostree/ot-builtin-gpg-sign.c b/src/ostree/ot-builtin-gpg-sign.c
index 6babbf2..bde9180 100644
--- a/src/ostree/ot-builtin-gpg-sign.c
+++ b/src/ostree/ot-builtin-gpg-sign.c
@@ -171,9 +171,8 @@ delete_signatures (OstreeRepo *repo,
while (!g_queue_is_empty (&signatures))
{
- GVariant *child = g_queue_pop_head (&signatures);
- g_variant_builder_add_value (&signature_builder, child);
- g_variant_unref (child);
+ g_autoptr(GVariant) sigchild = g_queue_pop_head (&signatures);
+ g_variant_builder_add_value (&signature_builder, sigchild);
}
g_variant_dict_insert_value (&metadata_dict,
diff --git a/src/ostree/ot-builtin-log.c b/src/ostree/ot-builtin-log.c
index 306f177..0a1d408 100644
--- a/src/ostree/ot-builtin-log.c
+++ b/src/ostree/ot-builtin-log.c
@@ -95,7 +95,7 @@ ostree_builtin_log (int argc,
g_autofree char *checksum = NULL;
OstreeDumpFlags flags = OSTREE_DUMP_NONE;
- context = g_option_context_new ("REF");
+ context = g_option_context_new ("REV");
if (!ostree_option_context_parse (context, options, &argc, &argv, invocation, &repo, cancellable, error))
goto out;
@@ -105,7 +105,7 @@ ostree_builtin_log (int argc,
if (argc <= 1)
{
- ot_util_usage_error (context, "A ref argument is required", error);
+ ot_util_usage_error (context, "A rev argument is required", error);
goto out;
}
rev = argv[1];
diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c
index e69d62e..ed0ec55 100644
--- a/src/ostree/ot-builtin-pull.c
+++ b/src/ostree/ot-builtin-pull.c
@@ -271,7 +271,7 @@ ostree_builtin_pull (int argc, char **argv, OstreeCommandInvocation *invocation,
{
GVariantBuilder builder;
- g_autoptr(GVariant) options = NULL;
+ g_autoptr(GVariant) pull_options = NULL;
g_auto(GLnxConsoleRef) console = { 0, };
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
@@ -378,9 +378,9 @@ ostree_builtin_pull (int argc, char **argv, OstreeCommandInvocation *invocation,
#endif /* OSTREE_DISABLE_GPGME */
}
- options = g_variant_ref_sink (g_variant_builder_end (&builder));
+ pull_options = g_variant_ref_sink (g_variant_builder_end (&builder));
- if (!ostree_repo_pull_with_options (repo, remote, options,
+ if (!ostree_repo_pull_with_options (repo, remote, pull_options,
progress, cancellable, error))
goto out;
diff --git a/src/ostree/ot-builtin-sign.c b/src/ostree/ot-builtin-sign.c
index c777748..2f90acd 100644
--- a/src/ostree/ot-builtin-sign.c
+++ b/src/ostree/ot-builtin-sign.c
@@ -167,7 +167,7 @@ ostree_builtin_sign (int argc, char **argv, OstreeCommandInvocation *invocation,
if ((n_key_ids == 0) || opt_filename)
{
g_autoptr (GVariantBuilder) builder = NULL;
- g_autoptr (GVariant) options = NULL;
+ g_autoptr (GVariant) sign_options = NULL;
builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
/* Use custom directory with public and revoked keys instead of system-wide directories */
@@ -176,9 +176,9 @@ ostree_builtin_sign (int argc, char **argv, OstreeCommandInvocation *invocation,
/* The last chance for verification source -- system files */
if (opt_filename)
g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (opt_filename));
- options = g_variant_builder_end (builder);
+ sign_options = g_variant_builder_end (builder);
- if (!ostree_sign_load_pk (sign, options, error))
+ if (!ostree_sign_load_pk (sign, sign_options, error))
goto out;
if (ostree_sign_commit_verify (sign,
diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c
index 4f9ff2b..3e0af5b 100644
--- a/src/ostree/ot-builtin-static-delta.c
+++ b/src/ostree/ot-builtin-static-delta.c
@@ -40,6 +40,10 @@ static gboolean opt_swap_endianness;
static gboolean opt_inline;
static gboolean opt_disable_bsdiff;
static gboolean opt_if_not_exists;
+static char **opt_key_ids;
+static char *opt_sign_name;
+static char *opt_keysfilename;
+static char *opt_keysdir;
#define BUILTINPROTO(name) static gboolean ot_static_delta_builtin_ ## name (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
@@ -48,6 +52,7 @@ BUILTINPROTO(show);
BUILTINPROTO(delete);
BUILTINPROTO(generate);
BUILTINPROTO(apply_offline);
+BUILTINPROTO(verify);
#undef BUILTINPROTO
@@ -67,6 +72,9 @@ static OstreeCommand static_delta_subcommands[] = {
{ "apply-offline", OSTREE_BUILTIN_FLAG_NONE,
ot_static_delta_builtin_apply_offline,
"Apply static delta file" },
+ { "verify", OSTREE_BUILTIN_FLAG_NONE,
+ ot_static_delta_builtin_verify,
+ "Verify static delta signatures" },
{ NULL, 0, NULL, NULL }
};
@@ -88,10 +96,20 @@ static GOptionEntry generate_options[] = {
{ "max-bsdiff-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_bsdiff_size, "Maximum size in megabytes to consider bsdiff compression for input files", NULL},
{ "max-chunk-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_chunk_size, "Maximum size of delta chunks in megabytes", NULL},
{ "filename", 0, 0, G_OPTION_ARG_FILENAME, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"},
+ { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Sign the delta with", "KEY_ID"},
+ { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"},
+#if defined(HAVE_LIBSODIUM)
+ { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME"},
+#endif
{ NULL }
};
static GOptionEntry apply_offline_options[] = {
+ { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"},
+#if defined(HAVE_LIBSODIUM)
+ { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME"},
+ { "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME"},
+#endif
{ NULL }
};
@@ -99,6 +117,15 @@ static GOptionEntry list_options[] = {
{ NULL }
};
+static GOptionEntry verify_options[] = {
+ { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name, "Signature type to use (defaults to 'ed25519')", "NAME"},
+#if defined(HAVE_LIBSODIUM)
+ { "keys-file", 0, 0, G_OPTION_ARG_STRING, &opt_keysfilename, "Read key(s) from file", "NAME"},
+ { "keys-dir", 0, 0, G_OPTION_ARG_STRING, &opt_keysdir, "Redefine system-wide directories with public and revoked keys for verification", "NAME"},
+#endif
+ { NULL }
+};
+
static void
static_delta_usage (char **argv,
gboolean is_error)
@@ -326,6 +353,60 @@ ot_static_delta_builtin_generate (int argc, char **argv, OstreeCommandInvocation
if (opt_endianness || opt_swap_endianness)
g_variant_builder_add (parambuilder, "{sv}", "endianness", g_variant_new_uint32 (endianness));
+ if (opt_key_ids || opt_keysfilename)
+ {
+ g_autoptr(GPtrArray) key_ids = g_ptr_array_new ();
+
+ for (char **iter = opt_key_ids; iter != NULL && *iter != NULL; ++iter)
+ g_ptr_array_add (key_ids, *iter);
+
+ if (opt_keysfilename)
+ {
+ g_autoptr (GFile) keyfile = NULL;
+ g_autoptr (GFileInputStream) key_stream_in = NULL;
+ g_autoptr (GDataInputStream) key_data_in = NULL;
+
+ if (!g_file_test (opt_keysfilename, G_FILE_TEST_IS_REGULAR))
+ {
+ g_warning ("Can't open file '%s' with keys", opt_keysfilename);
+ return glnx_throw (error, "File object '%s' is not a regular file", opt_keysfilename);
+ }
+
+ keyfile = g_file_new_for_path (opt_keysfilename);
+ key_stream_in = g_file_read (keyfile, NULL, error);
+ if (key_stream_in == NULL)
+ return FALSE;
+
+ key_data_in = g_data_input_stream_new (G_INPUT_STREAM(key_stream_in));
+ g_assert (key_data_in != NULL);
+
+ /* Use simple file format with just a list of base64 public keys per line */
+ while (TRUE)
+ {
+ gsize len = 0;
+ g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error);
+ g_autoptr (GVariant) sk = NULL;
+
+ if (*error != NULL)
+ return FALSE;
+
+ if (line == NULL)
+ break;
+
+ // Pass the key as a string
+ g_ptr_array_add (key_ids, g_strdup (line));
+ }
+ }
+
+ g_autoptr(GVariant) key_ids_v = g_variant_new_strv ((const char *const *)key_ids->pdata,
+ key_ids->len);
+ g_variant_builder_add (parambuilder, "{s@v}", "sign-key-ids",
+ g_variant_new_variant (g_steal_pointer (&key_ids_v)));
+ }
+ opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
+ g_variant_builder_add (parambuilder, "{sv}", "sign-name",
+ g_variant_new_bytestring (opt_sign_name));
+
g_print ("Generating static delta:\n");
g_print (" From: %s\n", from_resolved ? from_resolved : "empty");
g_print (" To: %s\n", to_resolved);
@@ -347,6 +428,9 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, OstreeCommandInvoc
{
g_autoptr(GOptionContext) context = NULL;
g_autoptr(OstreeRepo) repo = NULL;
+ g_autoptr (OstreeSign) sign = NULL;
+ char **key_ids;
+ int n_key_ids;
context = g_option_context_new ("");
if (!ostree_option_context_parse (context, apply_offline_options, &argc, &argv, invocation, &repo, cancellable, error))
@@ -362,13 +446,59 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, OstreeCommandInvoc
return FALSE;
}
+#if defined(HAVE_LIBSODIUM)
+ /* Initialize crypto system */
+ opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
+#endif
+
+ if (opt_sign_name)
+ {
+ sign = ostree_sign_get_by_name (opt_sign_name, error);
+ if (!sign)
+ return glnx_throw (error, "Signing type %s is not supported", opt_sign_name);
+
+ key_ids = argv + 3;
+ n_key_ids = argc - 3;
+ for (int i = 0; i < n_key_ids; i++)
+ {
+ g_autoptr (GVariant) pk = g_variant_new_string(key_ids[i]);
+ if (!ostree_sign_add_pk(sign, pk, error))
+ return FALSE;
+ }
+ if ((n_key_ids == 0) || opt_keysfilename)
+ {
+ g_autoptr (GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
+ g_autoptr (GVariant) options = NULL;
+
+ /* Use custom directory with public and revoked keys instead of system-wide directories */
+ if (opt_keysdir)
+ g_variant_builder_add (builder, "{sv}", "basedir", g_variant_new_string (opt_keysdir));
+ /* The last chance for verification source -- system files */
+ if (opt_keysfilename)
+ g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (opt_keysfilename));
+ options = g_variant_builder_end (builder);
+
+ if (!ostree_sign_load_pk (sign, options, error))
+ {
+ /* If it fails to load system default public keys, consider there no signature engine */
+ if (!opt_keysdir && !opt_keysfilename)
+ {
+ g_clear_error(error);
+ g_clear_object(&sign);
+ }
+ else
+ return FALSE;
+ }
+ }
+ }
+
const char *patharg = argv[2];
g_autoptr(GFile) path = g_file_new_for_path (patharg);
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
return FALSE;
- if (!ostree_repo_static_delta_execute_offline (repo, path, FALSE, cancellable, error))
+ if (!ostree_repo_static_delta_execute_offline_with_signature (repo, path, sign, FALSE, cancellable, error))
return FALSE;
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
@@ -377,6 +507,68 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, OstreeCommandInvoc
return TRUE;
}
+static gboolean
+ot_static_delta_builtin_verify (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
+{
+ g_autoptr (GOptionContext) context = g_option_context_new ("STATIC-DELTA-FILE [KEY-ID...]");
+ g_autoptr (OstreeRepo) repo = NULL;
+ gboolean verified;
+ char **key_ids;
+ int n_key_ids;
+
+ if (!ostree_option_context_parse (context, verify_options, &argc, &argv, invocation, &repo, cancellable, error))
+ return FALSE;
+
+ if (argc < 3)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "DELTA must be specified");
+ return FALSE;
+ }
+
+ opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
+
+ const char *delta_id = argv[2];
+
+ g_autoptr (OstreeSign) sign = ostree_sign_get_by_name (opt_sign_name, error);
+ if (!sign)
+ {
+ g_print("Sign-type not supported\n");
+ return FALSE;
+ }
+
+ key_ids = argv + 3;
+ n_key_ids = argc - 3;
+ for (int i = 0; i < n_key_ids; i++)
+ {
+ g_autoptr (GVariant) pk = g_variant_new_string(key_ids[i]);
+ if (!ostree_sign_add_pk(sign, pk, error))
+ return FALSE;
+ }
+ if ((n_key_ids == 0) || opt_keysfilename)
+ {
+ g_autoptr (GVariantBuilder) builder = NULL;
+ g_autoptr (GVariant) options = NULL;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
+ /* Use custom directory with public and revoked keys instead of system-wide directories */
+ if (opt_keysdir)
+ g_variant_builder_add (builder, "{sv}", "basedir", g_variant_new_string (opt_keysdir));
+ /* The last chance for verification source -- system files */
+ if (opt_keysfilename)
+ g_variant_builder_add (builder, "{sv}", "filename", g_variant_new_string (opt_keysfilename));
+ options = g_variant_builder_end (builder);
+
+ if (!ostree_sign_load_pk (sign, options, error))
+ return FALSE;
+ }
+
+ verified = ostree_repo_static_delta_verify_signature (repo, delta_id, sign, NULL, error);
+ g_print ("Verification %s\n", verified ? "OK" : "fails");
+
+ return verified;
+}
+
gboolean
ostree_builtin_static_delta (int argc, char **argv, OstreeCommandInvocation *invocation, GCancellable *cancellable, GError **error)
{
diff --git a/src/ostree/ot-dump.c b/src/ostree/ot-dump.c
index 38f3730..a8ed54a 100644
--- a/src/ostree/ot-dump.c
+++ b/src/ostree/ot-dump.c
@@ -114,6 +114,7 @@ dump_commit (GVariant *variant,
const gchar *subject;
const gchar *body;
guint64 timestamp;
+ g_autofree char *parent = NULL;
g_autofree char *str = NULL;
g_autofree char *version = NULL;
g_autoptr(GError) local_error = NULL;
@@ -129,6 +130,12 @@ dump_commit (GVariant *variant,
g_assert (local_error); /* Pacify static analysis */
errx (1, "Failed to read commit: %s", local_error->message);
}
+
+ if ((parent = ostree_commit_get_parent(variant)))
+ {
+ g_print ("Parent: %s\n", parent);
+ }
+
g_autofree char *contents = ostree_commit_get_content_checksum (variant) ?: "";
g_print ("ContentChecksum: %s\n", contents);
g_print ("Date: %s\n", str);
@@ -315,10 +322,11 @@ ot_dump_summary_bytes (GBytes *summary_bytes,
collection_map = g_variant_lookup_value (exts, OSTREE_SUMMARY_COLLECTION_MAP, G_VARIANT_TYPE ("a{sa(s(taya{sv}))}"));
if (collection_map != NULL)
{
+ g_autoptr(GVariant) collection_refs = NULL;
g_variant_iter_init (&iter, collection_map);
- while (g_variant_iter_loop (&iter, "{&s@a(s(taya{sv}))}", &collection_id, &refs))
- dump_summary_refs (collection_id, refs);
+ while (g_variant_iter_loop (&iter, "{&s@a(s(taya{sv}))}", &collection_id, &collection_refs))
+ dump_summary_refs (collection_id, collection_refs);
}
/* Print out the additional metadata. */
@@ -354,6 +362,22 @@ ot_dump_summary_bytes (GBytes *summary_bytes,
pretty_key = "Collection Map";
value_str = g_strdup ("(printed above)");
}
+ else if (g_strcmp0 (key, OSTREE_SUMMARY_MODE) == 0)
+ {
+ OstreeRepoMode repo_mode;
+ const char *repo_mode_str = g_variant_get_string (value, NULL);
+
+ pretty_key = "Repository Mode";
+ if (!ostree_repo_mode_from_string (repo_mode_str, &repo_mode, NULL))
+ value_str = g_strdup_printf ("Invalid (‘%s’)", repo_mode_str);
+ else
+ value_str = g_strdup (repo_mode_str);
+ }
+ else if (g_strcmp0 (key, OSTREE_SUMMARY_TOMBSTONE_COMMITS) == 0)
+ {
+ pretty_key = "Has Tombstone Commits";
+ value_str = g_strdup (g_variant_get_boolean (value) ? "Yes" : "No");
+ }
else
{
value_str = g_variant_print (value, FALSE);
diff --git a/src/ostree/ot-remote-builtin-add.c b/src/ostree/ot-remote-builtin-add.c
index 172625d..61539ec 100644
--- a/src/ostree/ot-remote-builtin-add.c
+++ b/src/ostree/ot-remote-builtin-add.c
@@ -104,7 +104,6 @@ ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocatio
g_autoptr(GString) sign_verify = NULL;
const char *remote_name;
const char *remote_url;
- char **iter;
g_autoptr(GVariantBuilder) optbuilder = NULL;
g_autoptr(GVariant) options = NULL;
gboolean ret = FALSE;
@@ -161,7 +160,7 @@ ot_remote_builtin_add (int argc, char **argv, OstreeCommandInvocation *invocatio
g_variant_builder_add (optbuilder, "{s@v}",
"contenturl", g_variant_new_variant (g_variant_new_string (opt_contenturl)));
- for (iter = opt_set; iter && *iter; iter++)
+ for (char **iter = opt_set; iter && *iter; iter++)
{
const char *keyvalue = *iter;
g_autofree char *subkey = NULL;
diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c
index 8a68e1f..6351bab 100644
--- a/src/switchroot/ostree-prepare-root.c
+++ b/src/switchroot/ostree-prepare-root.c
@@ -101,10 +101,9 @@ sysroot_is_configured_ro (const char *sysroot)
bool ret = false;
char *line = NULL;
size_t len = 0;
- ssize_t nread;
/* Note getline() will reuse the previous buffer */
bool in_sysroot = false;
- while ((nread = getline (&line, &len, f)) != -1)
+ while (getline (&line, &len, f) != -1)
{
/* This is an awful hack to avoid depending on GLib in the
* initramfs right now.
@@ -252,7 +251,7 @@ main(int argc, char *argv[])
* sysroot, we still need a writable /etc. And to avoid race conditions
* we ensure it's writable in the initramfs, before we switchroot at all.
*/
- if (mount ("/etc", "/etc", NULL, MS_BIND, NULL) < 0)
+ if (mount ("etc", "etc", NULL, MS_BIND, NULL) < 0)
err (EXIT_FAILURE, "failed to make /etc a bind mount");
/* Pass on the fact that we discovered a readonly sysroot to ostree-remount.service */
int fd = open (_OSTREE_SYSROOT_READONLY_STAMP, O_WRONLY | O_CREAT | O_CLOEXEC, 0644);
diff --git a/src/switchroot/ostree-remount.c b/src/switchroot/ostree-remount.c
index 5c313c8..3981682 100644
--- a/src/switchroot/ostree-remount.c
+++ b/src/switchroot/ostree-remount.c
@@ -106,11 +106,16 @@ main(int argc, char *argv[])
exit (EXIT_SUCCESS);
}
- /* Handle remounting /sysroot read-only now */
- if (unlink (_OSTREE_SYSROOT_READONLY_STAMP) == 0)
- {
- do_remount ("/sysroot", false);
- }
+ /* Handle remounting /sysroot; if it's explicitly marked as read-only (opt in)
+ * then ensure it's readonly, otherwise mount writable, the same as /
+ */
+ bool sysroot_configured_readonly = unlink (_OSTREE_SYSROOT_READONLY_STAMP) == 0;
+ do_remount ("/sysroot", !sysroot_configured_readonly);
+
+ /* And also make sure to make /etc rw again. We make this conditional on
+ * sysroot_configured_readonly because only in that case is it a bind-mount. */
+ if (sysroot_configured_readonly)
+ do_remount ("/etc", true);
/* If /var was created as as an OSTree default bind mount (instead of being a separate filesystem)
* then remounting the root mount read-only also remounted it.
diff --git a/tests/basic-test.sh b/tests/basic-test.sh
index fc193f4..9227b0c 100644
--- a/tests/basic-test.sh
+++ b/tests/basic-test.sh
@@ -750,15 +750,17 @@ rm files -rf && mkdir files
touch files/anemptyfile
touch files/anotheremptyfile
$CMD_PREFIX ostree --repo=repo commit --consume -b tree-with-empty-files --tree=dir=files
-$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} -z tree-with-empty-files tree-with-empty-files
+$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} tree-with-empty-files tree-with-empty-files
if files_are_hardlinked tree-with-empty-files/an{,other}emptyfile; then
fatal "--force-copy-zerosized failed"
fi
+# And pass the now-defunct -z option to validate it does nothing
rm tree-with-empty-files -rf
-$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} tree-with-empty-files tree-with-empty-files
-assert_files_hardlinked tree-with-empty-files/an{,other}emptyfile
-rm tree-with-empty-files -rf
-echo "ok checkout --force-copy-zerosized"
+$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} -z tree-with-empty-files tree-with-empty-files
+if files_are_hardlinked tree-with-empty-files/an{,other}emptyfile; then
+ fatal "--force-copy-zerosized failed"
+fi
+echo "ok checkout zero sized files are not hardlinked"
# These should merge, they're identical
$CMD_PREFIX ostree --repo=repo checkout ${CHECKOUT_H_ARGS} --union-identical -z tree-with-empty-files tree-with-empty-files
diff --git a/tests/bootloader-entries-crosscheck.py b/tests/bootloader-entries-crosscheck.py
index 41f6956..605bd08 100755
--- a/tests/bootloader-entries-crosscheck.py
+++ b/tests/bootloader-entries-crosscheck.py
@@ -73,36 +73,56 @@ with open(syslinuxpath) as f:
syslinux_entry = None
syslinux_default = None
for line in f:
- line = line.strip()
- if line.startswith('DEFAULT '):
+ try:
+ k, v = line.strip().split(" ", 1)
+ except ValueError:
+ continue
+ if k == 'DEFAULT':
if syslinux_entry is not None:
- syslinux_default = line.split(' ', 1)[1]
- elif line.startswith('LABEL '):
+ syslinux_default = v
+ elif k == 'LABEL':
if syslinux_entry is not None:
syslinux_entries.append(syslinux_entry)
syslinux_entry = {}
- syslinux_entry['title'] = line.split(' ', 1)[1]
- elif line.startswith('KERNEL '):
- syslinux_entry['linux'] = line.split(' ', 1)[1]
- elif line.startswith('INITRD '):
- syslinux_entry['initrd'] = line.split(' ', 1)[1]
- elif line.startswith('APPEND '):
- syslinux_entry['options'] = line.split(' ', 1)[1]
+ syslinux_entry['title'] = v
+ elif k == 'KERNEL':
+ syslinux_entry['linux'] = v
+ elif k == 'INITRD':
+ syslinux_entry['initrd'] = v
+ elif k == 'APPEND':
+ syslinux_entry['options'] = v
if syslinux_entry is not None:
syslinux_entries.append(syslinux_entry)
if len(entries) != len(syslinux_entries):
fatal("Found {0} loader entries, but {1} SYSLINUX entries\n".format(len(entries), len(syslinux_entries)))
-def assert_matches_key(a, b, key):
+
+def assert_eq(a, b):
+ assert a == b, "%r == %r" % (a, b)
+
+
+def assert_key_same_file(a, b, key):
aval = a[key]
bval = b[key]
- if aval != bval:
- fatal("Mismatch on {0}: {1} != {2}".format(key, aval, bval))
+ sys.stderr.write("aval: %r\nbval: %r\n" % (aval, bval))
+
+ # Paths in entries are always relative to /boot
+ entry = os.stat(sysroot + "/boot" + aval)
+
+ # Syslinux entries can be relative to /boot (if it's on another filesystem)
+ # or relative to / if /boot is on /.
+ s1 = os.stat(sysroot + bval)
+ s2 = os.stat(sysroot + "/boot" + bval)
+
+ # A symlink ensures that no matter what they point at the same file
+ assert_eq(entry, s1)
+ assert_eq(entry, s2)
+
for i,(entry,syslinuxentry) in enumerate(zip(entries, syslinux_entries)):
- assert_matches_key(entry, syslinuxentry, 'linux')
- assert_matches_key(entry, syslinuxentry, 'initrd')
+ assert_key_same_file(entry, syslinuxentry, 'linux')
+ assert_key_same_file(entry, syslinuxentry, 'initrd')
entry_ostree = get_ostree_option(entry['options'])
syslinux_ostree = get_ostree_option(syslinuxentry['options'])
if entry_ostree != syslinux_ostree:
diff --git a/tests/libtest.sh b/tests/libtest.sh
index ca457fa..7c66a5c 100755
--- a/tests/libtest.sh
+++ b/tests/libtest.sh
@@ -700,6 +700,12 @@ has_sign_ed25519 () {
return ${ret}
}
+skip_without_sign_ed25519() {
+ if ! has_sign_ed25519; then
+ skip "no ed25519 support compiled in"
+ fi
+}
+
# Keys for ed25519 signing tests
ED25519PUBLIC=
ED25519SEED=
diff --git a/tests/repo-finder-mount.c b/tests/repo-finder-mount.c
index 2cb1d23..3d068af 100644
--- a/tests/repo-finder-mount.c
+++ b/tests/repo-finder-mount.c
@@ -93,16 +93,16 @@ main (int argc, char **argv)
g_ptr_array_add (refs, NULL); /* NULL terminator */
- g_autoptr(GAsyncResult) result = NULL;
+ g_autoptr(GAsyncResult) async_result = NULL;
ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder),
(const OstreeCollectionRef * const *) refs->pdata,
- parent_repo, NULL, result_cb, &result);
+ parent_repo, NULL, result_cb, &async_result);
- while (result == NULL)
+ while (async_result == NULL)
g_main_context_iteration (context, TRUE);
g_autoptr(GPtrArray) results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder),
- result, &error);
+ async_result, &error);
g_assert_no_error (error);
/* Check that the results are correct: the invalid refs should have been
diff --git a/tests/test-admin-deploy-2.sh b/tests/test-admin-deploy-2.sh
index 0fa2df9..6df4877 100755
--- a/tests/test-admin-deploy-2.sh
+++ b/tests/test-admin-deploy-2.sh
@@ -26,7 +26,7 @@ set -euo pipefail
# Exports OSTREE_SYSROOT so --sysroot not needed.
setup_os_repository "archive" "syslinux"
-echo "1..7"
+echo "1..8"
${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime
rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime)
@@ -102,6 +102,13 @@ ${CMD_PREFIX} ostree admin pin -u 0
assert_n_pinned 0
echo "ok pin unpin"
+for p in medal 0medal '' 5000 9999999999999999999999999999999999999; do
+ if ${CMD_PREFIX} ostree admin pin ${p}; then
+ fatal "created invalid pin ${p}"
+ fi
+done
+echo "ok invalid pin"
+
${CMD_PREFIX} ostree admin pin 0 1
assert_n_pinned 2
assert_n_deployments 2
diff --git a/tests/test-basic-user.sh b/tests/test-basic-user.sh
index e56f828..fa17bee 100755
--- a/tests/test-basic-user.sh
+++ b/tests/test-basic-user.sh
@@ -75,6 +75,8 @@ $OSTREE fsck
rm test2-checkout -rf
$OSTREE checkout -U -H test2-unreadable test2-checkout
assert_file_has_mode test2-checkout/unreadable 400
+# Should not be hardlinked
+assert_streq $(stat -c "%h" test2-checkout/unreadable) 1
echo "ok bare-user handled unreadable file"
cd ${test_tmpdir}
diff --git a/tests/test-delta-ed25519.sh b/tests/test-delta-ed25519.sh
new file mode 100755
index 0000000..ef732cf
--- /dev/null
+++ b/tests/test-delta-ed25519.sh
@@ -0,0 +1,322 @@
+#!/bin/bash
+#
+# Copyright (C) 2011,2013 Colin Walters
+#
+# 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
+
+skip_without_user_xattrs
+
+skip_without_sign_ed25519
+
+bindatafiles="bash true ostree"
+
+echo '1..12'
+
+mkdir repo
+ostree_repo_init repo --mode=archive
+
+mkdir files
+for bin in ${bindatafiles}; do
+ cp $(which ${bin}) files
+done
+
+${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files
+
+function permuteFile() {
+ permutation=$(($1 % 2))
+ output=$2
+ case $permutation in
+ 0) dd if=/dev/zero count=40 bs=1 >> $output;;
+ 1) echo aheader | cat - $output >> $output.new && mv $output.new $output;;
+ esac
+}
+
+function permuteDirectory() {
+ permutation=$1
+ dir=$2
+ for x in ${dir}/*; do
+ for z in $(seq ${permutation}); do
+ permuteFile ${z} ${x}
+ done
+ done
+}
+
+get_assert_one_direntry_matching() {
+ local path=$1
+ local r=$2
+ local child=""
+ local bn
+ for p in ${path}/*; do
+ bn=$(basename $p)
+ if ! echo ${bn} | grep -q "$r"; then
+ continue
+ fi
+ if test -z "${child}"; then
+ child=${bn}
+ else
+ assert_not_reached "Expected only one child matching ${r} in ${path}";
+ fi
+ done
+ if test -z "${child}"; then
+ assert_not_reached "Failed to find child matching ${r}"
+ fi
+ echo ${child}
+}
+
+origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test)
+
+permuteDirectory 1 files
+${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files
+
+newrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test)
+
+# Test ostree sign with 'ed25519' module
+gen_ed25519_keys
+PUBLIC=${ED25519PUBLIC}
+SEED=${ED25519SEED}
+SECRET=${ED25519SECRET}
+WRONG_PUBLIC="$(gen_ed25519_random_public)"
+
+SECRETKEYS="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.ed25519)"
+echo ${SECRET} > ${SECRETKEYS}
+
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" > show-ed25519-key-signed-1.txt
+assert_file_has_content show-ed25519-key-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" "${WRONG_PUBLIC}" > show-ed25519-key-signed-2.txt
+assert_file_has_content show-ed25519-key-signed-2.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" "${PUBLIC}" > show-ed25519-key-signed-3.txt
+assert_file_has_content show-ed25519-key-signed-3.txt "Verification OK"
+
+deltaprefix=$(get_assert_one_direntry_matching repo/deltas '.')
+deltadir=$(get_assert_one_direntry_matching repo/deltas/${deltaprefix} '-')
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" > show-ed25519-key-inline-signed-1.txt
+assert_file_has_content show-ed25519-key-inline-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" "${WRONG_PUBLIC}" > show-ed25519-key-inline-signed-2.txt
+assert_file_has_content show-ed25519-key-inline-signed-2.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" "${PUBLIC}" > show-ed25519-key-inline-signed-3.txt
+assert_file_has_content show-ed25519-key-inline-signed-3.txt "Verification OK"
+
+echo 'ok verified with ed25519 (sign - key)'
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" > show-ed25519-keyfile-signed-1.txt
+assert_file_has_content show-ed25519-keyfile-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" "${WRONG_PUBLIC}" > show-ed25519-keyfile-signed-2.txt
+assert_file_has_content show-ed25519-keyfile-signed-2.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" "${PUBLIC}" > show-ed25519-keyfile-signed-3.txt
+assert_file_has_content show-ed25519-keyfile-signed-3.txt "Verification OK"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" > show-ed25519-keyfile-inline-signed-1.txt
+assert_file_has_content show-ed25519-keyfile-inline-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" "${WRONG_PUBLIC}" > show-ed25519-keyfile-inline-signed-2.txt
+assert_file_has_content show-ed25519-keyfile-inline-signed-2.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" "${PUBLIC}" > show-ed25519-keyfile-inline-signed-3.txt
+assert_file_has_content show-ed25519-keyfile-inline-signed-3.txt "Verification OK"
+
+echo 'ok verified with ed25519 (keyfile - key)'
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" > show-ed25519-key-bad-signed.txt && exit 1
+assert_file_has_content show-ed25519-key-bad-signed.txt "Verification fails"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" > show-ed25519-key-bad-inline-signed.txt && exit 1
+assert_file_has_content show-ed25519-key-bad-inline-signed.txt "Verification fails"
+
+echo 'ok Verification fails with ed25519 (sign - bad key)'
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" > show-ed25519-keyfile-bad-signed.txt && exit 1
+assert_file_has_content show-ed25519-keyfile-bad-signed.txt "Verification fails"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" > show-ed25519-keyfile-bad-inline-signed.txt && exit 1
+assert_file_has_content show-ed25519-keyfile-bad-inline-signed.txt "Verification fails"
+
+echo 'ok Verification fails with ed25519 (keyfile - bad key)'
+
+# Prepare files with public ed25519 signatures
+PUBKEYS="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.ed25519)"
+for((i=0;i<100;i++)); do
+ # Generate a list with some public signatures
+ gen_ed25519_random_public
+done > ${PUBKEYS}
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-bad-signed-1.txt && exit 1
+assert_file_has_content show-ed25519-file-bad-signed-1.txt "Verification fails"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-bad-signed-2.txt && exit 1
+assert_file_has_content show-ed25519-file-bad-signed-2.txt "Verification fails"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-inline-bad-signed-1.txt && exit 1
+assert_file_has_content show-ed25519-file-inline-bad-signed-1.txt "Verification fails"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-inline-bad-signed-2.txt && exit 1
+assert_file_has_content show-ed25519-file-inline-bad-signed-2.txt "Verification fails"
+
+echo 'ok Verification fails with ed25519 (sign - bad keys)'
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-bad-signed-3.txt && exit 1
+assert_file_has_content show-ed25519-file-bad-signed-3.txt "Verification fails"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-bad-signed-4.txt && exit 1
+assert_file_has_content show-ed25519-file-bad-signed-4.txt "Verification fails"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-inline-bad-signed-3.txt && exit 1
+assert_file_has_content show-ed25519-file-inline-bad-signed-3.txt "Verification fails"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-inline-bad-signed-4.txt && exit 1
+assert_file_has_content show-ed25519-file-inline-bad-signed-4.txt "Verification fails"
+
+echo 'ok Verification fails with ed25519 (keyfile - bad keys)'
+
+# Add correct key into the list
+echo ${PUBLIC} >> ${PUBKEYS}
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-signed-1.txt
+assert_file_has_content show-ed25519-file-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-signed-2.txt
+assert_file_has_content show-ed25519-file-signed-2.txt "Verification OK"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --sign=${SECRET}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-inline-signed-1.txt
+assert_file_has_content show-ed25519-file-inline-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-inline-signed-2.txt
+assert_file_has_content show-ed25519-file-inline-signed-2.txt "Verification OK"
+
+echo 'ok verified with ed25519 (sign - file)'
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-signed-3.txt
+assert_file_has_content show-ed25519-file-signed-3.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-signed-4.txt
+assert_file_has_content show-ed25519-file-signed-4.txt "Verification OK"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-file-inline-signed-3.txt
+assert_file_has_content show-ed25519-file-inline-signed-3.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-file-inline-signed-4.txt
+assert_file_has_content show-ed25519-file-inline-signed-4.txt "Verification OK"
+
+echo 'ok verified with ed25519 (keyfile - file)'
+
+# Test ostree sign with multiple 'ed25519' keys
+gen_ed25519_keys
+PUBLIC2=${ED25519PUBLIC}
+SEED2=${ED25519SEED}
+SECRET2=${ED25519SECRET}
+
+echo ${SECRET2} >> ${SECRETKEYS}
+echo ${PUBLIC2} >> ${PUBKEYS}
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" > show-ed25519-multiplekeys-signed-1.txt
+assert_file_has_content show-ed25519-multiplekeys-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC2}" > show-ed25519-multiplekeys-signed-2.txt
+assert_file_has_content show-ed25519-multiplekeys-signed-2.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" > show-ed25519-multiplekeys-bad-signed.txt && exit 1
+assert_file_has_content show-ed25519-multiplekeys-bad-signed.txt "Verification fails"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-multiplekeys-signed-3.txt
+assert_file_has_content show-ed25519-multiplekeys-signed-3.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-multiplekeys-signed-4.txt
+assert_file_has_content show-ed25519-multiplekeys-signed-4.txt "Verification OK"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC}" > show-ed25519-multiplekeys-inline-signed-1.txt
+assert_file_has_content show-ed25519-multiplekeys-inline-signed-1.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${PUBLIC2}" > show-ed25519-multiplekeys-inline-signed-2.txt
+assert_file_has_content show-ed25519-multiplekeys-inline-signed-2.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} "${WRONG_PUBLIC}" > show-ed25519-multiplekeys-bad-inline-signed.txt && exit 1
+assert_file_has_content show-ed25519-multiplekeys-bad-inline-signed.txt "Verification fails"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=ed25519 --keys-file=${SECRETKEYS}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} > show-ed25519-multiplekeys-inline-signed-3.txt
+assert_file_has_content show-ed25519-multiplekeys-inline-signed-3.txt "Verification OK"
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=ed25519 ${origrev}-${newrev} --keys-file=${PUBKEYS} "${WRONG_PUBLIC}" > show-ed25519-multiplekeys-inline-signed-4.txt
+assert_file_has_content show-ed25519-multiplekeys-inline-signed-4.txt "Verification OK"
+
+echo 'ok verified with ed25519 (multiple keys)'
+
+rm -rf repo2
+ostree_repo_init repo2 --mode=bare-user
+
+${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev}
+${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null
+${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline --sign-type=ed25519 --keys-file=${PUBKEYS} repo/deltas/${deltaprefix}/${deltadir}
+${CMD_PREFIX} ostree --repo=repo2 fsck
+${CMD_PREFIX} ostree --repo=repo2 ls ${newrev} >/dev/null
+
+echo 'ok apply offline with ed25519 (keyfile)'
+
+mkdir -p ${test_tmpdir}/{trusted,revoked}.ed25519.d
+
+rm -rf repo2
+ostree_repo_init repo2 --mode=bare-user
+
+echo ${PUBLIC} > ${test_tmpdir}/trusted.ed25519.d/correct
+${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev}
+${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null
+${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline --keys-dir=${test_tmpdir} repo/deltas/${deltaprefix}/${deltadir}
+${CMD_PREFIX} ostree --repo=repo2 fsck
+${CMD_PREFIX} ostree --repo=repo2 ls ${newrev} >/dev/null
+
+echo 'ok apply offline with ed25519 (keydir)'
+
+rm -rf repo2
+ostree_repo_init repo2 --mode=bare-user
+
+echo ${PUBLIC} > ${test_tmpdir}/revoked.ed25519.d/correct
+${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev}
+${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null
+if ${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline --keys-dir=${test_tmpdir} repo/deltas/${deltaprefix}/${deltadir}; then
+ exit 1
+fi
+
+rm -rf ${test_tmpdir}/{trusted,revoked}.ed25519.d
+
+echo 'ok apply offline with ed25519 revoking key mechanism (keydir)'
diff --git a/tests/test-delta-sign.sh b/tests/test-delta-sign.sh
new file mode 100755
index 0000000..86f12f9
--- /dev/null
+++ b/tests/test-delta-sign.sh
@@ -0,0 +1,174 @@
+#!/bin/bash
+#
+# Copyright (C) 2011,2013 Colin Walters
+#
+# 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
+
+skip_without_user_xattrs
+
+bindatafiles="bash true ostree"
+
+echo '1..7'
+
+# This is explicitly opt in for testing
+export OSTREE_DUMMY_SIGN_ENABLED=1
+
+mkdir repo
+ostree_repo_init repo --mode=archive
+
+mkdir files
+for bin in ${bindatafiles}; do
+ cp $(which ${bin}) files
+done
+
+${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files
+
+function permuteFile() {
+ permutation=$(($1 % 2))
+ output=$2
+ case $permutation in
+ 0) dd if=/dev/zero count=40 bs=1 >> $output;;
+ 1) echo aheader | cat - $output >> $output.new && mv $output.new $output;;
+ esac
+}
+
+function permuteDirectory() {
+ permutation=$1
+ dir=$2
+ for x in ${dir}/*; do
+ for z in $(seq ${permutation}); do
+ permuteFile ${z} ${x}
+ done
+ done
+}
+
+get_assert_one_direntry_matching() {
+ local path=$1
+ local r=$2
+ local child=""
+ local bn
+ for p in ${path}/*; do
+ bn=$(basename $p)
+ if ! echo ${bn} | grep -q "$r"; then
+ continue
+ fi
+ if test -z "${child}"; then
+ child=${bn}
+ else
+ assert_not_reached "Expected only one child matching ${r} in ${path}";
+ fi
+ done
+ if test -z "${child}"; then
+ assert_not_reached "Failed to find child matching ${r}"
+ fi
+ echo ${child}
+}
+
+origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test)
+
+permuteDirectory 1 files
+${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files
+
+newrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test)
+
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev}
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=dummy ${origrev}-${newrev} dummysign > show-not-signed.txt 2>&1 && exit 1
+assert_file_has_content show-not-signed.txt "Verification fails"
+assert_file_has_content show-not-signed.txt "no signatures in static-delta"
+
+deltaprefix=$(get_assert_one_direntry_matching repo/deltas '.')
+deltadir=$(get_assert_one_direntry_matching repo/deltas/${deltaprefix} '-')
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=dummy ${origrev}-${newrev} dummysign > show-inline-not-signed.txt 2>&1 && exit 1
+assert_file_has_content show-not-signed.txt "Verification fails"
+assert_file_has_content show-not-signed.txt "no signatures in static-delta"
+
+echo 'ok verify ok with unsigned deltas'
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=dummy --sign=dummysign
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=dummy ${origrev}-${newrev} dummysign > show-dummy-signed.txt
+assert_file_has_content show-dummy-signed.txt "Verification OK"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=dummy --sign=dummysign
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=dummy ${origrev}-${newrev} dummysign > show-dummy-inline-signed.txt
+assert_file_has_content show-dummy-inline-signed.txt "Verification OK"
+
+echo 'ok verified with dummy'
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --sign-type=dummy --sign=dummysign
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=dummy ${origrev}-${newrev} badsign > show-dummy-bad-signed.txt && exit 1
+assert_file_has_content show-dummy-bad-signed.txt "Verification fails"
+
+rm -rf repo/deltas/${deltaprefix}/${deltadir}/*
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline --sign-type=dummy --sign=dummysign
+${CMD_PREFIX} ostree --repo=repo static-delta verify --sign-type=dummy ${origrev}-${newrev} badsign > show-dummy-bad-inline-signed.txt && exit 1
+assert_file_has_content show-dummy-bad-inline-signed.txt "Verification fails"
+
+echo 'ok verification failed with dummy and bad key'
+
+rm -rf repo2
+ostree_repo_init repo2 --mode=bare-user
+
+${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev}
+${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null
+${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline repo/deltas/${deltaprefix}/${deltadir}
+${CMD_PREFIX} ostree --repo=repo2 fsck
+${CMD_PREFIX} ostree --repo=repo2 ls ${newrev} >/dev/null
+
+echo 'ok apply offline with no signature verification and no key'
+
+rm -rf repo2
+ostree_repo_init repo2 --mode=bare-user
+
+${CMD_PREFIX} ostree --repo=repo2 config set core.sign-verify-deltas true
+${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev}
+${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null
+${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline repo/deltas/${deltaprefix}/${deltadir} 2> apply-offline-verification-no-key.txt && exit 1
+assert_file_has_content apply-offline-verification-no-key.txt "Key is mandatory to check delta signature"
+
+echo 'ok apply offline failed with signature verification forced and no key'
+
+rm -rf repo2
+ostree_repo_init repo2 --mode=bare-user
+
+${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev}
+${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null
+${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline --sign-type=dummy repo/deltas/${deltaprefix}/${deltadir} dummysign
+${CMD_PREFIX} ostree --repo=repo2 fsck
+${CMD_PREFIX} ostree --repo=repo2 ls ${newrev} >/dev/null
+
+echo 'ok apply offline with dummy'
+
+rm -rf repo2
+ostree_repo_init repo2 --mode=bare-user
+
+${CMD_PREFIX} ostree --repo=repo2 pull-local repo ${origrev}
+${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null
+${CMD_PREFIX} ostree --repo=repo2 static-delta apply-offline --sign-type=dummy repo/deltas/${deltaprefix}/${deltadir} badsign 2> apply-offline-bad-key.txt && exit 1
+assert_file_has_content apply-offline-bad-key.txt "signature: dummy: incorrect signature"
+
+echo 'ok apply offline failed with dummy and bad key'
diff --git a/tests/test-libarchive.sh b/tests/test-libarchive.sh
index 174be80..73a58dd 100755
--- a/tests/test-libarchive.sh
+++ b/tests/test-libarchive.sh
@@ -37,7 +37,7 @@ mkdir foo
cd foo
mkdir -p usr/bin usr/lib
echo contents > usr/bin/foo
-touch usr/bin/foo0
+echo foo0 > usr/bin/foo0
ln usr/bin/foo usr/bin/bar
ln usr/bin/foo0 usr/bin/bar0
ln -s foo usr/bin/sl
@@ -45,8 +45,8 @@ mkdir -p usr/local/bin
ln usr/bin/foo usr/local/bin/baz
ln usr/bin/foo0 usr/local/bin/baz0
ln usr/bin/sl usr/local/bin/slhl
-touch usr/bin/setuidme
-touch usr/bin/skipme
+echo setuidme > usr/bin/setuidme
+echo skipme > usr/bin/skipme
echo "a library" > usr/lib/libfoo.so
echo "another library" > usr/lib/libbar.so
@@ -102,9 +102,9 @@ assert_valid_content () {
assert_file_has_content usr/bin/foo contents
assert_file_has_content usr/bin/bar contents
assert_file_has_content usr/local/bin/baz contents
- assert_file_empty usr/bin/foo0
- assert_file_empty usr/bin/bar0
- assert_file_empty usr/local/bin/baz0
+ assert_file_has_content usr/bin/foo0 foo0
+ assert_file_has_content usr/bin/bar0 foo0
+ assert_file_has_content usr/local/bin/baz0 foo0
assert_file_has_content usr/lib/libfoo.so 'a library'
assert_file_has_content usr/lib/libbar.so 'another library'
@@ -244,7 +244,7 @@ ${CMD_PREFIX} ostree --repo=repo2 commit \
--generate-sizes \
--tree=tar=foo.tar.gz
${CMD_PREFIX} ostree --repo=repo2 show --print-sizes test-tar > sizes.txt
-assert_file_has_content sizes.txt 'Compressed size (needed/total): 0[ ]bytes/1.1[ ]kB'
-assert_file_has_content sizes.txt 'Unpacked size (needed/total): 0[ ]bytes/900[ ]bytes'
-assert_file_has_content sizes.txt 'Number of objects (needed/total): 0/12'
+assert_file_has_content sizes.txt 'Compressed size (needed/total): 0[ ]bytes/1.2[ ]kB'
+assert_file_has_content sizes.txt 'Unpacked size (needed/total): 0[ ]bytes/921[ ]bytes'
+assert_file_has_content sizes.txt 'Number of objects (needed/total): 0/14'
echo "ok tar sizes metadata"
diff --git a/tests/test-osupdate-dtb.sh b/tests/test-osupdate-dtb.sh
new file mode 100755
index 0000000..9e0c468
--- /dev/null
+++ b/tests/test-osupdate-dtb.sh
@@ -0,0 +1,62 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 Red Hat, 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..1"
+
+# Exports OSTREE_SYSROOT so --sysroot not needed.
+kver="3.6.0"
+modulesdir="usr/lib/modules/${kver}"
+setup_os_repository "archive" "syslinux" ${modulesdir}
+
+cd ${test_tmpdir}
+os_repository_new_commit "test" "test with device tree directory"
+
+devicetree_path=osdata/${modulesdir}/dtb/asoc-board.dtb
+devicetree_overlay_path=osdata/${modulesdir}/dtb/overlays/overlay.dtbo
+
+mkdir -p osdata/${modulesdir}/dtb
+echo "a device tree" > ${devicetree_path}
+mkdir -p osdata/${modulesdir}/dtb/overlays
+echo "a device tree overlay" > ${devicetree_overlay_path}
+
+${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmaster/x86_64-runtime
+${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime
+${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo testos/buildmaster/x86_64-runtime
+${CMD_PREFIX} env OSTREE_SYSROOT_DEBUG=${OSTREE_SYSROOT_DEBUG},no-dtb ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime
+assert_has_file sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0
+assert_not_has_file sysroot/boot/ostree/testos-${bootcsum}/dtb/asoc-board.dtb 'a device tree'
+assert_streq $(ls sysroot/boot/ostree | wc -l) 1
+assert_streq $(find sysroot/boot/ostree -name '*.dtb' | wc -l) 0
+${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmaster/x86_64-runtime
+env OSTREE_SYSROOT_DEBUG=${OSTREE_SYSROOT_DEBUG},no-dtb ${CMD_PREFIX} ostree admin upgrade --os=testos
+${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buildmaster/x86_64-runtime
+${CMD_PREFIX} ostree admin upgrade --os=testos
+assert_streq $(ls sysroot/boot/ostree | wc -l) 2
+# Note that the bootcsum computed by the test suite doesn't include devicetree
+# And currently we end up installing the dtb for the *previous* deployment
+# too which is a bug - in the future this should be fixed to assert 1.
+assert_streq $(find sysroot/boot/ostree -name '*.dtb' | wc -l) 2
+
+echo "ok update with no dtb to dtb"
diff --git a/tests/test-repo-finder-config.c b/tests/test-repo-finder-config.c
index 0a2e9e6..b3e8a26 100644
--- a/tests/test-repo-finder-config.c
+++ b/tests/test-repo-finder-config.c
@@ -173,6 +173,9 @@ assert_create_remote (Fixture *fixture,
glnx_shutil_mkdir_p_at (fixture->tmpdir.fd, repo_name, 0700, NULL, &error);
g_assert_no_error (error);
+ glnx_shutil_mkdir_p_at (fixture->tmpdir.fd, "empty", 0700, NULL, &error);
+ g_assert_no_error (error);
+
g_autoptr(GFile) repo_path = g_file_get_child (fixture->working_dir, repo_name);
g_autoptr(OstreeRepo) repo = ostree_repo_new (repo_path);
ostree_repo_set_collection_id (repo, collection_id, &error);
@@ -193,7 +196,7 @@ assert_create_remote (Fixture *fixture,
g_autoptr(OstreeRepoFile) repo_file = NULL;
mtree = ostree_mutable_tree_new ();
- ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, ".", mtree, NULL, NULL, &error);
+ ostree_repo_write_dfd_to_mtree (repo, fixture->tmpdir.fd, "empty", mtree, NULL, NULL, &error);
g_assert_no_error (error);
ostree_repo_write_mtree (repo, mtree, (GFile **) &repo_file, NULL, &error);
g_assert_no_error (error);
@@ -227,7 +230,7 @@ test_repo_finder_config_mixed_configs (Fixture *fixture,
{
g_autoptr(OstreeRepoFinderConfig) finder = NULL;
g_autoptr(GMainContext) context = NULL;
- g_autoptr(GAsyncResult) result = NULL;
+ g_autoptr(GAsyncResult) async_result = NULL;
g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */
g_autoptr(GError) error = NULL;
gsize i;
@@ -263,13 +266,13 @@ test_repo_finder_config_mixed_configs (Fixture *fixture,
/* Resolve the refs. */
ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs,
- fixture->parent_repo, NULL, result_cb, &result);
+ fixture->parent_repo, NULL, result_cb, &async_result);
- while (result == NULL)
+ while (async_result == NULL)
g_main_context_iteration (context, TRUE);
results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder),
- result, &error);
+ async_result, &error);
g_assert_no_error (error);
g_assert_nonnull (results);
g_assert_cmpuint (results->len, ==, 3);
diff --git a/tests/test-repo-finder-mount.c b/tests/test-repo-finder-mount.c
index af2f5e0..45e58fa 100644
--- a/tests/test-repo-finder-mount.c
+++ b/tests/test-repo-finder-mount.c
@@ -190,6 +190,9 @@ assert_create_remote_va (Fixture *fixture,
ostree_repo_create (repo, OSTREE_REPO_MODE_ARCHIVE, NULL, &error);
g_assert_no_error (error);
+ glnx_shutil_mkdir_p_at (fixture->tmpdir.fd, "empty", 0700, NULL, &error);
+ g_assert_no_error (error);
+
/* Set up the refs from @.... */
for (const OstreeCollectionRef *ref = va_arg (args, const OstreeCollectionRef *);
ref != NULL;
@@ -201,7 +204,7 @@ assert_create_remote_va (Fixture *fixture,
gchar **out_checksum = va_arg (args, gchar **);
mtree = ostree_mutable_tree_new ();
- ostree_repo_write_dfd_to_mtree (repo, AT_FDCWD, ".", mtree, NULL, NULL, &error);
+ ostree_repo_write_dfd_to_mtree (repo, fixture->tmpdir.fd, "empty", mtree, NULL, NULL, &error);
g_assert_no_error (error);
ostree_repo_write_mtree (repo, mtree, (GFile **) &repo_file, NULL, &error);
g_assert_no_error (error);
@@ -314,7 +317,7 @@ test_repo_finder_mount_mixed_mounts (Fixture *fixture,
g_autoptr(OstreeRepoFinderMount) finder = NULL;
g_autoptr(GVolumeMonitor) monitor = NULL;
g_autoptr(GMainContext) context = NULL;
- g_autoptr(GAsyncResult) result = NULL;
+ g_autoptr(GAsyncResult) async_result = NULL;
g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */
g_autoptr(GError) error = NULL;
g_autoptr(GList) mounts = NULL; /* (element-type OstreeMockMount) */
@@ -392,13 +395,13 @@ test_repo_finder_mount_mixed_mounts (Fixture *fixture,
/* Resolve the refs. */
ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs,
fixture->parent_repo,
- NULL, result_cb, &result);
+ NULL, result_cb, &async_result);
- while (result == NULL)
+ while (async_result == NULL)
g_main_context_iteration (context, TRUE);
results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder),
- result, &error);
+ async_result, &error);
g_assert_no_error (error);
g_assert_nonnull (results);
g_assert_cmpuint (results->len, ==, 4);
@@ -463,7 +466,7 @@ test_repo_finder_mount_well_known (Fixture *fixture,
g_autoptr(OstreeRepoFinderMount) finder = NULL;
g_autoptr(GVolumeMonitor) monitor = NULL;
g_autoptr(GMainContext) context = NULL;
- g_autoptr(GAsyncResult) result = NULL;
+ g_autoptr(GAsyncResult) async_result = NULL;
g_autoptr(GPtrArray) results = NULL; /* (element-type OstreeRepoFinderResult) */
g_autoptr(GError) error = NULL;
g_autoptr(GList) mounts = NULL; /* (element-type OstreeMockMount) */
@@ -504,13 +507,13 @@ test_repo_finder_mount_well_known (Fixture *fixture,
/* Resolve the refs. */
ostree_repo_finder_resolve_async (OSTREE_REPO_FINDER (finder), refs,
fixture->parent_repo,
- NULL, result_cb, &result);
+ NULL, result_cb, &async_result);
- while (result == NULL)
+ while (async_result == NULL)
g_main_context_iteration (context, TRUE);
results = ostree_repo_finder_resolve_finish (OSTREE_REPO_FINDER (finder),
- result, &error);
+ async_result, &error);
g_assert_no_error (error);
g_assert_nonnull (results);
g_assert_cmpuint (results->len, ==, 2);
diff --git a/tests/test-summary-view.sh b/tests/test-summary-view.sh
index 14de029..f6278a8 100755
--- a/tests/test-summary-view.sh
+++ b/tests/test-summary-view.sh
@@ -64,5 +64,5 @@ echo "ok view summary"
${OSTREE} summary --raw > raw-summary.txt
assert_file_has_content_literal raw-summary.txt "('main', ("
assert_file_has_content_literal raw-summary.txt "('other', ("
-assert_file_has_content_literal raw-summary.txt "{'ostree.summary.last-modified': released-sha256.txt <