diff --git a/Makefile-bash.am b/Makefile-bash.am index e61829a2..2cb03151 100644 --- a/Makefile-bash.am +++ b/Makefile-bash.am @@ -19,3 +19,6 @@ completionsdir = @BASH_COMPLETIONSDIR@ dist_completions_DATA = bash/ostree + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS += BASH_COMPLETIONSDIR='$${datadir}/bash-completion/completions' diff --git a/Makefile-boot.am b/Makefile-boot.am index 8d7ade07..828187ec 100644 --- a/Makefile-boot.am +++ b/Makefile-boot.am @@ -38,6 +38,8 @@ endif if BUILDOPT_SYSTEMD systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ src/boot/ostree-remount.service +systemdtmpfilesdir = $(prefix)/lib/tmpfiles.d +dist_systemdtmpfiles_DATA = src/boot/ostree-tmpfiles.conf # Allow the distcheck install under $prefix test to pass AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemdsystemunitdir='$${libdir}/systemd/system' diff --git a/Makefile-switchroot.am b/Makefile-switchroot.am index dd24010e..70aa1c87 100644 --- a/Makefile-switchroot.am +++ b/Makefile-switchroot.am @@ -68,4 +68,7 @@ ostree_system_generator_SOURCES = src/switchroot/ostree-mount-util.h \ ostree_system_generator_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libostree ostree_system_generator_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) ostree_system_generator_LDADD = $(AM_LDFLAGS) libglnx.la libostree-1.la $(OT_INTERNAL_GIO_UNIX_LIBS) + +# Allow the distcheck install under $prefix test to pass +AM_DISTCHECK_CONFIGURE_FLAGS += --with-systemdsystemgeneratordir='$${libdir}/systemd/system-generators' endif diff --git a/Makefile-tests.am b/Makefile-tests.am index 82ce7209..6a52faeb 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -186,6 +186,7 @@ endif js_installed_tests = \ tests/test-core.js \ + tests/test-remotes-config-dir.js \ tests/test-sizes.js \ tests/test-sysroot.js \ $(NULL) diff --git a/Makefile.in b/Makefile.in index 73d58487..66a51b1e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -493,41 +493,44 @@ check_PROGRAMS = $(am__EXEEXT_11) $(am__EXEEXT_12) $(am__EXEEXT_13) @BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_59 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 @BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@systemdsystemgenerator_PROGRAMS = ostree-system-generator$(EXEEXT) @BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_60 = $(systemdsystemgenerator_PROGRAMS) -@BUILDOPT_FUSE_TRUE@am__append_61 = rofiles-fuse -@BUILDOPT_ASAN_TRUE@am__append_62 = OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc -@ENABLE_EXPERIMENTAL_API_TRUE@am__append_63 = $(experimental_test_scripts) -@ENABLE_EXPERIMENTAL_API_FALSE@am__append_64 = $(experimental_test_scripts) -@BUILDOPT_FUSE_TRUE@am__append_65 = tests/test-rofiles-fuse.sh -@BUILDOPT_FUSE_FALSE@am__append_66 = tests/test-rofiles-fuse.sh -@USE_LIBSOUP_TRUE@am__append_67 = tests/test-remote-cookies.sh -@BUILDOPT_GJS_TRUE@am__append_68 = $(js_tests) $(js_installed_tests) -@BUILDOPT_GJS_FALSE@am__append_69 = $(js_tests) -@BUILDOPT_GJS_FALSE@am__append_70 = $(js_installed_tests) -@ENABLE_INSTALLED_TESTS_FALSE@am__append_71 = -rpath $(abs_builddir) -@ENABLE_EXPERIMENTAL_API_TRUE@am__append_72 = \ + +# Allow the distcheck install under $prefix test to pass +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_61 = --with-systemdsystemgeneratordir='$${libdir}/systemd/system-generators' +@BUILDOPT_FUSE_TRUE@am__append_62 = rofiles-fuse +@BUILDOPT_ASAN_TRUE@am__append_63 = OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_64 = $(experimental_test_scripts) +@ENABLE_EXPERIMENTAL_API_FALSE@am__append_65 = $(experimental_test_scripts) +@BUILDOPT_FUSE_TRUE@am__append_66 = tests/test-rofiles-fuse.sh +@BUILDOPT_FUSE_FALSE@am__append_67 = tests/test-rofiles-fuse.sh +@USE_LIBSOUP_TRUE@am__append_68 = tests/test-remote-cookies.sh +@BUILDOPT_GJS_TRUE@am__append_69 = $(js_tests) $(js_installed_tests) +@BUILDOPT_GJS_FALSE@am__append_70 = $(js_tests) +@BUILDOPT_GJS_FALSE@am__append_71 = $(js_installed_tests) +@ENABLE_INSTALLED_TESTS_FALSE@am__append_72 = -rpath $(abs_builddir) +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_73 = \ @ENABLE_EXPERIMENTAL_API_TRUE@ tests/test-bloom \ @ENABLE_EXPERIMENTAL_API_TRUE@ tests/test-repo-finder-config \ @ENABLE_EXPERIMENTAL_API_TRUE@ tests/test-repo-finder-mount \ @ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) -@ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@am__append_73 = tests/test-repo-finder-avahi -@USE_LIBARCHIVE_TRUE@am__append_74 = tests/test-libarchive-import -@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_75 = $(_installed_or_uninstalled_test_scripts) -@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_76 = $(_installed_or_uninstalled_test_programs) -@ENABLE_INSTALLED_TESTS_TRUE@am__append_77 = install-installed-tests-extra +@ENABLE_EXPERIMENTAL_API_TRUE@@USE_AVAHI_TRUE@am__append_74 = tests/test-repo-finder-avahi +@USE_LIBARCHIVE_TRUE@am__append_75 = tests/test-libarchive-import +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_76 = $(_installed_or_uninstalled_test_scripts) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_77 = $(_installed_or_uninstalled_test_programs) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_78 = install-installed-tests-extra # Allow the distcheck install under $prefix test to pass -@BUILDOPT_SYSTEMD_TRUE@am__append_78 = --with-systemdsystemunitdir='$${libdir}/systemd/system' +@BUILDOPT_SYSTEMD_TRUE@am__append_79 = --with-systemdsystemunitdir='$${libdir}/systemd/system' # We're using the system grub2-mkconfig generator -@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_79 = src/boot/grub2/grub2-15_ostree -@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_80 = install-grub2-config-hook -@BUILDOPT_TRIVIAL_HTTPD_TRUE@@ENABLE_MAN_TRUE@am__append_81 = ostree-trivial-httpd.1 +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_80 = src/boot/grub2/grub2-15_ostree +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_81 = install-grub2-config-hook +@BUILDOPT_TRIVIAL_HTTPD_TRUE@@ENABLE_MAN_TRUE@am__append_82 = ostree-trivial-httpd.1 # We still want to distribute the source, even if we are not building it -@BUILDOPT_TRIVIAL_HTTPD_FALSE@@ENABLE_MAN_TRUE@am__append_82 = man/ostree-trivial-httpd.xml -@BUILDOPT_FUSE_TRUE@@ENABLE_MAN_TRUE@am__append_83 = rofiles-fuse.1 -@ENABLE_MAN_TRUE@am__append_84 = $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) -@ENABLE_MAN_TRUE@am__append_85 = \ +@BUILDOPT_TRIVIAL_HTTPD_FALSE@@ENABLE_MAN_TRUE@am__append_83 = man/ostree-trivial-httpd.xml +@BUILDOPT_FUSE_TRUE@@ENABLE_MAN_TRUE@am__append_84 = rofiles-fuse.1 +@ENABLE_MAN_TRUE@am__append_85 = $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) +@ENABLE_MAN_TRUE@am__append_86 = \ @ENABLE_MAN_TRUE@ $(man1_MANS) \ @ENABLE_MAN_TRUE@ $(man5_MANS) \ @ENABLE_MAN_TRUE@ $(NULL) @@ -551,6 +554,7 @@ DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__dist_gpginsttest_DATA_DIST) \ $(am__dist_gpginsttest_trusted_DATA_DIST) \ $(am__dist_gpgvinsttest_DATA_DIST) \ + $(am__dist_systemdtmpfiles_DATA_DIST) \ $(am__libostreeinclude_HEADERS_DIST) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno @@ -598,7 +602,8 @@ am__installdirs = "$(DESTDIR)$(installed_testdir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" \ "$(DESTDIR)$(completionsdir)" "$(DESTDIR)$(gpginsttestdir)" \ "$(DESTDIR)$(gpginsttest_trusteddir)" \ - "$(DESTDIR)$(gpgvinsttestdir)" "$(DESTDIR)$(dracutconfdir)" \ + "$(DESTDIR)$(gpgvinsttestdir)" \ + "$(DESTDIR)$(systemdtmpfilesdir)" "$(DESTDIR)$(dracutconfdir)" \ "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" \ "$(DESTDIR)$(installed_testdir)" \ "$(DESTDIR)$(installed_test_metadir)" \ @@ -1415,13 +1420,14 @@ am__dist_gpginsttest_trusted_DATA_DIST = \ tests/gpghome/trusted/pubring.gpg am__dist_gpgvinsttest_DATA_DIST = $(addprefix tests/gpg-verify-data/, \ gpg.conf lgpl2 lgpl2.sig pubring.gpg secring.gpg trustdb.gpg) +am__dist_systemdtmpfiles_DATA_DIST = src/boot/ostree-tmpfiles.conf DATA = $(dist_completions_DATA) $(dist_gpginsttest_DATA) \ $(dist_gpginsttest_trusted_DATA) $(dist_gpgvinsttest_DATA) \ - $(dracutconf_DATA) $(gir_DATA) $(gpgreadme_DATA) \ - $(installed_test_DATA) $(installed_test_meta_DATA) \ - $(mkinitcpioconf_DATA) $(nobase_installed_test_DATA) \ - $(noinst_DATA) $(pkgconfig_DATA) $(systemdsystemunit_DATA) \ - $(typelib_DATA) + $(dist_systemdtmpfiles_DATA) $(dracutconf_DATA) $(gir_DATA) \ + $(gpgreadme_DATA) $(installed_test_DATA) \ + $(installed_test_meta_DATA) $(mkinitcpioconf_DATA) \ + $(nobase_installed_test_DATA) $(noinst_DATA) $(pkgconfig_DATA) \ + $(systemdsystemunit_DATA) $(typelib_DATA) am__libostreeinclude_HEADERS_DIST = src/libostree/ostree.h \ src/libostree/ostree-async-progress.h \ src/libostree/ostree-autocleanups.h \ @@ -1635,8 +1641,8 @@ am__EXEEXT_19 = tests/test-find-remotes.sh \ tests/test-summary-collections.sh \ tests/test-pull-collections.sh $(am__EXEEXT_2) @ENABLE_EXPERIMENTAL_API_TRUE@am__EXEEXT_20 = $(am__EXEEXT_19) -am__EXEEXT_21 = tests/test-core.js tests/test-sizes.js \ - tests/test-sysroot.js $(am__EXEEXT_2) +am__EXEEXT_21 = tests/test-core.js tests/test-remotes-config-dir.js \ + tests/test-sizes.js tests/test-sysroot.js $(am__EXEEXT_2) @BUILDOPT_GJS_TRUE@am__EXEEXT_22 = $(js_tests) $(am__EXEEXT_21) am__EXEEXT_23 = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-basic-user-only.sh tests/test-basic-root.sh \ @@ -1675,7 +1681,7 @@ am__EXEEXT_23 = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-switchroot.sh tests/test-pull-contenturl.sh \ tests/test-pull-mirrorlist.sh tests/test-summary-update.sh \ tests/test-summary-view.sh $(am__EXEEXT_2) $(am__EXEEXT_20) \ - $(am__append_65) $(am__append_67) $(am__EXEEXT_22) + $(am__append_66) $(am__append_68) $(am__EXEEXT_22) @ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__EXEEXT_24 = \ @ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@ $(am__EXEEXT_23) am__EXEEXT_25 = $(am__EXEEXT_2) $(am__EXEEXT_24) @@ -1967,8 +1973,12 @@ AM_CPPFLAGS = -DDATADIR='"$(datadir)"' -DLIBEXECDIR='"$(libexecdir)"' \ -DSOUP_VERSION_MIN_REQUIRED=SOUP_VERSION_2_40 \ -DSOUP_VERSION_MAX_ALLOWED=SOUP_VERSION_2_48 AM_CFLAGS = -std=gnu99 $(WARN_CFLAGS) + +# Allow the distcheck install under $prefix test to pass AM_DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-man \ - --disable-maintainer-mode $(NULL) $(am__append_78) + --disable-maintainer-mode $(NULL) $(am__append_61) \ + $(am__append_79) \ + BASH_COMPLETIONSDIR='$${datadir}/bash-completion/completions' SUBDIRS = . $(am__append_14) NULL = BUILT_SOURCES = $(nodist_libostree_1_la_SOURCES) @@ -1980,7 +1990,7 @@ CLEANFILES = $(am__append_13) $(BUILT_SOURCES) $(am__append_46) \ tests/ostree-remount-symlink-stamp \ tests/rofiles-fuse-symlink-stamp tests/ostree \ tests/ostree-prepare-root tests/ostree-remount \ - tests/rofiles-fuse $(am__append_85) + tests/rofiles-fuse $(am__append_86) EXTRA_DIST = $(all_dist_test_scripts) $(all_dist_test_data) autogen.sh \ COPYING README.md $(am__append_15) libglnx/README.md \ libglnx/COPYING libglnx/libglnx.m4 $(NULL) \ @@ -1997,19 +2007,19 @@ EXTRA_DIST = $(all_dist_test_scripts) $(all_dist_test_data) autogen.sh \ src/libostree/ostree-repo-deprecated.h \ src/libostree/ostree-version.h src/ostree/parse-datetime.y \ buildutil/tap-driver.sh buildutil/tap-test tests/glib.supp \ - tests/ostree.supp $(NULL) $(am__append_64) $(am__append_66) \ - $(am__append_69) tests/libtest.sh $(am__append_70) \ + tests/ostree.supp $(NULL) $(am__append_65) $(am__append_67) \ + $(am__append_70) tests/libtest.sh $(am__append_71) \ tests/libostreetest.h tests/libtest.sh \ tests/gpg-verify-data/README.md $(NULL) \ src/boot/dracut/module-setup.sh src/boot/dracut/ostree.conf \ src/boot/mkinitcpio/ostree \ src/boot/ostree-prepare-root.service \ src/boot/ostree-remount.service src/boot/grub2/grub2-15_ostree \ - src/boot/grub2/ostree-grub-generator $(NULL) $(am__append_82) \ - $(am__append_84) + src/boot/grub2/ostree-grub-generator $(NULL) $(am__append_83) \ + $(am__append_85) bin_SCRIPTS = lib_LTLIBRARIES = libostree-1.la -pkglibexec_SCRIPTS = $(am__append_79) +pkglibexec_SCRIPTS = $(am__append_80) noinst_LTLIBRARIES = $(am__append_1) libglnx.la libbsdiff.la \ libotutil.la libostree-kernel-args.la $(am__append_18) \ libostreetest.la @@ -2039,7 +2049,7 @@ AM_TESTS_ENVIRONMENT = G_TEST_SRCDIR="$(abs_srcdir)" \ LD_LIBRARY_PATH=$$(cd $(top_builddir)/.libs && \ pwd)$${LD_LIBRARY_PATH:+:$${LD_LIBRARY_PATH}} PATH=$$(cd \ $(top_builddir)/tests && pwd):$${PATH} \ - OSTREE_FEATURES="$(OSTREE_FEATURES)" $(NULL) $(am__append_62) + OSTREE_FEATURES="$(OSTREE_FEATURES)" $(NULL) $(am__append_63) LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/buildutil/tap-driver.sh LOG_COMPILER = $(top_srcdir)/buildutil/tap-test installed_test_LTLIBRARIES = $(am__append_12) @@ -2079,8 +2089,8 @@ all_test_ltlibs = $(test_ltlibraries) $(uninstalled_test_ltlibraries) $(installe # This initializes some more variables # This is a special facility to chain together hooks easily -INSTALL_DATA_HOOKS = install-mkdir-remotes-d-hook $(am__append_77) \ - $(am__append_80) +INSTALL_DATA_HOOKS = install-mkdir-remotes-d-hook $(am__append_78) \ + $(am__append_81) 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) @@ -2439,9 +2449,9 @@ dist_uninstalled_test_scripts = tests/test-symbols.sh tests/coccinelle.sh # tests *only* run installed, to avoid having to run them twice in CI. # This overrides the glib-tap.mk emphasis on doing both, if we'd # used e.g. `dist_test_scripts`. -dist_test_scripts = $(NULL) $(am__append_75) -test_programs = $(NULL) $(am__append_72) $(am__append_73) \ - $(am__append_76) +dist_test_scripts = $(NULL) $(am__append_76) +test_programs = $(NULL) $(am__append_73) $(am__append_74) \ + $(am__append_77) _installed_or_uninstalled_test_scripts = tests/test-basic.sh \ tests/test-basic-user.sh tests/test-basic-user-only.sh \ tests/test-basic-root.sh tests/test-pull-subpath.sh \ @@ -2478,8 +2488,8 @@ _installed_or_uninstalled_test_scripts = tests/test-basic.sh \ tests/test-refs.sh tests/test-demo-buildsystem.sh \ tests/test-switchroot.sh tests/test-pull-contenturl.sh \ tests/test-pull-mirrorlist.sh tests/test-summary-update.sh \ - tests/test-summary-view.sh $(NULL) $(am__append_63) \ - $(am__append_65) $(am__append_67) $(am__append_68) + tests/test-summary-view.sh $(NULL) $(am__append_64) \ + $(am__append_66) $(am__append_68) $(am__append_69) experimental_test_scripts = \ tests/test-find-remotes.sh \ tests/test-fsck-collections.sh \ @@ -2528,6 +2538,7 @@ dist_test_extra_scripts = \ js_installed_tests = \ tests/test-core.js \ + tests/test-remotes-config-dir.js \ tests/test-sizes.js \ tests/test-sysroot.js \ $(NULL) @@ -2541,14 +2552,14 @@ libreaddir_rand_la_LIBADD = \ $(NULL) libreaddir_rand_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version \ - $(am__append_71) + $(am__append_72) _installed_or_uninstalled_test_programs = tests/test-varint \ tests/test-ot-unix-utils tests/test-bsdiff \ tests/test-mutable-tree tests/test-keyfile-utils \ tests/test-ot-opt-utils tests/test-ot-tool-util \ tests/test-gpg-verify-result tests/test-checksum \ tests/test-lzma tests/test-rollsum tests/test-basic-c \ - tests/test-sysroot-c tests/test-pull-c $(am__append_74) + tests/test-sysroot-c tests/test-pull-c $(am__append_75) common_tests_cflags = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx common_tests_ldadd = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_GIO_UNIX_LIBS) libostreetest_la_SOURCES = tests/libostreetest.c tests/test-mock-gio.c tests/test-mock-gio.h @@ -2629,6 +2640,8 @@ tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) @BUILDOPT_SYSTEMD_TRUE@systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ @BUILDOPT_SYSTEMD_TRUE@ src/boot/ostree-remount.service +@BUILDOPT_SYSTEMD_TRUE@systemdtmpfilesdir = $(prefix)/lib/tmpfiles.d +@BUILDOPT_SYSTEMD_TRUE@dist_systemdtmpfiles_DATA = src/boot/ostree-tmpfiles.conf @BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@grub2configdir = $(sysconfdir)/grub.d @ENABLE_MAN_TRUE@man1_files = ostree.1 ostree-admin-cleanup.1 \ @ENABLE_MAN_TRUE@ ostree-admin-config-diff.1 \ @@ -2647,8 +2660,8 @@ tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) @ENABLE_MAN_TRUE@ ostree-pull.1 ostree-refs.1 ostree-remote.1 \ @ENABLE_MAN_TRUE@ ostree-reset.1 ostree-rev-parse.1 \ @ENABLE_MAN_TRUE@ ostree-show.1 ostree-summary.1 \ -@ENABLE_MAN_TRUE@ ostree-static-delta.1 $(am__append_81) \ -@ENABLE_MAN_TRUE@ $(am__append_83) +@ENABLE_MAN_TRUE@ ostree-static-delta.1 $(am__append_82) \ +@ENABLE_MAN_TRUE@ $(am__append_84) @ENABLE_MAN_TRUE@man5_files = ostree.repo.5 ostree.repo-config.5 @ENABLE_MAN_TRUE@man1_MANS = $(addprefix man/,$(man1_files)) @ENABLE_MAN_TRUE@man5_MANS = $(addprefix man/,$(man5_files)) @@ -6464,6 +6477,27 @@ uninstall-dist_gpgvinsttestDATA: @list='$(dist_gpgvinsttest_DATA)'; test -n "$(gpgvinsttestdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(gpgvinsttestdir)'; $(am__uninstall_files_from_dir) +install-dist_systemdtmpfilesDATA: $(dist_systemdtmpfiles_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemdtmpfilesdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemdtmpfilesdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdtmpfilesdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdtmpfilesdir)" || exit $$?; \ + done + +uninstall-dist_systemdtmpfilesDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_systemdtmpfiles_DATA)'; test -n "$(systemdtmpfilesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemdtmpfilesdir)'; $(am__uninstall_files_from_dir) install-dracutconfDATA: $(dracutconf_DATA) @$(NORMAL_INSTALL) @list='$(dracutconf_DATA)'; test -n "$(dracutconfdir)" || list=; \ @@ -7583,6 +7617,13 @@ tests/test-core.js.log: tests/test-core.js --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-remotes-config-dir.js.log: tests/test-remotes-config-dir.js + @p='tests/test-remotes-config-dir.js'; \ + b='tests/test-remotes-config-dir.js'; \ + $(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-sizes.js.log: tests/test-sizes.js @p='tests/test-sizes.js'; \ b='tests/test-sizes.js'; \ @@ -7858,7 +7899,7 @@ install-binPROGRAMS: install-libLTLIBRARIES installdirs: installdirs-recursive installdirs-am: - for dir in "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(privlibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(systemdsystemgeneratordir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(mkinitcpioinstalldir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(completionsdir)" "$(DESTDIR)$(gpginsttestdir)" "$(DESTDIR)$(gpginsttest_trusteddir)" "$(DESTDIR)$(gpgvinsttestdir)" "$(DESTDIR)$(dracutconfdir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(installed_test_metadir)" "$(DESTDIR)$(mkinitcpioconfdir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(typelibdir)" "$(DESTDIR)$(libostreeincludedir)"; do \ + for dir in "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(privlibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(systemdsystemgeneratordir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(mkinitcpioinstalldir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(completionsdir)" "$(DESTDIR)$(gpginsttestdir)" "$(DESTDIR)$(gpginsttest_trusteddir)" "$(DESTDIR)$(gpgvinsttestdir)" "$(DESTDIR)$(systemdtmpfilesdir)" "$(DESTDIR)$(dracutconfdir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(installed_test_metadir)" "$(DESTDIR)$(mkinitcpioconfdir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(typelibdir)" "$(DESTDIR)$(libostreeincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) @@ -7949,8 +7990,9 @@ info-am: install-data-am: install-dist_completionsDATA \ install-dist_gpginsttestDATA \ install-dist_gpginsttest_trustedDATA \ - install-dist_gpgvinsttestDATA install-dracutconfDATA \ - install-dracutmodSCRIPTS install-girDATA install-gpgreadmeDATA \ + install-dist_gpgvinsttestDATA install-dist_systemdtmpfilesDATA \ + install-dracutconfDATA install-dracutmodSCRIPTS \ + install-girDATA install-gpgreadmeDATA \ install-installed_testDATA install-installed_testLTLIBRARIES \ install-installed_testPROGRAMS install-installed_testSCRIPTS \ install-installed_test_metaDATA \ @@ -8015,7 +8057,8 @@ ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-dist_completionsDATA uninstall-dist_gpginsttestDATA \ uninstall-dist_gpginsttest_trustedDATA \ - uninstall-dist_gpgvinsttestDATA uninstall-dracutconfDATA \ + uninstall-dist_gpgvinsttestDATA \ + uninstall-dist_systemdtmpfilesDATA uninstall-dracutconfDATA \ uninstall-dracutmodSCRIPTS uninstall-girDATA \ uninstall-gpgreadmeDATA uninstall-installed_testDATA \ uninstall-installed_testLTLIBRARIES \ @@ -8057,9 +8100,9 @@ uninstall-man: uninstall-man1 uninstall-man5 install-data install-data-am install-data-hook \ install-dist_completionsDATA install-dist_gpginsttestDATA \ install-dist_gpginsttest_trustedDATA \ - install-dist_gpgvinsttestDATA install-dracutconfDATA \ - install-dracutmodSCRIPTS install-dvi install-dvi-am \ - install-exec install-exec-am install-girDATA \ + install-dist_gpgvinsttestDATA install-dist_systemdtmpfilesDATA \ + install-dracutconfDATA install-dracutmodSCRIPTS install-dvi \ + install-dvi-am install-exec install-exec-am install-girDATA \ install-gpgreadmeDATA install-html install-html-am \ install-info install-info-am install-installed_testDATA \ install-installed_testLTLIBRARIES \ @@ -8082,7 +8125,8 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-dist_completionsDATA uninstall-dist_gpginsttestDATA \ uninstall-dist_gpginsttest_trustedDATA \ - uninstall-dist_gpgvinsttestDATA uninstall-dracutconfDATA \ + uninstall-dist_gpgvinsttestDATA \ + uninstall-dist_systemdtmpfilesDATA uninstall-dracutconfDATA \ uninstall-dracutmodSCRIPTS uninstall-girDATA \ uninstall-gpgreadmeDATA uninstall-installed_testDATA \ uninstall-installed_testLTLIBRARIES \ diff --git a/README.md b/README.md index 743d49df..3e72c061 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,22 @@ -libOSTree -====== +libostree +--------- New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs.org/en/latest/ ) ----- -This project is now known as "libOSTree", renamed from "OSTree"; the focus is on -the shared library. However, in most of the rest of the documentation, we will -use the term "OSTree", since it's slightly shorter, and changing all -documentation at once is impractical. We expect to transition to the new name -over time. +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 +libostree's shared library, rather than users directly invoking the command line +tools (except for build systems). However, in most of the rest of the +documentation, we will use the term "OSTree", since it's slightly shorter, and +changing all documentation at once is impractical. We expect to transition to +the new name over time. -libOSTree is a library and suite of command line tools that combines a -"git-like" model for committing and downloading bootable filesystem trees, along -with a layer for deploying them and managing the bootloader configuration. +As implied above, libostree is both a shared library and suite of command line +tools that combines a "git-like" model for committing and downloading bootable +filesystem trees, along with a layer for deploying them and managing the +bootloader configuration. The core OSTree model is like git in that it checksums individual files and has a content-addressed-object store. It's unlike git in that it "checks out" the @@ -24,16 +27,14 @@ of **Features:** - - Atomic upgrades and rollback for the system + - Transactional upgrades and rollback for the system - Replicating content incrementally over HTTP via GPG signatures and "pinned TLS" support - Support for parallel installing more than just 2 bootable roots - Binary history on the server side (and client) - Introspectable shared library API for build and deployment systems - -This last point is important - you should think of the OSTree command -line as effectively a "demo" for the shared library. The intent is that -package managers, system upgrade tools, container build tools and the like -use OSTree as a "deduplicating hardlink store". + - Flexible support for multiple branches and repositories, supporting + projects like [flatpak](https://github.com/flatpak/flatpak) which + use libostree for applications, rather than hosts. Projects using OSTree --------------------- @@ -87,6 +88,7 @@ Once you have a git clone or recursive archive, building is the same as almost every autotools project: ``` +git submodule update --init env NOCONFIGURE=1 ./autogen.sh ./configure --prefix=... make diff --git a/apidoc/html/index.html b/apidoc/html/index.html index cce508d9..f894a4dc 100644 --- a/apidoc/html/index.html +++ b/apidoc/html/index.html @@ -14,7 +14,7 @@
-

for OSTree 2017.10

+

for OSTree 2017.11


@@ -25,7 +25,7 @@ Core repository-independent functions — Create, validate, and convert core data types
-Content-addressed object store — A git-like storage system for operating system binaries +OstreeRepo: Content-addressed object store — A git-like storage system for operating system binaries
In-memory modifiable filesystem tree — Modifiable filesystem tree diff --git a/apidoc/html/ostree-Core-repository-independent-functions.html b/apidoc/html/ostree-Core-repository-independent-functions.html index 5025b76f..6f1b1c39 100644 --- a/apidoc/html/ostree-Core-repository-independent-functions.html +++ b/apidoc/html/ostree-Core-repository-independent-functions.html @@ -7,7 +7,7 @@ - + @@ -20,7 +20,7 @@ Home Up Prev -Next +Next
@@ -1627,7 +1627,7 @@ ostree_raw_file_to_content_stream (GError **error);

Convert from a "bare" file representation into an OSTREE_OBJECT_TYPE_FILE stream. This is a fundamental operation -for writing data to an OstreeRepo.

+for writing data to an OstreeRepo.

Parameters

diff --git a/apidoc/html/ostree-GPG-signature-verification-results.html b/apidoc/html/ostree-GPG-signature-verification-results.html index 8eae5500..3e8ec0d2 100644 --- a/apidoc/html/ostree-GPG-signature-verification-results.html +++ b/apidoc/html/ostree-GPG-signature-verification-results.html @@ -136,7 +136,7 @@

Description

OstreeGpgVerifyResult contains verification details for GPG signatures -read from a detached OstreeRepo metadata object.

+read from a detached OstreeRepo metadata object.

Use ostree_gpg_verify_result_count_all() and ostree_gpg_verify_result_count_valid() to quickly check overall signature validity.

@@ -482,7 +482,7 @@ ostree_gpg_verify_result_require_valid_signature GError **error);

Checks if the result contains at least one signature from the trusted keyring. You can call this function immediately after -ostree_repo_verify_summary() or ostree_repo_verify_commit_ext() - +ostree_repo_verify_summary() or ostree_repo_verify_commit_ext() - it will handle the NULL result and filled error too.

@@ -666,6 +666,16 @@ The attribute's GVariantType is shown in brackets.

+ + + + +
 

OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY

+

[G_VARIANT_TYPE_STRING] Fingerprint of the signing key's primary key + (will be the same as OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT if the + the signature is already from the primary key rather than a subkey, + and will be the empty string if the key is missing.)

+
 
diff --git a/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html b/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html index bf60a751..bbf55d39 100644 --- a/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html +++ b/apidoc/html/ostree-In-memory-modifiable-filesystem-tree.html @@ -6,7 +6,7 @@ - + @@ -19,7 +19,7 @@ Home Up -Prev +Prev Next
@@ -151,7 +151,7 @@

Description

-

In order to commit content into an OstreeRepo, it must first be +

In order to commit content into an OstreeRepo, it must first be imported into an OstreeMutableTree. There are several high level APIs to create an initiable OstreeMutableTree from a physical filesystem directory, but they may also be computed diff --git a/apidoc/html/ostree-Content-addressed-object-store.html b/apidoc/html/ostree-OstreeRepo.html similarity index 81% rename from apidoc/html/ostree-Content-addressed-object-store.html rename to apidoc/html/ostree-OstreeRepo.html index ee519691..2f5d24a7 100644 --- a/apidoc/html/ostree-Content-addressed-object-store.html +++ b/apidoc/html/ostree-OstreeRepo.html @@ -2,7 +2,7 @@ -Content-addressed object store: OSTree API references +OstreeRepo: Content-addressed object store: OSTree API references @@ -15,7 +15,7 @@ @@ -23,16 +23,16 @@

-
+
-

Content-addressed object store

-

Content-addressed object store — A git-like storage system for operating system binaries

+

OstreeRepo: Content-addressed object store

+

OstreeRepo: Content-addressed object store — A git-like storage system for operating system binaries

-

Functions

+

Functions

@@ -44,39 +44,39 @@ gboolean @@ -84,7 +84,7 @@ gboolean @@ -92,7 +92,7 @@ void @@ -100,7 +100,7 @@ gboolean @@ -108,7 +108,7 @@ gboolean @@ -116,15 +116,15 @@ gboolean @@ -132,7 +132,7 @@ gboolean @@ -140,15 +140,15 @@ GFile * @@ -156,7 +156,7 @@ GKeyFile * @@ -164,7 +164,7 @@ int @@ -172,7 +172,7 @@ GKeyFile * @@ -180,7 +180,7 @@ gboolean @@ -188,7 +188,7 @@ gboolean @@ -196,7 +196,7 @@ gboolean @@ -204,7 +204,7 @@ char ** @@ -212,7 +212,7 @@ gboolean @@ -220,7 +220,7 @@ gboolean @@ -228,7 +228,7 @@ gboolean @@ -236,7 +236,7 @@ gboolean @@ -244,7 +244,7 @@ gboolean @@ -252,7 +252,7 @@ gboolean @@ -260,7 +260,7 @@ gboolean @@ -268,7 +268,7 @@ gboolean @@ -276,7 +276,7 @@ gboolean @@ -284,15 +284,15 @@ gboolean @@ -300,7 +300,7 @@ gboolean @@ -308,7 +308,7 @@ gboolean @@ -316,7 +316,7 @@ gboolean @@ -324,7 +324,7 @@ gboolean @@ -332,7 +332,7 @@ gboolean @@ -340,7 +340,7 @@ void @@ -348,7 +348,7 @@ void @@ -356,7 +356,7 @@ gboolean @@ -364,7 +364,7 @@ gboolean @@ -372,7 +372,7 @@ gboolean @@ -380,7 +380,7 @@ gboolean @@ -388,7 +388,7 @@ gboolean @@ -396,7 +396,7 @@ gboolean @@ -404,7 +404,7 @@ void @@ -412,7 +412,7 @@ gboolean @@ -420,7 +420,7 @@ gboolean @@ -428,7 +428,7 @@ gboolean @@ -436,7 +436,7 @@ gboolean @@ -444,7 +444,7 @@ gboolean @@ -452,7 +452,7 @@ void @@ -460,7 +460,7 @@ gboolean @@ -468,7 +468,7 @@ gboolean @@ -476,7 +476,7 @@ gboolean @@ -484,7 +484,7 @@ gboolean @@ -492,7 +492,7 @@ gboolean @@ -500,7 +500,7 @@ gboolean @@ -508,7 +508,7 @@ gboolean @@ -516,7 +516,7 @@ gboolean @@ -524,7 +524,7 @@ gboolean @@ -532,7 +532,7 @@ gboolean @@ -540,7 +540,7 @@ gboolean @@ -548,7 +548,7 @@ gboolean @@ -556,7 +556,7 @@ gboolean @@ -564,7 +564,7 @@ gboolean @@ -572,7 +572,7 @@ gboolean @@ -580,7 +580,7 @@ gboolean @@ -588,23 +588,23 @@ gboolean @@ -612,7 +612,7 @@ GVariant * @@ -620,7 +620,7 @@ void @@ -628,7 +628,7 @@ void @@ -636,15 +636,15 @@ void @@ -652,7 +652,7 @@ void @@ -660,7 +660,7 @@ OstreeRepoDevInoCache * @@ -668,7 +668,7 @@ OstreeRepoDevInoCache * @@ -676,7 +676,7 @@ void @@ -684,7 +684,7 @@ GType @@ -692,7 +692,7 @@ gboolean @@ -700,7 +700,7 @@ gboolean @@ -708,7 +708,7 @@ gboolean @@ -716,7 +716,7 @@ gboolean @@ -724,7 +724,7 @@ gboolean @@ -732,7 +732,7 @@ gboolean @@ -740,7 +740,7 @@ gboolean @@ -748,7 +748,7 @@ gboolean @@ -756,7 +756,7 @@ gboolean @@ -764,7 +764,7 @@ gboolean @@ -772,7 +772,7 @@ gboolean @@ -780,7 +780,7 @@ gboolean @@ -788,7 +788,7 @@ gboolean @@ -796,7 +796,7 @@ gboolean @@ -804,7 +804,7 @@ gboolean @@ -812,7 +812,7 @@ gboolean @@ -820,7 +820,7 @@ gboolean @@ -828,7 +828,7 @@ gboolean @@ -836,7 +836,7 @@ GHashTable * @@ -844,7 +844,7 @@ gboolean @@ -852,7 +852,7 @@ gboolean @@ -860,7 +860,7 @@ void @@ -868,7 +868,7 @@ void @@ -876,7 +876,7 @@ void @@ -884,7 +884,7 @@ void @@ -892,7 +892,7 @@ gboolean @@ -900,15 +900,15 @@ gboolean @@ -916,7 +916,7 @@ gboolean @@ -924,7 +924,7 @@ gboolean @@ -932,7 +932,7 @@ gboolean @@ -940,7 +940,7 @@ gboolean @@ -948,7 +948,7 @@ gboolean @@ -956,7 +956,7 @@ gboolean @@ -964,7 +964,7 @@ void @@ -972,7 +972,7 @@ gboolean @@ -980,7 +980,7 @@ gboolean @@ -988,7 +988,7 @@ gboolean @@ -996,7 +996,7 @@ OstreeGpgVerifyResult * @@ -1004,7 +1004,7 @@ gboolean @@ -1012,7 +1012,7 @@ OstreeGpgVerifyResult * @@ -1020,7 +1020,7 @@ OstreeGpgVerifyResult * @@ -1028,7 +1028,7 @@ OstreeGpgVerifyResult * @@ -1036,14 +1036,14 @@ gboolean
-ostree_repo_mode_from_string () +ostree_repo_mode_from_string ()
-OstreeRepo * +OstreeRepo * -ostree_repo_open_at () +ostree_repo_open_at ()
-OstreeRepo * +OstreeRepo * -ostree_repo_new () +ostree_repo_new ()
-OstreeRepo * +OstreeRepo * -ostree_repo_new_for_sysroot_path () +ostree_repo_new_for_sysroot_path ()
-OstreeRepo * +OstreeRepo * -ostree_repo_new_default () +ostree_repo_new_default ()
-ostree_repo_open () +ostree_repo_open ()
-ostree_repo_set_disable_fsync () +ostree_repo_set_disable_fsync ()
-ostree_repo_get_disable_fsync () +ostree_repo_get_disable_fsync ()
-ostree_repo_is_system () +ostree_repo_is_system ()
-ostree_repo_is_writable () +ostree_repo_is_writable ()
-OstreeRepo * +OstreeRepo * -ostree_repo_create_at () +ostree_repo_create_at ()
-ostree_repo_create () +ostree_repo_create ()
-ostree_repo_get_path () +ostree_repo_get_path ()
-OstreeRepoMode +OstreeRepoMode -ostree_repo_get_mode () +ostree_repo_get_mode ()
-ostree_repo_get_config () +ostree_repo_get_config ()
-ostree_repo_get_dfd () +ostree_repo_get_dfd ()
-ostree_repo_copy_config () +ostree_repo_copy_config ()
-ostree_repo_remote_add () +ostree_repo_remote_add ()
-ostree_repo_remote_delete () +ostree_repo_remote_delete ()
-ostree_repo_remote_change () +ostree_repo_remote_change ()
-ostree_repo_remote_list () +ostree_repo_remote_list ()
-ostree_repo_remote_get_url () +ostree_repo_remote_get_url ()
-ostree_repo_remote_get_gpg_verify () +ostree_repo_remote_get_gpg_verify ()
-ostree_repo_remote_get_gpg_verify_summary () +ostree_repo_remote_get_gpg_verify_summary ()
-ostree_repo_remote_gpg_import () +ostree_repo_remote_gpg_import ()
-ostree_repo_remote_fetch_summary () +ostree_repo_remote_fetch_summary ()
-ostree_repo_remote_fetch_summary_with_options () +ostree_repo_remote_fetch_summary_with_options ()
-ostree_repo_reload_config () +ostree_repo_reload_config ()
-ostree_repo_get_remote_boolean_option () +ostree_repo_get_remote_boolean_option ()
-ostree_repo_get_remote_list_option () +ostree_repo_get_remote_list_option ()
-ostree_repo_get_remote_option () +ostree_repo_get_remote_option ()
-OstreeRepo * +OstreeRepo * -ostree_repo_get_parent () +ostree_repo_get_parent ()
-ostree_repo_write_config () +ostree_repo_write_config ()
-ostree_repo_scan_hardlinks () +ostree_repo_scan_hardlinks ()
-ostree_repo_prepare_transaction () +ostree_repo_prepare_transaction ()
-ostree_repo_commit_transaction () +ostree_repo_commit_transaction ()
-ostree_repo_abort_transaction () +ostree_repo_abort_transaction ()
-ostree_repo_transaction_set_refspec () +ostree_repo_transaction_set_refspec ()
-ostree_repo_transaction_set_ref () +ostree_repo_transaction_set_ref ()
-ostree_repo_set_ref_immediate () +ostree_repo_set_ref_immediate ()
-ostree_repo_set_alias_ref_immediate () +ostree_repo_set_alias_ref_immediate ()
-ostree_repo_set_cache_dir () +ostree_repo_set_cache_dir ()
-ostree_repo_sign_delta () +ostree_repo_sign_delta ()
-ostree_repo_has_object () +ostree_repo_has_object ()
-ostree_repo_write_metadata () +ostree_repo_write_metadata ()
-ostree_repo_write_metadata_async () +ostree_repo_write_metadata_async ()
-ostree_repo_write_metadata_finish () +ostree_repo_write_metadata_finish ()
-ostree_repo_write_content () +ostree_repo_write_content ()
-ostree_repo_write_metadata_trusted () +ostree_repo_write_metadata_trusted ()
-ostree_repo_write_metadata_stream_trusted () +ostree_repo_write_metadata_stream_trusted ()
-ostree_repo_write_content_trusted () +ostree_repo_write_content_trusted ()
-ostree_repo_write_content_async () +ostree_repo_write_content_async ()
-ostree_repo_write_content_finish () +ostree_repo_write_content_finish ()
-ostree_repo_resolve_rev () +ostree_repo_resolve_rev ()
-ostree_repo_resolve_rev_ext () +ostree_repo_resolve_rev_ext ()
-ostree_repo_list_refs () +ostree_repo_list_refs ()
-ostree_repo_list_refs_ext () +ostree_repo_list_refs_ext ()
-ostree_repo_remote_list_refs () +ostree_repo_remote_list_refs ()
-ostree_repo_load_variant () +ostree_repo_load_variant ()
-ostree_repo_load_commit () +ostree_repo_load_commit ()
-ostree_repo_load_variant_if_exists () +ostree_repo_load_variant_if_exists ()
-ostree_repo_load_file () +ostree_repo_load_file ()
-ostree_repo_load_object_stream () +ostree_repo_load_object_stream ()
-ostree_repo_query_object_storage_size () +ostree_repo_query_object_storage_size ()
-ostree_repo_import_object_from () +ostree_repo_import_object_from ()
-ostree_repo_import_object_from_with_trust () +ostree_repo_import_object_from_with_trust ()
-ostree_repo_import_archive_to_mtree () +ostree_repo_import_archive_to_mtree ()
-ostree_repo_export_tree_to_archive () +ostree_repo_export_tree_to_archive ()
-ostree_repo_delete_object () +ostree_repo_delete_object ()
-OstreeRepoCommitFilterResult +OstreeRepoCommitFilterResult -(*OstreeRepoCommitFilter) () +(*OstreeRepoCommitFilter) ()
-OstreeRepoCommitModifier * +OstreeRepoCommitModifier * -ostree_repo_commit_modifier_new () +ostree_repo_commit_modifier_new ()
-(*OstreeRepoCommitModifierXattrCallback) () +(*OstreeRepoCommitModifierXattrCallback) ()
-ostree_repo_commit_modifier_set_xattr_callback () +ostree_repo_commit_modifier_set_xattr_callback ()
-ostree_repo_commit_modifier_set_sepolicy () +ostree_repo_commit_modifier_set_sepolicy ()
-ostree_repo_commit_modifier_set_devino_cache () +ostree_repo_commit_modifier_set_devino_cache ()
-OstreeRepoCommitModifier * +OstreeRepoCommitModifier * -ostree_repo_commit_modifier_ref () +ostree_repo_commit_modifier_ref ()
-ostree_repo_commit_modifier_unref () +ostree_repo_commit_modifier_unref ()
-ostree_repo_devino_cache_new () +ostree_repo_devino_cache_new ()
-ostree_repo_devino_cache_ref () +ostree_repo_devino_cache_ref ()
-ostree_repo_devino_cache_unref () +ostree_repo_devino_cache_unref ()
-ostree_repo_devino_cache_get_type () +ostree_repo_devino_cache_get_type ()
-ostree_repo_write_directory_to_mtree () +ostree_repo_write_directory_to_mtree ()
-ostree_repo_write_dfd_to_mtree () +ostree_repo_write_dfd_to_mtree ()
-ostree_repo_write_archive_to_mtree () +ostree_repo_write_archive_to_mtree ()
-ostree_repo_write_mtree () +ostree_repo_write_mtree ()
-ostree_repo_write_commit () +ostree_repo_write_commit ()
-ostree_repo_write_commit_with_time () +ostree_repo_write_commit_with_time ()
-ostree_repo_read_commit_detached_metadata () +ostree_repo_read_commit_detached_metadata ()
-ostree_repo_write_commit_detached_metadata () +ostree_repo_write_commit_detached_metadata ()
-ostree_repo_checkout_tree () +ostree_repo_checkout_tree ()
-ostree_repo_checkout_tree_at () +ostree_repo_checkout_tree_at ()
-ostree_repo_checkout_at () +ostree_repo_checkout_at ()
-ostree_repo_checkout_gc () +ostree_repo_checkout_gc ()
-ostree_repo_read_commit () +ostree_repo_read_commit ()
-ostree_repo_list_objects () +ostree_repo_list_objects ()
-ostree_repo_list_commit_objects_starting_with () +ostree_repo_list_commit_objects_starting_with ()
-ostree_repo_list_static_delta_names () +ostree_repo_list_static_delta_names ()
-ostree_repo_static_delta_generate () +ostree_repo_static_delta_generate ()
-ostree_repo_static_delta_execute_offline () +ostree_repo_static_delta_execute_offline ()
-ostree_repo_traverse_new_reachable () +ostree_repo_traverse_new_reachable ()
-ostree_repo_traverse_commit () +ostree_repo_traverse_commit ()
-ostree_repo_traverse_commit_union () +ostree_repo_traverse_commit_union ()
-ostree_repo_commit_traverse_iter_cleanup () +ostree_repo_commit_traverse_iter_cleanup ()
-ostree_repo_commit_traverse_iter_clear () +ostree_repo_commit_traverse_iter_clear ()
-ostree_repo_commit_traverse_iter_get_dir () +ostree_repo_commit_traverse_iter_get_dir ()
-ostree_repo_commit_traverse_iter_get_file () +ostree_repo_commit_traverse_iter_get_file ()
-ostree_repo_commit_traverse_iter_init_commit () +ostree_repo_commit_traverse_iter_init_commit ()
-ostree_repo_commit_traverse_iter_init_dirtree () +ostree_repo_commit_traverse_iter_init_dirtree ()
-OstreeRepoCommitIterResult +OstreeRepoCommitIterResult -ostree_repo_commit_traverse_iter_next () +ostree_repo_commit_traverse_iter_next ()
-ostree_repo_prune () +ostree_repo_prune ()
-ostree_repo_prune_static_deltas () +ostree_repo_prune_static_deltas ()
-ostree_repo_prune_from_reachable () +ostree_repo_prune_from_reachable ()
-ostree_repo_pull () +ostree_repo_pull ()
-ostree_repo_pull_one_dir () +ostree_repo_pull_one_dir ()
-ostree_repo_pull_with_options () +ostree_repo_pull_with_options ()
-ostree_repo_pull_default_console_progress_changed () +ostree_repo_pull_default_console_progress_changed ()
-ostree_repo_sign_commit () +ostree_repo_sign_commit ()
-ostree_repo_append_gpg_signature () +ostree_repo_append_gpg_signature ()
-ostree_repo_add_gpg_signature_summary () +ostree_repo_add_gpg_signature_summary ()
-ostree_repo_gpg_verify_data () +ostree_repo_gpg_verify_data ()
-ostree_repo_verify_commit () +ostree_repo_verify_commit ()
-ostree_repo_verify_commit_ext () +ostree_repo_verify_commit_ext ()
-ostree_repo_verify_commit_for_remote () +ostree_repo_verify_commit_for_remote ()
-ostree_repo_verify_summary () +ostree_repo_verify_summary ()
-ostree_repo_regenerate_summary () +ostree_repo_regenerate_summary ()
-

Description

-

The OstreeRepo is like git, a content-addressed object store. +

Description

+

The OstreeRepo is like git, a content-addressed object store. Unlike git, it records uid, gid, and extended attributes.

-

There are three possible "modes" for an OstreeRepo; -OSTREE_REPO_MODE_BARE is very simple - content files are +

There are three possible "modes" for an OstreeRepo; +OSTREE_REPO_MODE_BARE is very simple - content files are represented exactly as they are, and checkouts are just hardlinks. -OSTREE_REPO_MODE_BARE_USER is similar, except the uid/gids are not +OSTREE_REPO_MODE_BARE_USER is similar, except the uid/gids are not set on the files, and checkouts as hardlinks hardlinks work only for user checkouts. -A OSTREE_REPO_MODE_ARCHIVE_Z2 repository in contrast stores +A OSTREE_REPO_MODE_ARCHIVE_Z2 repository in contrast stores content files zlib-compressed. It is suitable for non-root-owned repositories that can be served via a static HTTP server.

-

Creating an OstreeRepo does not invoke any file I/O, and thus needs +

Creating an OstreeRepo does not invoke any file I/O, and thus needs to be initialized, either from an existing contents or with a new -repository. If you have an existing repo, use ostree_repo_open() +repository. If you have an existing repo, use ostree_repo_open() to load it from disk and check its validity. To initialize a new -repository in the given filepath, use ostree_repo_create() instead.

+repository in the given filepath, use ostree_repo_create() instead.

To store content in the repo, first start a transaction with -ostree_repo_prepare_transaction(). Then create a +ostree_repo_prepare_transaction(). Then create a OstreeMutableTree, and apply functions such as -ostree_repo_write_directory_to_mtree() to traverse a physical +ostree_repo_write_directory_to_mtree() to traverse a physical filesystem and write content, possibly multiple times.

Once the OstreeMutableTree is complete, write all of its metadata -with ostree_repo_write_mtree(), and finally create a commit with -ostree_repo_write_commit().

+with ostree_repo_write_mtree(), and finally create a commit with +ostree_repo_write_commit().

Collection IDs

A collection ID is a globally unique identifier which, if set, is used to @@ -1161,7 +1161,7 @@ identify refs from a repository which are mirrored elsewhere, such as in mirror repositories or peer to peer networks.

This is separate from the collection-id configuration key for a remote, which is used to store the collection ID of the repository that remote points to.

-

The collection ID should only be set on an OstreeRepo if it is the canonical +

The collection ID should only be set on an OstreeRepo if it is the canonical collection for some refs.

A collection ID must be a reverse DNS name, where the domain name is under the control of the curator of the collection, so they can demonstrate ownership @@ -1172,25 +1172,25 @@ collection IDs, see ostree_validate_collection_id()

-

Functions

+

Functions

ostree_repo_mode_from_string ()

gboolean
 ostree_repo_mode_from_string (const char *mode,
-                              OstreeRepoMode *out_mode,
+                              OstreeRepoMode *out_mode,
                               GError **error);

ostree_repo_open_at ()

-
OstreeRepo *
+
OstreeRepo *
 ostree_repo_open_at (int dfd,
                      const char *path,
                      GCancellable *cancellable,
                      GError **error);
-

This combines ostree_repo_new() (but using fd-relative access) with -ostree_repo_open(). Use this when you know you should be operating on an -already extant repository. If you want to create one, use ostree_repo_create_at().

+

This combines ostree_repo_new() (but using fd-relative access) with +ostree_repo_open(). Use this when you know you should be operating on an +already extant repository. If you want to create one, use ostree_repo_create_at().

Parameters

@@ -1224,7 +1224,7 @@ already extant repository. If you want to create one, use

ostree_repo_new ()

-
OstreeRepo *
+
OstreeRepo *
 ostree_repo_new (GFile *path);

Parameters

@@ -1251,10 +1251,10 @@ ostree_repo_new (GFile *pa

ostree_repo_new_for_sysroot_path ()

-
OstreeRepo *
+
OstreeRepo *
 ostree_repo_new_for_sysroot_path (GFile *repo_path,
                                   GFile *sysroot_path);
-

Creates a new OstreeRepo instance, taking the system root path explicitly +

Creates a new OstreeRepo instance, taking the system root path explicitly instead of assuming "/".

Parameters

@@ -1288,10 +1288,10 @@ instead of assuming "/".


ostree_repo_new_default ()

-
OstreeRepo *
+
OstreeRepo *
 ostree_repo_new_default (void);

If the current working directory appears to be an OSTree -repository, create a new OstreeRepo object for accessing it. +repository, create a new OstreeRepo object for accessing it. Otherwise use the path in the OSTREE_REPO environment variable (if defined) or else the default system repository located at /ostree/repo.

@@ -1305,7 +1305,7 @@ Otherwise use the path in the OSTREE_REPO environment variable

ostree_repo_open ()

gboolean
-ostree_repo_open (OstreeRepo *self,
+ostree_repo_open (OstreeRepo *self,
                   GCancellable *cancellable,
                   GError **error);
@@ -1313,7 +1313,7 @@ ostree_repo_open (

ostree_repo_set_disable_fsync ()

void
-ostree_repo_set_disable_fsync (OstreeRepo *self,
+ostree_repo_set_disable_fsync (OstreeRepo *self,
                                gboolean disable_fsync);

Disable requests to fsync() to stable storage during commits. This option should only be used by build system tools which are creating @@ -1330,7 +1330,7 @@ ensuring data consistency.

- + @@ -1346,8 +1346,8 @@ ensuring data consistency.

ostree_repo_get_disable_fsync ()

gboolean
-ostree_repo_get_disable_fsync (OstreeRepo *self);
-

For more information see ostree_repo_set_disable_fsync().

+ostree_repo_get_disable_fsync (OstreeRepo *self); +

For more information see ostree_repo_set_disable_fsync().

Parameters

self

An OstreeRepo

An OstreeRepo

 
@@ -1358,7 +1358,7 @@ ostree_repo_get_disable_fsync ( - +

self

An OstreeRepo

An OstreeRepo

 
@@ -1372,7 +1372,7 @@ ostree_repo_get_disable_fsync (

ostree_repo_is_system ()

gboolean
-ostree_repo_is_system (OstreeRepo *repo);
+ostree_repo_is_system (OstreeRepo *repo);

Parameters

@@ -1397,7 +1397,7 @@ ostree_repo_is_system (

ostree_repo_is_writable ()

gboolean
-ostree_repo_is_writable (OstreeRepo *self,
+ostree_repo_is_writable (OstreeRepo *self,
                          GError **error);

Returns whether the repository is writable by the current user. If the repository is not writable, the error @@ -1432,21 +1432,21 @@ If the repository is not writable, the error<


ostree_repo_create_at ()

-
OstreeRepo *
+
OstreeRepo *
 ostree_repo_create_at (int dfd,
                        const char *path,
-                       OstreeRepoMode mode,
+                       OstreeRepoMode mode,
                        GVariant *options,
                        GCancellable *cancellable,
                        GError **error);
-

This is a file-descriptor relative version of ostree_repo_create(). +

This is a file-descriptor relative version of ostree_repo_create(). Create the underlying structure on disk for the repository, and call -ostree_repo_open_at() on the result, preparing it for use.

+ostree_repo_open_at() on the result, preparing it for use.

If a repository already exists at dfd + path (defined by an objects/ subdirectory existing), then this function will simply call -ostree_repo_open_at(). In other words, this function cannot be used to change +ostree_repo_open_at(). In other words, this function cannot be used to change the mode or configuration (repo/config) of an existing repo.

The options dict may contain:

@@ -1503,12 +1503,12 @@ the mode or configuration (repo/config) of an exist

ostree_repo_create ()

gboolean
-ostree_repo_create (OstreeRepo *self,
-                    OstreeRepoMode mode,
+ostree_repo_create (OstreeRepo *self,
+                    OstreeRepoMode mode,
                     GCancellable *cancellable,
                     GError **error);

Create the underlying structure on disk for the repository, and call -ostree_repo_open() on the result, preparing it for use.

+ostree_repo_open() on the result, preparing it for use.

Since version 2016.8, this function will succeed on an existing repository, and finish creating any necessary files in a partially created repository. However, this function cannot change the mode @@ -1516,8 +1516,8 @@ of an existing repository, and will silently ignore an attempt to do so.

Since 2017.9, "existing repository" is defined by the existence of an objects subdirectory.

-

This function predates ostree_repo_create_at(). It is an error to call -this function on a repository initialized via ostree_repo_open_at().

+

This function predates ostree_repo_create_at(). It is an error to call +this function on a repository initialized via ostree_repo_open_at().

Parameters

@@ -1529,7 +1529,7 @@ this function on a repository initialized via

self

-
+ @@ -1555,8 +1555,8 @@ this function on a repository initialized via

ostree_repo_get_path ()

GFile *
-ostree_repo_get_path (OstreeRepo *self);
-

Note that since the introduction of ostree_repo_open_at(), this function may +ostree_repo_get_path (OstreeRepo *self); +

Note that since the introduction of ostree_repo_open_at(), this function may return a process-specific path in /proc if the repository was created using that API. In general, you should avoid use of this API.

@@ -1583,14 +1583,14 @@ that API. In general, you should avoid use of this API.


ostree_repo_get_mode ()

-
OstreeRepoMode
-ostree_repo_get_mode (OstreeRepo *self);
+
OstreeRepoMode
+ostree_repo_get_mode (OstreeRepo *self);

ostree_repo_get_config ()

GKeyFile *
-ostree_repo_get_config (OstreeRepo *self);
+ostree_repo_get_config (OstreeRepo *self);

Returns

The repository configuration; do not modify.

@@ -1601,7 +1601,7 @@ ostree_repo_get_config (

ostree_repo_get_dfd ()

int
-ostree_repo_get_dfd (OstreeRepo *self);
+ostree_repo_get_dfd (OstreeRepo *self);

In some cases it's useful for applications to access the repository directly; for example, writing content into repo/tmp ensures it's on the same filesystem. Another case is detecting the mtime on the @@ -1631,7 +1631,7 @@ repository (to see whether a ref was written).

ostree_repo_copy_config ()

GKeyFile *
-ostree_repo_copy_config (OstreeRepo *self);
+ostree_repo_copy_config (OstreeRepo *self);

Returns

A newly-allocated copy of the repository config.

@@ -1642,7 +1642,7 @@ ostree_repo_copy_config (

ostree_repo_remote_add ()

gboolean
-ostree_repo_remote_add (OstreeRepo *self,
+ostree_repo_remote_add (OstreeRepo *self,
                         const char *name,
                         const char *url,
                         GVariant *options,
@@ -1707,7 +1707,7 @@ mapped as follows:

ostree_repo_remote_delete ()

gboolean
-ostree_repo_remote_delete (OstreeRepo *self,
+ostree_repo_remote_delete (OstreeRepo *self,
                            const char *name,
                            GCancellable *cancellable,
                            GError **error);
@@ -1751,16 +1751,16 @@ remote does not exist.

ostree_repo_remote_change ()

gboolean
-ostree_repo_remote_change (OstreeRepo *self,
+ostree_repo_remote_change (OstreeRepo *self,
                            GFile *sysroot,
-                           OstreeRepoRemoteChange changeop,
+                           OstreeRepoRemoteChange changeop,
                            const char *name,
                            const char *url,
                            GVariant *options,
                            GCancellable *cancellable,
                            GError **error);

A combined function handling the equivalent of -ostree_repo_remote_add(), ostree_repo_remote_delete(), with more +ostree_repo_remote_add(), ostree_repo_remote_delete(), with more options.

Parameters

@@ -1819,9 +1819,9 @@ options.

ostree_repo_remote_list ()

char **
-ostree_repo_remote_list (OstreeRepo *self,
+ostree_repo_remote_list (OstreeRepo *self,
                          guint *out_n_remotes);
-

List available remote names in an OstreeRepo. Remote names are sorted +

List available remote names in an OstreeRepo. Remote names are sorted alphabetically. If no remotes are available the function returns NULL.

Parameters

@@ -1856,7 +1856,7 @@ array of remote names.

ostree_repo_remote_get_url ()

gboolean
-ostree_repo_remote_get_url (OstreeRepo *self,
+ostree_repo_remote_get_url (OstreeRepo *self,
                             const char *name,
                             char **out_url,
                             GError **error);
@@ -1905,7 +1905,7 @@ error if the provided remote does not exist.

ostree_repo_remote_get_gpg_verify ()

gboolean
-ostree_repo_remote_get_gpg_verify (OstreeRepo *self,
+ostree_repo_remote_get_gpg_verify (OstreeRepo *self,
                                    const char *name,
                                    gboolean *out_gpg_verify,
                                    GError **error);
@@ -1956,7 +1956,7 @@ not exist.

ostree_repo_remote_get_gpg_verify_summary ()

gboolean
 ostree_repo_remote_get_gpg_verify_summary
-                               (OstreeRepo *self,
+                               (OstreeRepo *self,
                                 const char *name,
                                 gboolean *out_gpg_verify_summary,
                                 GError **error);
@@ -2006,7 +2006,7 @@ remote does not exist.

ostree_repo_remote_gpg_import ()

gboolean
-ostree_repo_remote_gpg_import (OstreeRepo *self,
+ostree_repo_remote_gpg_import (OstreeRepo *self,
                                const char *name,
                                GInputStream *source_stream,
                                const char * const *key_ids,
@@ -2081,7 +2081,7 @@ keys, or NULL. 

ostree_repo_remote_fetch_summary ()

gboolean
-ostree_repo_remote_fetch_summary (OstreeRepo *self,
+ostree_repo_remote_fetch_summary (OstreeRepo *self,
                                   const char *name,
                                   GBytes **out_summary,
                                   GBytes **out_signatures,
@@ -2155,14 +2155,14 @@ signature data, or NULL. 

ostree_repo_remote_fetch_summary_with_options ()

gboolean
 ostree_repo_remote_fetch_summary_with_options
-                               (OstreeRepo *self,
+                               (OstreeRepo *self,
                                 const char *name,
                                 GVariant *options,
                                 GBytes **out_summary,
                                 GBytes **out_signatures,
                                 GCancellable *cancellable,
                                 GError **error);
-

Like ostree_repo_remote_fetch_summary(), but supports an extensible set of flags. +

Like ostree_repo_remote_fetch_summary(), but supports an extensible set of flags. The following are currently defined:

  • override-url (s): Fetch summary from this URL if remote specifies no metalink in options

  • @@ -2226,10 +2226,10 @@ signature data, or NULL.

    ostree_repo_reload_config ()

    gboolean
    -ostree_repo_reload_config (OstreeRepo *self,
    +ostree_repo_reload_config (OstreeRepo *self,
                                GCancellable *cancellable,
                                GError **error);
    -

    By default, an OstreeRepo will cache the remote configuration and its +

    By default, an OstreeRepo will cache the remote configuration and its own repo/config data. This API can be used to reload it.

    Parameters

    @@ -2263,7 +2263,7 @@ own repo/config data. This API can be used to reload it.

    ostree_repo_get_remote_boolean_option ()

    gboolean
    -ostree_repo_get_remote_boolean_option (OstreeRepo *self,
    +ostree_repo_get_remote_boolean_option (OstreeRepo *self,
                                            const char *remote_name,
                                            const char *option_name,
                                            gboolean default_value,
    @@ -2331,7 +2331,7 @@ set

    ostree_repo_get_remote_list_option ()

    gboolean
    -ostree_repo_get_remote_list_option (OstreeRepo *self,
    +ostree_repo_get_remote_list_option (OstreeRepo *self,
                                         const char *remote_name,
                                         const char *option_name,
                                         char ***out_value,
    @@ -2392,7 +2392,7 @@ set

    ostree_repo_get_remote_option ()

    gboolean
    -ostree_repo_get_remote_option (OstreeRepo *self,
    +ostree_repo_get_remote_option (OstreeRepo *self,
                                    const char *remote_name,
                                    const char *option_name,
                                    const char *default_value,
    @@ -2457,8 +2457,8 @@ set


    ostree_repo_get_parent ()

    -
    OstreeRepo *
    -ostree_repo_get_parent (OstreeRepo *self);
    +
    OstreeRepo *
    +ostree_repo_get_parent (OstreeRepo *self);

    Before this function can be used, ostree_repo_init() must have been called.

    @@ -2486,7 +2486,7 @@ called.

    ostree_repo_write_config ()

    gboolean
    -ostree_repo_write_config (OstreeRepo *self,
    +ostree_repo_write_config (OstreeRepo *self,
                               GKeyFile *new_config,
                               GError **error);

    Save new_config @@ -2526,18 +2526,22 @@ simply adds a reference.

    ostree_repo_scan_hardlinks ()

    gboolean
    -ostree_repo_scan_hardlinks (OstreeRepo *self,
    +ostree_repo_scan_hardlinks (OstreeRepo *self,
                                 GCancellable *cancellable,
                                 GError **error);
    -

    When ostree builds a mutable tree from directory like in -ostree_repo_write_directory_to_mtree(), it has to scan all files that you -pass in and compute their checksums. If your commit contains hardlinks from -ostree's existing repo, ostree can build a mapping of device numbers and -inodes to their checksum.

    +

    This function is deprecated in favor of using ostree_repo_devino_cache_new(), +which allows a precise mapping to be built up between hardlink checkout files +and their checksums between ostree_repo_checkout_at() and +ostree_repo_write_directory_to_mtree().

    +

    When invoking ostree_repo_write_directory_to_mtree(), it has to compute the +checksum of all files. If your commit contains hardlinks from a checkout, +this functions builds a mapping of device numbers and inodes to their +checksum.

    There is an upfront cost to creating this mapping, as this will scan the entire objects directory. If your commit is composed of mostly hardlinks to existing ostree objects, then this will speed up considerably, so call it -before you call ostree_write_directory_to_mtree() or similar.

    +before you call ostree_write_directory_to_mtree() or similar. However, +ostree_repo_devino_cache_new() is better as it avoids scanning all objects.

    Parameters

An OstreeRepo

An OstreeRepo

 
@@ -2549,7 +2553,7 @@ before you call ostree_write_directory_to_mtree() - + @@ -2570,14 +2574,14 @@ before you call ostree_write_directory_to_mtree()

ostree_repo_prepare_transaction ()

gboolean
-ostree_repo_prepare_transaction (OstreeRepo *self,
+ostree_repo_prepare_transaction (OstreeRepo *self,
                                  gboolean *out_transaction_resume,
                                  GCancellable *cancellable,
                                  GError **error);

Starts or resumes a transaction. In order to write to a repo, you need to start a transaction. You can complete the transaction with -ostree_repo_commit_transaction(), or abort the transaction with -ostree_repo_abort_transaction().

+ostree_repo_commit_transaction(), or abort the transaction with +ostree_repo_abort_transaction().

Currently, transactions are not atomic, and aborting a transaction will not erase any data you write during the transaction.

@@ -2591,7 +2595,7 @@ will not erase any data you write during the transaction.

- + @@ -2619,13 +2623,13 @@ pulls use per-commit state/.commitpartial files.

ostree_repo_commit_transaction ()

gboolean
-ostree_repo_commit_transaction (OstreeRepo *self,
-                                OstreeRepoTransactionStats *out_stats,
+ostree_repo_commit_transaction (OstreeRepo *self,
+                                OstreeRepoTransactionStats *out_stats,
                                 GCancellable *cancellable,
                                 GError **error);

Complete the transaction. Any refs set with -ostree_repo_transaction_set_ref() or -ostree_repo_transaction_set_refspec() will be written out.

+ostree_repo_transaction_set_ref() or +ostree_repo_transaction_set_refspec() will be written out.

Parameters

self

An OstreeRepo

An OstreeRepo

 

self

An OstreeRepo

An OstreeRepo

 
@@ -2637,7 +2641,7 @@ ostree_repo_commit_transaction ( - + @@ -2664,7 +2668,7 @@ that happened during this transaction.

ostree_repo_abort_transaction ()

gboolean
-ostree_repo_abort_transaction (OstreeRepo *self,
+ostree_repo_abort_transaction (OstreeRepo *self,
                                GCancellable *cancellable,
                                GError **error);
@@ -2672,10 +2676,10 @@ ostree_repo_abort_transaction (

ostree_repo_transaction_set_refspec ()

void
-ostree_repo_transaction_set_refspec (OstreeRepo *self,
+ostree_repo_transaction_set_refspec (OstreeRepo *self,
                                      const char *refspec,
                                      const char *checksum);
-

Like ostree_repo_transaction_set_ref(), but takes concatenated +

Like ostree_repo_transaction_set_ref(), but takes concatenated refspec format as input instead of separate remote and name arguments.

@@ -2690,7 +2694,7 @@ arguments.

- + @@ -2711,7 +2715,7 @@ arguments.

ostree_repo_transaction_set_ref ()

void
-ostree_repo_transaction_set_ref (OstreeRepo *self,
+ostree_repo_transaction_set_ref (OstreeRepo *self,
                                  const char *remote,
                                  const char *ref,
                                  const char *checksum);
@@ -2725,8 +2729,8 @@ remote.

is NULL, then record that the ref should be deleted.

The change will not be written out immediately, but when the transaction -is completed with ostree_repo_commit_transaction(). If the transaction -is instead aborted with ostree_repo_abort_transaction(), no changes will +is completed with ostree_repo_commit_transaction(). If the transaction +is instead aborted with ostree_repo_abort_transaction(), no changes will be made to the repository.

Parameters

@@ -2739,7 +2743,7 @@ be made to the repository.

- + @@ -2765,13 +2769,13 @@ be made to the repository.

ostree_repo_set_ref_immediate ()

gboolean
-ostree_repo_set_ref_immediate (OstreeRepo *self,
+ostree_repo_set_ref_immediate (OstreeRepo *self,
                                const char *remote,
                                const char *ref,
                                const char *checksum,
                                GCancellable *cancellable,
                                GError **error);
-

This is like ostree_repo_transaction_set_ref(), except it may be +

This is like ostree_repo_transaction_set_ref(), except it may be invoked outside of a transaction. This is presently safe for the case where we're creating or overwriting an existing ref.

@@ -2785,7 +2789,7 @@ case where we're creating or overwriting an existing ref.

- + @@ -2821,13 +2825,13 @@ case where we're creating or overwriting an existing ref.

ostree_repo_set_alias_ref_immediate ()

gboolean
-ostree_repo_set_alias_ref_immediate (OstreeRepo *self,
+ostree_repo_set_alias_ref_immediate (OstreeRepo *self,
                                      const char *remote,
                                      const char *ref,
                                      const char *target,
                                      GCancellable *cancellable,
                                      GError **error);
-

Like ostree_repo_set_ref_immediate(), but creates an alias.

+

Like ostree_repo_set_ref_immediate(), but creates an alias.

Parameters

self

An OstreeRepo

An OstreeRepo

 

self

An OstreeRepo

An OstreeRepo

 

self

An OstreeRepo

An OstreeRepo

 

self

An OstreeRepo

An OstreeRepo

 
@@ -2839,7 +2843,7 @@ ostree_repo_set_alias_ref_immediate ( - + @@ -2875,7 +2879,7 @@ ostree_repo_set_alias_ref_immediate (

ostree_repo_set_cache_dir ()

gboolean
-ostree_repo_set_cache_dir (OstreeRepo *self,
+ostree_repo_set_cache_dir (OstreeRepo *self,
                            int dfd,
                            const char *path,
                            GCancellable *cancellable,
@@ -2895,7 +2899,7 @@ write permissions in the repo, where the cache is normally stored.

- + @@ -2927,7 +2931,7 @@ write permissions in the repo, where the cache is normally stored.

ostree_repo_sign_delta ()

gboolean
-ostree_repo_sign_delta (OstreeRepo *self,
+ostree_repo_sign_delta (OstreeRepo *self,
                         const gchar *from_commit,
                         const gchar *to_commit,
                         const gchar *key_id,
@@ -2988,7 +2992,7 @@ Add a GPG signature to a static delta.

ostree_repo_has_object ()

gboolean
-ostree_repo_has_object (OstreeRepo *self,
+ostree_repo_has_object (OstreeRepo *self,
                         OstreeObjectType objtype,
                         const char *checksum,
                         gboolean *out_have_object,
@@ -3049,7 +3053,7 @@ ostree_repo_has_object (
 

ostree_repo_write_metadata ()

gboolean
-ostree_repo_write_metadata (OstreeRepo *self,
+ostree_repo_write_metadata (OstreeRepo *self,
                             OstreeObjectType objtype,
                             const char *expected_checksum,
                             GVariant *object,
@@ -3115,7 +3119,7 @@ computed checksum.

ostree_repo_write_metadata_async ()

void
-ostree_repo_write_metadata_async (OstreeRepo *self,
+ostree_repo_write_metadata_async (OstreeRepo *self,
                                   OstreeObjectType objtype,
                                   const char *expected_checksum,
                                   GVariant *object,
@@ -3179,7 +3183,7 @@ the checksum expected_checksum
 

ostree_repo_write_metadata_finish ()

gboolean
-ostree_repo_write_metadata_finish (OstreeRepo *self,
+ostree_repo_write_metadata_finish (OstreeRepo *self,
                                    GAsyncResult *result,
                                    guchar **out_csum,
                                    GError **error);
@@ -3188,7 +3192,7 @@ ostree_repo_write_metadata_finish (

ostree_repo_write_content ()

gboolean
-ostree_repo_write_content (OstreeRepo *self,
+ostree_repo_write_content (OstreeRepo *self,
                            const char *expected_checksum,
                            GInputStream *object_input,
                            guint64 length,
@@ -3254,7 +3258,7 @@ be returned as out_csum
 

ostree_repo_write_metadata_trusted ()

gboolean
-ostree_repo_write_metadata_trusted (OstreeRepo *self,
+ostree_repo_write_metadata_trusted (OstreeRepo *self,
                                     OstreeObjectType objtype,
                                     const char *checksum,
                                     GVariant *variant,
@@ -3312,7 +3316,7 @@ trusted.

ostree_repo_write_metadata_stream_trusted ()

gboolean
 ostree_repo_write_metadata_stream_trusted
-                               (OstreeRepo *self,
+                               (OstreeRepo *self,
                                 OstreeObjectType objtype,
                                 const char *checksum,
                                 GInputStream *object_input,
@@ -3375,7 +3379,7 @@ trusted.

ostree_repo_write_content_trusted ()

gboolean
-ostree_repo_write_content_trusted (OstreeRepo *self,
+ostree_repo_write_content_trusted (OstreeRepo *self,
                                    const char *checksum,
                                    GInputStream *object_input,
                                    guint64 length,
@@ -3437,7 +3441,7 @@ disk, for example.

ostree_repo_write_content_async ()

void
-ostree_repo_write_content_async (OstreeRepo *self,
+ostree_repo_write_content_async (OstreeRepo *self,
                                  const char *expected_checksum,
                                  GInputStream *object,
                                  guint64 length,
@@ -3502,11 +3506,11 @@ checksum expected_checksum
 

ostree_repo_write_content_finish ()

gboolean
-ostree_repo_write_content_finish (OstreeRepo *self,
+ostree_repo_write_content_finish (OstreeRepo *self,
                                   GAsyncResult *result,
                                   guchar **out_csum,
                                   GError **error);
-

Completes an invocation of ostree_repo_write_content_async().

+

Completes an invocation of ostree_repo_write_content_async().

Parameters

self

An OstreeRepo

An OstreeRepo

 

self

An OstreeRepo

An OstreeRepo

 
@@ -3518,7 +3522,7 @@ ostree_repo_write_content_finish ( - + @@ -3544,7 +3548,7 @@ ostree_repo_write_content_finish (

ostree_repo_resolve_rev ()

gboolean
-ostree_repo_resolve_rev (OstreeRepo *self,
+ostree_repo_resolve_rev (OstreeRepo *self,
                          const char *refspec,
                          gboolean allow_noent,
                          char **out_rev,
@@ -3596,15 +3600,15 @@ is true and it does not exist. 

ostree_repo_resolve_rev_ext ()

gboolean
-ostree_repo_resolve_rev_ext (OstreeRepo *self,
+ostree_repo_resolve_rev_ext (OstreeRepo *self,
                              const char *refspec,
                              gboolean allow_noent,
-                             OstreeRepoResolveRevExtFlags flags,
+                             OstreeRepoResolveRevExtFlags flags,
                              char **out_rev,
                              GError **error);

Look up the given refspec, returning the checksum it references in the parameter out_rev -. Differently from ostree_repo_resolve_rev(), +. Differently from ostree_repo_resolve_rev(), this will not fall back to searching through remote repos if a local ref is specified but not found.

@@ -3655,7 +3659,7 @@ is true and it does not exist.

ostree_repo_list_refs ()

gboolean
-ostree_repo_list_refs (OstreeRepo *self,
+ostree_repo_list_refs (OstreeRepo *self,
                        const char *refspec_prefix,
                        GHashTable **out_all_refs,
                        GCancellable *cancellable,
@@ -3708,10 +3712,10 @@ refspecs which have refspec_prefix
 

ostree_repo_list_refs_ext ()

gboolean
-ostree_repo_list_refs_ext (OstreeRepo *self,
+ostree_repo_list_refs_ext (OstreeRepo *self,
                            const char *refspec_prefix,
                            GHashTable **out_all_refs,
-                           OstreeRepoListRefsExtFlags flags,
+                           OstreeRepoListRefsExtFlags flags,
                            GCancellable *cancellable,
                            GError **error);

If refspec_prefix @@ -3720,7 +3724,7 @@ with their current values in out_all_refsrefspec_prefix as a prefix. Differently from -ostree_repo_list_refs(), the prefix will not be removed from the ref +ostree_repo_list_refs(), the prefix will not be removed from the ref name.

Parameters

@@ -3769,7 +3773,7 @@ name.

ostree_repo_remote_list_refs ()

gboolean
-ostree_repo_remote_list_refs (OstreeRepo *self,
+ostree_repo_remote_list_refs (OstreeRepo *self,
                               const char *remote_name,
                               GHashTable **out_all_refs,
                               GCancellable *cancellable,
@@ -3816,7 +3820,7 @@ ostree_repo_remote_list_refs (
 

ostree_repo_load_variant ()

gboolean
-ostree_repo_load_variant (OstreeRepo *self,
+ostree_repo_load_variant (OstreeRepo *self,
                           OstreeObjectType objtype,
                           const char *sha256,
                           GVariant **out_variant,
@@ -3868,14 +3872,14 @@ result in out_variant
 

ostree_repo_load_commit ()

gboolean
-ostree_repo_load_commit (OstreeRepo *self,
+ostree_repo_load_commit (OstreeRepo *self,
                          const char *checksum,
                          GVariant **out_commit,
-                         OstreeRepoCommitState *out_state,
+                         OstreeRepoCommitState *out_state,
                          GError **error);
-

A version of ostree_repo_load_variant() specialized to commits, +

A version of ostree_repo_load_variant() specialized to commits, capable of returning extended state information. Currently -the only extended state is OSTREE_REPO_COMMIT_STATE_PARTIAL, which +the only extended state is OSTREE_REPO_COMMIT_STATE_PARTIAL, which means that only a sub-path of the commit is available.

Parameters

@@ -3919,7 +3923,7 @@ means that only a sub-path of the commit is available.

ostree_repo_load_variant_if_exists ()

gboolean
-ostree_repo_load_variant_if_exists (OstreeRepo *self,
+ostree_repo_load_variant_if_exists (OstreeRepo *self,
                                     OstreeObjectType objtype,
                                     const char *sha256,
                                     GVariant **out_variant,
@@ -3972,7 +3976,7 @@ exists, storing the result in out_variant
 

ostree_repo_load_file ()

gboolean
-ostree_repo_load_file (OstreeRepo *self,
+ostree_repo_load_file (OstreeRepo *self,
                        const char *checksum,
                        GInputStream **out_input,
                        GFileInfo **out_file_info,
@@ -4033,7 +4037,7 @@ content (for regular files), the metadata, and extended attributes.

ostree_repo_load_object_stream ()

gboolean
-ostree_repo_load_object_stream (OstreeRepo *self,
+ostree_repo_load_object_stream (OstreeRepo *self,
                                 OstreeObjectType objtype,
                                 const char *checksum,
                                 GInputStream **out_input,
@@ -4095,7 +4099,7 @@ repositories.

ostree_repo_query_object_storage_size ()

gboolean
-ostree_repo_query_object_storage_size (OstreeRepo *self,
+ostree_repo_query_object_storage_size (OstreeRepo *self,
                                        OstreeObjectType objtype,
                                        const char *sha256,
                                        guint64 *out_size,
@@ -4151,8 +4155,8 @@ compression has been applied.

ostree_repo_import_object_from ()

gboolean
-ostree_repo_import_object_from (OstreeRepo *self,
-                                OstreeRepo *source,
+ostree_repo_import_object_from (OstreeRepo *self,
+                                OstreeRepo *source,
                                 OstreeObjectType objtype,
                                 const char *checksum,
                                 GCancellable *cancellable,
@@ -4214,8 +4218,8 @@ hard link operation.

ostree_repo_import_object_from_with_trust ()

gboolean
 ostree_repo_import_object_from_with_trust
-                               (OstreeRepo *self,
-                                OstreeRepo *source,
+                               (OstreeRepo *self,
+                                OstreeRepo *source,
                                 OstreeObjectType objtype,
                                 const char *checksum,
                                 gboolean trusted,
@@ -4282,11 +4286,11 @@ hard link operation.

ostree_repo_import_archive_to_mtree ()

gboolean
-ostree_repo_import_archive_to_mtree (OstreeRepo *self,
+ostree_repo_import_archive_to_mtree (OstreeRepo *self,
                                      OstreeRepoImportArchiveOptions *opts,
                                      void *archive,
                                      OstreeMutableTree *mtree,
-                                     OstreeRepoCommitModifier *modifier,
+                                     OstreeRepoCommitModifier *modifier,
                                      GCancellable *cancellable,
                                      GError **error);

Import an archive file archive @@ -4305,7 +4309,7 @@ file structure to mtree

- + @@ -4346,7 +4350,7 @@ file structure to mtree

ostree_repo_export_tree_to_archive ()

gboolean
-ostree_repo_export_tree_to_archive (OstreeRepo *self,
+ostree_repo_export_tree_to_archive (OstreeRepo *self,
                                     OstreeRepoExportArchiveOptions *opts,
                                     OstreeRepoFile *root,
                                     void *archive,
@@ -4368,7 +4372,7 @@ file structure to mtree
 
- + @@ -4404,7 +4408,7 @@ file structure to mtree

ostree_repo_delete_object ()

gboolean
-ostree_repo_delete_object (OstreeRepo *self,
+ostree_repo_delete_object (OstreeRepo *self,
                            OstreeObjectType objtype,
                            const char *sha256,
                            GCancellable *cancellable,
@@ -4455,8 +4459,8 @@ is thrown if the object does not exist.


OstreeRepoCommitFilter ()

-
OstreeRepoCommitFilterResult
-(*OstreeRepoCommitFilter) (OstreeRepo *repo,
+
OstreeRepoCommitFilterResult
+(*OstreeRepoCommitFilter) (OstreeRepo *repo,
                            const char *path,
                            GFileInfo *file_info,
                            gpointer user_data);
@@ -4494,15 +4498,15 @@ is thrown if the object does not exist.

Returns

-

OstreeRepoCommitFilterResult saying whether or not to commit this file

+

OstreeRepoCommitFilterResult saying whether or not to commit this file


ostree_repo_commit_modifier_new ()

-
OstreeRepoCommitModifier *
-ostree_repo_commit_modifier_new (OstreeRepoCommitModifierFlags flags,
-                                 OstreeRepoCommitFilter commit_filter,
+
OstreeRepoCommitModifier *
+ostree_repo_commit_modifier_new (OstreeRepoCommitModifierFlags flags,
+                                 OstreeRepoCommitFilter commit_filter,
                                  gpointer user_data,
                                  GDestroyNotify destroy_notify);
@@ -4548,7 +4552,7 @@ ostree_repo_commit_modifier_new (

OstreeRepoCommitModifierXattrCallback ()

GVariant *
 (*OstreeRepoCommitModifierXattrCallback)
-                               (OstreeRepo *repo,
+                               (OstreeRepo *repo,
                                 const char *path,
                                 GFileInfo *file_info,
                                 gpointer user_data);
@@ -4558,8 +4562,8 @@ ostree_repo_commit_modifier_new (

ostree_repo_commit_modifier_set_xattr_callback ()

void
 ostree_repo_commit_modifier_set_xattr_callback
-                               (OstreeRepoCommitModifier *modifier,
-                                OstreeRepoCommitModifierXattrCallback callback,
+                               (OstreeRepoCommitModifier *modifier,
+                                OstreeRepoCommitModifierXattrCallback callback,
                                 GDestroyNotify destroy,
                                 gpointer user_data);

If set, this function should return extended attributes to use for @@ -4577,7 +4581,7 @@ repository.

- + @@ -4605,14 +4609,14 @@ repository.

ostree_repo_commit_modifier_set_sepolicy ()

void
 ostree_repo_commit_modifier_set_sepolicy
-                               (OstreeRepoCommitModifier *modifier,
+                               (OstreeRepoCommitModifier *modifier,
                                 OstreeSePolicy *sepolicy);

If policy is non-NULL, use it to look up labels to use for "security.selinux" extended attributes.

Note that any policy specified this way operates in addition to any extended attributes provided via -ostree_repo_commit_modifier_set_xattr_callback(). However if both +ostree_repo_commit_modifier_set_xattr_callback(). However if both specify a value for "security.selinux", then the one from the policy wins.

@@ -4626,7 +4630,7 @@ policy wins.

- + @@ -4643,12 +4647,12 @@ policy wins.

ostree_repo_commit_modifier_set_devino_cache ()

void
 ostree_repo_commit_modifier_set_devino_cache
-                               (OstreeRepoCommitModifier *modifier,
+                               (OstreeRepoCommitModifier *modifier,
                                 OstreeRepoDevInoCache *cache);

See the documentation for -ostree_repo_devino_cache_new(). This function can +ostree_repo_devino_cache_new(). This function can then be used for later calls to -ostree_repo_write_directory_to_mtree() to optimize commits.

+ostree_repo_write_directory_to_mtree() to optimize commits.

Note if your process has multiple writers, you should use separate OSTreeRepo instances if you want to also use this API.

This function will add a reference to cache @@ -4680,23 +4684,23 @@ should avoid further mutation of the cache.


ostree_repo_commit_modifier_ref ()

-
OstreeRepoCommitModifier *
-ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier);
+
OstreeRepoCommitModifier *
+ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier);

ostree_repo_commit_modifier_unref ()

void
-ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier);
+ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier);

ostree_repo_devino_cache_new ()

OstreeRepoDevInoCache *
 ostree_repo_devino_cache_new (void);
-

OSTree has support for pairing ostree_repo_checkout_tree_at() using +

OSTree has support for pairing ostree_repo_checkout_tree_at() using hardlinks in combination with a later -ostree_repo_write_directory_to_mtree() using a (normally modified) +ostree_repo_write_directory_to_mtree() using a (normally modified) directory. In order for OSTree to optimally detect just the new files, use this function and fill in the devino_to_csum_cache member of OstreeRepoCheckoutAtOptions, then call @@ -4729,10 +4733,10 @@ ostree_repo_devino_cache_get_type (

ostree_repo_write_directory_to_mtree ()

gboolean
-ostree_repo_write_directory_to_mtree (OstreeRepo *self,
+ostree_repo_write_directory_to_mtree (OstreeRepo *self,
                                       GFile *dir,
                                       OstreeMutableTree *mtree,
-                                      OstreeRepoCommitModifier *modifier,
+                                      OstreeRepoCommitModifier *modifier,
                                       GCancellable *cancellable,
                                       GError **error);

Store objects for dir @@ -4787,11 +4791,11 @@ overlaying the resulting filesystem hierarchy into m

ostree_repo_write_dfd_to_mtree ()

gboolean
-ostree_repo_write_dfd_to_mtree (OstreeRepo *self,
+ostree_repo_write_dfd_to_mtree (OstreeRepo *self,
                                 int dfd,
                                 const char *path,
                                 OstreeMutableTree *mtree,
-                                OstreeRepoCommitModifier *modifier,
+                                OstreeRepoCommitModifier *modifier,
                                 GCancellable *cancellable,
                                 GError **error);

Store as objects all contents of the directory referred to by dfd @@ -4853,10 +4857,10 @@ resulting filesystem hierarchy into mtree

ostree_repo_write_archive_to_mtree ()

gboolean
-ostree_repo_write_archive_to_mtree (OstreeRepo *self,
+ostree_repo_write_archive_to_mtree (OstreeRepo *self,
                                     GFile *archive,
                                     OstreeMutableTree *mtree,
-                                    OstreeRepoCommitModifier *modifier,
+                                    OstreeRepoCommitModifier *modifier,
                                     gboolean autocreate_parents,
                                     GCancellable *cancellable,
                                     GError **error);
@@ -4875,7 +4879,7 @@ file structure to mtree
- + @@ -4916,7 +4920,7 @@ file structure to mtree

ostree_repo_write_mtree ()

gboolean
-ostree_repo_write_mtree (OstreeRepo *self,
+ostree_repo_write_mtree (OstreeRepo *self,
                          OstreeMutableTree *mtree,
                          GFile **out_file,
                          GCancellable *cancellable,
@@ -4970,7 +4974,7 @@ the mtree
 

ostree_repo_write_commit ()

gboolean
-ostree_repo_write_commit (OstreeRepo *self,
+ostree_repo_write_commit (OstreeRepo *self,
                           const char *parent,
                           const char *subject,
                           const char *body,
@@ -5045,7 +5049,7 @@ and root_metadata_checksum
 

ostree_repo_write_commit_with_time ()

gboolean
-ostree_repo_write_commit_with_time (OstreeRepo *self,
+ostree_repo_write_commit_with_time (OstreeRepo *self,
                                     const char *parent,
                                     const char *subject,
                                     const char *body,
@@ -5127,7 +5131,7 @@ and root_metadata_checksum
 

ostree_repo_read_commit_detached_metadata ()

gboolean
 ostree_repo_read_commit_detached_metadata
-                               (OstreeRepo *self,
+                               (OstreeRepo *self,
                                 const char *checksum,
                                 GVariant **out_metadata,
                                 GCancellable *cancellable,
@@ -5179,7 +5183,7 @@ to NULL.

ostree_repo_write_commit_detached_metadata ()

gboolean
 ostree_repo_write_commit_detached_metadata
-                               (OstreeRepo *self,
+                               (OstreeRepo *self,
                                 const char *checksum,
                                 GVariant *metadata,
                                 GCancellable *cancellable,
@@ -5232,9 +5236,9 @@ data will be deleted.

ostree_repo_checkout_tree ()

gboolean
-ostree_repo_checkout_tree (OstreeRepo *self,
-                           OstreeRepoCheckoutMode mode,
-                           OstreeRepoCheckoutOverwriteMode overwrite_mode,
+ostree_repo_checkout_tree (OstreeRepo *self,
+                           OstreeRepoCheckoutMode mode,
+                           OstreeRepoCheckoutOverwriteMode overwrite_mode,
                            GFile *destination,
                            OstreeRepoFile *source,
                            GFileInfo *source_info,
@@ -5306,7 +5310,7 @@ files are checked out.

ostree_repo_checkout_tree_at ()

gboolean
-ostree_repo_checkout_tree_at (OstreeRepo *self,
+ostree_repo_checkout_tree_at (OstreeRepo *self,
                               OstreeRepoCheckoutOptions *options,
                               int destination_dfd,
                               const char *destination_path,
@@ -5314,14 +5318,14 @@ ostree_repo_checkout_tree_at (GCancellable *cancellable,
                               GError **error);

ostree_repo_checkout_tree_at is deprecated and should not be used in newly-written code.

-

Similar to ostree_repo_checkout_tree(), but uses directory-relative +

Similar to ostree_repo_checkout_tree(), but uses directory-relative paths for the destination, uses a new OstreeRepoCheckoutAtOptions, and takes a commit checksum and optional subpath pair, rather than requiring use of GFile APIs for the caller.

-

Note in addition that unlike ostree_repo_checkout_tree(), the +

Note in addition that unlike ostree_repo_checkout_tree(), the default is not to use the repository-internal uncompressed objects cache.

-

This function is deprecated. Use ostree_repo_checkout_at() instead.

+

This function is deprecated. Use ostree_repo_checkout_at() instead.

[skip]

Parameters

@@ -5375,20 +5379,20 @@ cache.

ostree_repo_checkout_at ()

gboolean
-ostree_repo_checkout_at (OstreeRepo *self,
+ostree_repo_checkout_at (OstreeRepo *self,
                          OstreeRepoCheckoutAtOptions *options,
                          int destination_dfd,
                          const char *destination_path,
                          const char *commit,
                          GCancellable *cancellable,
                          GError **error);
-

Similar to ostree_repo_checkout_tree(), but uses directory-relative +

Similar to ostree_repo_checkout_tree(), but uses directory-relative paths for the destination, uses a new OstreeRepoCheckoutAtOptions, and takes a commit checksum and optional subpath pair, rather than requiring use of GFile APIs for the caller.

-

It also replaces ostree_repo_checkout_at() which was not safe to +

It also replaces ostree_repo_checkout_at() which was not safe to use with GObject introspection.

-

Note in addition that unlike ostree_repo_checkout_tree(), the +

Note in addition that unlike ostree_repo_checkout_tree(), the default is not to use the repository-internal uncompressed objects cache.

@@ -5443,7 +5447,7 @@ cache.

ostree_repo_checkout_gc ()

gboolean
-ostree_repo_checkout_gc (OstreeRepo *self,
+ostree_repo_checkout_gc (OstreeRepo *self,
                          GCancellable *cancellable,
                          GError **error);

Call this after finishing a succession of checkout operations; it @@ -5481,7 +5485,7 @@ cache.

ostree_repo_read_commit ()

gboolean
-ostree_repo_read_commit (OstreeRepo *self,
+ostree_repo_read_commit (OstreeRepo *self,
                          const char *ref,
                          GFile **out_root,
                          char **out_commit,
@@ -5537,8 +5541,8 @@ ostree_repo_read_commit (
 

ostree_repo_list_objects ()

gboolean
-ostree_repo_list_objects (OstreeRepo *self,
-                          OstreeRepoListObjectsFlags flags,
+ostree_repo_list_objects (OstreeRepo *self,
+                          OstreeRepoListObjectsFlags flags,
                           GHashTable **out_objects,
                           GCancellable *cancellable,
                           GError **error);
@@ -5547,7 +5551,7 @@ repository, returning data in out_objectsout_objects
maps from keys returned by ostree_object_name_serialize() -to GVariant values of type OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE.

+to GVariant values of type OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE.

Parameters

self

a OstreeRepo

a OstreeRepo

 

self

An OstreeRepo

An OstreeRepo

 

self

An OstreeRepo

An OstreeRepo

 

modifier

An OstreeRepoCommitModifier

An OstreeRepoCommitModifier

 

modifier

An OstreeRepoCommitModifier

An OstreeRepoCommitModifier

 

self

An OstreeRepo

An OstreeRepo

 
@@ -5596,7 +5600,7 @@ will be set

ostree_repo_list_commit_objects_starting_with ()

gboolean
 ostree_repo_list_commit_objects_starting_with
-                               (OstreeRepo *self,
+                               (OstreeRepo *self,
                                 const char *start,
                                 GHashTable **out_commits,
                                 GCancellable *cancellable,
@@ -5652,7 +5656,7 @@ will be set

ostree_repo_list_static_delta_names ()

gboolean
-ostree_repo_list_static_delta_names (OstreeRepo *self,
+ostree_repo_list_static_delta_names (OstreeRepo *self,
                                      GPtrArray **out_deltas,
                                      GCancellable *cancellable,
                                      GError **error);
@@ -5696,8 +5700,8 @@ repository, returning its result in out_deltas

ostree_repo_static_delta_generate ()

gboolean
-ostree_repo_static_delta_generate (OstreeRepo *self,
-                                   OstreeStaticDeltaGenerateOpt opt,
+ostree_repo_static_delta_generate (OstreeRepo *self,
+                                   OstreeStaticDeltaGenerateOpt opt,
                                    const char *from,
                                    const char *to,
                                    GVariant *metadata,
@@ -5783,7 +5787,7 @@ for input files

ostree_repo_static_delta_execute_offline ()

gboolean
 ostree_repo_static_delta_execute_offline
-                               (OstreeRepo *self,
+                               (OstreeRepo *self,
                                 GFile *dir_or_file,
                                 gboolean skip_validation,
                                 GCancellable *cancellable,
@@ -5847,7 +5851,7 @@ ostree_repo_traverse_new_reachable (
 

ostree_repo_traverse_commit ()

gboolean
-ostree_repo_traverse_commit (OstreeRepo *repo,
+ostree_repo_traverse_commit (OstreeRepo *repo,
                              const char *commit_checksum,
                              int maxdepth,
                              GHashTable **out_reachable,
@@ -5905,7 +5909,7 @@ from commit_checksum
 

ostree_repo_traverse_commit_union ()

gboolean
-ostree_repo_traverse_commit_union (OstreeRepo *repo,
+ostree_repo_traverse_commit_union (OstreeRepo *repo,
                                    const char *commit_checksum,
                                    int maxdepth,
                                    GHashTable *inout_reachable,
@@ -5984,8 +5988,8 @@ ostree_repo_commit_traverse_iter_get_dir
                                 char **out_content_checksum,
                                 char **out_meta_checksum);

Return information on the current directory. This function may -only be called if OSTREE_REPO_COMMIT_ITER_RESULT_DIR was returned -from ostree_repo_commit_traverse_iter_next().

+only be called if OSTREE_REPO_COMMIT_ITER_RESULT_DIR was returned +from ostree_repo_commit_traverse_iter_next().

Parameters

@@ -6028,8 +6032,8 @@ ostree_repo_commit_traverse_iter_get_file char **out_name, char **out_checksum);

Return information on the current file. This function may only be -called if OSTREE_REPO_COMMIT_ITER_RESULT_FILE was returned from -ostree_repo_commit_traverse_iter_next().

+called if OSTREE_REPO_COMMIT_ITER_RESULT_FILE was returned from +ostree_repo_commit_traverse_iter_next().

Parameters

@@ -6064,9 +6068,9 @@ called if gboolean ostree_repo_commit_traverse_iter_init_commit (OstreeRepoCommitTraverseIter *iter, - OstreeRepo *repo, + OstreeRepo *repo, GVariant *commit, - OstreeRepoCommitTraverseFlags flags, + OstreeRepoCommitTraverseFlags flags, GError **error);

Initialize (in place) an iterator over the root of a commit object.

@@ -6113,9 +6117,9 @@ ostree_repo_commit_traverse_iter_init_commit
gboolean
 ostree_repo_commit_traverse_iter_init_dirtree
                                (OstreeRepoCommitTraverseIter *iter,
-                                OstreeRepo *repo,
+                                OstreeRepo *repo,
                                 GVariant *dirtree,
-                                OstreeRepoCommitTraverseFlags flags,
+                                OstreeRepoCommitTraverseFlags flags,
                                 GError **error);

Initialize (in place) an iterator over a directory tree.

@@ -6159,22 +6163,22 @@ ostree_repo_commit_traverse_iter_init_dirtree

ostree_repo_commit_traverse_iter_next ()

-
OstreeRepoCommitIterResult
+
OstreeRepoCommitIterResult
 ostree_repo_commit_traverse_iter_next (OstreeRepoCommitTraverseIter *iter,
                                        GCancellable *cancellable,
                                        GError **error);

Step the interator to the next item. Files will be returned first, then subdirectories. Call this in a loop; upon encountering -OSTREE_REPO_COMMIT_ITER_RESULT_END, there will be no more files or -directories. If OSTREE_REPO_COMMIT_ITER_RESULT_DIR is returned, -then call ostree_repo_commit_traverse_iter_get_dir() to retrieve +OSTREE_REPO_COMMIT_ITER_RESULT_END, there will be no more files or +directories. If OSTREE_REPO_COMMIT_ITER_RESULT_DIR is returned, +then call ostree_repo_commit_traverse_iter_get_dir() to retrieve data for that directory. Similarly, if -OSTREE_REPO_COMMIT_ITER_RESULT_FILE is returned, call -ostree_repo_commit_traverse_iter_get_file().

-

If OSTREE_REPO_COMMIT_ITER_RESULT_ERROR is returned, it is a +OSTREE_REPO_COMMIT_ITER_RESULT_FILE is returned, call +ostree_repo_commit_traverse_iter_get_file().

+

If OSTREE_REPO_COMMIT_ITER_RESULT_ERROR is returned, it is a program error to call any further API on iter except for -ostree_repo_commit_traverse_iter_clear().

+ostree_repo_commit_traverse_iter_clear().

Parameters

@@ -6207,8 +6211,8 @@ program error to call any further API on iter

ostree_repo_prune ()

gboolean
-ostree_repo_prune (OstreeRepo *self,
-                   OstreeRepoPruneFlags flags,
+ostree_repo_prune (OstreeRepo *self,
+                   OstreeRepoPruneFlags flags,
                    gint depth,
                    gint *out_objects_total,
                    gint *out_objects_pruned,
@@ -6219,12 +6223,12 @@ ostree_repo_prune (
-

However, if OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY is provided, instead +

However, if OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY is provided, instead of traversing all commits, only refs will be used. Particularly when combined with depth , this is a convenient way to delete history from the repository.

-

Use the OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE to just determine +

Use the OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE to just determine statistics on objects that would be deleted, without actually deleting them.

@@ -6284,7 +6288,7 @@ deleting them.

ostree_repo_prune_static_deltas ()

gboolean
-ostree_repo_prune_static_deltas (OstreeRepo *self,
+ostree_repo_prune_static_deltas (OstreeRepo *self,
                                  const char *commit,
                                  GCancellable *cancellable,
                                  GError **error);
@@ -6329,7 +6333,7 @@ non existing commit.

ostree_repo_prune_from_reachable ()

gboolean
-ostree_repo_prune_from_reachable (OstreeRepo *self,
+ostree_repo_prune_from_reachable (OstreeRepo *self,
                                   OstreeRepoPruneOptions *options,
                                   gint *out_objects_total,
                                   gint *out_objects_pruned,
@@ -6337,13 +6341,13 @@ ostree_repo_prune_from_reachable (GCancellable *cancellable,
                                   GError **error);

Delete content from the repository. This function is the "backend" -half of the higher level ostree_repo_prune(). To use this function, +half of the higher level ostree_repo_prune(). To use this function, you determine the root set yourself, and this function finds all other unreferenced objects and deletes them.

Use this API when you want to perform more selective pruning - for example, retain all commits from a production branch, but just GC some history from your dev branch.

-

The OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE flag may be specified to just determine +

The OSTREE_REPO_PRUNE_FLAGS_NO_PRUNE flag may be specified to just determine statistics on objects that would be deleted, without actually deleting them.

Parameters

@@ -6397,10 +6401,10 @@ statistics on objects that would be deleted, without actually deleting them.

ostree_repo_pull ()

gboolean
-ostree_repo_pull (OstreeRepo *self,
+ostree_repo_pull (OstreeRepo *self,
                   const char *remote_name,
                   char **refs_to_fetch,
-                  OstreeRepoPullFlags flags,
+                  OstreeRepoPullFlags flags,
                   OstreeAsyncProgress *progress,
                   GCancellable *cancellable,
                   GError **error);
@@ -6411,12 +6415,12 @@ commit, all metadata, and all content objects, storing them safely on disk in self .

If flags - contains OSTREE_REPO_PULL_FLAGS_MIRROR, and + contains OSTREE_REPO_PULL_FLAGS_MIRROR, and the refs_to_fetch is NULL, and the remote repository contains a summary file, then all refs will be fetched.

If flags - contains OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY, then only the + contains OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY, then only the metadata for the commits in refs_to_fetch is pulled.

Warning: This API will iterate the thread default main context, @@ -6475,15 +6479,15 @@ one around this call.

ostree_repo_pull_one_dir ()

gboolean
-ostree_repo_pull_one_dir (OstreeRepo *self,
+ostree_repo_pull_one_dir (OstreeRepo *self,
                           const char *remote_name,
                           const char *dir_to_pull,
                           char **refs_to_fetch,
-                          OstreeRepoPullFlags flags,
+                          OstreeRepoPullFlags flags,
                           OstreeAsyncProgress *progress,
                           GCancellable *cancellable,
                           GError **error);
-

This is similar to ostree_repo_pull(), but only fetches a single +

This is similar to ostree_repo_pull(), but only fetches a single subpath.

Parameters

@@ -6542,20 +6546,20 @@ subpath.

ostree_repo_pull_with_options ()

gboolean
-ostree_repo_pull_with_options (OstreeRepo *self,
+ostree_repo_pull_with_options (OstreeRepo *self,
                                const char *remote_name_or_baseurl,
                                GVariant *options,
                                OstreeAsyncProgress *progress,
                                GCancellable *cancellable,
                                GError **error);
-

Like ostree_repo_pull(), but supports an extensible set of flags. +

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; 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

  • +
  • 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

  • @@ -6565,6 +6569,7 @@ string to pull the latest commit for that ref

  • 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

  • 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.

  • @@ -6661,7 +6666,7 @@ and user_data

    ostree_repo_sign_commit ()

    gboolean
    -ostree_repo_sign_commit (OstreeRepo *self,
    +ostree_repo_sign_commit (OstreeRepo *self,
                              const gchar *commit_checksum,
                              const gchar *key_id,
                              const gchar *homedir,
    @@ -6715,7 +6720,7 @@ ostree_repo_sign_commit (
     

    ostree_repo_append_gpg_signature ()

    gboolean
    -ostree_repo_append_gpg_signature (OstreeRepo *self,
    +ostree_repo_append_gpg_signature (OstreeRepo *self,
                                       const gchar *commit_checksum,
                                       GBytes *signature_bytes,
                                       GCancellable *cancellable,
    @@ -6763,7 +6768,7 @@ ostree_repo_append_gpg_signature (
     

    ostree_repo_add_gpg_signature_summary ()

    gboolean
    -ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
    +ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
                                            const gchar **key_id,
                                            const gchar *homedir,
                                            GCancellable *cancellable,
    @@ -6811,7 +6816,7 @@ ostree_repo_add_gpg_signature_summary (
     

    ostree_repo_gpg_verify_data ()

    OstreeGpgVerifyResult *
    -ostree_repo_gpg_verify_data (OstreeRepo *self,
    +ostree_repo_gpg_verify_data (OstreeRepo *self,
                                  const gchar *remote_name,
                                  GBytes *data,
                                  GBytes *signatures,
    @@ -6889,7 +6894,7 @@ the verifications using GPG keys in the keyrings of all remotes.

    ostree_repo_verify_commit ()

    gboolean
    -ostree_repo_verify_commit (OstreeRepo *self,
    +ostree_repo_verify_commit (OstreeRepo *self,
                                const gchar *commit_checksum,
                                GFile *keyringdir,
                                GFile *extra_keyring,
    @@ -6949,7 +6954,7 @@ checksum commit_checksum
     

    ostree_repo_verify_commit_ext ()

    OstreeGpgVerifyResult *
    -ostree_repo_verify_commit_ext (OstreeRepo *self,
    +ostree_repo_verify_commit_ext (OstreeRepo *self,
                                    const gchar *commit_checksum,
                                    GFile *keyringdir,
                                    GFile *extra_keyring,
    @@ -7010,7 +7015,7 @@ ostree_repo_verify_commit_ext (
     

    ostree_repo_verify_commit_for_remote ()

    OstreeGpgVerifyResult *
    -ostree_repo_verify_commit_for_remote (OstreeRepo *self,
    +ostree_repo_verify_commit_for_remote (OstreeRepo *self,
                                           const gchar *commit_checksum,
                                           const gchar *remote_name,
                                           GCancellable *cancellable,
    @@ -7067,7 +7072,7 @@ configured for remote
     

    ostree_repo_verify_summary ()

    OstreeGpgVerifyResult *
    -ostree_repo_verify_summary (OstreeRepo *self,
    +ostree_repo_verify_summary (OstreeRepo *self,
                                 const char *remote_name,
                                 GBytes *summary,
                                 GBytes *signatures,
    @@ -7130,7 +7135,7 @@ ostree_repo_verify_summary (
     

    ostree_repo_regenerate_summary ()

    gboolean
    -ostree_repo_regenerate_summary (OstreeRepo *self,
    +ostree_repo_regenerate_summary (OstreeRepo *self,
                                     GVariant *additional_metadata,
                                     GCancellable *cancellable,
                                     GError **error);
    @@ -7183,7 +7188,7 @@ order.

    -

    Types and Values

    +

    Types and Values

    OstreeRepo

    typedef struct OstreeRepo OstreeRepo;
    @@ -7193,7 +7198,7 @@ order.


    enum OstreeRepoMode

    -

    See the documentation of OstreeRepo for more information about the +

    See the documentation of OstreeRepo for more information about the possible modes.

    Members

    @@ -7408,6 +7413,13 @@ in bytes, counting only content objects.

+ + + + +
 

OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES

+

Exclude remote refs. Since: 2017.11

+
 
@@ -7582,6 +7594,13 @@ in bytes, counting only content objects.

  + +

OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL

+ +

Like UNION_FILES, but error if files are not identical (requires hardlink checkouts)

+ +  +
@@ -7783,7 +7802,7 @@ as - List of pack file checksums in which this object appears

OSTREE_REPO_PULL_FLAGS_MIRROR

-

Write out refs suitable for mirrors

+

Write out refs suitable for mirrors and fetch all refs if none requested

  diff --git a/apidoc/html/ostree-Root-partition-mount-point.html b/apidoc/html/ostree-Root-partition-mount-point.html index f954485f..a632249a 100644 --- a/apidoc/html/ostree-Root-partition-mount-point.html +++ b/apidoc/html/ostree-Root-partition-mount-point.html @@ -217,7 +217,7 @@ -OstreeRepo * +OstreeRepo * ostree_sysroot_repo () @@ -353,7 +353,7 @@

Description

A OstreeSysroot object represents a physical root filesystem, which in particular should contain a toplevel /ostree directory. -Inside this directory is an OstreeRepo in /ostree/repo, plus a set +Inside this directory is an OstreeRepo in /ostree/repo, plus a set of deployments in /ostree/deploy.

This class is not by default safe against concurrent use by threads or external processes. You can use ostree_sysroot_lock() to @@ -971,7 +971,7 @@ and old boot versions, but does NOT prune the repository.


ostree_sysroot_repo ()

-
OstreeRepo *
+
OstreeRepo *
 ostree_sysroot_repo (OstreeSysroot *self);

This function is a variant of ostree_sysroot_get_repo() that cannot fail, and returns a cached repository. Can only be called after ostree_sysroot_load() @@ -1003,7 +1003,7 @@ has been invoked successfully.

ostree_sysroot_get_repo ()

gboolean
 ostree_sysroot_get_repo (OstreeSysroot *self,
-                         OstreeRepo **out_repo,
+                         OstreeRepo **out_repo,
                          GCancellable *cancellable,
                          GError **error);

Retrieve the OSTree repository in sysroot self @@ -1611,6 +1611,10 @@ except the merge deployment and the booted deployment will be garbage collected.

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is specified, then all current deployments will be kept.

+

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING is +specified, then pending deployments will be kept.

+

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK is +specified, then rollback deployments will be kept.

If OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is specified, then instead of prepending, the new deployment will be added right after the booted or merge deployment, instead of first.

@@ -1706,6 +1710,16 @@ later, instead.

    + +

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING

+  +  + + +

OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK

+  +  +
diff --git a/apidoc/html/ostree-Simple-upgrade-class.html b/apidoc/html/ostree-Simple-upgrade-class.html index b087b3c0..3097a612 100644 --- a/apidoc/html/ostree-Simple-upgrade-class.html +++ b/apidoc/html/ostree-Simple-upgrade-class.html @@ -424,7 +424,7 @@ ostree_sysroot_upgrader_get_origin_description

ostree_sysroot_upgrader_check_timestamps ()

gboolean
 ostree_sysroot_upgrader_check_timestamps
-                               (OstreeRepo *repo,
+                               (OstreeRepo *repo,
                                 const char *from_rev,
                                 const char *to_rev,
                                 GError **error);
@@ -471,7 +471,7 @@ attackers which provide a client with an older commit.

ostree_sysroot_upgrader_pull ()

gboolean
 ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self,
-                              OstreeRepoPullFlags flags,
+                              OstreeRepoPullFlags flags,
                               OstreeSysrootUpgraderPullFlags upgrader_flags,
                               OstreeAsyncProgress *progress,
                               gboolean *out_changed,
@@ -538,7 +538,7 @@ ref locally.  Then out_changed
 
gboolean
 ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
                                       const char *dir_to_pull,
-                                      OstreeRepoPullFlags flags,
+                                      OstreeRepoPullFlags flags,
                                       OstreeSysrootUpgraderPullFlags upgrader_flags,
                                       OstreeAsyncProgress *progress,
                                       gboolean *out_changed,
diff --git a/apidoc/html/ostree-ostree-repo-file.html b/apidoc/html/ostree-ostree-repo-file.html
index 512dc266..180e2b34 100644
--- a/apidoc/html/ostree-ostree-repo-file.html
+++ b/apidoc/html/ostree-ostree-repo-file.html
@@ -56,7 +56,7 @@
 
 
 
-OstreeRepo *
+OstreeRepo *
 
 
 ostree_repo_file_get_repo ()
@@ -170,7 +170,7 @@ ostree_repo_file_get_xattrs (
 

ostree_repo_file_get_repo ()

-
OstreeRepo *
+
OstreeRepo *
 ostree_repo_file_get_repo (OstreeRepoFile *self);

Returns

diff --git a/apidoc/html/ostree.devhelp2 b/apidoc/html/ostree.devhelp2 index 65aac791..0534c578 100644 --- a/apidoc/html/ostree.devhelp2 +++ b/apidoc/html/ostree.devhelp2 @@ -3,7 +3,7 @@ - + @@ -81,150 +81,150 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -386,53 +386,57 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -456,18 +460,19 @@ + - - - - - - - - - + + + + + + + + + diff --git a/apidoc/html/reference.html b/apidoc/html/reference.html index ff9e9081..fb9f5113 100644 --- a/apidoc/html/reference.html +++ b/apidoc/html/reference.html @@ -27,7 +27,7 @@ Core repository-independent functions — Create, validate, and convert core data types
-Content-addressed object store — A git-like storage system for operating system binaries +OstreeRepo: Content-addressed object store — A git-like storage system for operating system binaries
In-memory modifiable filesystem tree — Modifiable filesystem tree @@ -594,47 +594,47 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
-OstreeRepo, typedef in Content-addressed object store +OstreeRepo, typedef in OstreeRepo
-OstreeRepoCheckoutMode, enum in Content-addressed object store +OstreeRepoCheckoutMode, enum in OstreeRepo
-OstreeRepoCheckoutOverwriteMode, enum in Content-addressed object store +OstreeRepoCheckoutOverwriteMode, enum in OstreeRepo
-OstreeRepoCommitFilter, user_function in Content-addressed object store +OstreeRepoCommitFilter, user_function in OstreeRepo
-OstreeRepoCommitFilterResult, enum in Content-addressed object store +OstreeRepoCommitFilterResult, enum in OstreeRepo
-OstreeRepoCommitIterResult, enum in Content-addressed object store +OstreeRepoCommitIterResult, enum in OstreeRepo
-OstreeRepoCommitModifier, typedef in Content-addressed object store +OstreeRepoCommitModifier, typedef in OstreeRepo
-OstreeRepoCommitModifierFlags, enum in Content-addressed object store +OstreeRepoCommitModifierFlags, enum in OstreeRepo
-OstreeRepoCommitModifierXattrCallback, user_function in Content-addressed object store +OstreeRepoCommitModifierXattrCallback, user_function in OstreeRepo
-OstreeRepoCommitState, enum in Content-addressed object store +OstreeRepoCommitState, enum in OstreeRepo
-OstreeRepoCommitTraverseFlags, enum in Content-addressed object store +OstreeRepoCommitTraverseFlags, enum in OstreeRepo
@@ -642,155 +642,155 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
-OstreeRepoListObjectsFlags, enum in Content-addressed object store +OstreeRepoListObjectsFlags, enum in OstreeRepo
-OstreeRepoListRefsExtFlags, enum in Content-addressed object store +OstreeRepoListRefsExtFlags, enum in OstreeRepo
-OstreeRepoMode, enum in Content-addressed object store +OstreeRepoMode, enum in OstreeRepo
-OstreeRepoPruneFlags, enum in Content-addressed object store +OstreeRepoPruneFlags, enum in OstreeRepo
-OstreeRepoPullFlags, enum in Content-addressed object store +OstreeRepoPullFlags, enum in OstreeRepo
-OstreeRepoRemoteChange, enum in Content-addressed object store +OstreeRepoRemoteChange, enum in OstreeRepo
-OstreeRepoResolveRevExtFlags, enum in Content-addressed object store +OstreeRepoResolveRevExtFlags, enum in OstreeRepo
-OstreeRepoTransactionStats, struct in Content-addressed object store +OstreeRepoTransactionStats, struct in OstreeRepo
-ostree_repo_abort_transaction, function in Content-addressed object store +ostree_repo_abort_transaction, function in OstreeRepo
-ostree_repo_add_gpg_signature_summary, function in Content-addressed object store +ostree_repo_add_gpg_signature_summary, function in OstreeRepo
-ostree_repo_append_gpg_signature, function in Content-addressed object store +ostree_repo_append_gpg_signature, function in OstreeRepo
-ostree_repo_checkout_at, function in Content-addressed object store +ostree_repo_checkout_at, function in OstreeRepo
-ostree_repo_checkout_gc, function in Content-addressed object store +ostree_repo_checkout_gc, function in OstreeRepo
-ostree_repo_checkout_tree, function in Content-addressed object store +ostree_repo_checkout_tree, function in OstreeRepo
-ostree_repo_checkout_tree_at, function in Content-addressed object store +ostree_repo_checkout_tree_at, function in OstreeRepo
-ostree_repo_commit_modifier_new, function in Content-addressed object store +ostree_repo_commit_modifier_new, function in OstreeRepo
-ostree_repo_commit_modifier_ref, function in Content-addressed object store +ostree_repo_commit_modifier_ref, function in OstreeRepo
-ostree_repo_commit_modifier_set_devino_cache, function in Content-addressed object store +ostree_repo_commit_modifier_set_devino_cache, function in OstreeRepo
-ostree_repo_commit_modifier_set_sepolicy, function in Content-addressed object store +ostree_repo_commit_modifier_set_sepolicy, function in OstreeRepo
-ostree_repo_commit_modifier_set_xattr_callback, function in Content-addressed object store +ostree_repo_commit_modifier_set_xattr_callback, function in OstreeRepo
-ostree_repo_commit_modifier_unref, function in Content-addressed object store +ostree_repo_commit_modifier_unref, function in OstreeRepo
-ostree_repo_commit_transaction, function in Content-addressed object store +ostree_repo_commit_transaction, function in OstreeRepo
-ostree_repo_commit_traverse_iter_cleanup, function in Content-addressed object store +ostree_repo_commit_traverse_iter_cleanup, function in OstreeRepo
-ostree_repo_commit_traverse_iter_clear, function in Content-addressed object store +ostree_repo_commit_traverse_iter_clear, function in OstreeRepo
-ostree_repo_commit_traverse_iter_get_dir, function in Content-addressed object store +ostree_repo_commit_traverse_iter_get_dir, function in OstreeRepo
-ostree_repo_commit_traverse_iter_get_file, function in Content-addressed object store +ostree_repo_commit_traverse_iter_get_file, function in OstreeRepo
-ostree_repo_commit_traverse_iter_init_commit, function in Content-addressed object store +ostree_repo_commit_traverse_iter_init_commit, function in OstreeRepo
-ostree_repo_commit_traverse_iter_init_dirtree, function in Content-addressed object store +ostree_repo_commit_traverse_iter_init_dirtree, function in OstreeRepo
-ostree_repo_commit_traverse_iter_next, function in Content-addressed object store +ostree_repo_commit_traverse_iter_next, function in OstreeRepo
-ostree_repo_copy_config, function in Content-addressed object store +ostree_repo_copy_config, function in OstreeRepo
-ostree_repo_create, function in Content-addressed object store +ostree_repo_create, function in OstreeRepo
-ostree_repo_create_at, function in Content-addressed object store +ostree_repo_create_at, function in OstreeRepo
-ostree_repo_delete_object, function in Content-addressed object store +ostree_repo_delete_object, function in OstreeRepo
-ostree_repo_devino_cache_get_type, function in Content-addressed object store +ostree_repo_devino_cache_get_type, function in OstreeRepo
-ostree_repo_devino_cache_new, function in Content-addressed object store +ostree_repo_devino_cache_new, function in OstreeRepo
-ostree_repo_devino_cache_ref, function in Content-addressed object store +ostree_repo_devino_cache_ref, function in OstreeRepo
-ostree_repo_devino_cache_unref, function in Content-addressed object store +ostree_repo_devino_cache_unref, function in OstreeRepo
-ostree_repo_export_tree_to_archive, function in Content-addressed object store +ostree_repo_export_tree_to_archive, function in OstreeRepo
@@ -842,379 +842,379 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
-ostree_repo_get_config, function in Content-addressed object store +ostree_repo_get_config, function in OstreeRepo
-ostree_repo_get_dfd, function in Content-addressed object store +ostree_repo_get_dfd, function in OstreeRepo
-ostree_repo_get_disable_fsync, function in Content-addressed object store +ostree_repo_get_disable_fsync, function in OstreeRepo
-ostree_repo_get_mode, function in Content-addressed object store +ostree_repo_get_mode, function in OstreeRepo
-ostree_repo_get_parent, function in Content-addressed object store +ostree_repo_get_parent, function in OstreeRepo
-ostree_repo_get_path, function in Content-addressed object store +ostree_repo_get_path, function in OstreeRepo
-ostree_repo_get_remote_boolean_option, function in Content-addressed object store +ostree_repo_get_remote_boolean_option, function in OstreeRepo
-ostree_repo_get_remote_list_option, function in Content-addressed object store +ostree_repo_get_remote_list_option, function in OstreeRepo
-ostree_repo_get_remote_option, function in Content-addressed object store +ostree_repo_get_remote_option, function in OstreeRepo
-ostree_repo_gpg_verify_data, function in Content-addressed object store +ostree_repo_gpg_verify_data, function in OstreeRepo
-ostree_repo_has_object, function in Content-addressed object store +ostree_repo_has_object, function in OstreeRepo
-ostree_repo_import_archive_to_mtree, function in Content-addressed object store +ostree_repo_import_archive_to_mtree, function in OstreeRepo
-ostree_repo_import_object_from, function in Content-addressed object store +ostree_repo_import_object_from, function in OstreeRepo
-ostree_repo_import_object_from_with_trust, function in Content-addressed object store +ostree_repo_import_object_from_with_trust, function in OstreeRepo
-ostree_repo_is_system, function in Content-addressed object store +ostree_repo_is_system, function in OstreeRepo
-ostree_repo_is_writable, function in Content-addressed object store +ostree_repo_is_writable, function in OstreeRepo
-ostree_repo_list_commit_objects_starting_with, function in Content-addressed object store +ostree_repo_list_commit_objects_starting_with, function in OstreeRepo
-ostree_repo_list_objects, function in Content-addressed object store +ostree_repo_list_objects, function in OstreeRepo
-OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE, macro in Content-addressed object store +OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE, macro in OstreeRepo
-ostree_repo_list_refs, function in Content-addressed object store +ostree_repo_list_refs, function in OstreeRepo
-ostree_repo_list_refs_ext, function in Content-addressed object store +ostree_repo_list_refs_ext, function in OstreeRepo
-ostree_repo_list_static_delta_names, function in Content-addressed object store +ostree_repo_list_static_delta_names, function in OstreeRepo
-ostree_repo_load_commit, function in Content-addressed object store +ostree_repo_load_commit, function in OstreeRepo
-ostree_repo_load_file, function in Content-addressed object store +ostree_repo_load_file, function in OstreeRepo
-ostree_repo_load_object_stream, function in Content-addressed object store +ostree_repo_load_object_stream, function in OstreeRepo
-ostree_repo_load_variant, function in Content-addressed object store +ostree_repo_load_variant, function in OstreeRepo
-ostree_repo_load_variant_if_exists, function in Content-addressed object store +ostree_repo_load_variant_if_exists, function in OstreeRepo
-ostree_repo_mode_from_string, function in Content-addressed object store +ostree_repo_mode_from_string, function in OstreeRepo
-ostree_repo_new, function in Content-addressed object store +ostree_repo_new, function in OstreeRepo
-ostree_repo_new_default, function in Content-addressed object store +ostree_repo_new_default, function in OstreeRepo
-ostree_repo_new_for_sysroot_path, function in Content-addressed object store +ostree_repo_new_for_sysroot_path, function in OstreeRepo
-ostree_repo_open, function in Content-addressed object store +ostree_repo_open, function in OstreeRepo
-ostree_repo_open_at, function in Content-addressed object store +ostree_repo_open_at, function in OstreeRepo
-ostree_repo_prepare_transaction, function in Content-addressed object store +ostree_repo_prepare_transaction, function in OstreeRepo
-ostree_repo_prune, function in Content-addressed object store +ostree_repo_prune, function in OstreeRepo
-ostree_repo_prune_from_reachable, function in Content-addressed object store +ostree_repo_prune_from_reachable, function in OstreeRepo
-ostree_repo_prune_static_deltas, function in Content-addressed object store +ostree_repo_prune_static_deltas, function in OstreeRepo
-ostree_repo_pull, function in Content-addressed object store +ostree_repo_pull, function in OstreeRepo
-ostree_repo_pull_default_console_progress_changed, function in Content-addressed object store +ostree_repo_pull_default_console_progress_changed, function in OstreeRepo
-ostree_repo_pull_one_dir, function in Content-addressed object store +ostree_repo_pull_one_dir, function in OstreeRepo
-ostree_repo_pull_with_options, function in Content-addressed object store +ostree_repo_pull_with_options, function in OstreeRepo
-ostree_repo_query_object_storage_size, function in Content-addressed object store +ostree_repo_query_object_storage_size, function in OstreeRepo
-ostree_repo_read_commit, function in Content-addressed object store +ostree_repo_read_commit, function in OstreeRepo
-ostree_repo_read_commit_detached_metadata, function in Content-addressed object store +ostree_repo_read_commit_detached_metadata, function in OstreeRepo
-ostree_repo_regenerate_summary, function in Content-addressed object store +ostree_repo_regenerate_summary, function in OstreeRepo
-ostree_repo_reload_config, function in Content-addressed object store +ostree_repo_reload_config, function in OstreeRepo
-ostree_repo_remote_add, function in Content-addressed object store +ostree_repo_remote_add, function in OstreeRepo
-ostree_repo_remote_change, function in Content-addressed object store +ostree_repo_remote_change, function in OstreeRepo
-ostree_repo_remote_delete, function in Content-addressed object store +ostree_repo_remote_delete, function in OstreeRepo
-ostree_repo_remote_fetch_summary, function in Content-addressed object store +ostree_repo_remote_fetch_summary, function in OstreeRepo
-ostree_repo_remote_fetch_summary_with_options, function in Content-addressed object store +ostree_repo_remote_fetch_summary_with_options, function in OstreeRepo
-ostree_repo_remote_get_gpg_verify, function in Content-addressed object store +ostree_repo_remote_get_gpg_verify, function in OstreeRepo
-ostree_repo_remote_get_gpg_verify_summary, function in Content-addressed object store +ostree_repo_remote_get_gpg_verify_summary, function in OstreeRepo
-ostree_repo_remote_get_url, function in Content-addressed object store +ostree_repo_remote_get_url, function in OstreeRepo
-ostree_repo_remote_gpg_import, function in Content-addressed object store +ostree_repo_remote_gpg_import, function in OstreeRepo
-ostree_repo_remote_list, function in Content-addressed object store +ostree_repo_remote_list, function in OstreeRepo
-ostree_repo_remote_list_refs, function in Content-addressed object store +ostree_repo_remote_list_refs, function in OstreeRepo
-ostree_repo_resolve_rev, function in Content-addressed object store +ostree_repo_resolve_rev, function in OstreeRepo
-ostree_repo_resolve_rev_ext, function in Content-addressed object store +ostree_repo_resolve_rev_ext, function in OstreeRepo
-ostree_repo_scan_hardlinks, function in Content-addressed object store +ostree_repo_scan_hardlinks, function in OstreeRepo
-ostree_repo_set_alias_ref_immediate, function in Content-addressed object store +ostree_repo_set_alias_ref_immediate, function in OstreeRepo
-ostree_repo_set_cache_dir, function in Content-addressed object store +ostree_repo_set_cache_dir, function in OstreeRepo
-ostree_repo_set_disable_fsync, function in Content-addressed object store +ostree_repo_set_disable_fsync, function in OstreeRepo
-ostree_repo_set_ref_immediate, function in Content-addressed object store +ostree_repo_set_ref_immediate, function in OstreeRepo
-ostree_repo_sign_commit, function in Content-addressed object store +ostree_repo_sign_commit, function in OstreeRepo
-ostree_repo_sign_delta, function in Content-addressed object store +ostree_repo_sign_delta, function in OstreeRepo
-ostree_repo_static_delta_execute_offline, function in Content-addressed object store +ostree_repo_static_delta_execute_offline, function in OstreeRepo
-ostree_repo_static_delta_generate, function in Content-addressed object store +ostree_repo_static_delta_generate, function in OstreeRepo
-ostree_repo_transaction_set_ref, function in Content-addressed object store +ostree_repo_transaction_set_ref, function in OstreeRepo
-ostree_repo_transaction_set_refspec, function in Content-addressed object store +ostree_repo_transaction_set_refspec, function in OstreeRepo
-ostree_repo_traverse_commit, function in Content-addressed object store +ostree_repo_traverse_commit, function in OstreeRepo
-ostree_repo_traverse_commit_union, function in Content-addressed object store +ostree_repo_traverse_commit_union, function in OstreeRepo
-ostree_repo_traverse_new_reachable, function in Content-addressed object store +ostree_repo_traverse_new_reachable, function in OstreeRepo
-ostree_repo_verify_commit, function in Content-addressed object store +ostree_repo_verify_commit, function in OstreeRepo
-ostree_repo_verify_commit_ext, function in Content-addressed object store +ostree_repo_verify_commit_ext, function in OstreeRepo
-ostree_repo_verify_commit_for_remote, function in Content-addressed object store +ostree_repo_verify_commit_for_remote, function in OstreeRepo
-ostree_repo_verify_summary, function in Content-addressed object store +ostree_repo_verify_summary, function in OstreeRepo
-ostree_repo_write_archive_to_mtree, function in Content-addressed object store +ostree_repo_write_archive_to_mtree, function in OstreeRepo
-ostree_repo_write_commit, function in Content-addressed object store +ostree_repo_write_commit, function in OstreeRepo
-ostree_repo_write_commit_detached_metadata, function in Content-addressed object store +ostree_repo_write_commit_detached_metadata, function in OstreeRepo
-ostree_repo_write_commit_with_time, function in Content-addressed object store +ostree_repo_write_commit_with_time, function in OstreeRepo
-ostree_repo_write_config, function in Content-addressed object store +ostree_repo_write_config, function in OstreeRepo
-ostree_repo_write_content, function in Content-addressed object store +ostree_repo_write_content, function in OstreeRepo
-ostree_repo_write_content_async, function in Content-addressed object store +ostree_repo_write_content_async, function in OstreeRepo
-ostree_repo_write_content_finish, function in Content-addressed object store +ostree_repo_write_content_finish, function in OstreeRepo
-ostree_repo_write_content_trusted, function in Content-addressed object store +ostree_repo_write_content_trusted, function in OstreeRepo
-ostree_repo_write_dfd_to_mtree, function in Content-addressed object store +ostree_repo_write_dfd_to_mtree, function in OstreeRepo
-ostree_repo_write_directory_to_mtree, function in Content-addressed object store +ostree_repo_write_directory_to_mtree, function in OstreeRepo
-ostree_repo_write_metadata, function in Content-addressed object store +ostree_repo_write_metadata, function in OstreeRepo
-ostree_repo_write_metadata_async, function in Content-addressed object store +ostree_repo_write_metadata_async, function in OstreeRepo
-ostree_repo_write_metadata_finish, function in Content-addressed object store +ostree_repo_write_metadata_finish, function in OstreeRepo
-ostree_repo_write_metadata_stream_trusted, function in Content-addressed object store +ostree_repo_write_metadata_stream_trusted, function in OstreeRepo
-ostree_repo_write_metadata_trusted, function in Content-addressed object store +ostree_repo_write_metadata_trusted, function in OstreeRepo
-ostree_repo_write_mtree, function in Content-addressed object store +ostree_repo_write_mtree, function in OstreeRepo

S

@@ -1263,7 +1263,7 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
-OstreeStaticDeltaGenerateOpt, enum in Content-addressed object store +OstreeStaticDeltaGenerateOpt, enum in OstreeRepo
diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index 90bec167..5f061c00 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -268,6 +268,7 @@ ostree_mutable_tree_get_type
ostree-repo +OstreeRepo OstreeRepo OstreeRepoMode ostree_repo_mode_from_string diff --git a/apidoc/version.xml b/apidoc/version.xml index f473df1c..73fd4e08 100644 --- a/apidoc/version.xml +++ b/apidoc/version.xml @@ -1 +1 @@ -2017.10 \ No newline at end of file +2017.11 \ No newline at end of file diff --git a/bash/ostree b/bash/ostree index f4305f69..40326102 100644 --- a/bash/ostree +++ b/bash/ostree @@ -1,5 +1,3 @@ -#!/bin/bash -# # bash completion file for ostree commands # # This script provides completion of: @@ -253,6 +251,9 @@ _ostree_admin_deploy() { local boolean_options=" $main_boolean_options --retain + --retain-pending + --retain-rollback + --not-as-default --karg-proc-cmdline " @@ -695,6 +696,7 @@ _ostree_checkout() { --require-hardlinks -H --union --union-add + --union-identical --user-mode -U --whiteouts " diff --git a/configure b/configure index 1313c436..d7ba44d7 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 2017.10. +# Generated by GNU Autoconf 2.69 for libostree 2017.11. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libostree' PACKAGE_TARNAME='libostree' -PACKAGE_VERSION='2017.10' -PACKAGE_STRING='libostree 2017.10' +PACKAGE_VERSION='2017.11' +PACKAGE_STRING='libostree 2017.11' PACKAGE_BUGREPORT='walters@verbum.org' PACKAGE_URL='' @@ -1537,7 +1537,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 2017.10 to adapt to many kinds of systems. +\`configure' configures libostree 2017.11 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1607,7 +1607,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libostree 2017.10:";; + short | recursive ) echo "Configuration of libostree 2017.11:";; esac cat <<\_ACEOF @@ -1846,7 +1846,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libostree configure 2017.10 +libostree configure 2017.11 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2261,7 +2261,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 2017.10, which was +It was created by libostree $as_me 2017.11, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3129,7 +3129,7 @@ fi # Define the identity of the package. PACKAGE='libostree' - VERSION='2017.10' + VERSION='2017.11' # Some tools Automake needs. @@ -5863,9 +5863,9 @@ test -n "$YACC" || YACC="yacc" YEAR_VERSION=2017 -RELEASE_VERSION=10 +RELEASE_VERSION=11 -PACKAGE_VERSION=2017.10 +PACKAGE_VERSION=2017.11 if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then : @@ -5884,6 +5884,7 @@ else -Werror=pointer-arith -Werror=init-self \ -Werror=missing-declarations \ -Werror=return-type \ + -Werror=switch \ -Werror=overflow \ -Werror=int-conversion \ -Werror=parenthesis \ @@ -18029,7 +18030,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 2017.10, which was +This file was extended by libostree $as_me 2017.11, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -18095,7 +18096,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 2017.10 +libostree config.status 2017.11 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -19785,7 +19786,7 @@ fi echo " - libOSTree $VERSION ($release_build_type) + libostree $VERSION ($release_build_type) =============== diff --git a/configure.ac b/configure.ac index 5c13e742..2461f4d0 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl update libostree-released.sym from libostree-devel.sym, and update the check dnl in test-symbols.sh, and also set is_release_build=yes below. Then make dnl another post-release commit to bump the version, and set is_release_build=no. m4_define([year_version], [2017]) -m4_define([release_version], [10]) +m4_define([release_version], [11]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) is_release_build=yes @@ -40,6 +40,7 @@ CC_CHECK_FLAGS_APPEND([WARN_CFLAGS], [CFLAGS], [\ -Werror=pointer-arith -Werror=init-self \ -Werror=missing-declarations \ -Werror=return-type \ + -Werror=switch \ -Werror=overflow \ -Werror=int-conversion \ -Werror=parenthesis \ @@ -525,7 +526,7 @@ src/libostree/ostree-version.h AC_OUTPUT echo " - libOSTree $VERSION ($release_build_type) + libostree $VERSION ($release_build_type) =============== diff --git a/man/ostree-admin-deploy.xml b/man/ostree-admin-deploy.xml index 347a4ba9..ec705b93 100644 --- a/man/ostree-admin-deploy.xml +++ b/man/ostree-admin-deploy.xml @@ -89,6 +89,30 @@ Boston, MA 02111-1307, USA. + + + + + Do not delete pending deployments. + + + + + + + + Do not delete rollback deployments. + + + + + + + + Append rather than prepend new deployment. + + + diff --git a/man/ostree-checkout.xml b/man/ostree-checkout.xml index c8585878..aba70741 100644 --- a/man/ostree-checkout.xml +++ b/man/ostree-checkout.xml @@ -97,6 +97,15 @@ Boston, MA 02111-1307, USA. + + + + Like --union, but error out + if a file would be replaced with a different file. Add new files + and directories, ignore identical files, and keep existing + directories. Requires -H. + + diff --git a/man/ostree-init.xml b/man/ostree-init.xml index fb35c0da..2ec1b67a 100644 --- a/man/ostree-init.xml +++ b/man/ostree-init.xml @@ -67,9 +67,13 @@ Boston, MA 02111-1307, USA. ="MODE" - - Initialize repository in given mode (bare, bare-user, archive-z2). Default is "bare". - + Initialize repository in given mode + (bare, bare-user, + archive). The default is + bare. Note that for + archive the repository configuration file + will actually have archive-z2, as that's the + historical name. diff --git a/man/ostree-pull.xml b/man/ostree-pull.xml index 59a6dbc8..a3d0b7a0 100644 --- a/man/ostree-pull.xml +++ b/man/ostree-pull.xml @@ -103,7 +103,12 @@ Boston, MA 02111-1307, USA. - Write refs suitable for a mirror. + Write refs suitable for a mirror, i.e. refs are stored in the + heads/ directory rather than the + remotes/ directory. This makes the target repo + suitable to be exported for other clients to pull from as an ostree + remote. If no specific refs are specified, all refs will be fetched (the + remote must have a summary file present). @@ -152,7 +157,7 @@ Boston, MA 02111-1307, USA. Perform a complete mirror of the remote. (This is likely most useful if your repository is also - archive-z2 mode) + archive mode) $ ostree --repo=repo pull remote_name exampleos/x86_64/standard diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml index cf0bf7c0..388b9e62 100644 --- a/man/ostree.repo-config.xml +++ b/man/ostree.repo-config.xml @@ -76,7 +76,7 @@ Boston, MA 02111-1307, USA. mode - One of bare, bare-user or archive-z2. + One of bare, bare-user or archive-z2 (note that archive is used everywhere else.) @@ -122,6 +122,27 @@ Boston, MA 02111-1307, USA. keep free. The default value is 3. + + add-remotes-config-dir + + + Boolean value controlling whether new remotes will be added + in the remotes configuration directory. Defaults to + true for system ostree repositories. When + this is false, remotes will be added in + the repository's config file. + + + This only applies to repositories that use a remotes + configuration directory such as system ostree repositories, + which use /etc/ostree/remotes.d. + Non-system repositories do not use a remotes configuration + directory unless one is specified when the repository is + opened. + + + + diff --git a/src/boot/ostree-tmpfiles.conf b/src/boot/ostree-tmpfiles.conf new file mode 100644 index 00000000..49e2dcb3 --- /dev/null +++ b/src/boot/ostree-tmpfiles.conf @@ -0,0 +1,19 @@ +# Copyright (C) 2017 Colin Walters +# +# 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. + +# https://github.com/ostreedev/ostree/issues/393 +R! /var/tmp/ostree-unlock-ovl.* diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index 01f182f6..07f918a1 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -18,6 +18,9 @@ ***/ /* Add new symbols here. Release commits should copy this section into -released.sym. */ +LIBOSTREE_2017.12 { +} LIBOSTREE_2017.11; + /* Stub section for the stable release *after* this development one; don't * edit this other than to update the last number. This is just a copy/paste diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym index fe98858d..03cb952d 100644 --- a/src/libostree/libostree-released.sym +++ b/src/libostree/libostree-released.sym @@ -427,6 +427,9 @@ LIBOSTREE_2017.10 { */ } LIBOSTREE_2017.8; +LIBOSTREE_2017.11 { +} LIBOSTREE_2017.10; + /* NOTE: Only add more content here in release commits! See the * comments at the top of this file. */ diff --git a/src/libostree/ostree-bootloader-grub2.c b/src/libostree/ostree-bootloader-grub2.c index ff83f151..d917281c 100644 --- a/src/libostree/ostree-bootloader-grub2.c +++ b/src/libostree/ostree-bootloader-grub2.c @@ -75,18 +75,17 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); - g_autoptr(GFile) efi_basedir = NULL; + /* Look for the BIOS path first */ if (g_file_query_exists (self->config_path_bios, NULL)) { + /* If we found it, we're done */ *out_is_active = TRUE; - ret = TRUE; - goto out; + return TRUE; } - efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI"); + g_autoptr(GFile) efi_basedir = g_file_resolve_relative_path (self->sysroot->path, "boot/efi/EFI"); g_clear_object (&self->config_path_efi); @@ -98,17 +97,16 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!direnum) - goto out; + return FALSE; while (TRUE) { GFileInfo *file_info; const char *fname; - g_autofree char *subdir_grub_cfg = NULL; if (!g_file_enumerator_iterate (direnum, &file_info, NULL, cancellable, error)) - goto out; + return FALSE; if (file_info == NULL) break; @@ -119,8 +117,9 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) continue; - subdir_grub_cfg = g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); - + g_autofree char *subdir_grub_cfg = + g_build_filename (gs_file_get_path_cached (efi_basedir), fname, "grub.cfg", NULL); + if (g_file_test (subdir_grub_cfg, G_FILE_TEST_EXISTS)) { self->config_path_efi = g_file_new_for_path (subdir_grub_cfg); @@ -128,20 +127,18 @@ _ostree_bootloader_grub2_query (OstreeBootloader *bootloader, } } + /* If we found the EFI path, we're done */ if (self->config_path_efi) { self->is_efi = TRUE; *out_is_active = TRUE; - ret = TRUE; - goto out; + return TRUE; } } else *out_is_active = FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } static const char * @@ -150,6 +147,10 @@ _ostree_bootloader_grub2_get_name (OstreeBootloader *bootloader) return "grub2"; } +/* This implementation is quite complex; see this issue for + * a starting point: + * https://github.com/ostreedev/ostree/issues/717 + */ gboolean _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot, int bootversion, @@ -157,13 +158,6 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GString) output = g_string_new (""); - g_autoptr(GOutputStream) out_stream = NULL; - g_autoptr(GPtrArray) loader_configs = NULL; - guint i; - gsize bytes_written; - gboolean is_efi; /* So... yeah. Just going to hardcode these. */ static const char hardcoded_video[] = "load_video\n" "set gfxpayload=keep\n"; @@ -178,16 +172,18 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot g_assert (grub2_prepare_root_cache != NULL); /* Passed from the parent */ - is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL; + gboolean is_efi = g_getenv ("_OSTREE_GRUB2_IS_EFI") != NULL; - out_stream = g_unix_output_stream_new (target_fd, FALSE); + g_autoptr(GOutputStream) out_stream = g_unix_output_stream_new (target_fd, FALSE); + g_autoptr(GPtrArray) loader_configs = NULL; if (!_ostree_sysroot_read_boot_loader_configs (sysroot, bootversion, &loader_configs, cancellable, error)) - goto out; + return FALSE; - for (i = 0; i < loader_configs->len; i++) + g_autoptr(GString) output = g_string_new (""); + for (guint i = 0; i < loader_configs->len; i++) { OstreeBootconfigParser *config = loader_configs->pdata[i]; const char *title; @@ -217,13 +213,9 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot g_string_append (output, hardcoded_insmods); g_string_append (output, grub2_prepare_root_cache); g_string_append_c (output, '\n'); - + if (!kernel) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No \"linux\" key in bootloader config"); - goto out; - } + return glnx_throw (error, "No \"linux\" key in bootloader config"); g_string_append (output, "linux"); if (is_efi) g_string_append (output, GRUB2_EFI_SUFFIX); @@ -256,13 +248,12 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot g_string_append (output, "}\n"); } + gsize bytes_written; if (!g_output_stream_write_all (out_stream, output->str, output->len, &bytes_written, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } typedef struct { @@ -271,19 +262,24 @@ typedef struct { gboolean is_efi; } Grub2ChildSetupData; +/* Post-fork, pre-exec child setup for grub2-mkconfig */ static void grub2_child_setup (gpointer user_data) { Grub2ChildSetupData *cdata = user_data; setenv ("_OSTREE_GRUB2_BOOTVERSION", cdata->bootversion_str, TRUE); - /* We have to pass our state to the child */ + /* We have to pass our state (whether or not we're using EFI) to the child */ if (cdata->is_efi) setenv ("_OSTREE_GRUB2_IS_EFI", "1", TRUE); + /* Everything below this is dealing with the chroot case; if + * we're not doing that, return early. + */ if (!cdata->root) return; + /* TODO: investigate replacing this with bwrap */ if (chdir (cdata->root) != 0) { perror ("chdir"); @@ -321,6 +317,7 @@ grub2_child_setup (gpointer user_data) } } +/* Main entrypoint for writing GRUB configuration. */ static gboolean _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, int bootversion, @@ -328,23 +325,13 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, GError **error) { OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); - gboolean ret = FALSE; - g_autoptr(GFile) new_config_path = NULL; - g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion); - g_autoptr(GFile) config_path_efi_dir = NULL; - g_autofree char *grub2_mkconfig_chroot = NULL; - gboolean use_system_grub2_mkconfig = TRUE; - const gchar *grub_exec = NULL; - const char *grub_argv[4] = { NULL, "-o", NULL, NULL}; - GSpawnFlags grub_spawnflags = G_SPAWN_SEARCH_PATH; - int grub2_estatus; - Grub2ChildSetupData cdata = { NULL, }; + /* Autotests can set this envvar to select which code path to test, useful for OS installers as well */ + gboolean use_system_grub2_mkconfig = TRUE; #ifdef USE_BUILTIN_GRUB2_MKCONFIG use_system_grub2_mkconfig = FALSE; #endif - /* Autotests can set this envvar to select which code path to test, useful for OS installers as well */ - grub_exec = g_getenv ("OSTREE_GRUB2_EXEC"); + const gchar *grub_exec = g_getenv ("OSTREE_GRUB2_EXEC"); if (grub_exec) { if (g_str_has_suffix (grub_exec, GRUB2_MKCONFIG_PATH)) @@ -355,6 +342,7 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, else grub_exec = use_system_grub2_mkconfig ? GRUB2_MKCONFIG_PATH : TARGET_PREFIX "/lib/ostree/ostree-grub-generator"; + g_autofree char *grub2_mkconfig_chroot = NULL; if (use_system_grub2_mkconfig && ostree_sysroot_get_booted_deployment (self->sysroot) == NULL && g_file_has_parent (self->sysroot->path, NULL)) { @@ -381,13 +369,15 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, grub2_mkconfig_chroot = g_file_get_path (tool_deployment_root); } + g_autoptr(GFile) new_config_path = NULL; + g_autoptr(GFile) config_path_efi_dir = NULL; if (self->is_efi) { config_path_efi_dir = g_file_get_parent (self->config_path_efi); new_config_path = g_file_get_child (config_path_efi_dir, "grub.cfg.new"); /* We use grub2-mkconfig to write to a temporary file first */ if (!ot_gfile_ensure_unlinked (new_config_path, cancellable, error)) - goto out; + return FALSE; } else { @@ -395,12 +385,16 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, bootversion); } + const char *grub_argv[4] = { NULL, "-o", NULL, NULL}; + Grub2ChildSetupData cdata = { NULL, }; grub_argv[0] = grub_exec; grub_argv[2] = gs_file_get_path_cached (new_config_path); + GSpawnFlags grub_spawnflags = G_SPAWN_SEARCH_PATH; if (!g_getenv ("OSTREE_DEBUG_GRUB2")) grub_spawnflags |= G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL; cdata.root = grub2_mkconfig_chroot; + g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion); cdata.bootversion_str = bootversion_str; cdata.is_efi = self->is_efi; /* Note in older versions of the grub2 package, this script doesn't even try @@ -411,54 +405,47 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, Upstream is fixed though. */ + int grub2_estatus; if (!g_spawn_sync (NULL, (char**)grub_argv, NULL, grub_spawnflags, grub2_child_setup, &cdata, NULL, NULL, &grub2_estatus, error)) - goto out; + return FALSE; if (!g_spawn_check_exit_status (grub2_estatus, error)) { g_prefix_error (error, "%s: ", grub_argv[0]); - goto out; + return FALSE; } /* Now let's fdatasync() for the new file */ { glnx_fd_close int new_config_fd = -1; if (!glnx_openat_rdonly (AT_FDCWD, gs_file_get_path_cached (new_config_path), TRUE, &new_config_fd, error)) - goto out; + return FALSE; if (fdatasync (new_config_fd) < 0) - { - (void)glnx_throw_errno_prefix (error, "fdatasync"); - goto out; - } + return glnx_throw_errno_prefix (error, "fdatasync"); } if (self->is_efi) { g_autoptr(GFile) config_path_efi_old = g_file_get_child (config_path_efi_dir, "grub.cfg.old"); - + /* copy current to old */ if (!ot_gfile_ensure_unlinked (config_path_efi_old, cancellable, error)) - goto out; + return FALSE; if (!g_file_copy (self->config_path_efi, config_path_efi_old, G_FILE_COPY_OVERWRITE, cancellable, NULL, NULL, error)) - goto out; + return FALSE; /* NOTE: NON-ATOMIC REPLACEMENT; WE can't do anything else on FAT; * see https://bugzilla.gnome.org/show_bug.cgi?id=724246 */ if (!ot_gfile_ensure_unlinked (self->config_path_efi, cancellable, error)) - goto out; + return FALSE; if (rename (gs_file_get_path_cached (new_config_path), gs_file_get_path_cached (self->config_path_efi)) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "rename"); } - - ret = TRUE; - out: - return ret; + + return TRUE; } static gboolean diff --git a/src/libostree/ostree-bootloader-syslinux.c b/src/libostree/ostree-bootloader-syslinux.c index 05cb173e..16f287b9 100644 --- a/src/libostree/ostree-bootloader-syslinux.c +++ b/src/libostree/ostree-bootloader-syslinux.c @@ -59,44 +59,33 @@ _ostree_bootloader_syslinux_get_name (OstreeBootloader *bootloader) } static gboolean -append_config_from_boostree_loader_entries (OstreeBootloaderSyslinux *self, - gboolean regenerate_default, - int bootversion, - GPtrArray *new_lines, - GCancellable *cancellable, - GError **error) +append_config_from_loader_entries (OstreeBootloaderSyslinux *self, + gboolean regenerate_default, + int bootversion, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) { - gboolean ret = FALSE; - g_autoptr(GPtrArray) boostree_loader_configs = NULL; - guint i; - - if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &boostree_loader_configs, + g_autoptr(GPtrArray) loader_configs = NULL; + if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, &loader_configs, cancellable, error)) - goto out; + return FALSE; - for (i = 0; i < boostree_loader_configs->len; i++) + for (guint i = 0; i < loader_configs->len; i++) { - OstreeBootconfigParser *config = boostree_loader_configs->pdata[i]; - const char *val; - - val = ostree_bootconfig_parser_get (config, "title"); + OstreeBootconfigParser *config = loader_configs->pdata[i]; + const char *val = ostree_bootconfig_parser_get (config, "title"); if (!val) val = "(Untitled)"; if (regenerate_default && i == 0) - { - g_ptr_array_add (new_lines, g_strdup_printf ("DEFAULT %s", val)); - } + g_ptr_array_add (new_lines, g_strdup_printf ("DEFAULT %s", val)); g_ptr_array_add (new_lines, g_strdup_printf ("LABEL %s", val)); - + val = ostree_bootconfig_parser_get (config, "linux"); if (!val) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No \"linux\" key in bootloader config"); - goto out; - } + return glnx_throw (error, "No \"linux\" key in bootloader config"); g_ptr_array_add (new_lines, g_strdup_printf ("\tKERNEL %s", val)); val = ostree_bootconfig_parser_get (config, "initrd"); @@ -108,72 +97,57 @@ append_config_from_boostree_loader_entries (OstreeBootloaderSyslinux *self, g_ptr_array_add (new_lines, g_strdup_printf ("\tAPPEND %s", val)); } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, - int bootversion, - GCancellable *cancellable, - GError **error) + int bootversion, + GCancellable *cancellable, + GError **error) { - gboolean ret = FALSE; OstreeBootloaderSyslinux *self = OSTREE_BOOTLOADER_SYSLINUX (bootloader); - g_autoptr(GFile) new_config_path = NULL; - g_autofree char *config_contents = NULL; - g_autofree char *new_config_contents = NULL; - g_autoptr(GPtrArray) new_lines = NULL; - g_autoptr(GPtrArray) tmp_lines = NULL; + + g_autoptr(GFile) new_config_path = + ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg", bootversion); + + /* This should follow the symbolic link to the current bootversion. */ + g_autofree char *config_contents = + glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL, + cancellable, error); + if (!config_contents) + return FALSE; + + g_auto(GStrv) lines = g_strsplit (config_contents, "\n", -1); + g_autoptr(GPtrArray) new_lines = g_ptr_array_new_with_free_func (g_free); + g_autoptr(GPtrArray) tmp_lines = g_ptr_array_new_with_free_func (g_free); + g_autofree char *kernel_arg = NULL; gboolean saw_default = FALSE; gboolean regenerate_default = FALSE; gboolean parsing_label = FALSE; - char **lines = NULL; - char **iter; - guint i; - - new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/syslinux.cfg", - bootversion); - - /* This should follow the symbolic link to the current bootversion. */ - config_contents = glnx_file_get_contents_utf8_at (AT_FDCWD, gs_file_get_path_cached (self->config_path), NULL, - cancellable, error); - if (!config_contents) - goto out; - - lines = g_strsplit (config_contents, "\n", -1); - new_lines = g_ptr_array_new_with_free_func (g_free); - tmp_lines = g_ptr_array_new_with_free_func (g_free); - /* Note special iteration condition here; we want to also loop one * more time at the end where line = NULL to ensure we finish off * processing the last LABEL. */ - iter = lines; - while (TRUE) + for (char **iter = lines; iter; iter++) { - char *line = *iter; + const char *line = *iter; gboolean skip = FALSE; - if (parsing_label && + if (parsing_label && (line == NULL || !g_str_has_prefix (line, "\t"))) { parsing_label = FALSE; if (kernel_arg == NULL) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No KERNEL argument found after LABEL"); - goto out; - } + return glnx_throw (error, "No KERNEL argument found after LABEL"); /* If this is a non-ostree kernel, just emit the lines * we saw. */ if (!g_str_has_prefix (kernel_arg, "/ostree/")) { - for (i = 0; i < tmp_lines->len; i++) + for (guint i = 0; i < tmp_lines->len; i++) { g_ptr_array_add (new_lines, tmp_lines->pdata[i]); tmp_lines->pdata[i] = NULL; /* Transfer ownership */ @@ -211,55 +185,37 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, * the title to hopefully avoid regressions. */ if (g_str_has_prefix (line, "DEFAULT ostree:") || /* old format */ strstr (line, "(ostree") != NULL) /* new format */ - { - regenerate_default = TRUE; - } + regenerate_default = TRUE; skip = TRUE; } - - if (skip) - { - g_free (line); - } - else + + if (!skip) { if (parsing_label) - { - g_ptr_array_add (tmp_lines, line); - } + g_ptr_array_add (tmp_lines, g_strdup (line)); else - { - g_ptr_array_add (new_lines, line); - } + g_ptr_array_add (new_lines, g_strdup (line)); } - /* Transfer ownership */ - *iter = NULL; - iter++; } if (!saw_default) regenerate_default = TRUE; - if (!append_config_from_boostree_loader_entries (self, regenerate_default, - bootversion, new_lines, - cancellable, error)) - goto out; - - new_config_contents = _ostree_sysroot_join_lines (new_lines); - { - g_autoptr(GBytes) new_config_contents_bytes = - g_bytes_new_static (new_config_contents, - strlen (new_config_contents)); - - if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, + if (!append_config_from_loader_entries (self, regenerate_default, + bootversion, new_lines, cancellable, error)) - goto out; - } - - ret = TRUE; - out: - g_free (lines); /* Note we freed elements individually */ - return ret; + return FALSE; + + g_autofree char *new_config_contents = _ostree_sysroot_join_lines (new_lines); + g_autoptr(GBytes) new_config_contents_bytes = + g_bytes_new_static (new_config_contents, + strlen (new_config_contents)); + + if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, + cancellable, error)) + return FALSE; + + return TRUE; } static void diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c index 81ea95a6..ce5d516c 100644 --- a/src/libostree/ostree-bootloader-uboot.c +++ b/src/libostree/ostree-bootloader-uboot.c @@ -62,6 +62,44 @@ _ostree_bootloader_uboot_get_name (OstreeBootloader *bootloader) return "U-Boot"; } +/* Append system's uEnv.txt, if it exists in $deployment/usr/lib/ostree-boot/ */ +static gboolean +append_system_uenv (OstreeBootloaderUboot *self, + const char *bootargs, + GPtrArray *new_lines, + GCancellable *cancellable, + GError **error) +{ + glnx_fd_close int uenv_fd = -1; + __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; + const char *uenv_path = NULL; + const char *ostree_arg = NULL; + + kargs = _ostree_kernel_args_from_string (bootargs); + ostree_arg = _ostree_kernel_args_get_last_value (kargs, "ostree"); + if (!ostree_arg) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No ostree= kernel argument found in boot loader configuration file"); + return FALSE; + } + ostree_arg += 1; + uenv_path = glnx_strjoina (ostree_arg, "/usr/lib/ostree-boot/uEnv.txt"); + if (!ot_openat_ignore_enoent (self->sysroot->sysroot_fd, uenv_path, &uenv_fd, error)) + return FALSE; + if (uenv_fd != -1) + { + char *uenv = glnx_fd_readall_utf8 (uenv_fd, NULL, cancellable, error); + if (!uenv) + { + g_prefix_error (error, "Reading %s: ", uenv_path); + return FALSE; + } + g_ptr_array_add (new_lines, uenv); + } + return TRUE; +} + static gboolean create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, int bootversion, @@ -77,61 +115,35 @@ create_config_from_boot_loader_entries (OstreeBootloaderUboot *self, cancellable, error)) return FALSE; - /* U-Boot doesn't support a menu so just pick the first one since the list is ordered */ - config = boot_loader_configs->pdata[0]; - - val = ostree_bootconfig_parser_get (config, "linux"); - if (!val) + for (int i = 0; i < boot_loader_configs->len; i++) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No \"linux\" key in bootloader config"); - return FALSE; - } - g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image=%s", val)); - - val = ostree_bootconfig_parser_get (config, "initrd"); - if (val) - g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image=%s", val)); - - val = ostree_bootconfig_parser_get (config, "options"); - if (val) - { - glnx_fd_close int uenv_fd = -1; - __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; - const char *uenv_path = NULL; - const char *ostree_arg = NULL; - - g_ptr_array_add (new_lines, g_strdup_printf ("bootargs=%s", val)); - - /* Append system's uEnv.txt, if it exists in $deployment/usr/lib/ostree-boot/ */ - kargs = _ostree_kernel_args_from_string (val); - ostree_arg = _ostree_kernel_args_get_last_value (kargs, "ostree"); - if (!ostree_arg) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No ostree= kernel argument found in boot loader configuration file"); - return FALSE; - } - ostree_arg += 1; - uenv_path = glnx_strjoina (ostree_arg, "/usr/lib/ostree-boot/uEnv.txt"); - uenv_fd = openat (self->sysroot->sysroot_fd, uenv_path, O_CLOEXEC | O_RDONLY); - if (uenv_fd != -1) - { - char *uenv = glnx_fd_readall_utf8 (uenv_fd, NULL, cancellable, error); - if (!uenv) - { - g_prefix_error (error, "Reading %s: ", uenv_path); - return FALSE; - } - g_ptr_array_add (new_lines, uenv); - } + g_autofree char *index_suffix = NULL; + if (i == 0) + index_suffix = g_strdup (""); else + index_suffix = g_strdup_printf ("%d", i+1); + config = boot_loader_configs->pdata[i]; + + val = ostree_bootconfig_parser_get (config, "linux"); + if (!val) { - if (errno != ENOENT) - { - g_prefix_error (error, "openat %s: ", uenv_path); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No \"linux\" key in bootloader config"); + return FALSE; + } + g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image%s=%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)); + + val = ostree_bootconfig_parser_get (config, "options"); + if (val) + { + g_ptr_array_add (new_lines, g_strdup_printf ("bootargs%s=%s", index_suffix, val)); + if (i == 0) + if (!append_system_uenv (self, val, new_lines, cancellable, error)) return FALSE; - } } } diff --git a/src/libostree/ostree-core-private.h b/src/libostree/ostree-core-private.h index 799bd228..5a2835d5 100644 --- a/src/libostree/ostree-core-private.h +++ b/src/libostree/ostree-core-private.h @@ -179,6 +179,13 @@ _ostree_raw_file_to_archive_stream (GInputStream *input, gboolean ostree_validate_collection_id (const char *collection_id, GError **error); #endif /* !OSTREE_ENABLE_EXPERIMENTAL_API */ +gboolean +_ostree_compare_timestamps (const char *current_rev, + guint64 current_ts, + const char *new_rev, + guint64 new_ts, + GError **error); + #if (defined(OSTREE_COMPILATION) || GLIB_CHECK_VERSION(2, 44, 0)) && !defined(OSTREE_ENABLE_EXPERIMENTAL_API) #include #include "ostree-ref.h" diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index c13d2f2e..7d34278a 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -312,7 +312,7 @@ _ostree_file_header_new (GFileInfo *file_info, * @file_info: a #GFileInfo * @xattrs: (allow-none): Optional extended attribute array * - * Returns: (transfer full): A new #GVariant containing file header for an archive-z2 repository + * Returns: (transfer full): A new #GVariant containing file header for an archive repository */ GVariant * _ostree_zlib_file_header_new (GFileInfo *file_info, @@ -2086,6 +2086,38 @@ ostree_commit_get_timestamp (GVariant *commit_variant) return GUINT64_FROM_BE (ret); } +/* Used in pull/deploy to validate we're not being downgraded */ +gboolean +_ostree_compare_timestamps (const char *current_rev, + guint64 current_ts, + const char *new_rev, + guint64 new_ts, + GError **error) +{ + /* Newer timestamp is OK */ + if (new_ts > current_ts) + return TRUE; + /* If they're equal, ensure they're the same rev */ + if (new_ts == current_ts || strcmp (current_rev, new_rev) == 0) + return TRUE; + + /* Looks like a downgrade, format an error message */ + g_autoptr(GDateTime) current_dt = g_date_time_new_from_unix_utc (current_ts); + g_autoptr(GDateTime) new_dt = g_date_time_new_from_unix_utc (new_ts); + + if (current_dt == NULL || new_dt == NULL) + return glnx_throw (error, "Upgrade target revision '%s' timestamp (%" G_GINT64_FORMAT ") or current revision '%s' timestamp (%" G_GINT64_FORMAT ") is invalid", + new_rev, new_ts, + current_rev, current_ts); + + g_autofree char *current_ts_str = g_date_time_format (current_dt, "%c"); + g_autofree char *new_ts_str = g_date_time_format (new_dt, "%c"); + + return glnx_throw (error, "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'", + new_rev, new_ts_str, current_rev, current_ts_str); +} + + GVariant * _ostree_detached_metadata_append_gpg_sig (GVariant *existing_metadata, GBytes *signature_bytes) diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c index 99756e2b..9b731489 100644 --- a/src/libostree/ostree-gpg-verifier.c +++ b/src/libostree/ostree-gpg-verifier.c @@ -187,14 +187,14 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, gpg_error = gpgme_data_new_from_fd (&kdata, fd); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); + ot_gpgme_throw (gpg_error, error, "Loading data from fd %i", fd); goto out; } gpg_error = gpgme_op_import (result->context, kdata); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); + ot_gpgme_throw (gpg_error, error, "Failed to import key"); goto out; } } @@ -212,8 +212,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, 0 /* do not copy */); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to read signed data: "); + ot_gpgme_throw (gpg_error, error, "Unable to read signed data"); goto out; } @@ -223,16 +222,14 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, 0 /* do not copy */); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to read signature: "); + ot_gpgme_throw (gpg_error, error, "Unable to read signature"); goto out; } gpg_error = gpgme_op_verify (result->context, signature_buffer, data_buffer, NULL); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to complete signature verification: "); + ot_gpgme_throw (gpg_error, error, "Unable to complete signature verification"); goto out; } @@ -368,31 +365,22 @@ _ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *self, GCancellable *cancellable, GError **error) { - const char *global_keyring_path = g_getenv ("OSTREE_GPG_HOME"); - g_autoptr(GFile) global_keyring_dir = NULL; - gboolean ret = FALSE; - g_return_val_if_fail (OSTREE_IS_GPG_VERIFIER (self), FALSE); + const char *global_keyring_path = g_getenv ("OSTREE_GPG_HOME"); if (global_keyring_path == NULL) global_keyring_path = DATADIR "/ostree/trusted.gpg.d/"; if (g_file_test (global_keyring_path, G_FILE_TEST_IS_DIR)) { - global_keyring_dir = g_file_new_for_path (global_keyring_path); + g_autoptr(GFile) global_keyring_dir = g_file_new_for_path (global_keyring_path); if (!_ostree_gpg_verifier_add_keyring_dir (self, global_keyring_dir, cancellable, error)) - { - g_prefix_error (error, "Reading keyring directory '%s'", - gs_file_get_path_cached (global_keyring_dir)); - goto out; - } + return glnx_prefix_error (error, "Reading keyring directory '%s'", + gs_file_get_path_cached (global_keyring_dir)); } - ret = TRUE; - -out: - return ret; + return TRUE; } OstreeGpgVerifier* diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c index f6689e63..5be6b2e1 100644 --- a/src/libostree/ostree-gpg-verify-result.c +++ b/src/libostree/ostree-gpg-verify-result.c @@ -63,7 +63,8 @@ static OstreeGpgSignatureAttr all_signature_attrs[] = { OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, - OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL + OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY }; static void ostree_gpg_verify_result_initable_iface_init (GInitableIface *iface); @@ -133,8 +134,7 @@ ostree_gpg_verify_result_initable_init (GInitable *initable, gpg_error = gpgme_new (&result->context); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to create context: "); + ot_gpgme_throw (gpg_error, error, "Unable to create context"); goto out; } @@ -328,9 +328,9 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, * (OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING). */ for (ii = 0; ii < n_attrs; ii++) { - if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT || - attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME || - attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL) + if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY) { (void) gpgme_get_key (result->context, signature->fpr, &key, 0); break; @@ -373,11 +373,7 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, break; case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT: - if (key != NULL && key->subkeys != NULL) - v_string = key->subkeys->fpr; - else - v_string = signature->fpr; - child = g_variant_new_string (v_string); + child = g_variant_new_string (signature->fpr); break; case OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP: @@ -418,6 +414,14 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, child = g_variant_new_string (v_string); break; + case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY: + if (key != NULL && key->subkeys != NULL) + v_string = key->subkeys->fpr; + if (v_string == NULL) + v_string = ""; + child = g_variant_new_string (v_string); + break; + default: g_critical ("Invalid signature attribute (%d)", attrs[ii]); g_variant_builder_clear (&builder); @@ -535,6 +539,7 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, gint64 exp_timestamp; const char *type_string; const char *fingerprint; + const char *fingerprint_primary; const char *pubkey_algo; const char *user_name; const char *user_email; @@ -550,7 +555,7 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, /* Verify the variant's type string. This code is * not prepared to handle just any random GVariant. */ type_string = g_variant_get_type_string (variant); - g_return_if_fail (strcmp (type_string, "(bbbbbsxxssss)") == 0); + g_return_if_fail (strcmp (type_string, "(bbbbbsxxsssss)") == 0); /* The default format roughly mimics the verify output generated by * check_sig_and_print() in gnupg/g10/mainproc.c, though obviously @@ -564,6 +569,8 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, "b", &key_missing); g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT, "&s", &fingerprint); + g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY, + "&s", &fingerprint_primary); g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP, "x", ×tamp); g_variant_get_child (variant, OSTREE_GPG_SIGNATURE_ATTR_EXP_TIMESTAMP, @@ -628,8 +635,26 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, user_name, user_email); } + if (!key_missing && (g_strcmp0 (fingerprint, fingerprint_primary) != 0)) + { + const char *key_id_primary; + + len = strlen (fingerprint_primary); + key_id_primary = (len > 16) ? fingerprint_primary + len - 16 : + fingerprint_primary; + + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + + g_string_append_printf (output_buffer, + "Primary key ID %s\n", key_id_primary); + } + if (exp_timestamp > 0) { + if (line_prefix != NULL) + g_string_append (output_buffer, line_prefix); + date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp); if (date_time_utc == NULL) { @@ -642,9 +667,6 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, date_time_local = g_date_time_to_local (date_time_utc); formatted_date_time = g_date_time_format (date_time_local, "%c"); - if (line_prefix != NULL) - g_string_append (output_buffer, line_prefix); - if (sig_expired) { g_string_append_printf (output_buffer, diff --git a/src/libostree/ostree-gpg-verify-result.h b/src/libostree/ostree-gpg-verify-result.h index f5fadd59..3064ed8e 100644 --- a/src/libostree/ostree-gpg-verify-result.h +++ b/src/libostree/ostree-gpg-verify-result.h @@ -64,6 +64,11 @@ typedef struct OstreeGpgVerifyResult OstreeGpgVerifyResult; * @OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL: * [#G_VARIANT_TYPE_STRING] The email address of the signing key's primary * user + * @OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY: + * [#G_VARIANT_TYPE_STRING] Fingerprint of the signing key's primary key + * (will be the same as OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT if the + * the signature is already from the primary key rather than a subkey, + * and will be the empty string if the key is missing.) * * Signature attributes available from an #OstreeGpgVerifyResult. * The attribute's #GVariantType is shown in brackets. @@ -80,7 +85,8 @@ typedef enum { OSTREE_GPG_SIGNATURE_ATTR_PUBKEY_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_HASH_ALGO_NAME, OSTREE_GPG_SIGNATURE_ATTR_USER_NAME, - OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL + OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL, + OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT_PRIMARY, } OstreeGpgSignatureAttr; _OSTREE_PUBLIC diff --git a/src/libostree/ostree-libarchive-private.h b/src/libostree/ostree-libarchive-private.h index 870ddf82..2797fbac 100644 --- a/src/libostree/ostree-libarchive-private.h +++ b/src/libostree/ostree-libarchive-private.h @@ -38,6 +38,28 @@ typedef struct archive OtAutoArchiveWrite; G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveWrite, archive_write_free) typedef struct archive OtAutoArchiveRead; G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveRead, archive_read_free) + +static inline OtAutoArchiveRead * +ot_open_archive_read (const char *path, GError **error) +{ + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); + +#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL + archive_read_support_filter_all (a); +#else + archive_read_support_compression_all (a); +#endif + archive_read_support_format_all (a); + if (archive_read_open_filename (a, path, 8192) != ARCHIVE_OK) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", archive_error_string (a)); + return NULL; + } + + return g_steal_pointer (&a); +} + #endif G_END_DECLS diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 3deaa297..868cd186 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -188,8 +188,6 @@ create_file_copy_from_input_at (OstreeRepo *repo, GCancellable *cancellable, GError **error) { - const gboolean union_mode = options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; - const gboolean add_mode = options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES; const gboolean sepolicy_enabled = options->sepolicy && !repo->disable_xattrs; g_autoptr(GVariant) modified_xattrs = NULL; @@ -218,23 +216,51 @@ create_file_copy_from_input_at (OstreeRepo *repo, return FALSE; } - if (symlinkat (g_file_info_get_symlink_target (file_info), - destination_dfd, destination_name) < 0) + const char *target = g_file_info_get_symlink_target (file_info); + if (symlinkat (target, destination_dfd, destination_name) < 0) { + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "symlinkat"); + /* Handle union/add behaviors if we get EEXIST */ - if (errno == EEXIST && union_mode) + switch (options->overwrite_mode) { - /* Unioning? Let's unlink and try again */ - (void) unlinkat (destination_dfd, destination_name, 0); - if (symlinkat (g_file_info_get_symlink_target (file_info), - destination_dfd, destination_name) < 0) - return glnx_throw_errno (error); + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + return glnx_throw_errno_prefix (error, "symlinkat"); + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + { + /* Unioning? Let's unlink and try again */ + (void) unlinkat (destination_dfd, destination_name, 0); + if (symlinkat (target, destination_dfd, destination_name) < 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + } + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + /* Note early return - we don't want to set the xattrs below */ + return TRUE; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + { + /* See the comments for the hardlink version of this + * for why we do this. + */ + struct stat dest_stbuf; + if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + if (S_ISLNK (dest_stbuf.st_mode)) + { + g_autofree char *dest_target = + glnx_readlinkat_malloc (destination_dfd, destination_name, + cancellable, error); + if (!dest_target) + return FALSE; + /* In theory we could also compare xattrs...but eh */ + if (g_str_equal (dest_target, target)) + return TRUE; + } + errno = EEXIST; + return glnx_throw_errno_prefix (error, "symlinkat"); + } } - else if (errno == EEXIST && add_mode) - /* Note early return - we don't want to set the xattrs below */ - return TRUE; - else - return glnx_throw_errno (error); } /* Process ownership and xattrs now that we made the link */ @@ -255,7 +281,6 @@ create_file_copy_from_input_at (OstreeRepo *repo, else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { g_auto(GLnxTmpfile) tmpf = { 0, }; - GLnxLinkTmpfileReplaceMode replace_mode; if (!glnx_open_tmpfile_linkable_at (destination_dfd, ".", O_WRONLY | O_CLOEXEC, &tmpf, error)) @@ -278,12 +303,23 @@ create_file_copy_from_input_at (OstreeRepo *repo, return FALSE; /* The add/union/none behaviors map directly to GLnxLinkTmpfileReplaceMode */ - if (add_mode) - replace_mode = GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST; - else if (union_mode) - replace_mode = GLNX_LINK_TMPFILE_REPLACE; - else - replace_mode = GLNX_LINK_TMPFILE_NOREPLACE; + GLnxLinkTmpfileReplaceMode replace_mode; + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + replace_mode = GLNX_LINK_TMPFILE_NOREPLACE; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + replace_mode = GLNX_LINK_TMPFILE_REPLACE; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + replace_mode = GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + /* We don't support copying in union identical */ + g_assert_not_reached (); + break; + } if (!glnx_link_tmpfile_at (&tmpf, replace_mode, destination_dfd, destination_name, @@ -329,25 +365,61 @@ checkout_file_hardlink (OstreeRepo *self, else if (allow_noent && errno == ENOENT) { } - else if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES) + else if (errno == EEXIST) { - /* In this mode, we keep existing content. Distinguish this case though to - * avoid inserting into the devino cache. - */ - ret_result = HARDLINK_RESULT_SKIP_EXISTED; - } - else if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) - { - /* Idiocy, from man rename(2) - * - * "If oldpath and newpath are existing hard links referring to - * the same file, then rename() does nothing, and returns a - * success status." - * - * So we can't make this atomic. - */ - (void) unlinkat (destination_dfd, destination_name, 0); - goto again; + /* When we get EEXIST, we need to handle the different overwrite modes. */ + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + /* Just throw */ + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + /* In this mode, we keep existing content. Distinguish this case though to + * avoid inserting into the devino cache. + */ + ret_result = HARDLINK_RESULT_SKIP_EXISTED; + break; + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + { + /* Idiocy, from man rename(2) + * + * "If oldpath and newpath are existing hard links referring to + * the same file, then rename() does nothing, and returns a + * success status." + * + * So we can't make this atomic. + */ + (void) unlinkat (destination_dfd, destination_name, 0); + goto again; + } + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + { + /* In this mode, we error out on EEXIST *unless* the files are already + * hardlinked, which is what rpm-ostree wants for package layering. + * https://github.com/projectatomic/rpm-ostree/issues/982 + * + * This should be similar to the librpm version: + * https://github.com/rpm-software-management/rpm/blob/e3cd2bc85e0578f158d14e6f9624eb955c32543b/lib/rpmfi.c#L921 + * in rpmfilesCompare(). + */ + struct stat src_stbuf; + if (!glnx_fstatat (srcfd, loose_path, &src_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + struct stat dest_stbuf; + if (!glnx_fstatat (destination_dfd, destination_name, &dest_stbuf, + AT_SYMLINK_NOFOLLOW, error)) + return FALSE; + const gboolean is_identical = + (src_stbuf.st_dev == dest_stbuf.st_dev && + src_stbuf.st_ino == dest_stbuf.st_ino); + if (is_identical) + ret_result = HARDLINK_RESULT_SKIP_EXISTED; + else + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); + break; + } + } } else { @@ -652,12 +724,20 @@ checkout_tree_at_recurse (OstreeRepo *self, */ if (TEMP_FAILURE_RETRY (mkdirat (destination_parent_fd, destination_name, 0700)) < 0) { - if (errno == EEXIST && - (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES - || options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES)) - did_exist = TRUE; - else - return glnx_throw_errno (error); + if (errno != EEXIST) + return glnx_throw_errno_prefix (error, "mkdirat"); + + switch (options->overwrite_mode) + { + case OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: + return glnx_throw_errno_prefix (error, "mkdirat"); + /* All of these cases are the same for directories */ + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: + case OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: + case OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: + did_exist = TRUE; + break; + } } } @@ -1001,6 +1081,9 @@ ostree_repo_checkout_at (OstreeRepo *self, g_return_val_if_fail (!(options->force_copy && options->no_copy_fallback), FALSE); g_return_val_if_fail (!options->sepolicy || options->force_copy, FALSE); + /* union identical requires hardlink mode */ + g_return_val_if_fail (!(options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL && + !options->no_copy_fallback), FALSE); g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error); if (!commit_root) @@ -1120,11 +1203,8 @@ ostree_repo_checkout_gc (OstreeRepo *self, if (stbuf.st_nlink == 1) { - if (unlinkat (dfd_iter.fd, dent->d_name, 0) != 0) - { - glnx_set_error_from_errno (error); - return FALSE; - } + if (!glnx_unlinkat (dfd_iter.fd, dent->d_name, 0, error)) + return FALSE; } } } diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 1c6e5e8d..5d28dca8 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -34,6 +34,7 @@ #include "ostree.h" #include "ostree-core-private.h" #include "ostree-repo-private.h" +#include "ostree-sepolicy-private.h" #include "ostree-repo-file-enumerator.h" #include "ostree-checksum-input-stream.h" #include "ostree-varint.h" @@ -1028,35 +1029,33 @@ devino_cache_lookup (OstreeRepo *self, * @cancellable: Cancellable * @error: Error * - * When ostree builds a mutable tree from directory like in - * ostree_repo_write_directory_to_mtree(), it has to scan all files that you - * pass in and compute their checksums. If your commit contains hardlinks from - * ostree's existing repo, ostree can build a mapping of device numbers and - * inodes to their checksum. + * This function is deprecated in favor of using ostree_repo_devino_cache_new(), + * which allows a precise mapping to be built up between hardlink checkout files + * and their checksums between `ostree_repo_checkout_at()` and + * `ostree_repo_write_directory_to_mtree()`. + * + * When invoking ostree_repo_write_directory_to_mtree(), it has to compute the + * checksum of all files. If your commit contains hardlinks from a checkout, + * this functions builds a mapping of device numbers and inodes to their + * checksum. * * There is an upfront cost to creating this mapping, as this will scan the * entire objects directory. If your commit is composed of mostly hardlinks to * existing ostree objects, then this will speed up considerably, so call it - * before you call ostree_write_directory_to_mtree() or similar. + * before you call ostree_write_directory_to_mtree() or similar. However, + * ostree_repo_devino_cache_new() is better as it avoids scanning all objects. */ gboolean ostree_repo_scan_hardlinks (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_return_val_if_fail (self->in_transaction == TRUE, FALSE); if (!self->loose_object_devino_hash) self->loose_object_devino_hash = (GHashTable*)ostree_repo_devino_cache_new (); g_hash_table_remove_all (self->loose_object_devino_hash); - if (!scan_loose_devino (self, self->loose_object_devino_hash, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return scan_loose_devino (self, self->loose_object_devino_hash, cancellable, error); } /** @@ -1132,6 +1131,7 @@ rename_pending_loose_objects (OstreeRepo *self, GCancellable *cancellable, GError **error) { + GLNX_AUTO_PREFIX_ERROR ("rename pending", error); g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (self->commit_stagedir_fd, ".", FALSE, &dfd_iter, error)) @@ -1224,11 +1224,10 @@ cleanup_tmpdir (OstreeRepo *self, GCancellable *cancellable, GError **error) { + GLNX_AUTO_PREFIX_ERROR ("tmpdir cleanup", error); + const guint64 curtime_secs = g_get_real_time () / 1000000; + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; - guint64 curtime_secs; - - curtime_secs = g_get_real_time () / 1000000; - if (!glnx_dirfd_iterator_init_at (self->tmp_dir_fd, ".", TRUE, &dfd_iter, error)) return FALSE; @@ -1256,7 +1255,7 @@ cleanup_tmpdir (OstreeRepo *self, { if (errno == ENOENT) /* Did another cleanup win? */ continue; - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "fstatat(%s)", dent->d_name); } /* First, if it's a directory which needs locking, but it's @@ -1283,7 +1282,7 @@ cleanup_tmpdir (OstreeRepo *self, * from *other* boots */ if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error)) - return FALSE; + return glnx_prefix_error (error, "Removing %s", dent->d_name); } /* FIXME - move OSTREE_REPO_TMPDIR_FETCHER underneath the * staging/boot-id scheme as well, since all of the "did it get @@ -1308,7 +1307,7 @@ cleanup_tmpdir (OstreeRepo *self, if (delta > self->tmp_expiry_seconds) { if (!glnx_shutil_rm_rf_at (dfd_iter.fd, dent->d_name, cancellable, error)) - return FALSE; + return glnx_prefix_error (error, "Removing %s", dent->d_name); } } } @@ -1535,7 +1534,7 @@ ostree_repo_commit_transaction (OstreeRepo *self, if (g_getenv ("OSTREE_SUPPRESS_SYNCFS") == NULL) { if (syncfs (self->tmp_dir_fd) < 0) - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "syncfs"); } if (!rename_pending_loose_objects (self, cancellable, error)) @@ -2335,6 +2334,10 @@ create_tree_variant_from_hashes (GHashTable *file_checksums, return serialized_tree; } +/* If any filtering is set up, perform it, and return modified file info in + * @out_modified_info. Note that if no filtering is applied, @out_modified_info + * will simply be another reference (with incremented refcount) to @file_info. + */ OstreeRepoCommitFilterResult _ostree_repo_commit_modifier_apply (OstreeRepo *self, OstreeRepoCommitModifier *modifier, @@ -2410,24 +2413,6 @@ ptrarray_path_join (GPtrArray *path) return g_string_free (path_buf, FALSE); } -static gboolean -apply_commit_filter (OstreeRepo *self, - OstreeRepoCommitModifier *modifier, - const char *relpath, - GFileInfo *file_info, - GFileInfo **out_modified_info) -{ - if (modifier == NULL || - (modifier->filter == NULL && - (modifier->flags & OSTREE_REPO_COMMIT_MODIFIER_FLAGS_CANONICAL_PERMISSIONS) == 0)) - { - *out_modified_info = g_object_ref (file_info); - return OSTREE_REPO_COMMIT_FILTER_ALLOW; - } - - return _ostree_repo_commit_modifier_apply (self, modifier, relpath, file_info, out_modified_info); -} - static gboolean get_modified_xattrs (OstreeRepo *self, OstreeRepoCommitModifier *modifier, @@ -2498,6 +2483,16 @@ get_modified_xattrs (OstreeRepo *self, { g_autoptr(GVariantBuilder) builder = NULL; + if (ret_xattrs) + { + /* drop out any existing SELinux policy from the set, so we don't end up + * counting it twice in the checksum */ + g_autoptr(GVariant) new_ret_xattrs = NULL; + new_ret_xattrs = _ostree_filter_selinux_xattr (ret_xattrs); + g_variant_unref (ret_xattrs); + ret_xattrs = g_steal_pointer (&new_ret_xattrs); + } + /* ret_xattrs may be NULL */ builder = ot_util_variant_builder_from_variant (ret_xattrs, G_VARIANT_TYPE ("a(ayay)")); @@ -2564,7 +2559,7 @@ write_directory_content_to_mtree_internal (OstreeRepo *self, if (modifier != NULL) child_relpath = ptrarray_path_join (path); - filter_result = apply_commit_filter (self, modifier, child_relpath, child_info, &modified_info); + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, child_relpath, child_info, &modified_info); if (filter_result != OSTREE_REPO_COMMIT_FILTER_ALLOW) { @@ -2733,7 +2728,7 @@ write_directory_to_mtree_internal (OstreeRepo *self, relpath = ptrarray_path_join (path); g_autoptr(GFileInfo) modified_info = NULL; - filter_result = apply_commit_filter (self, modifier, relpath, child_info, &modified_info); + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info); if (filter_result == OSTREE_REPO_COMMIT_FILTER_ALLOW) { @@ -2803,8 +2798,8 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self, OstreeRepoCommitFilterResult filter_result; struct stat dir_stbuf; - if (fstat (src_dfd_iter->fd, &dir_stbuf) != 0) - return glnx_throw_errno (error); + if (!glnx_fstat (src_dfd_iter->fd, &dir_stbuf, error)) + return FALSE; child_info = _ostree_stbuf_to_gfileinfo (&dir_stbuf); @@ -2812,7 +2807,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self, { relpath = ptrarray_path_join (path); - filter_result = apply_commit_filter (self, modifier, relpath, child_info, &modified_info); + filter_result = _ostree_repo_commit_modifier_apply (self, modifier, relpath, child_info, &modified_info); } else { diff --git a/src/libostree/ostree-repo-finder-mount.c b/src/libostree/ostree-repo-finder-mount.c index 7f257f68..b7b15bf0 100644 --- a/src/libostree/ostree-repo-finder-mount.c +++ b/src/libostree/ostree-repo-finder-mount.c @@ -314,7 +314,9 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde g_autoptr(GHashTable) repo_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ - if (!ostree_repo_list_collection_refs (repo, refs[i]->collection_id, &repo_refs, cancellable, &local_error)) + if (!ostree_repo_list_collection_refs (repo, refs[i]->collection_id, &repo_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, + cancellable, &local_error)) { g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its refs could not be listed: %s", refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message); diff --git a/src/libostree/ostree-repo-libarchive.c b/src/libostree/ostree-repo-libarchive.c index 1839a088..b34e4871 100644 --- a/src/libostree/ostree-repo-libarchive.c +++ b/src/libostree/ostree-repo-libarchive.c @@ -123,24 +123,30 @@ squash_trailing_slashes (char *path) *endp = '\0'; } +/* Like archive_entry_stat(), but since some archives only store the permission + * mode bits in hardlink entries, so let's just make it into a regular file. + * Yes, this hack will work even if it's a hardlink to a symlink. + */ +static void +read_archive_entry_stat (struct archive_entry *entry, + struct stat *stbuf) +{ + const struct stat *st = archive_entry_stat (entry); + + *stbuf = *st; + if (archive_entry_hardlink (entry)) + stbuf->st_mode |= S_IFREG; +} + +/* Create a GFileInfo from archive_entry_stat() */ static GFileInfo * file_info_from_archive_entry (struct archive_entry *entry) { - const struct stat *st = archive_entry_stat (entry); - struct stat st_copy; + struct stat stbuf; + read_archive_entry_stat (entry, &stbuf); - /* Some archives only store the permission mode bits in hardlink entries, so - * let's just make it into a regular file. Yes, this hack will work even if - * it's a hardlink to a symlink. */ - if (archive_entry_hardlink (entry)) - { - st_copy = *st; - st_copy.st_mode |= S_IFREG; - st = &st_copy; - } - - g_autoptr(GFileInfo) info = _ostree_stbuf_to_gfileinfo (st); - if (S_ISLNK (st->st_mode)) + g_autoptr(GFileInfo) info = _ostree_stbuf_to_gfileinfo (&stbuf); + if (S_ISLNK (stbuf.st_mode)) g_file_info_set_attribute_byte_string (info, "standard::symlink-target", archive_entry_symlink (entry)); @@ -247,7 +253,18 @@ aic_get_final_path (OstreeRepoArchiveImportContext *ctx, const char *path, GError **error) { - if (ctx->opts->use_ostree_convention) + if (ctx->opts->translate_pathname) + { + struct stat stbuf; + path = path_relative (path, error); + read_archive_entry_stat (ctx->entry, &stbuf); + char *ret = ctx->opts->translate_pathname (ctx->repo, &stbuf, path, + ctx->opts->translate_pathname_user_data); + if (ret) + return ret; + /* Fall through */ + } + else if (ctx->opts->use_ostree_convention) return path_relative_ostree (path, error); return g_strdup (path_relative (path, error)); } @@ -258,7 +275,6 @@ aic_get_final_entry_pathname (OstreeRepoArchiveImportContext *ctx, { const char *pathname = archive_entry_pathname (ctx->entry); g_autofree char *final = aic_get_final_path (ctx, pathname, error); - if (final == NULL) return NULL; @@ -642,17 +658,17 @@ aic_import_entry (OstreeRepoArchiveImportContext *ctx, GCancellable *cancellable, GError **error) { - g_autoptr(GFileInfo) fi = NULL; - g_autoptr(OstreeMutableTree) parent = NULL; g_autofree char *path = aic_get_final_entry_pathname (ctx, error); if (path == NULL) return FALSE; + g_autoptr(GFileInfo) fi = NULL; if (aic_apply_modifier_filter (ctx, path, &fi) == OSTREE_REPO_COMMIT_FILTER_SKIP) return TRUE; + g_autoptr(OstreeMutableTree) parent = NULL; if (!aic_get_parent_dir (ctx, path, &parent, cancellable, error)) return FALSE; @@ -861,7 +877,11 @@ ostree_repo_import_archive_to_mtree (OstreeRepo *self, g_file_info_set_attribute_uint32 (fi, "unix::gid", 0); g_file_info_set_attribute_uint32 (fi, "unix::mode", DEFAULT_DIRMODE); - if (!aic_ensure_parent_dir_with_file_info (&aictx, mtree, "/", fi, NULL, + g_autoptr(GFileInfo) mfi = NULL; + (void)_ostree_repo_commit_modifier_apply (self, modifier, "/", + fi, &mfi); + + if (!aic_ensure_parent_dir_with_file_info (&aictx, mtree, "/", mfi, NULL, cancellable, error)) goto out; } @@ -903,18 +923,9 @@ ostree_repo_write_archive_to_mtree (OstreeRepo *self, g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; -#ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL - archive_read_support_filter_all (a); -#else - archive_read_support_compression_all (a); -#endif - archive_read_support_format_all (a); - if (archive_read_open_filename (a, gs_file_get_path_cached (archive), 8192) != ARCHIVE_OK) - { - propagate_libarchive_error (error, a); - goto out; - } - + a = ot_open_archive_read (gs_file_get_path_cached (archive), error); + if (!a) + goto out; opts.autocreate_parents = !!autocreate_parents; if (!ostree_repo_import_archive_to_mtree (self, &opts, a, mtree, modifier, cancellable, error)) diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index e38e48bc..865cb120 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -154,10 +154,32 @@ struct OstreeRepo { gboolean generate_sizes; guint64 tmp_expiry_seconds; gchar *collection_id; + gboolean add_remotes_config_dir; /* Add new remotes in remotes.d dir */ OstreeRepo *parent_repo; }; +/* Taken from flatpak; may be made into public API later */ +typedef OstreeRepo _OstreeRepoAutoTransaction; +static inline void +_ostree_repo_auto_transaction_cleanup (void *p) +{ + OstreeRepo *repo = p; + if (repo) + (void) ostree_repo_abort_transaction (repo, NULL, NULL); +} + +static inline _OstreeRepoAutoTransaction * +_ostree_repo_auto_transaction_start (OstreeRepo *repo, + GCancellable *cancellable, + GError **error) +{ + if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) + return NULL; + return (_OstreeRepoAutoTransaction *)repo; +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC (_OstreeRepoAutoTransaction, _ostree_repo_auto_transaction_cleanup) + typedef struct { dev_t dev; ino_t ino; @@ -396,11 +418,12 @@ gboolean ostree_repo_set_collection_id (OstreeRepo *self, const gchar *collection_id, GError **error); -gboolean ostree_repo_list_collection_refs (OstreeRepo *self, - const char *match_collection_id, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error); +gboolean ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error); void ostree_repo_transaction_set_collection_ref (OstreeRepo *self, const OstreeCollectionRef *ref, diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c index 7cd9eb2c..6ea899bc 100644 --- a/src/libostree/ostree-repo-prune.c +++ b/src/libostree/ostree-repo-prune.c @@ -43,13 +43,7 @@ prune_commitpartial_file (OstreeRepo *repo, GError **error) { g_autofree char *path = _ostree_get_commitpartial_path (checksum); - if (unlinkat (repo->repo_dir_fd, path, 0) != 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "unlinkat"); - } - - return TRUE; + return ot_ensure_unlinked_at (repo->repo_dir_fd, path, error); } static gboolean @@ -147,8 +141,8 @@ _ostree_repo_prune_tmp (OstreeRepo *self, if (has_sig_suffix) dent->d_name[len - 4] = '.'; - if (unlinkat (dfd_iter.fd, dent->d_name, 0) < 0) - return glnx_throw_errno_prefix (error, "unlinkat"); + if (!glnx_unlinkat (dfd_iter.fd, dent->d_name, 0, error)) + return FALSE; } } @@ -335,7 +329,7 @@ ostree_repo_prune (OstreeRepo *self, g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeChecksumRef utf8) */ if (!ostree_repo_list_collection_refs (self, NULL, &all_collection_refs, - cancellable, error)) + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, cancellable, error)) return FALSE; GLNX_HASH_TABLE_FOREACH_V (all_collection_refs, const char*, checksum) diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index e21342fe..92aeb5bc 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -104,6 +104,7 @@ typedef struct { GBytes *summary_data_sig; GVariant *summary; GHashTable *summary_deltas_checksums; + GHashTable *ref_original_commits; /* Maps checksum to commit, used by timestamp checks */ GPtrArray *static_delta_superblocks; GHashTable *expected_commit_sizes; /* Maps commit checksum to known size */ GHashTable *commit_to_depth; /* Maps commit checksum maximum depth */ @@ -136,6 +137,7 @@ typedef struct { guint n_fetched_localcache_metadata; guint n_fetched_localcache_content; + gboolean timestamp_check; /* Verify commit timestamps */ int maxdepth; guint64 start_time; @@ -1355,11 +1357,8 @@ static_deltapart_fetch_on_complete (GObject *object, goto out; /* From here on, if we fail to apply the delta, we'll re-fetch it */ - if (unlinkat (_ostree_fetcher_get_dfd (fetcher), temp_path, 0) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + if (!glnx_unlinkat (_ostree_fetcher_get_dfd (fetcher), temp_path, 0, error)) + goto out; in = g_unix_input_stream_new (fd, FALSE); @@ -1589,6 +1588,9 @@ verify_bindings (OtPullData *pull_data, return TRUE; } +/* Look at a commit object, and determine whether there are + * more things to fetch. + */ static gboolean scan_commit_object (OtPullData *pull_data, const char *checksum, @@ -1597,19 +1599,8 @@ scan_commit_object (OtPullData *pull_data, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - /* If we found a legacy transaction flag, assume we have to scan. - * We always do a scan of dirtree objects; see - * https://github.com/ostreedev/ostree/issues/543 - */ - OstreeRepoCommitState commitstate; - g_autoptr(GVariant) commit = NULL; - g_autoptr(GVariant) parent_csum = NULL; - const guchar *parent_csum_bytes = NULL; gpointer depthp; gint depth; - gboolean is_partial; - if (g_hash_table_lookup_extended (pull_data->commit_to_depth, checksum, NULL, &depthp)) { @@ -1632,31 +1623,60 @@ scan_commit_object (OtPullData *pull_data, cancellable, error); if (!process_verify_result (pull_data, checksum, result, error)) - goto out; + return FALSE; } + /* If we found a legacy transaction flag, assume we have to scan. + * We always do a scan of dirtree objects; see + * https://github.com/ostreedev/ostree/issues/543 + */ + OstreeRepoCommitState commitstate; + g_autoptr(GVariant) commit = NULL; if (!ostree_repo_load_commit (pull_data->repo, checksum, &commit, &commitstate, error)) - goto out; + return FALSE; /* If ref is non-NULL then the commit we fetched was requested through the * branch, otherwise we requested a commit checksum without specifying a branch. */ if (!verify_bindings (pull_data, commit, ref, error)) + return glnx_prefix_error (error, "Commit %s", checksum); + + if (pull_data->timestamp_check) { - g_prefix_error (error, "Commit %s: ", checksum); - goto out; + /* We don't support timestamp checking while recursing right now */ + g_assert (ref); + g_assert_cmpint (recursion_depth, ==, 0); + const char *orig_rev = NULL; + if (!g_hash_table_lookup_extended (pull_data->ref_original_commits, + ref, NULL, (void**)&orig_rev)) + g_assert_not_reached (); + + g_autoptr(GVariant) orig_commit = NULL; + if (orig_rev) + { + if (!ostree_repo_load_commit (pull_data->repo, orig_rev, + &orig_commit, NULL, error)) + return glnx_prefix_error (error, "Reading %s for timestamp-check", ref->ref_name); + + guint64 orig_ts = ostree_commit_get_timestamp (orig_commit); + guint64 new_ts = ostree_commit_get_timestamp (commit); + if (!_ostree_compare_timestamps (orig_rev, orig_ts, checksum, new_ts, error)) + return FALSE; + } } /* If we found a legacy transaction flag, assume all commits are partial */ - is_partial = commitstate_is_partial (pull_data, commitstate); + gboolean is_partial = commitstate_is_partial (pull_data, commitstate); /* PARSE OSTREE_SERIALIZED_COMMIT_VARIANT */ + g_autoptr(GVariant) parent_csum = NULL; + const guchar *parent_csum_bytes = NULL; g_variant_get_child (commit, 1, "@ay", &parent_csum); if (g_variant_n_children (parent_csum) > 0) { parent_csum_bytes = ostree_checksum_bytes_peek_validate (parent_csum, error); if (parent_csum_bytes == NULL) - goto out; + return FALSE; } if (parent_csum_bytes != NULL && pull_data->maxdepth == -1) @@ -1672,7 +1692,7 @@ scan_commit_object (OtPullData *pull_data, int parent_depth; ostree_checksum_inplace_from_bytes (parent_csum_bytes, parent_checksum); - + if (g_hash_table_lookup_extended (pull_data->commit_to_depth, parent_checksum, NULL, &parent_depthp)) { @@ -1711,11 +1731,11 @@ scan_commit_object (OtPullData *pull_data, tree_contents_csum_bytes = ostree_checksum_bytes_peek_validate (tree_contents_csum, error); if (tree_contents_csum_bytes == NULL) - goto out; + return FALSE; tree_meta_csum_bytes = ostree_checksum_bytes_peek_validate (tree_meta_csum, error); if (tree_meta_csum_bytes == NULL) - goto out; + return FALSE; queue_scan_one_metadata_object_c (pull_data, tree_contents_csum_bytes, OSTREE_OBJECT_TYPE_DIR_TREE, "/", recursion_depth + 1, NULL); @@ -1724,9 +1744,7 @@ scan_commit_object (OtPullData *pull_data, OSTREE_OBJECT_TYPE_DIR_META, NULL, recursion_depth + 1, NULL); } - ret = TRUE; - out: - return ret; + return TRUE; } static void @@ -2506,22 +2524,11 @@ static gboolean validate_variant_is_csum (GVariant *csum, GError **error) { - gboolean ret = FALSE; - if (!g_variant_is_of_type (csum, G_VARIANT_TYPE ("ay"))) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid checksum variant of type '%s', expected 'ay'", - g_variant_get_type_string (csum)); - goto out; - } + return glnx_throw (error, "Invalid checksum variant of type '%s', expected 'ay'", + g_variant_get_type_string (csum)); - if (!ostree_validate_structureof_csum_v (csum, error)) - goto out; - - ret = TRUE; - out: - return ret; + return ostree_validate_structureof_csum_v (csum, error); } /* Load the summary from the cache if the provided .sig file is the same as the @@ -2534,27 +2541,19 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); - - glnx_fd_close int prev_fd = -1; - g_autoptr(GBytes) old_sig_contents = NULL; - if (self->cache_dir_fd == -1) return TRUE; + const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); + glnx_fd_close int prev_fd = -1; if (!ot_openat_ignore_enoent (self->cache_dir_fd, summary_cache_sig_file, &prev_fd, error)) - goto out; - + return FALSE; if (prev_fd < 0) - { - ret = TRUE; - goto out; - } + return TRUE; /* Note early return */ - old_sig_contents = glnx_fd_readall_bytes (prev_fd, cancellable, error); + g_autoptr(GBytes) old_sig_contents = glnx_fd_readall_bytes (prev_fd, cancellable, error); if (!old_sig_contents) - goto out; + return FALSE; if (g_bytes_compare (old_sig_contents, summary_sig) == 0) { @@ -2569,25 +2568,21 @@ _ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self, if (errno == ENOENT) { (void) unlinkat (self->cache_dir_fd, summary_cache_sig_file, 0); - ret = TRUE; - goto out; + return TRUE; /* Note early return */ } - glnx_set_error_from_errno (error); - goto out; + return glnx_throw_errno_prefix (error, "openat(%s)", summary_cache_file); } summary_data = glnx_fd_readall_bytes (summary_fd, cancellable, error); if (!summary_data) - goto out; + return FALSE; *summary = summary_data; } - ret = TRUE; - - out: - return ret; + return TRUE; } +/* Replace the current summary+signature with new versions */ static gboolean _ostree_repo_cache_summary (OstreeRepo *self, const char *remote, @@ -2596,36 +2591,31 @@ _ostree_repo_cache_summary (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote); - const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_DIR, "/", remote, ".sig"); - if (self->cache_dir_fd == -1) return TRUE; if (!glnx_shutil_mkdir_p_at (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, 0775, cancellable, error)) - goto out; + 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), self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW, cancellable, error)) - goto out; + 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)) - goto out; - - ret = TRUE; - out: - return ret; + return FALSE; + return TRUE; } static OstreeFetcher * @@ -2717,18 +2707,19 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self, _ostree_fetcher_set_proxy (fetcher, http_proxy); } - { - g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); - /* TODO; port away from this; a bit hard since both libsoup and libcurl - * expect a file. Doing ot_fdrel_to_gfile() works for now though. - */ - GFile*repo_path = ostree_repo_get_path (self); - g_autofree char *jar_path = - g_build_filename (gs_file_get_path_cached (repo_path), cookie_file, NULL); + if (!_ostree_repo_remote_name_is_file (remote_name)) + { + g_autofree char *cookie_file = g_strdup_printf ("%s.cookies.txt", remote_name); + /* TODO; port away from this; a bit hard since both libsoup and libcurl + * expect a file. Doing ot_fdrel_to_gfile() works for now though. + */ + GFile*repo_path = ostree_repo_get_path (self); + g_autofree char *jar_path = + g_build_filename (gs_file_get_path_cached (repo_path), cookie_file, NULL); - if (g_file_test (jar_path, G_FILE_TEST_IS_REGULAR)) - _ostree_fetcher_set_cookie_jar (fetcher, jar_path); - } + if (g_file_test (jar_path, G_FILE_TEST_IS_REGULAR)) + _ostree_fetcher_set_cookie_jar (fetcher, jar_path); + } success = TRUE; @@ -3199,6 +3190,7 @@ initiate_request (OtPullData *pull_data, * * 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 * * 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. @@ -3275,10 +3267,12 @@ ostree_repo_pull_with_options (OstreeRepo *self, (void) g_variant_lookup (options, "http-headers", "@a(ss)", &pull_data->extra_headers); (void) g_variant_lookup (options, "update-frequency", "u", &update_frequency); (void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos); + (void) g_variant_lookup (options, "timestamp-check", "b", &pull_data->timestamp_check); } g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE); + g_return_val_if_fail (!pull_data->timestamp_check || pull_data->maxdepth == 0, FALSE); g_return_val_if_fail (!opt_collection_refs_set || (refs_to_fetch == NULL && override_commit_ids == NULL), FALSE); if (refs_to_fetch && override_commit_ids) @@ -3322,6 +3316,9 @@ ostree_repo_pull_with_options (OstreeRepo *self, pull_data->summary_deltas_checksums = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, (GDestroyNotify)g_free); + pull_data->ref_original_commits = g_hash_table_new_full (ostree_collection_ref_hash, ostree_collection_ref_equal, + (GDestroyNotify)NULL, + (GDestroyNotify)g_variant_unref); pull_data->scanned_metadata = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, (GDestroyNotify)g_variant_unref, NULL); pull_data->fetched_detached_metadata = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -3596,7 +3593,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, } - /* We can't use static deltas if pulling into an archive-z2 repo. */ + /* We can't use static deltas if pulling into an archive repo. */ if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2) { if (pull_data->require_static_deltas) @@ -3923,6 +3920,24 @@ ostree_repo_pull_with_options (OstreeRepo *self, ref_with_collection = ostree_collection_ref_dup (ref); } + /* If we have timestamp checking enabled, find the current value of + * the ref, and store its timestamp in the hash map, to check later. + */ + if (pull_data->timestamp_check) + { + g_autofree char *from_rev = NULL; + if (!ostree_repo_resolve_rev (pull_data->repo, ref_with_collection->ref_name, TRUE, + &from_rev, error)) + goto out; + /* Explicitly store NULL if there's no previous revision. We do + * this so we can assert() if we somehow didn't find a ref in the + * hash at all. Note we don't copy the collection-ref, so the + * lifetime of this hash must be equal to `requested_refs_to_fetch`. + */ + g_hash_table_insert (pull_data->ref_original_commits, ref_with_collection, + g_steal_pointer (&from_rev)); + } + g_hash_table_replace (updated_requested_refs_to_fetch, g_steal_pointer (&ref_with_collection), g_steal_pointer (&contents)); @@ -4223,6 +4238,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_clear_pointer (&pull_data->scanned_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->fetched_detached_metadata, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->summary_deltas_checksums, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&pull_data->ref_original_commits, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_fallback_content, (GDestroyNotify) g_hash_table_unref); g_clear_pointer (&pull_data->requested_metadata, (GDestroyNotify) g_hash_table_unref); diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index 6c113fb6..b9b00896 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -560,7 +560,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self, if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) return FALSE; - if (remote) + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES) && remote) { prefix_path = glnx_strjoina ("refs/remotes/", remote, "/"); path = glnx_strjoina (prefix_path, ref_prefix); @@ -620,32 +620,35 @@ _ostree_repo_list_refs_internal (OstreeRepo *self, ret_all_refs, cancellable, error)) return FALSE; - g_string_truncate (base_path, 0); - - if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) - return FALSE; - - while (TRUE) + if (!(flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES)) { - struct dirent *dent; - glnx_fd_close int remote_dfd = -1; + g_string_truncate (base_path, 0); - if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) - return FALSE; - if (!dent) - break; - - if (dent->d_type != DT_DIR) - continue; - - if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) + if (!glnx_dirfd_iterator_init_at (self->repo_dir_fd, "refs/remotes", TRUE, &dfd_iter, error)) return FALSE; - if (!enumerate_refs_recurse (self, dent->d_name, flags, NULL, remote_dfd, base_path, - remote_dfd, ".", - ret_all_refs, - cancellable, error)) - return FALSE; + while (TRUE) + { + struct dirent *dent; + glnx_fd_close int remote_dfd = -1; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (!dent) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, dent->d_name, flags, NULL, remote_dfd, base_path, + remote_dfd, ".", + ret_all_refs, + cancellable, error)) + return FALSE; + } } } @@ -1004,11 +1007,8 @@ _ostree_repo_write_ref (OstreeRepo *self, { if (dfd >= 0) { - if (unlinkat (dfd, ref->ref_name, 0) != 0) - { - if (errno != ENOENT) - return glnx_throw_errno (error); - } + if (!ot_ensure_unlinked_at (dfd, ref->ref_name, error)) + return FALSE; } } else if (rev != NULL) @@ -1101,27 +1101,33 @@ _ostree_repo_update_collection_refs (OstreeRepo *self, * @self: Repo * @match_collection_id: (nullable): If non-%NULL, only list refs from this collection * @out_all_refs: (out) (element-type OstreeCollectionRef utf8): Mapping from collection–ref to checksum + * @flags: Options controlling listing behavior * @cancellable: Cancellable * @error: Error * - * List all local and mirrored refs, mapping them to the commit checksums they - * currently point to in @out_all_refs. If @match_collection_id is specified, - * the results will be limited to those with an equal collection ID. + * List all local, mirrored, and remote refs, mapping them to the commit + * checksums they currently point to in @out_all_refs. If @match_collection_id + * is specified, the results will be limited to those with an equal collection + * ID. * * #OstreeCollectionRefs are guaranteed to be returned with their collection ID * set to a non-%NULL value; so no refs from `refs/heads` will be listed if no * collection ID is configured for the repository * (ostree_repo_get_collection_id()). * + * If you want to exclude refs from `refs/remotes`, use + * %OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES in @flags. + * * Returns: %TRUE on success, %FALSE otherwise * Since: 2017.8 */ gboolean -ostree_repo_list_collection_refs (OstreeRepo *self, - const char *match_collection_id, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error) +ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error) { g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); @@ -1130,6 +1136,10 @@ ostree_repo_list_collection_refs (OstreeRepo *self, if (match_collection_id != NULL && !ostree_validate_collection_id (match_collection_id, error)) return FALSE; + const gchar *refs_dirs[] = { "refs/mirrors", "refs/remotes", NULL }; + if (flags & OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES) + refs_dirs[1] = NULL; + g_autoptr(GHashTable) ret_all_refs = NULL; ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash, @@ -1150,7 +1160,7 @@ ostree_repo_list_collection_refs (OstreeRepo *self, if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) return FALSE; - if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE, + if (!enumerate_refs_recurse (self, NULL, flags, main_collection_id, refs_heads_dfd, base_path, refs_heads_dfd, ".", ret_all_refs, cancellable, error)) @@ -1159,36 +1169,65 @@ ostree_repo_list_collection_refs (OstreeRepo *self, g_string_truncate (base_path, 0); - gboolean refs_mirrors_exists = FALSE; - if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, "refs/mirrors", - &dfd_iter, &refs_mirrors_exists, error)) - return FALSE; - - while (refs_mirrors_exists) + for (const char **iter = refs_dirs; iter && *iter; iter++) { - struct dirent *dent; - glnx_fd_close int collection_dfd = -1; - - if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) - return FALSE; - if (!dent) - break; - - if (dent->d_type != DT_DIR) - continue; - - if (match_collection_id != NULL && g_strcmp0 (match_collection_id, dent->d_name) != 0) - continue; - - if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &collection_dfd, error)) + const char *refs_dir = *iter; + gboolean refs_dir_exists = FALSE; + if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, refs_dir, + &dfd_iter, &refs_dir_exists, error)) return FALSE; - if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE, - dent->d_name, collection_dfd, base_path, - collection_dfd, ".", - ret_all_refs, - cancellable, error)) - return FALSE; + while (refs_dir_exists) + { + struct dirent *dent; + glnx_fd_close int subdir_fd = -1; + const gchar *current_collection_id; + g_autofree gchar *remote_collection_id = NULL; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (!dent) + break; + + if (dent->d_type != DT_DIR) + continue; + + if (g_strcmp0 (refs_dir, "refs/mirrors") == 0) + { + if (match_collection_id != NULL && g_strcmp0 (match_collection_id, dent->d_name) != 0) + continue; + else + current_collection_id = dent->d_name; + } + else /* refs_dir = "refs/remotes" */ + { + g_autoptr(GError) local_error = NULL; + if (!ostree_repo_get_remote_option (self, dent->d_name, "collection-id", + NULL, &remote_collection_id, &local_error) || + !ostree_validate_collection_id (remote_collection_id, &local_error)) + { + g_debug ("Ignoring remote ‘%s’ due to no valid collection ID being configured for it: %s", + dent->d_name, local_error->message); + g_clear_error (&local_error); + continue; + } + + if (match_collection_id != NULL && g_strcmp0 (match_collection_id, remote_collection_id) != 0) + continue; + else + current_collection_id = remote_collection_id; + } + + if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &subdir_fd, error)) + return FALSE; + + if (!enumerate_refs_recurse (self, NULL, flags, + current_collection_id, subdir_fd, base_path, + subdir_fd, ".", + ret_all_refs, + cancellable, error)) + return FALSE; + } } ot_transfer_out_value (out_all_refs, &ret_all_refs); diff --git a/src/libostree/ostree-repo-static-delta-processing.c b/src/libostree/ostree-repo-static-delta-processing.c index 6b1dc337..2e75ea28 100644 --- a/src/libostree/ostree-repo-static-delta-processing.c +++ b/src/libostree/ostree-repo-static-delta-processing.c @@ -608,7 +608,7 @@ dispatch_open_splice_and_close (OstreeRepo *repo, } else { - /* Slower path, for symlinks and unpacking deltas into archive-z2 */ + /* Slower path, for symlinks and unpacking deltas into archive */ g_autoptr(GFileInfo) finfo = _ostree_mode_uidgid_to_gfileinfo (state->mode, state->uid, state->gid); diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 795016ce..0a7cf3e3 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -47,9 +47,36 @@ #include #include +/* ABI Size checks for ostree-repo.h, only for LP64 systems; + * https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models + */ +#if __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 8 && __SIZEOF_INT__ == 4 +G_STATIC_ASSERT(sizeof(OstreeRepoTransactionStats) == sizeof(int) * 4 + 8 * 5); +G_STATIC_ASSERT(sizeof(OstreeRepoImportArchiveOptions) == sizeof(int) * 9 + 4 + sizeof(void*) * 8); +G_STATIC_ASSERT(sizeof(OstreeRepoExportArchiveOptions) == sizeof(int) * 9 + 4 + 8 + sizeof(void*) * 8); +G_STATIC_ASSERT(sizeof(OstreeRepoCheckoutAtOptions) == + sizeof(OstreeRepoCheckoutMode) + sizeof(OstreeRepoCheckoutOverwriteMode) + + sizeof(int)*6 + + sizeof(int)*5 + + sizeof(int) + + sizeof(void*)*2 + + sizeof(int)*6 + + sizeof(void*)*7); +G_STATIC_ASSERT(sizeof(OstreeRepoCommitTraverseIter) == + sizeof(int) + sizeof(int) + + sizeof(void*) * 10 + + 130 + 6); /* 6 byte hole */ +G_STATIC_ASSERT(sizeof(OstreeRepoPruneOptions) == + sizeof(OstreeRepoPruneFlags) + + 4 + + sizeof(void*) + + sizeof(int) * 12 + + sizeof(void*) * 7); +#endif + /** * SECTION:ostree-repo - * @title: Content-addressed object store + * @title: OstreeRepo: Content-addressed object store * @short_description: A git-like storage system for operating system binaries * * The #OstreeRepo is like git, a content-addressed object store. @@ -556,14 +583,32 @@ ostree_repo_class_init (OstreeRepoClass *klass) object_class->set_property = ostree_repo_set_property; object_class->finalize = ostree_repo_finalize; + /** + * OstreeRepo:path: + * + * Path to repository. Note that if this repository was created + * via `ostree_repo_new_at()`, this value will refer to a value in + * the Linux kernel's `/proc/self/fd` directory. Generally, you + * should avoid using this property at all; you can gain a reference + * to the repository's directory fd via `ostree_repo_get_dfd()` and + * use file-descriptor relative operations. + */ g_object_class_install_property (object_class, PROP_PATH, - g_param_spec_object ("path", - "", - "", + g_param_spec_object ("path", "Path", "Path", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - + /** + * OstreeRepo:sysroot-path: + * + * A system using libostree for the host has a "system" repository; this + * property will be set for repositories referenced via + * `ostree_sysroot_repo()` for example. + * + * You should avoid using this property; if your code is operating + * on a system repository, use `OstreeSysroot` and access the repository + * object via `ostree_sysroot_repo()`. + */ g_object_class_install_property (object_class, PROP_SYSROOT_PATH, g_param_spec_object ("sysroot-path", @@ -571,7 +616,15 @@ ostree_repo_class_init (OstreeRepoClass *klass) "", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - + /** + * OstreeRepo:remotes-config-dir: + * + * Path to directory containing remote definitions. The default is `NULL`. + * If a `sysroot-path` property is defined, this value will default to + * `${sysroot_path}/etc/ostree/remotes.d`. + * + * This value will only be used for system repositories. + */ g_object_class_install_property (object_class, PROP_REMOTES_CONFIG_DIR, g_param_spec_string ("remotes-config-dir", @@ -880,6 +933,40 @@ ostree_repo_write_config (OstreeRepo *self, { g_return_val_if_fail (self->inited, FALSE); + /* Ensure that any remotes in the new config aren't defined in a + * separate config file. + */ + gsize num_groups; + g_auto(GStrv) groups = g_key_file_get_groups (new_config, &num_groups); + for (gsize i = 0; i < num_groups; i++) + { + g_autoptr(OstreeRemote) new_remote = ostree_remote_new_from_keyfile (new_config, groups[i]); + if (new_remote != NULL) + { + g_autoptr(GError) local_error = NULL; + + g_autoptr(OstreeRemote) cur_remote = + _ostree_repo_get_remote (self, new_remote->name, &local_error); + if (cur_remote == NULL) + { + if (!g_error_matches (local_error, G_IO_ERROR, + G_IO_ERROR_NOT_FOUND)) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + } + else if (cur_remote->file != NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, + "Remote \"%s\" already defined in %s", + new_remote->name, + gs_file_get_path_cached (cur_remote->file)); + return FALSE; + } + } + } + gsize len; g_autofree char *data = g_key_file_to_data (new_config, &len, error); if (!glnx_file_replace_contents_at (self->repo_dir_fd, "config", @@ -957,8 +1044,12 @@ impl_repo_remote_add (OstreeRepo *self, remote = ostree_remote_new (name); + /* Only add repos in remotes.d if the repo option + * add-remotes-config-dir is true. This is the default for system + * repos. + */ g_autoptr(GFile) etc_ostree_remotes_d = get_remotes_d_dir (self, sysroot); - if (etc_ostree_remotes_d) + if (etc_ostree_remotes_d && self->add_remotes_config_dir) { g_autoptr(GError) local_error = NULL; @@ -1076,8 +1167,8 @@ impl_repo_remote_delete (OstreeRepo *self, if (remote->file != NULL) { - if (unlink (gs_file_get_path_cached (remote->file)) != 0) - return glnx_throw_errno (error); + if (!glnx_unlinkat (AT_FDCWD, gs_file_get_path_cached (remote->file), 0, error)) + return FALSE; } else { @@ -1412,8 +1503,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_op_import (source_context, data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to import keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to import keys"); goto out; } @@ -1438,8 +1528,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_get_key (source_context, key_ids[ii], &key, 0); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to find key \"%s\": ", key_ids[ii]); + ot_gpgme_throw (gpg_error, error, "Unable to find key \"%s\"", key_ids[ii]); goto out; } @@ -1466,8 +1555,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, if (gpgme_err_code (gpg_error) != GPG_ERR_EOF) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to list keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to list keys"); goto out; } } @@ -1539,8 +1627,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_data_new (&data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to create data buffer: "); + ot_gpgme_throw (gpg_error, error, "Unable to create data buffer"); goto out; } @@ -1549,8 +1636,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to export keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to export keys"); goto out; } @@ -1559,8 +1645,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, gpg_error = gpgme_op_import (target_context, data_buffer); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to import keys: "); + ot_gpgme_throw (gpg_error, error, "Unable to import keys"); goto out; } @@ -1575,8 +1660,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, { if (import_status->result != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); - g_prefix_error (error, "Unable to import key \"%s\": ", + ot_gpgme_throw (gpg_error, error, "Unable to import key \"%s\"", import_status->fpr); goto out; } @@ -1994,10 +2078,6 @@ static GFile * get_remotes_d_dir (OstreeRepo *self, GFile *sysroot) { - /* Support explicit override */ - if (self->sysroot_dir != NULL && self->remotes_config_dir != NULL) - return g_file_resolve_relative_path (self->sysroot_dir, self->remotes_config_dir); - g_autoptr(GFile) sysroot_owned = NULL; /* Very complicated sysroot logic; this bit breaks the otherwise mostly clean * layering between OstreeRepo and OstreeSysroot. First, If a sysroot was @@ -2033,10 +2113,18 @@ get_remotes_d_dir (OstreeRepo *self, if (sysroot == NULL && sysroot_ref == NULL) sysroot = self->sysroot_dir; - /* Did we find a sysroot? If not, NULL means use the repo config, otherwise - * return the path in /etc. + /* Was the config directory specified? If so, use that with the + * optional sysroot prepended. If not, return the path in /etc if the + * sysroot was found and NULL otherwise to use the repo config. */ - if (sysroot == NULL) + if (self->remotes_config_dir != NULL) + { + if (sysroot == NULL) + return g_file_new_for_path (self->remotes_config_dir); + else + return g_file_resolve_relative_path (sysroot, self->remotes_config_dir); + } + else if (sysroot == NULL) return NULL; else return g_file_resolve_relative_path (sysroot, SYSCONF_REMOTES); @@ -2178,6 +2266,17 @@ reload_core_config (OstreeRepo *self, } } + /* By default, only add remotes in a remotes config directory for + * system repos. This is to preserve legacy behavior for non-system + * repos that specify a remotes config dir (flatpak). + */ + { gboolean is_system = ostree_repo_is_system (self); + + if (!ot_keyfile_get_boolean_with_default (self->config, "core", "add-remotes-config-dir", + is_system, &self->add_remotes_config_dir, error)) + return FALSE; + } + return TRUE; } @@ -2316,8 +2415,8 @@ ostree_repo_open (OstreeRepo *self, /* Note - we don't return this error yet! */ } - if (fstat (self->objects_dir_fd, &stbuf) != 0) - return glnx_throw_errno (error); + if (!glnx_fstat (self->objects_dir_fd, &stbuf, error)) + return FALSE; self->owner_uid = stbuf.st_uid; if (stbuf.st_uid != getuid () || stbuf.st_gid != getgid ()) @@ -2703,8 +2802,8 @@ load_metadata_internal (OstreeRepo *self, if (fd != -1) { - if (fstat (fd, &stbuf) < 0) - return glnx_throw_errno (error); + if (!glnx_fstat (fd, &stbuf, error)) + return FALSE; if (out_variant) { @@ -3127,7 +3226,7 @@ _ostree_repo_has_loose_object (OstreeRepo *self, if (errno == ENOENT) ; /* Next dfd */ else - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "fstatat(%s)", loose_path_buf); } else { @@ -3210,15 +3309,12 @@ ostree_repo_delete_object (OstreeRepo *self, _ostree_loose_path (meta_loose, sha256, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode); - if (TEMP_FAILURE_RETRY (unlinkat (self->objects_dir_fd, meta_loose, 0)) < 0) - { - if (G_UNLIKELY (errno != ENOENT)) - return glnx_throw_errno_prefix (error, "unlinkat(%s)", meta_loose); - } + if (!ot_ensure_unlinked_at (self->objects_dir_fd, meta_loose, error)) + return FALSE; } - if (TEMP_FAILURE_RETRY (unlinkat (self->objects_dir_fd, loose_path, 0)) < 0) - return glnx_throw_errno_prefix (error, "Deleting object %s.%s", sha256, ostree_object_type_to_string (objtype)); + if (!glnx_unlinkat (self->objects_dir_fd, loose_path, 0, error)) + return glnx_prefix_error (error, "Deleting object %s.%s", sha256, ostree_object_type_to_string (objtype)); /* If the repository is configured to use tombstone commits, create one when deleting a commit. */ if (objtype == OSTREE_OBJECT_TYPE_COMMIT) @@ -3297,6 +3393,9 @@ import_one_object_link (OstreeRepo *self, GCancellable *cancellable, GError **error) { + const char *errprefix = glnx_strjoina ("Importing ", checksum, ".", + ostree_object_type_to_string (objtype)); + GLNX_AUTO_PREFIX_ERROR (errprefix, error); char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; _ostree_loose_path (loose_path_buf, checksum, objtype, self->mode); @@ -3343,7 +3442,7 @@ import_one_object_link (OstreeRepo *self, return TRUE; } else - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "linkat"); } if (objtype == OSTREE_OBJECT_TYPE_COMMIT) @@ -3650,7 +3749,7 @@ ostree_repo_load_commit (OstreeRepo *self, } else if (errno != ENOENT) { - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "fstatat(%s)", commitpartial_path); } } @@ -4123,26 +4222,23 @@ sign_data (OstreeRepo *self, } else if (err != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Unable to lookup key ID %s: ", key_id); + ot_gpgme_throw (err, error, "Unable to lookup key ID %s", key_id); goto out; } /* Add the key to the context as a signer */ if ((err = gpgme_signers_add (context, key)) != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Error signing commit: "); + ot_gpgme_throw (err, error, "Error signing commit"); goto out; } - + { gsize len; const char *buf = g_bytes_get_data (input_data, &len); if ((err = gpgme_data_new_from_mem (&commit_buffer, buf, len, FALSE)) != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Failed to create buffer from commit file: "); + ot_gpgme_throw (err, error, "Failed to create buffer from commit file"); goto out; } } @@ -4152,8 +4248,7 @@ sign_data (OstreeRepo *self, if ((err = gpgme_op_sign (context, commit_buffer, signature_buffer, GPGME_SIG_MODE_DETACH)) != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Failure signing commit file: "); + ot_gpgme_throw (err, error, "Failure signing commit file"); goto out; } @@ -4219,11 +4314,14 @@ ostree_repo_sign_commit (OstreeRepo *self, /* The verify operation is merely to parse any existing signatures to * check if the commit has already been signed with the given key ID. - * We want to avoid storing duplicate signatures in the metadata. */ + * We want to avoid storing duplicate signatures in the metadata. We + * pass the homedir so that the signing key can be imported, allowing + * subkey signatures to be recognised. */ g_autoptr(GError) local_error = NULL; + g_autoptr(GFile) verify_keydir = g_file_new_for_path (homedir); g_autoptr(OstreeGpgVerifyResult) result =_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata, - NULL, NULL, NULL, + NULL, verify_keydir, NULL, cancellable, &local_error); if (!result) { @@ -4534,32 +4632,23 @@ _ostree_repo_verify_commit_internal (OstreeRepo *self, GCancellable *cancellable, GError **error) { - OstreeGpgVerifyResult *result = NULL; g_autoptr(GVariant) commit_variant = NULL; - g_autoptr(GVariant) metadata = NULL; - g_autoptr(GBytes) signed_data = NULL; - /* Load the commit */ if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, commit_checksum, &commit_variant, error)) - { - g_prefix_error (error, "Failed to read commit: "); - goto out; - } + return glnx_prefix_error_null (error, "Failed to read commit"); /* Load the metadata */ + g_autoptr(GVariant) metadata = NULL; if (!ostree_repo_read_commit_detached_metadata (self, commit_checksum, &metadata, cancellable, error)) - { - g_prefix_error (error, "Failed to read detached metadata: "); - goto out; - } + return glnx_prefix_error_null (error, "Failed to read detached metadata"); - signed_data = g_variant_get_data_as_bytes (commit_variant); + g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit_variant); /* XXX This is a hackish way to indicate to use ALL remote-specific * keyrings in the signature verification. We want this when @@ -4567,17 +4656,10 @@ _ostree_repo_verify_commit_internal (OstreeRepo *self, if (remote_name == NULL) remote_name = OSTREE_ALL_REMOTES; - result = _ostree_repo_gpg_verify_with_metadata (self, - signed_data, - metadata, - remote_name, - keyringdir, - extra_keyring, - cancellable, - error); - -out: - return result; + return _ostree_repo_gpg_verify_with_metadata (self, signed_data, + metadata, remote_name, + keyringdir, extra_keyring, + cancellable, error); } /** @@ -4609,10 +4691,7 @@ ostree_repo_verify_commit (OstreeRepo *self, cancellable, error); if (!ostree_gpg_verify_result_require_valid_signature (result, error)) - { - g_prefix_error (error, "Commit %s: ", commit_checksum); - return FALSE; - } + return glnx_prefix_error (error, "Commit %s", commit_checksum); return TRUE; } @@ -4907,14 +4986,12 @@ ostree_repo_regenerate_summary (OstreeRepo *self, g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC))); } - /* Add refs which have a collection specified. ostree_repo_list_collection_refs() - * is guaranteed to only return refs which are in refs/mirrors, or those which - * are in refs/heads if the repository configuration specifies a collection ID - * (which we put in the main refs map, rather than the collection map, for - * backwards compatibility). */ + /* Add refs which have a collection specified, which could be in refs/mirrors, + * refs/heads, and/or refs/remotes. */ { g_autoptr(GHashTable) collection_refs = NULL; - if (!ostree_repo_list_collection_refs (self, NULL, &collection_refs, cancellable, error)) + if (!ostree_repo_list_collection_refs (self, NULL, &collection_refs, + OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error)) return FALSE; gsize collection_map_size = 0; @@ -4949,6 +5026,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self, const char *collection_id = collection_iter->data; GHashTable *ref_map = g_hash_table_lookup (collection_map, collection_id); + /* We put the local repo's collection ID in the main refs map, rather + * than the collection map, for backwards compatibility. */ gboolean is_main_collection_id = (main_collection_id != NULL && g_str_equal (collection_id, main_collection_id)); if (!is_main_collection_id) @@ -5009,11 +5088,8 @@ ostree_repo_regenerate_summary (OstreeRepo *self, error)) return FALSE; - if (unlinkat (self->repo_dir_fd, "summary.sig", 0) < 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "unlinkat"); - } + if (!ot_ensure_unlinked_at (self->repo_dir_fd, "summary.sig", error)) + return FALSE; return TRUE; } @@ -5072,19 +5148,17 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - gboolean reusing_dir = FALSE; - gboolean did_lock; - g_autofree char *tmpdir_name = NULL; - glnx_fd_close int tmpdir_fd = -1; - g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; - g_return_val_if_fail (_ostree_repo_is_locked_tmpdir (tmpdir_prefix), FALSE); /* Look for existing tmpdir (with same prefix) to reuse */ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; if (!glnx_dirfd_iterator_init_at (tmpdir_dfd, ".", FALSE, &dfd_iter, error)) - goto out; + return FALSE; + gboolean reusing_dir = FALSE; + gboolean did_lock = FALSE; + g_autofree char *tmpdir_name = NULL; + glnx_fd_close int tmpdir_fd = -1; while (tmpdir_name == NULL) { struct dirent *dent; @@ -5092,7 +5166,7 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, g_autoptr(GError) local_error = NULL; if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) - goto out; + return FALSE; if (dent == NULL) break; @@ -5113,7 +5187,7 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, else { g_propagate_error (error, g_steal_pointer (&local_error)); - goto out; + return FALSE; } } @@ -5122,12 +5196,12 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, if (!_ostree_repo_try_lock_tmpdir (tmpdir_dfd, dent->d_name, file_lock_out, &did_lock, error)) - goto out; + return FALSE; if (!did_lock) continue; /* Touch the reused directory so that we don't accidentally - * remove it due to being old when cleaning up the tmpdir + * remove it due to being old when cleaning up the tmpdir. */ (void)futimens (existing_tmpdir_fd, NULL); @@ -5139,24 +5213,22 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, while (tmpdir_name == NULL) { - g_autofree char *tmpdir_name_template = g_strconcat (tmpdir_prefix, "XXXXXX", NULL); - glnx_fd_close int new_tmpdir_fd = -1; - /* No existing tmpdir found, create a new */ - + g_autofree char *tmpdir_name_template = g_strconcat (tmpdir_prefix, "XXXXXX", NULL); if (!glnx_mkdtempat (tmpdir_dfd, tmpdir_name_template, 0777, error)) - goto out; + return FALSE; + glnx_fd_close int new_tmpdir_fd = -1; if (!glnx_opendirat (tmpdir_dfd, tmpdir_name_template, FALSE, &new_tmpdir_fd, error)) - goto out; + return FALSE; /* Note, at this point we can race with another process that picks up this * new directory. If that happens we need to retry, making a new directory. */ if (!_ostree_repo_try_lock_tmpdir (tmpdir_dfd, tmpdir_name_template, file_lock_out, &did_lock, error)) - goto out; + return FALSE; if (!did_lock) continue; @@ -5166,16 +5238,11 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, if (tmpdir_name_out) *tmpdir_name_out = g_steal_pointer (&tmpdir_name); - if (tmpdir_fd_out) *tmpdir_fd_out = glnx_steal_fd (&tmpdir_fd); - if (reusing_dir_out) *reusing_dir_out = reusing_dir; - - ret = TRUE; - out: - return ret; + return TRUE; } /* See ostree-repo-private.h for more information about this */ diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 8766e6df..227fe597 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -22,6 +22,8 @@ #pragma once +#include + #include "ostree-core.h" #include "ostree-types.h" #include "ostree-async-progress.h" @@ -475,10 +477,12 @@ gboolean ostree_repo_list_refs (OstreeRepo *self, * OstreeRepoListRefsExtFlags: * @OSTREE_REPO_LIST_REFS_EXT_NONE: No flags. * @OSTREE_REPO_LIST_REFS_EXT_ALIASES: Only list aliases. Since: 2017.10 + * @OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES: Exclude remote refs. Since: 2017.11 */ typedef enum { OSTREE_REPO_LIST_REFS_EXT_NONE = 0, - OSTREE_REPO_LIST_REFS_EXT_ALIASES = 1, + OSTREE_REPO_LIST_REFS_EXT_ALIASES = (1 << 0), + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES = (1 << 1), } OstreeRepoListRefsExtFlags; _OSTREE_PUBLIC @@ -686,6 +690,31 @@ gboolean ostree_repo_write_archive_to_mtree (OstreeRepo * GCancellable *cancellable, GError **error); +/** + * OstreeRepoImportArchiveTranslatePathname: + * @repo: Repo + * @stbuf: Stat buffer + * @src_path: Path in the archive + * @user_data: User data + * + * Possibly change a pathname while importing an archive. If %NULL is returned, + * then @src_path will be used unchanged. Otherwise, return a new pathname which + * will be freed via `g_free()`. + * + * This pathname translation will be performed *before* any processing from an + * active `OstreeRepoCommitModifier`. Will be invoked for all directory and file + * types, first with outer directories, then their sub-files and directories. + * + * Note that enabling pathname translation will always override the setting for + * `use_ostree_convention`. + * + * Since: 2017.11 + */ +typedef char *(*OstreeRepoImportArchiveTranslatePathname) (OstreeRepo *repo, + const struct stat *stbuf, + const char *src_path, + gpointer user_data); + /** * OstreeRepoImportArchiveOptions: (skip) * @@ -701,7 +730,9 @@ typedef struct { guint reserved : 28; guint unused_uint[8]; - gpointer unused_ptrs[8]; + OstreeRepoImportArchiveTranslatePathname translate_pathname; + gpointer translate_pathname_user_data; + gpointer unused_ptrs[6]; } OstreeRepoImportArchiveOptions; _OSTREE_PUBLIC @@ -724,6 +755,7 @@ typedef struct { guint disable_xattrs : 1; guint reserved : 31; + /* 4 byte hole on 64 bit arches */ guint64 timestamp_secs; guint unused_uint[8]; @@ -800,11 +832,13 @@ typedef enum { * @OSTREE_REPO_CHECKOUT_OVERWRITE_NONE: No special options * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES: When layering checkouts, unlink() and replace existing files, but do not modify existing directories * @OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES: Only add new files/directories + * @OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL: Like UNION_FILES, but error if files are not identical (requires hardlink checkouts) */ typedef enum { OSTREE_REPO_CHECKOUT_OVERWRITE_NONE = 0, OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1, OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES = 2, /* Since: 2017.3 */ + OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL = 3, /* Since: 2017.11 */ } OstreeRepoCheckoutOverwriteMode; _OSTREE_PUBLIC @@ -838,6 +872,7 @@ typedef struct { gboolean force_copy; /* Since: 2017.6 */ gboolean bareuseronly_dirs; /* Since: 2017.7 */ gboolean unused_bools[5]; + /* 4 byte hole on 64 bit */ const char *subpath; @@ -972,6 +1007,7 @@ gboolean ostree_repo_traverse_commit_union (OstreeRepo *repo, struct _OstreeRepoCommitTraverseIter { gboolean initialized; + /* 4 byte hole on 64 bit */ gpointer dummy[10]; char dummy_checksum_data[(OSTREE_SHA256_STRING_LEN+1)*2]; }; @@ -1060,6 +1096,8 @@ gboolean ostree_repo_prune (OstreeRepo *self, struct _OstreeRepoPruneOptions { OstreeRepoPruneFlags flags; + /* 4 byte hole on 64 bit */ + GHashTable *reachable; /* Set (object names) */ gboolean unused_bools[6]; @@ -1081,7 +1119,7 @@ gboolean ostree_repo_prune_from_reachable (OstreeRepo *self, /** * OstreeRepoPullFlags: * @OSTREE_REPO_PULL_FLAGS_NONE: No special options for pull - * @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors + * @OSTREE_REPO_PULL_FLAGS_MIRROR: Write out refs suitable for mirrors and fetch all refs if none requested * @OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY: Fetch only the commit metadata * @OSTREE_REPO_PULL_FLAGS_UNTRUSTED: Don't trust local remote * @OSTREE_REPO_PULL_FLAGS_BAREUSERONLY_FILES: Since 2017.7. Reject writes of content objects with modes outside of 0775. @@ -1185,11 +1223,12 @@ gchar *ostree_repo_resolve_keyring_for_collection (OstreeRepo *self, GError **error); _OSTREE_PUBLIC -gboolean ostree_repo_list_collection_refs (OstreeRepo *self, - const char *match_collection_id, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error); +gboolean ostree_repo_list_collection_refs (OstreeRepo *self, + const char *match_collection_id, + GHashTable **out_all_refs, + OstreeRepoListRefsExtFlags flags, + GCancellable *cancellable, + GError **error); #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ diff --git a/src/libostree/ostree-sepolicy.c b/src/libostree/ostree-sepolicy.c index 6012d9da..64670092 100644 --- a/src/libostree/ostree-sepolicy.c +++ b/src/libostree/ostree-sepolicy.c @@ -521,7 +521,7 @@ ostree_sepolicy_get_label (OstreeSePolicy *self, if (errno == ENOENT) *out_label = NULL; else - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "selabel_lookup"); } else { diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c index 79663b66..da239c78 100644 --- a/src/libostree/ostree-sysroot-cleanup.c +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -21,6 +21,7 @@ #include "config.h" #include "otutil.h" +#include "ostree-repo-private.h" #include "ostree-linuxfsutil.h" #include "ostree-sysroot-private.h" @@ -201,73 +202,64 @@ list_all_boot_directories (OstreeSysroot *self, return ret; } +/* A sysroot has at most one active "boot version" (pair of version,subversion) + * out of a total of 4 possible. This function deletes from the filesystem the 3 + * other versions that aren't active. + */ static gboolean cleanup_other_bootversions (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - int cleanup_bootversion; - int cleanup_subbootversion; - g_autoptr(GFile) cleanup_boot_dir = NULL; + const int cleanup_bootversion = self->bootversion == 0 ? 1 : 0; + const int cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; + /* Reusable buffer for path */ + g_autoptr(GString) buf = g_string_new (""); - cleanup_bootversion = self->bootversion == 0 ? 1 : 0; - cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0; + /* These directories are for the other major version */ + g_string_truncate (buf, 0); g_string_append_printf (buf, "boot/loader.%d", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.0", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.1", cleanup_bootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; - g_clear_object (&cleanup_boot_dir); + /* And finally the other subbootversion */ + g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/boot.%d.%d", self->bootversion, cleanup_subbootversion); + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, buf->str, cancellable, error)) + return FALSE; - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; - g_clear_object (&cleanup_boot_dir); - - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.0", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; - g_clear_object (&cleanup_boot_dir); - - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.1", cleanup_bootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; - g_clear_object (&cleanup_boot_dir); - - cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion, - cleanup_subbootversion); - if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error)) - goto out; - g_clear_object (&cleanup_boot_dir); - - ret = TRUE; - out: - return ret; + return TRUE; } +/* As the bootloader configuration changes, we will have leftover deployments + * on disk. This function deletes all deployments which aren't actively + * referenced. + */ static gboolean cleanup_old_deployments (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; + /* Gather the device/inode of the rootfs, so we can double + * check we won't delete it. + */ struct stat root_stbuf; - guint i; - g_autoptr(GHashTable) active_deployment_dirs = NULL; - g_autoptr(GHashTable) active_boot_checksums = NULL; - g_autoptr(GPtrArray) all_deployment_dirs = NULL; - g_autoptr(GPtrArray) all_boot_dirs = NULL; + if (!glnx_fstatat (AT_FDCWD, "/", &root_stbuf, 0, error)) + return FALSE; - if (stat ("/", &root_stbuf) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } - - active_deployment_dirs = g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); - active_boot_checksums = g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); - - for (i = 0; i < self->deployments->len; i++) + /* 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_autoptr(GHashTable) active_boot_checksums = + g_hash_table_new_full (g_str_hash, (GEqualFunc)g_str_equal, g_free, NULL); + for (guint i = 0; i < self->deployments->len; i++) { OstreeDeployment *deployment = self->deployments->pdata[i]; char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); @@ -277,11 +269,12 @@ cleanup_old_deployments (OstreeSysroot *self, g_hash_table_replace (active_boot_checksums, bootcsum, bootcsum); } + /* Find all deployment directories, both active and inactive */ + g_autoptr(GPtrArray) all_deployment_dirs = NULL; if (!list_all_deployment_directories (self, &all_deployment_dirs, cancellable, error)) - goto out; - - for (i = 0; i < all_deployment_dirs->len; i++) + return FALSE; + for (guint i = 0; i < all_deployment_dirs->len; i++) { OstreeDeployment *deployment = all_deployment_dirs->pdata[i]; g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); @@ -294,13 +287,10 @@ cleanup_old_deployments (OstreeSysroot *self, if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_fd, error)) - goto out; + return FALSE; - if (fstat (deployment_fd, &stbuf) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + if (!glnx_fstat (deployment_fd, &stbuf, error)) + return FALSE; /* This shouldn't happen, because higher levels should * disallow having the booted deployment not in the active @@ -309,22 +299,24 @@ cleanup_old_deployments (OstreeSysroot *self, stbuf.st_ino == root_stbuf.st_ino) continue; + /* This deployment wasn't referenced, so delete it */ if (!_ostree_linuxfs_fd_alter_immutable_flag (deployment_fd, FALSE, cancellable, error)) - goto out; - - if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error)) - goto out; + return FALSE; if (!glnx_shutil_rm_rf_at (self->sysroot_fd, origin_relpath, cancellable, error)) - goto out; + return FALSE; + if (!glnx_shutil_rm_rf_at (self->sysroot_fd, deployment_path, cancellable, error)) + return FALSE; } } + /* Clean up boot directories */ + g_autoptr(GPtrArray) all_boot_dirs = NULL; if (!list_all_boot_directories (self, &all_boot_dirs, cancellable, error)) - goto out; - - for (i = 0; i < all_boot_dirs->len; i++) + return FALSE; + + for (guint i = 0; i < all_boot_dirs->len; i++) { GFile *bootdir = all_boot_dirs->pdata[i]; g_autofree char *osname = NULL; @@ -338,14 +330,13 @@ cleanup_old_deployments (OstreeSysroot *self, continue; if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (bootdir), cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } +/* Delete the ref bindings for a non-active boot version */ static gboolean cleanup_ref_prefix (OstreeRepo *repo, int bootversion, @@ -353,36 +344,24 @@ cleanup_ref_prefix (OstreeRepo *repo, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autofree char *prefix = NULL; + g_autofree char *prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion); g_autoptr(GHashTable) refs = NULL; - GHashTableIter hashiter; - gpointer hashkey, hashvalue; - - prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion); - if (!ostree_repo_list_refs_ext (repo, prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error)) - goto out; + return FALSE; - if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) - goto out; - - g_hash_table_iter_init (&hashiter, refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + GLNX_HASH_TABLE_FOREACH (refs, const char *, ref) { - const char *ref = hashkey; - ostree_repo_transaction_set_refspec (repo, ref, NULL); + if (!ostree_repo_set_ref_immediate (repo, NULL, ref, NULL, cancellable, error)) + return FALSE; } - if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) - goto out; - - ret = TRUE; - out: - ostree_repo_abort_transaction (repo, cancellable, NULL); - return ret; + return TRUE; } +/* libostree holds a ref for each deployment's exact checksum to avoid it being + * GC'd even if the origin ref changes. This function resets those refs + * to match active deployments. + */ static gboolean generate_deployment_refs (OstreeSysroot *self, OstreeRepo *repo, @@ -392,46 +371,38 @@ generate_deployment_refs (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - int cleanup_bootversion; - int cleanup_subbootversion; - guint i; - - cleanup_bootversion = (bootversion == 0) ? 1 : 0; - cleanup_subbootversion = (subbootversion == 0) ? 1 : 0; + int cleanup_bootversion = (bootversion == 0) ? 1 : 0; + int cleanup_subbootversion = (subbootversion == 0) ? 1 : 0; if (!cleanup_ref_prefix (repo, cleanup_bootversion, 0, cancellable, error)) - goto out; + return FALSE; if (!cleanup_ref_prefix (repo, cleanup_bootversion, 1, cancellable, error)) - goto out; + return FALSE; if (!cleanup_ref_prefix (repo, bootversion, cleanup_subbootversion, cancellable, error)) - goto out; + return FALSE; - for (i = 0; i < deployments->len; i++) + g_autoptr(_OstreeRepoAutoTransaction) txn = + _ostree_repo_auto_transaction_start (repo, cancellable, error); + if (!txn) + return FALSE; + for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; g_autofree char *refname = g_strdup_printf ("ostree/%d/%d/%u", bootversion, subbootversion, i); - if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) - goto out; - ostree_repo_transaction_set_refspec (repo, refname, ostree_deployment_get_csum (deployment)); - - if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) - goto out; } + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) + return FALSE; - ret = TRUE; - out: - ostree_repo_abort_transaction (repo, cancellable, NULL); - return ret; + return TRUE; } static gboolean @@ -442,12 +413,10 @@ prune_repo (OstreeRepo *repo, gint n_objects_total; gint n_objects_pruned; guint64 freed_space; - gboolean ret = FALSE; - if (!ostree_repo_prune (repo, OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY, 0, &n_objects_total, &n_objects_pruned, &freed_space, cancellable, error)) - goto out; + return FALSE; if (freed_space > 0) { @@ -455,10 +424,7 @@ prune_repo (OstreeRepo *repo, g_print ("Freed objects: %s\n", freed_space_str); } - ret = TRUE; - -out: - return ret; + return TRUE; } /** diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 60fbc1d3..62ebd6b6 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -171,8 +171,8 @@ copy_dir_recurse (int src_parent_dfd, return FALSE; /* Create with mode 0700, we'll fchmod/fchown later */ - if (mkdirat (dest_parent_dfd, name, 0700) != 0) - return glnx_throw_errno (error); + if (!glnx_ensure_dir (dest_parent_dfd, name, 0700, error)) + return FALSE; if (!glnx_opendirat (dest_parent_dfd, name, TRUE, &dest_dfd, error)) return FALSE; @@ -882,46 +882,187 @@ ostree_sysroot_write_origin_file (OstreeSysroot *sysroot, cancellable, error); } -/* Originally OSTree defined kernels to be found underneath /boot - * in the tree. But that means when mounting /boot at runtime - * we end up masking the content underneath, triggering a warning. - * - * For that reason, and also consistency with the "/usr defines the OS" model we - * later switched to defining the in-tree kernels to be found under - * /usr/lib/ostree-boot. - */ -static gboolean -get_kernel_from_tree (int deployment_dfd, - int *out_boot_dfd, - char **out_kernel_srcpath, - char **out_kernel_namever, - char **out_initramfs_srcpath, - char **out_initramfs_namever, - char **out_bootcsum, - GCancellable *cancellable, - GError **error) +typedef struct { + int boot_dfd; + char *kernel_srcpath; + char *kernel_namever; + char *initramfs_srcpath; + char *initramfs_namever; + char *bootcsum; +} OstreeKernelLayout; +static void +_ostree_kernel_layout_free (OstreeKernelLayout *layout) { - g_autofree char *ret_kernel_srcpath = NULL; - g_autofree char *ret_kernel_namever = NULL; - g_autofree char *ret_initramfs_srcpath = NULL; - g_autofree char *ret_initramfs_namever = NULL; - g_autofree char *kernel_checksum = NULL; - g_autofree char *initramfs_checksum = NULL; + if (layout->boot_dfd != -1) + (void) close (layout->boot_dfd); + g_free (layout->kernel_srcpath); + g_free (layout->kernel_namever); + g_free (layout->initramfs_srcpath); + g_free (layout->initramfs_namever); + g_free (layout->bootcsum); + g_free (layout); +} +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeKernelLayout, _ostree_kernel_layout_free); - glnx_fd_close int ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE); - if (ret_boot_dfd == -1) +static OstreeKernelLayout* +_ostree_kernel_layout_new (void) +{ + OstreeKernelLayout *ret = g_new0 (OstreeKernelLayout, 1); + ret->boot_dfd = -1; + return ret; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_usrlib_modules (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *kver = NULL; + /* Look in usr/lib/modules */ + g_auto(GLnxDirFdIterator) mod_dfditer = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (deployment_dfd, "usr/lib/modules", &mod_dfditer, + &exists, error)) + return FALSE; + if (!exists) { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "%s", "openat(usr/lib/ostree-boot)"); - else - { - if (!glnx_opendirat (deployment_dfd, "boot", TRUE, &ret_boot_dfd, error)) - return FALSE; - } + /* No usr/lib/modules? We're done */ + *out_layout = NULL; + return TRUE; } + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + /* Reusable buffer for path string */ + g_autoptr(GString) pathbuf = g_string_new (""); + /* Loop until we find something that looks like a valid /usr/lib/modules/$kver */ + while (ret_layout->boot_dfd == -1) + { + struct dirent *dent; + struct stat stbuf; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&mod_dfditer, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + + /* It's a directory, look for /vmlinuz as a regular file */ + g_string_truncate (pathbuf, 0); + g_string_append_printf (pathbuf, "%s/vmlinuz", dent->d_name); + if (fstatat (mod_dfditer.fd, pathbuf->str, &stbuf, 0) < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat(%s)", pathbuf->str); + else + continue; + } + else + { + /* Not a regular file? Loop again */ + if (!S_ISREG (stbuf.st_mode)) + continue; + } + + /* Looks valid, this should exit the loop */ + if (!glnx_opendirat (mod_dfditer.fd, dent->d_name, FALSE, &ret_layout->boot_dfd, error)) + return FALSE; + kver = g_strdup (dent->d_name); + ret_layout->kernel_srcpath = g_strdup ("vmlinuz"); + ret_layout->kernel_namever = g_strdup_printf ("vmlinuz-%s", kver); + } + + if (ret_layout->boot_dfd == -1) + { + *out_layout = NULL; + /* No kernel found? We're done. */ + return TRUE; + } + + /* We found a module directory, compute the checksum */ + g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); + glnx_fd_close int fd = -1; + /* Checksum the kernel */ + if (!glnx_openat_rdonly (ret_layout->boot_dfd, "vmlinuz", TRUE, &fd, error)) + return FALSE; + g_autoptr(GInputStream) in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + g_clear_object (&in); + (void) close (fd); fd = -1; + + /* Look for an initramfs, but it's optional; since there wasn't any precedent + * for this, let's be a bit conservative and support both `initramfs.img` and + * `initramfs`. + */ + const char *initramfs_paths[] = {"initramfs.img", "initramfs"}; + const char *initramfs_path = NULL; + for (guint i = 0; i < G_N_ELEMENTS(initramfs_paths); i++) + { + initramfs_path = initramfs_paths[i]; + if (!ot_openat_ignore_enoent (ret_layout->boot_dfd, initramfs_path, &fd, error)) + return FALSE; + if (fd != -1) + break; + else + initramfs_path = NULL; + } + if (fd != -1) + { + g_assert (initramfs_path); + ret_layout->initramfs_srcpath = g_strdup (initramfs_path); + ret_layout->initramfs_namever = g_strdup_printf ("initramfs-%s.img", kver); + in = g_unix_input_stream_new (fd, FALSE); + if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) + return FALSE; + } + + ret_layout->bootcsum = g_strdup (g_checksum_get_string (checksum)); + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* See get_kernel_from_tree() below */ +static gboolean +get_kernel_from_tree_legacy_layouts (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + const char *legacy_paths[] = {"usr/lib/ostree-boot", "boot"}; + g_autofree char *kernel_checksum = NULL; + g_autofree char *initramfs_checksum = NULL; + g_autoptr(OstreeKernelLayout) ret_layout = _ostree_kernel_layout_new (); + + for (guint i = 0; i < G_N_ELEMENTS (legacy_paths); i++) + { + const char *path = legacy_paths[i]; + ret_layout->boot_dfd = glnx_opendirat_with_errno (deployment_dfd, path, TRUE); + if (ret_layout->boot_dfd == -1) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "openat(%s)", path); + } + else + break; + } + + if (ret_layout->boot_dfd == -1) + { + /* No legacy found? We're done */ + *out_layout = NULL; + return TRUE; + } + + /* ret_layout->boot_dfd will point to either /usr/lib/ostree-boot or /boot, let's + * inspect it. + */ g_auto(GLnxDirFdIterator) dfditer = { 0, }; - if (!glnx_dirfd_iterator_init_at (ret_boot_dfd, ".", FALSE, &dfditer, error)) + if (!glnx_dirfd_iterator_init_at (ret_layout->boot_dfd, ".", FALSE, &dfditer, error)) return FALSE; while (TRUE) @@ -930,62 +1071,144 @@ get_kernel_from_tree (int deployment_dfd, if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error)) return FALSE; - if (dent == NULL) break; const char *name = dent->d_name; - if (ret_kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) + /* See if this is the kernel */ + if (ret_layout->kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) { const char *dash = strrchr (name, '-'); g_assert (dash); + /* In this version, we require that the tree builder generated a + * sha256 of the kernel+initramfs and appended it to the file names. + */ if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { kernel_checksum = g_strdup (dash + 1); - ret_kernel_srcpath = g_strdup (name); - ret_kernel_namever = g_strndup (name, dash - name); + ret_layout->kernel_srcpath = g_strdup (name); + ret_layout->kernel_namever = g_strndup (name, dash - name); } } - else if (ret_initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) + /* See if this is the initramfs */ + else if (ret_layout->initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) { const char *dash = strrchr (name, '-'); g_assert (dash); if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { initramfs_checksum = g_strdup (dash + 1); - ret_initramfs_srcpath = g_strdup (name); - ret_initramfs_namever = g_strndup (name, dash - name); + ret_layout->initramfs_srcpath = g_strdup (name); + ret_layout->initramfs_namever = g_strndup (name, dash - name); } } - if (ret_kernel_srcpath != NULL && ret_initramfs_srcpath != NULL) + /* If we found both a kernel and initramfs, break out of the loop */ + if (ret_layout->kernel_srcpath != NULL && ret_layout->initramfs_srcpath != NULL) break; } - if (ret_kernel_srcpath == NULL) + /* No kernel found? We're done */ + if (ret_layout->kernel_srcpath == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Failed to find kernel in /usr/lib/ostree-boot or /boot"); - return FALSE; + *out_layout = NULL; + return TRUE; } - if (ret_initramfs_srcpath != NULL) + /* The kernel/initramfs checksums must be the same */ + if (ret_layout->initramfs_srcpath != NULL) { + g_assert (kernel_checksum != NULL); + g_assert (initramfs_checksum != NULL); if (strcmp (kernel_checksum, initramfs_checksum) != 0) + return glnx_throw (error, "Mismatched kernel checksum vs initrd"); + } + + ret_layout->bootcsum = g_steal_pointer (&kernel_checksum); + + *out_layout = g_steal_pointer (&ret_layout); + return TRUE; +} + +/* Locate kernel/initramfs in the tree; the current standard is to look in + * /usr/lib/modules/$kver/vmlinuz first. + * + * Originally OSTree defined kernels to be found underneath /boot + * in the tree. But that means when mounting /boot at runtime + * we end up masking the content underneath, triggering a warning. + * + * For that reason, and also consistency with the "/usr defines the OS" model we + * later switched to defining the in-tree kernels to be found under + * /usr/lib/ostree-boot. But since then, Fedora at least switched to storing the + * kernel in /usr/lib/modules, which makes sense and isn't ostree-specific, so + * we prefer that now. However, the default Fedora layout doesn't put the + * initramfs there, so we need to look in /usr/lib/ostree-boot first. + */ +static gboolean +get_kernel_from_tree (int deployment_dfd, + OstreeKernelLayout **out_layout, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeKernelLayout) usrlib_modules_layout = NULL; + 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)) + return FALSE; + + /* Gather the legacy layout */ + if (!get_kernel_from_tree_legacy_layouts (deployment_dfd, &legacy_layout, cancellable, error)) + return FALSE; + + /* Evaluate the state of both layouts. If there's no legacy layout + * If a legacy layout exists, and it has + * an initramfs but the module layout doesn't, the legacy layout wins. This is + * what happens with rpm-ostree with Fedora today, until rpm-ostree learns the + * new layout. + */ + if (legacy_layout == NULL) + { + /* No legacy layout, let's see if we have a module layout...*/ + if (usrlib_modules_layout == NULL) { + /* Both layouts are not found? Throw. */ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Mismatched kernel checksum vs initrd"); + "Failed to find kernel in /usr/lib/modules, /usr/lib/ostree-boot or /boot"); return FALSE; } + else + { + /* No legacy, just usr/lib/modules? We're done */ + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + } + else if (usrlib_modules_layout != NULL && + usrlib_modules_layout->initramfs_srcpath == NULL && + legacy_layout->initramfs_srcpath != NULL) + { + /* Does the module path not have an initramfs, but the legacy does? Prefer + * the latter then, to make rpm-ostree work as is today. + */ + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; + } + /* Prefer module layout */ + else if (usrlib_modules_layout != NULL) + { + *out_layout = g_steal_pointer (&usrlib_modules_layout); + return TRUE; + } + else + { + /* And finally fall back to legacy; we know one exists since we + * checked first above. + */ + g_assert (legacy_layout->kernel_srcpath); + *out_layout = g_steal_pointer (&legacy_layout); + return TRUE; } - - *out_boot_dfd = glnx_steal_fd (&ret_boot_dfd); - *out_kernel_srcpath = g_steal_pointer (&ret_kernel_srcpath); - *out_kernel_namever = g_steal_pointer (&ret_kernel_namever); - *out_initramfs_srcpath = g_steal_pointer (&ret_initramfs_srcpath); - *out_initramfs_namever = g_steal_pointer (&ret_initramfs_namever); - *out_bootcsum = g_steal_pointer (&kernel_checksum); - return TRUE; } /* We used to syncfs(), but that doesn't flush the journal on XFS, @@ -1315,18 +1538,8 @@ install_deployment_kernel (OstreeSysroot *sysroot, return FALSE; /* Find the kernel/initramfs in the tree */ - glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_srcpath = NULL; - g_autofree char *tree_kernel_namever = NULL; - g_autofree char *tree_initramfs_srcpath = NULL; - g_autofree char *tree_initramfs_namever = NULL; - g_autofree char *tree_bootcsum = NULL; - if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_srcpath, - &tree_kernel_namever, - &tree_initramfs_srcpath, - &tree_initramfs_namever, - &tree_bootcsum, + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, cancellable, error)) return FALSE; @@ -1336,7 +1549,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, const char *osname = ostree_deployment_get_osname (deployment); const char *bootcsum = ostree_deployment_get_bootcsum (deployment); - g_assert_cmpstr (bootcsum, ==, tree_bootcsum); + g_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-%s-%d.conf", osname, @@ -1355,12 +1568,13 @@ install_deployment_kernel (OstreeSysroot *sysroot, * it doesn't exist already. */ struct stat stbuf; - if (fstatat (bootcsum_dfd, tree_kernel_namever, &stbuf, 0) != 0) + if (fstatat (bootcsum_dfd, kernel_layout->kernel_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", tree_kernel_namever); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_srcpath, - bootcsum_dfd, tree_kernel_namever, + return glnx_throw_errno_prefix (error, "fstat %s", kernel_layout->kernel_namever); + if (!hardlink_or_copy_at (kernel_layout->boot_dfd, + kernel_layout->kernel_srcpath, + bootcsum_dfd, kernel_layout->kernel_namever, sysroot->debug_flags, cancellable, error)) return FALSE; @@ -1369,15 +1583,15 @@ install_deployment_kernel (OstreeSysroot *sysroot, /* If we have an initramfs, then install it into * /boot/ostree/osname-${bootcsum} if it doesn't exist already. */ - if (tree_initramfs_srcpath) + if (kernel_layout->initramfs_srcpath) { - g_assert (tree_initramfs_namever); - if (fstatat (bootcsum_dfd, tree_initramfs_namever, &stbuf, 0) != 0) + g_assert (kernel_layout->initramfs_namever); + if (fstatat (bootcsum_dfd, kernel_layout->initramfs_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", tree_initramfs_namever); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_srcpath, - bootcsum_dfd, tree_initramfs_namever, + return glnx_throw_errno_prefix (error, "fstat %s", kernel_layout->initramfs_namever); + if (!hardlink_or_copy_at (kernel_layout->boot_dfd, kernel_layout->initramfs_srcpath, + bootcsum_dfd, kernel_layout->initramfs_namever, sysroot->debug_flags, cancellable, error)) return FALSE; @@ -1458,12 +1672,12 @@ install_deployment_kernel (OstreeSysroot *sysroot, g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment)); ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key); - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_kernel_namever, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->kernel_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath); - if (tree_initramfs_namever) + if (kernel_layout->initramfs_namever) { - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_initramfs_namever, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", kernel_layout->initramfs_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath); } @@ -2084,22 +2298,12 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, return FALSE; } - glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_srcpath = NULL; - g_autofree char *tree_kernel_namever = NULL; - g_autofree char *tree_initramfs_srcpath = NULL; - g_autofree char *tree_initramfs_namever = NULL; - g_autofree char *tree_bootcsum = NULL; - if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_srcpath, - &tree_kernel_namever, - &tree_initramfs_srcpath, - &tree_initramfs_namever, - &new_bootcsum, + g_autoptr(OstreeKernelLayout) kernel_layout = NULL; + if (!get_kernel_from_tree (deployment_dfd, &kernel_layout, cancellable, error)) return FALSE; - _ostree_deployment_set_bootcsum (new_deployment, new_bootcsum); + _ostree_deployment_set_bootcsum (new_deployment, kernel_layout->bootcsum); /* Create an empty boot configuration; we will merge things into * it as we go. diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c index 8afea3a6..f028fa7c 100644 --- a/src/libostree/ostree-sysroot-upgrader.c +++ b/src/libostree/ostree-sysroot-upgrader.c @@ -24,6 +24,7 @@ #include "ostree.h" #include "ostree-sysroot-upgrader.h" +#include "ostree-core-private.h" /** * SECTION:ostree-sysroot-upgrader @@ -429,26 +430,10 @@ ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo, error)) return FALSE; - if (ostree_commit_get_timestamp (old_commit) > ostree_commit_get_timestamp (new_commit)) - { - GDateTime *old_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (old_commit)); - GDateTime *new_ts = g_date_time_new_from_unix_utc (ostree_commit_get_timestamp (new_commit)); - g_autofree char *old_ts_str = NULL; - g_autofree char *new_ts_str = NULL; - - if (old_ts == NULL || new_ts == NULL) - return glnx_throw (error, "Upgrade target revision '%s' timestamp (%" G_GINT64_FORMAT ") or current revision '%s' timestamp (%" G_GINT64_FORMAT ") is invalid", - to_rev, ostree_commit_get_timestamp (new_commit), - from_rev, ostree_commit_get_timestamp (old_commit)); - - old_ts_str = g_date_time_format (old_ts, "%c"); - new_ts_str = g_date_time_format (new_ts, "%c"); - g_date_time_unref (old_ts); - g_date_time_unref (new_ts); - - return glnx_throw (error, "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit", - to_rev, new_ts_str, from_rev, old_ts_str); - } + if (!_ostree_compare_timestamps (from_rev, ostree_commit_get_timestamp (old_commit), + to_rev, ostree_commit_get_timestamp (new_commit), + error)) + return FALSE; return TRUE; } @@ -536,9 +521,23 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, if (self->origin_remote && (upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC) == 0) { - if (!ostree_repo_pull_one_dir (repo, self->origin_remote, dir_to_pull, refs_to_fetch, - flags, progress, - cancellable, error)) + g_autoptr(GVariantBuilder) optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (dir_to_pull && *dir_to_pull) + g_variant_builder_add (optbuilder, "{s@v}", "subdir", + g_variant_new_variant (g_variant_new_string (dir_to_pull))); + g_variant_builder_add (optbuilder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (flags))); + /* Add the timestamp check, unless disabled */ + if ((upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER) == 0) + g_variant_builder_add (optbuilder, "{s@v}", "timestamp-check", + g_variant_new_variant (g_variant_new_boolean (TRUE))); + + g_variant_builder_add (optbuilder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch, -1))); + g_autoptr(GVariant) opts = g_variant_ref_sink (g_variant_builder_end (optbuilder)); + if (!ostree_repo_pull_with_options (repo, self->origin_remote, + opts, progress, + cancellable, error)) return FALSE; if (progress) diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index 86a4f37a..18475d35 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -256,7 +256,7 @@ ensure_sysroot_fd (OstreeSysroot *self, * Access a file descriptor that refers to the root directory of this * sysroot. ostree_sysroot_load() must have been invoked prior to * calling this function. - * + * * Returns: A file descriptor valid for the lifetime of @self */ int @@ -276,7 +276,7 @@ _ostree_sysroot_bump_mtime (OstreeSysroot *self, glnx_set_prefix_error_from_errno (error, "%s", "futimens"); return FALSE; } - return TRUE; + return TRUE; } /** @@ -471,8 +471,8 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, if (dent == NULL) break; - if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0) != 0) - return glnx_throw_errno (error); + if (!glnx_fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0, error)) + return FALSE; if (g_str_has_prefix (dent->d_name, "ostree-") && g_str_has_suffix (dent->d_name, ".conf") && @@ -772,6 +772,13 @@ ensure_repo (OstreeSysroot *self, */ g_weak_ref_init (&self->repo->sysroot, self); self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT; + + /* Reload the repo config in case any defaults depend on knowing if this is + * a system repo. + */ + if (!ostree_repo_reload_config (self->repo, NULL, error)) + return FALSE; + return TRUE; } @@ -894,7 +901,7 @@ ostree_sysroot_get_subbootversion (OstreeSysroot *self) /** * ostree_sysroot_get_booted_deployment: * @self: Sysroot - * + * * Returns: (transfer none): The currently booted deployment, or %NULL if none */ OstreeDeployment * @@ -1377,7 +1384,7 @@ lock_in_thread (GTask *task, * @cancellable: Cancellable * @callback: Callback * @user_data: User data - * + * * An asynchronous version of ostree_sysroot_lock(). */ void @@ -1395,7 +1402,7 @@ ostree_sysroot_lock_async (OstreeSysroot *self, * @self: Self * @result: Result * @error: Error - * + * * Call when ostree_sysroot_lock_async() is ready. */ gboolean @@ -1413,7 +1420,7 @@ ostree_sysroot_lock_finish (OstreeSysroot *self, * @osname: Name group of operating system checkouts * @cancellable: Cancellable * @error: Error - * + * * Initialize the directory structure for an "osname", which is a * group of operating system deployments, with a shared `/var`. One * is required for generating a deployment. @@ -1487,6 +1494,12 @@ ostree_sysroot_init_osname (OstreeSysroot *self, * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is * specified, then all current deployments will be kept. * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING is + * specified, then pending deployments will be kept. + * + * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK is + * specified, then rollback deployments will be kept. + * * If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is * specified, then instead of prepending, the new deployment will be * added right after the booted or merge deployment, instead of first. @@ -1505,70 +1518,91 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - guint i; - OstreeDeployment *booted_deployment = NULL; - g_autoptr(GPtrArray) deployments = NULL; - g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); - const gboolean postclean = (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN) == 0; - OstreeSysrootWriteDeploymentsOpts write_opts = { .do_postclean = postclean }; - gboolean retain = (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0; - const gboolean make_default = !((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0); - gboolean added_new = FALSE; + const gboolean postclean = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN) == 0; + const gboolean make_default = + !((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0); + const gboolean retain_pending = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING) > 0; + const gboolean retain_rollback = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK) > 0; + gboolean retain = + (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0; - deployments = ostree_sysroot_get_deployments (sysroot); - booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot); + OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); if (osname == NULL && booted_deployment) osname = ostree_deployment_get_osname (booted_deployment); + gboolean added_new = FALSE; + g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); if (make_default) { g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); added_new = TRUE; } - for (i = 0; i < deployments->len; i++) + /* without a booted and a merge deployment, retain_pending/rollback become meaningless; + * let's just retain all deployments in that case */ + if (!booted_deployment && !merge_deployment && (retain_pending || retain_rollback)) + retain = TRUE; + + /* tracks when we come across the booted deployment */ + gboolean before_booted = TRUE; + gboolean before_merge = TRUE; + for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; - const gboolean is_merge_or_booted = - ostree_deployment_equal (deployment, booted_deployment) || - ostree_deployment_equal (deployment, merge_deployment); - - /* Keep deployments with different osnames, as well as the - * booted and merge deployments - */ - if (retain || - (osname != NULL && strcmp (ostree_deployment_get_osname (deployment), osname) != 0) || - is_merge_or_booted) - { - g_ptr_array_add (new_deployments, g_object_ref (deployment)); - } + const gboolean osname_matches = + (osname == NULL || g_str_equal (ostree_deployment_get_osname (deployment), osname)); + const gboolean is_booted = ostree_deployment_equal (deployment, booted_deployment); + const gboolean is_merge = ostree_deployment_equal (deployment, merge_deployment); - if (!added_new) + if (is_booted) + before_booted = FALSE; + if (is_merge) + before_merge = FALSE; + + /* use the booted deployment as the "crossover" point between pending and rollback + * deployments, fall back on merge deployment */ + const gboolean passed_crossover = booted_deployment ? !before_booted : !before_merge; + + /* Retain deployment if: + * - we're explicitly asked to, or + * - the deployment is for another osname, or + * - we're keeping pending deployments and this is a pending deployment, or + * - this is the merge or boot deployment, or + * - we're keeping rollback deployments and this is a rollback deployment + */ + if (retain + || !osname_matches + || (retain_pending && !passed_crossover) + || (is_booted || is_merge) + || (retain_rollback && passed_crossover)) + g_ptr_array_add (new_deployments, g_object_ref (deployment)); + + /* add right after booted/merge deployment */ + if (!added_new && passed_crossover) { g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); added_new = TRUE; } } - /* In this non-default case , an improvement in the future would be - * to put the new deployment right after the current default in the - * order. - */ + /* add it last if no crossover defined (or it's the first deployment in the sysroot) */ if (!added_new) { g_ptr_array_add (new_deployments, g_object_ref (new_deployment)); added_new = TRUE; } + OstreeSysrootWriteDeploymentsOpts write_opts = { .do_postclean = postclean }; if (!ostree_sysroot_write_deployments_with_options (sysroot, new_deployments, &write_opts, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } /* Deploy a copy of @target_deployment */ @@ -1704,8 +1738,8 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, "/usr", 0755, error)) return FALSE; - if (!glnx_mkdtempat (AT_FDCWD, development_ovldir, 0755, error)) - return FALSE; + if (g_mkdtemp_full (development_ovldir, 0755) == NULL) + return glnx_throw_errno_prefix (error, "mkdtemp"); } development_ovl_upper = glnx_strjoina (development_ovldir, "/upper"); diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h index 3d2446f9..f2573d6b 100644 --- a/src/libostree/ostree-sysroot.h +++ b/src/libostree/ostree-sysroot.h @@ -207,6 +207,8 @@ typedef enum { OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN = (1 << 0), OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT = (1 << 1), OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN = (1 << 2), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING = (1 << 3), + OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK = (1 << 4), } OstreeSysrootSimpleWriteDeploymentFlags; _OSTREE_PUBLIC diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h index 32b401e9..d26969af 100644 --- a/src/libostree/ostree-version.h +++ b/src/libostree/ostree-version.h @@ -44,7 +44,7 @@ * * Since: 2017.4 */ -#define OSTREE_RELEASE_VERSION (10) +#define OSTREE_RELEASE_VERSION (11) /** * OSTREE_VERSION @@ -53,7 +53,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION (2017.10) +#define OSTREE_VERSION (2017.11) /** * OSTREE_VERSION_S: @@ -63,7 +63,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION_S "2017.10" +#define OSTREE_VERSION_S "2017.11" #define OSTREE_ENCODE_VERSION(year,release) \ ((year) << 16 | (release)) diff --git a/src/libotutil/ot-fs-utils.c b/src/libotutil/ot-fs-utils.c index 2f0ae19c..9100b85b 100644 --- a/src/libotutil/ot-fs-utils.c +++ b/src/libotutil/ot-fs-utils.c @@ -90,6 +90,7 @@ ot_openat_read_stream (int dfd, return TRUE; } +/* Like unlinkat() but ignore ENOENT */ gboolean ot_ensure_unlinked_at (int dfd, const char *path, diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c index 99f4879e..f8a13269 100644 --- a/src/libotutil/ot-gpg-utils.c +++ b/src/libotutil/ot-gpg-utils.c @@ -26,20 +26,23 @@ #include "libglnx.h" -void -ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, - GError **error) +/* Like glnx_throw_errno_prefix, but takes @gpg_error */ +gboolean +ot_gpgme_throw (gpgme_error_t gpg_error, GError **error, + const char *fmt, ...) { + if (error == NULL) + return FALSE; + GIOErrorEnum errcode; char errbuf[1024]; /* XXX This list is incomplete. Add cases as needed. */ - switch (gpgme_err_code (gpg_error)) { /* special case - shouldn't be here */ case GPG_ERR_NO_ERROR: - g_return_if_reached (); + g_assert_not_reached (); /* special case - abort on out-of-memory */ case GPG_ERR_ENOMEM: @@ -63,6 +66,12 @@ ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, g_set_error (error, G_IO_ERROR, errcode, "%s: %s", gpgme_strsource (gpg_error), errbuf); + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_va (*error, fmt, args); + va_end (args); + + return FALSE; } gboolean @@ -99,7 +108,7 @@ ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, NULL, tmp_home_dir); if (gpg_error != GPG_ERR_NO_ERROR) { - ot_gpgme_error_to_gio_error (gpg_error, error); + ot_gpgme_throw (gpg_error, error, "gpgme_ctx_set_engine_info"); goto out; } @@ -376,7 +385,6 @@ ot_gpgme_data_input (GInputStream *input_stream) if (gpg_error != GPG_ERR_NO_ERROR) { g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); - ot_gpgme_error_to_gio_error (gpg_error, NULL); g_assert_not_reached (); } @@ -399,7 +407,6 @@ ot_gpgme_data_output (GOutputStream *output_stream) if (gpg_error != GPG_ERR_NO_ERROR) { g_assert (gpgme_err_code (gpg_error) == GPG_ERR_ENOMEM); - ot_gpgme_error_to_gio_error (gpg_error, NULL); g_assert_not_reached (); } @@ -416,11 +423,7 @@ ot_gpgme_new_ctx (const char *homedir, g_auto(gpgme_ctx_t) context = NULL; if ((err = gpgme_new (&context)) != GPG_ERR_NO_ERROR) - { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Unable to create gpg context: "); - return NULL; - } + return ot_gpgme_throw (err, error, "Unable to create gpg context"), NULL; if (homedir != NULL) { @@ -430,12 +433,7 @@ ot_gpgme_new_ctx (const char *homedir, if ((err = gpgme_ctx_set_engine_info (context, info->protocol, NULL, homedir)) != GPG_ERR_NO_ERROR) - { - ot_gpgme_error_to_gio_error (err, error); - g_prefix_error (error, "Unable to set gpg homedir to '%s': ", - homedir); - return NULL; - } + return ot_gpgme_throw (err, error, "Unable to set gpg homedir to '%s'", homedir), NULL; } return g_steal_pointer (&context); diff --git a/src/libotutil/ot-gpg-utils.h b/src/libotutil/ot-gpg-utils.h index b639e5ac..bd2810f8 100644 --- a/src/libotutil/ot-gpg-utils.h +++ b/src/libotutil/ot-gpg-utils.h @@ -30,7 +30,8 @@ G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_data_t, gpgme_data_release, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_ctx_t, gpgme_release, NULL) G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_key_t, gpgme_key_unref, NULL) -void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error); +gboolean ot_gpgme_throw (gpgme_error_t gpg_error, GError **error, + const char *fmt, ...) G_GNUC_PRINTF (3, 4); gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, char **out_tmp_home_dir, diff --git a/src/ostree/ot-admin-builtin-cleanup.c b/src/ostree/ot-admin-builtin-cleanup.c index 13caa7f4..a3b0a880 100644 --- a/src/ostree/ot-admin-builtin-cleanup.c +++ b/src/ostree/ot-admin-builtin-cleanup.c @@ -52,9 +52,6 @@ ot_admin_builtin_cleanup (int argc, char **argv, GCancellable *cancellable, GErr &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c index 5df4923c..e46ad025 100644 --- a/src/ostree/ot-admin-builtin-deploy.c +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -33,6 +33,9 @@ #include static gboolean opt_retain; +static gboolean opt_retain_pending; +static gboolean opt_retain_rollback; +static gboolean opt_not_as_default; static char **opt_kernel_argv; static char **opt_kernel_argv_append; static gboolean opt_kernel_proc_cmdline; @@ -47,7 +50,10 @@ static char *opt_origin_path; static GOptionEntry options[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, { "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" }, - { "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployment", NULL }, + { "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployments", NULL }, + { "retain-pending", 0, 0, G_OPTION_ARG_NONE, &opt_retain_pending, "Do not delete pending deployments", NULL }, + { "retain-rollback", 0, 0, G_OPTION_ARG_NONE, &opt_retain_rollback, "Do not delete rollback deployments", NULL }, + { "not-as-default", 0, 0, G_OPTION_ARG_NONE, &opt_not_as_default, "Append rather than prepend new deployment", NULL }, { "karg-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_proc_cmdline, "Import current /proc/cmdline", NULL }, { "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" }, @@ -57,64 +63,53 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *refspec; - g_autoptr(GOptionContext) context = NULL; - g_autoptr(OstreeSysroot) sysroot = NULL; - g_autoptr(GKeyFile) origin = NULL; - g_autoptr(OstreeRepo) repo = NULL; - g_autoptr(OstreeDeployment) new_deployment = NULL; - g_autoptr(OstreeDeployment) merge_deployment = NULL; - g_autofree char *revision = NULL; __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; - context = g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment"); + g_autoptr(GOptionContext) context = + g_option_context_new ("REFSPEC - Checkout revision REFSPEC as the new default deployment"); + g_autoptr(OstreeSysroot) sysroot = NULL; if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) - goto out; + return FALSE; if (argc < 2) { ot_util_usage_error (context, "REF/REV must be specified", error); - goto out; + return FALSE; } - refspec = argv[1]; + const char *refspec = argv[1]; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) - goto out; + OstreeRepo *repo = ostree_sysroot_repo (sysroot); /* Find the currently booted deployment, if any; we will ensure it * is present in the new deployment list. */ if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, cancellable, error)) - { - g_prefix_error (error, "Looking for booted deployment: "); - goto out; - } + return glnx_prefix_error (error, "Looking for booted deployment"); + g_autoptr(GKeyFile) origin = NULL; if (opt_origin_path) { origin = g_key_file_new (); - + if (!g_key_file_load_from_file (origin, opt_origin_path, 0, error)) - goto out; + return FALSE; } else { origin = ostree_sysroot_origin_new_from_refspec (sysroot, refspec); } + g_autofree char *revision = NULL; if (!ostree_repo_resolve_rev (repo, refspec, FALSE, &revision, error)) - goto out; + return FALSE; - merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname); + g_autoptr(OstreeDeployment) merge_deployment = + ostree_sysroot_get_merge_deployment (sysroot, opt_osname); /* Here we perform cleanup of any leftover data from previous * partial failures. This avoids having to call @@ -124,10 +119,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro * we find it. */ if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error)) - { - g_prefix_error (error, "Performing initial cleanup: "); - goto out; - } + return glnx_prefix_error (error, "Performing initial cleanup"); kargs = _ostree_kernel_args_new (); @@ -137,7 +129,7 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro if (opt_kernel_proc_cmdline) { if (!_ostree_kernel_args_append_proc_cmdline (kargs, cancellable, error)) - goto out; + return FALSE; } else if (merge_deployment) { @@ -157,24 +149,29 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro _ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append); } - { - g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs); + g_autoptr(OstreeDeployment) new_deployment = NULL; + g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs); + if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment, + kargs_strv, &new_deployment, cancellable, error)) + return FALSE; - if (!ostree_sysroot_deploy_tree (sysroot, - opt_osname, revision, origin, - merge_deployment, kargs_strv, - &new_deployment, - cancellable, error)) - goto out; - } + OstreeSysrootSimpleWriteDeploymentFlags flags = 0; + if (opt_retain) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN; + else + { + if (opt_retain_pending) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING; + if (opt_retain_rollback) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK; + } - if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, - new_deployment, merge_deployment, - opt_retain ? OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN : 0, - cancellable, error)) - goto out; + if (opt_not_as_default) + flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT; - ret = TRUE; - out: - return ret; + if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment, + merge_deployment, flags, cancellable, error)) + return FALSE; + + return TRUE; } diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c index 0419f2e1..99672866 100644 --- a/src/ostree/ot-admin-builtin-diff.c +++ b/src/ostree/ot-admin-builtin-diff.c @@ -63,9 +63,6 @@ ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, &sysroot, cancellable, error)) goto out; - - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname, cancellable, error)) diff --git a/src/ostree/ot-admin-builtin-init-fs.c b/src/ostree/ot-admin-builtin-init-fs.c index c1fa16b0..a92d67dc 100644 --- a/src/ostree/ot-admin-builtin-init-fs.c +++ b/src/ostree/ot-admin-builtin-init-fs.c @@ -41,57 +41,51 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GError **error) { - g_autoptr(GOptionContext) context = NULL; - g_autoptr(OstreeSysroot) sysroot = NULL; - gboolean ret = FALSE; - glnx_fd_close int root_dfd = -1; - g_autoptr(OstreeSysroot) target_sysroot = NULL; - guint i; - const char *normal_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"}; - - context = g_option_context_new ("PATH - Initialize a root filesystem"); + g_autoptr(GOptionContext) context = g_option_context_new ("PATH - Initialize a root filesystem"); if (!ostree_admin_option_context_parse (context, options, &argc, &argv, - OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, - &sysroot, cancellable, error)) - goto out; + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED | + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, + NULL, cancellable, error)) + return FALSE; if (argc < 2) { ot_util_usage_error (context, "PATH must be specified", error); - goto out; + return FALSE; } - if (!glnx_opendirat (AT_FDCWD, argv[1], TRUE, &root_dfd, error)) - goto out; - { g_autoptr(GFile) dir = g_file_new_for_path (argv[1]); - target_sysroot = ostree_sysroot_new (dir); - } + const char *sysroot_path = argv[1]; - for (i = 0; i < G_N_ELEMENTS(normal_toplevels); i++) + glnx_fd_close int root_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, sysroot_path, TRUE, &root_dfd, error)) + return FALSE; + + const char *normal_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"}; + for (guint i = 0; i < G_N_ELEMENTS (normal_toplevels); i++) { if (!glnx_shutil_mkdir_p_at (root_dfd, normal_toplevels[i], 0755, cancellable, error)) - goto out; + return FALSE; } - + if (!glnx_shutil_mkdir_p_at (root_dfd, "root", 0700, cancellable, error)) - goto out; + return FALSE; if (!glnx_shutil_mkdir_p_at (root_dfd, "tmp", 01777, cancellable, error)) - goto out; + return FALSE; if (fchmodat (root_dfd, "tmp", 01777, 0) == -1) { glnx_set_prefix_error_from_errno (error, "chmod: %s", "tmp"); - goto out; + return FALSE; } + g_autoptr(GFile) dir = g_file_new_for_path (sysroot_path); + g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (dir); + if (!ostree_sysroot_ensure_initialized (sysroot, cancellable, error)) + return FALSE; - if (!ostree_sysroot_ensure_initialized (target_sysroot, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c index 0694ba77..0770b1b2 100644 --- a/src/ostree/ot-admin-builtin-instutil.c +++ b/src/ostree/ot-admin-builtin-instutil.c @@ -65,10 +65,7 @@ ostree_admin_instutil_option_context_new_with_commands (void) gboolean ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - OstreeAdminInstUtilCommand *subcommand; const char *subcommand_name = NULL; - g_autofree char *prgname = NULL; int in, out; for (in = 1, out = 1; in < argc; in++, out++) @@ -94,7 +91,7 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr argc = out; - subcommand = admin_instutil_subcommands; + OstreeAdminInstUtilCommand *subcommand = admin_instutil_subcommands; while (subcommand->name) { if (g_strcmp0 (subcommand_name, subcommand->name) == 0) @@ -104,14 +101,12 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr if (!subcommand->name) { - g_autoptr(GOptionContext) context = NULL; - g_autofree char *help; - - context = ostree_admin_instutil_option_context_new_with_commands (); + g_autoptr(GOptionContext) context = + ostree_admin_instutil_option_context_new_with_commands (); /* This will not return for some options (e.g. --version). */ if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, - OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, NULL, cancellable, error)) { if (subcommand_name == NULL) @@ -126,19 +121,16 @@ ot_admin_builtin_instutil (int argc, char **argv, GCancellable *cancellable, GEr } } - help = g_option_context_get_help (context, FALSE, NULL); + g_autofree char *help = g_option_context_get_help (context, FALSE, NULL); g_printerr ("%s", help); - - goto out; + return FALSE; } - prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name); + g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), subcommand_name); g_set_prgname (prgname); if (!subcommand->fn (argc, argv, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return FALSE; + + return TRUE; } diff --git a/src/ostree/ot-admin-builtin-set-origin.c b/src/ostree/ot-admin-builtin-set-origin.c index c49f575a..e6020cbe 100644 --- a/src/ostree/ot-admin-builtin-set-origin.c +++ b/src/ostree/ot-admin-builtin-set-origin.c @@ -75,9 +75,6 @@ ot_admin_builtin_set_origin (int argc, char **argv, GCancellable *cancellable, G if (argc > 3) branch = argv[3]; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c index 3dd7aec5..56107974 100644 --- a/src/ostree/ot-admin-builtin-status.c +++ b/src/ostree/ot-admin-builtin-status.c @@ -108,9 +108,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) goto out; diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c index f85e39e1..48fb2726 100644 --- a/src/ostree/ot-admin-builtin-switch.c +++ b/src/ostree/ot-admin-builtin-switch.c @@ -47,54 +47,38 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GOptionContext) context = NULL; + g_autoptr(GOptionContext) context = + g_option_context_new ("REF - Construct new tree from REF and deploy it"); g_autoptr(OstreeSysroot) sysroot = NULL; - const char *new_provided_refspec = NULL; - g_autoptr(OstreeRepo) repo = NULL; - g_autofree char *origin_refspec = NULL; - g_autofree char *origin_remote = NULL; - g_autofree char *origin_ref = NULL; - g_autofree char *new_remote = NULL; - g_autofree char *new_ref = NULL; - g_autofree char *new_refspec = NULL; - const char* remote; - g_autoptr(OstreeSysrootUpgrader) upgrader = NULL; - g_autoptr(OstreeAsyncProgress) progress = NULL; - gboolean changed; - GKeyFile *old_origin; - g_autoptr(GKeyFile) new_origin = NULL; - - context = g_option_context_new ("REF - Construct new tree from REF and deploy it"); - if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) - goto out; + return FALSE; if (argc < 2) { ot_util_usage_error (context, "REF must be specified", error); - goto out; + return FALSE; } - new_provided_refspec = argv[1]; + const char *new_provided_refspec = argv[1]; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - - upgrader = ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname, - OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, - cancellable, error); + g_autoptr(OstreeSysrootUpgrader) upgrader = + ostree_sysroot_upgrader_new_for_os_with_flags (sysroot, opt_osname, + OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED, + cancellable, error); if (!upgrader) - goto out; + return FALSE; - old_origin = ostree_sysroot_upgrader_get_origin (upgrader); - origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL); - + GKeyFile *old_origin = ostree_sysroot_upgrader_get_origin (upgrader); + g_autofree char *origin_refspec = g_key_file_get_string (old_origin, "origin", "refspec", NULL); + g_autofree char *origin_remote = NULL; + g_autofree char *origin_ref = NULL; if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error)) - goto out; + return FALSE; + g_autofree char *new_remote = NULL; + g_autofree char *new_ref = NULL; /* Allow just switching remotes */ if (g_str_has_suffix (new_provided_refspec, ":")) { @@ -105,14 +89,11 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro else { if (!ostree_parse_refspec (new_provided_refspec, &new_remote, &new_ref, error)) - goto out; + return FALSE; } - if (!new_remote) - remote = origin_remote; - else - remote = new_remote; - + const char* remote = new_remote ?: origin_remote; + g_autofree char *new_refspec = NULL; if (remote) new_refspec = g_strconcat (remote, ":", new_ref, NULL); else @@ -122,54 +103,52 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Old and new refs are equal: %s", new_refspec); - goto out; + return FALSE; } - new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec); + g_autoptr(GKeyFile) new_origin = ostree_sysroot_origin_new_from_refspec (sysroot, new_refspec); if (!ostree_sysroot_upgrader_set_origin (upgrader, new_origin, cancellable, error)) - goto out; + return FALSE; { g_auto(GLnxConsoleRef) console = { 0, }; glnx_console_lock (&console); + g_autoptr(OstreeAsyncProgress) progress = NULL; if (console.is_tty) progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); /* Always allow older...there's not going to be a chronological * relationship necessarily. */ + gboolean changed; if (!ostree_sysroot_upgrader_pull (upgrader, 0, OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER, progress, &changed, cancellable, error)) - goto out; + return FALSE; if (progress) ostree_async_progress_finish (progress); } if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) - goto out; - - if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error)) - goto out; + return FALSE; + OstreeRepo *repo = ostree_sysroot_repo (sysroot); if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error)) - goto out; + return FALSE; g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref); ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL); - + if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error)) - goto out; - + return FALSE; + if (opt_reboot) { if (!ot_admin_execve_reboot (sysroot, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c index c0ff89ef..d16c927e 100644 --- a/src/ostree/ot-admin-builtin-undeploy.c +++ b/src/ostree/ot-admin-builtin-undeploy.c @@ -60,8 +60,6 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr return FALSE; } - if (!ostree_sysroot_load (sysroot, cancellable, error)) - return FALSE; current_deployments = ostree_sysroot_get_deployments (sysroot); deploy_index_str = argv[1]; diff --git a/src/ostree/ot-admin-builtin-unlock.c b/src/ostree/ot-admin-builtin-unlock.c index 05397414..36d99edb 100644 --- a/src/ostree/ot-admin-builtin-unlock.c +++ b/src/ostree/ot-admin-builtin-unlock.c @@ -65,9 +65,6 @@ ot_admin_builtin_unlock (int argc, char **argv, GCancellable *cancellable, GErro goto out; } - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); if (!booted_deployment) { diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c index b939278c..8944904b 100644 --- a/src/ostree/ot-admin-builtin-upgrade.c +++ b/src/ostree/ot-admin-builtin-upgrade.c @@ -57,44 +57,34 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GOptionContext) context = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed"); + g_autoptr(OstreeSysroot) sysroot = NULL; - g_autoptr(OstreeSysrootUpgrader) upgrader = NULL; - g_autoptr(GKeyFile) origin = NULL; - g_autoptr(OstreeAsyncProgress) progress = NULL; - gboolean changed; - OstreeSysrootUpgraderPullFlags upgraderpullflags = 0; - - context = g_option_context_new ("Construct new tree from current origin and deploy it, if it changed"); - if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) - goto out; + return FALSE; if (opt_pull_only && opt_deploy_only) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot simultaneously specify --pull-only and --deploy-only"); - goto out; + return FALSE; } else if (opt_pull_only && opt_reboot) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Cannot simultaneously specify --pull-only and --reboot"); - goto out; + return FALSE; } - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - - upgrader = ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, - cancellable, error); + g_autoptr(OstreeSysrootUpgrader) upgrader = + ostree_sysroot_upgrader_new_for_os (sysroot, opt_osname, + cancellable, error); if (!upgrader) - goto out; + return FALSE; - origin = ostree_sysroot_upgrader_dup_origin (upgrader); + g_autoptr(GKeyFile) origin = ostree_sysroot_upgrader_dup_origin (upgrader); if (origin != NULL) { gboolean origin_changed = FALSE; @@ -122,16 +112,19 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr { /* XXX GCancellable parameter is not used. */ if (!ostree_sysroot_upgrader_set_origin (upgrader, origin, NULL, error)) - goto out; + return FALSE; } } + gboolean changed; + OstreeSysrootUpgraderPullFlags upgraderpullflags = 0; if (opt_deploy_only) upgraderpullflags |= OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC; { g_auto(GLnxConsoleRef) console = { 0, }; glnx_console_lock (&console); + g_autoptr(OstreeAsyncProgress) progress = NULL; if (console.is_tty) progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console); @@ -152,7 +145,7 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr */ if (opt_pull_only) (void) ostree_sysroot_cleanup (sysroot, NULL, NULL); - goto out; + return FALSE; } if (progress) @@ -168,17 +161,15 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr if (!opt_pull_only) { if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error)) - goto out; + return FALSE; } if (opt_reboot) { if (!ot_admin_execve_reboot (sysroot, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c index a0a66b6a..6a99db04 100644 --- a/src/ostree/ot-admin-functions.c +++ b/src/ostree/ot-admin-functions.c @@ -151,13 +151,15 @@ ot_admin_sysroot_lock (OstreeSysroot *sysroot, gboolean ot_admin_execve_reboot (OstreeSysroot *sysroot, GError **error) { - g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/"); + OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot); - if (g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot)) - { - if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0) - return glnx_throw_errno (error); - } + /* If the sysroot isn't booted, we shouldn't reboot, even if somehow the user + * asked for it; might accidentally be specified in a build script, etc. + */ + if (!booted) + return TRUE; + if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0) + return glnx_throw_errno_prefix (error, "execve(systemctl reboot)"); return TRUE; } diff --git a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c index 07bd1eaa..8ff0dc47 100644 --- a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c +++ b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c @@ -53,9 +53,6 @@ ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, GCancellable *c &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - if (argc >= 2) { bootversion = (guint) g_ascii_strtoull (argv[1], NULL, 10); diff --git a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c index c754b18a..cbca7db3 100644 --- a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c +++ b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c @@ -204,9 +204,6 @@ ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, GCancel &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) { diff --git a/src/ostree/ot-admin-instutil-builtin-set-kargs.c b/src/ostree/ot-admin-instutil-builtin-set-kargs.c index 1a37022c..7a98feb7 100644 --- a/src/ostree/ot-admin-instutil-builtin-set-kargs.c +++ b/src/ostree/ot-admin-instutil-builtin-set-kargs.c @@ -66,9 +66,6 @@ ot_admin_instutil_builtin_set_kargs (int argc, char **argv, GCancellable *cancel &sysroot, cancellable, error)) goto out; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; - deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) { diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c index 16aaec03..ce0b2ffa 100644 --- a/src/ostree/ot-builtin-admin.c +++ b/src/ostree/ot-builtin-admin.c @@ -126,7 +126,7 @@ ostree_builtin_admin (int argc, char **argv, GCancellable *cancellable, GError * /* This will not return for some options (e.g. --version). */ if (ostree_admin_option_context_parse (context, NULL, &argc, &argv, - OSTREE_ADMIN_BUILTIN_FLAG_NONE | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED, + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT, NULL, cancellable, error)) { if (subcommand_name == NULL) diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index a31d3685..170d24e9 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -37,6 +37,7 @@ static gboolean opt_disable_cache; static char *opt_subpath; static gboolean opt_union; static gboolean opt_union_add; +static gboolean opt_union_identical; static gboolean opt_whiteouts; static gboolean opt_from_stdin; static char *opt_from_file; @@ -72,6 +73,7 @@ static GOptionEntry options[] = { { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL }, { "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL }, + { "union-identical", 0, 0, G_OPTION_ARG_NONE, &opt_union_identical, "When layering checkouts, error out if a file would be replaced with a different version, but add new files and directories", NULL }, { "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL }, { "allow-noent", 0, 0, G_OPTION_ARG_NONE, &opt_allow_noent, "Do nothing if specified path does not exist", NULL }, { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &opt_from_stdin, "Process many checkouts from standard input", NULL }, @@ -99,7 +101,7 @@ process_one_checkout (OstreeRepo *repo, * convenient infrastructure for testing C APIs with data. */ if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || - opt_union_add || opt_force_copy || opt_bareuseronly_dirs) + opt_union_add || opt_force_copy || opt_bareuseronly_dirs || opt_union_identical) { OstreeRepoCheckoutAtOptions options = { 0, }; @@ -112,6 +114,18 @@ process_one_checkout (OstreeRepo *repo, "Cannot specify both --union and --union-add"); goto out; } + if (opt_union && opt_union_identical) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --union and --union-identical"); + goto out; + } + if (opt_union_add && opt_union_identical) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Cannot specify both --union-add and --union-identical "); + goto out; + } if (opt_require_hardlinks && opt_force_copy) { glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy"); @@ -121,6 +135,16 @@ process_one_checkout (OstreeRepo *repo, options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; else if (opt_union_add) options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES; + else if (opt_union_identical) + { + if (!opt_require_hardlinks) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "--union-identical requires --require-hardlinks"); + goto out; + } + options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_IDENTICAL; + } if (opt_whiteouts) options.process_whiteouts = TRUE; if (subpath) diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 6d1ce060..3b9e3630 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -30,6 +30,7 @@ #include "ot-tool-util.h" #include "parse-datetime.h" #include "ostree-repo-private.h" +#include "ostree-libarchive-private.h" static char *opt_subject; static char *opt_body; @@ -46,7 +47,9 @@ static char **opt_detached_metadata_strings; static gboolean opt_link_checkout_speedup; static gboolean opt_skip_if_unchanged; static gboolean opt_tar_autocreate_parents; +static char *opt_tar_pathname_filter; static gboolean opt_no_xattrs; +static char *opt_selinux_policy; static gboolean opt_canonical_permissions; static char **opt_trees; static gint opt_owner_uid = -1; @@ -93,8 +96,10 @@ static GOptionEntry options[] = { { "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Set file ownership group id", "GID" }, { "canonical-permissions", 0, 0, G_OPTION_ARG_NONE, &opt_canonical_permissions, "Canonicalize permissions in the same way bare-user does for hardlinked files", NULL }, { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL }, + { "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" }, { "link-checkout-speedup", 0, 0, G_OPTION_ARG_NONE, &opt_link_checkout_speedup, "Optimize for commits of trees composed of hardlinks into the repository", NULL }, { "tar-autocreate-parents", 0, 0, G_OPTION_ARG_NONE, &opt_tar_autocreate_parents, "When loading tar archives, automatically create parent directories as needed", NULL }, + { "tar-pathname-filter", 0, 0, G_OPTION_ARG_STRING, &opt_tar_pathname_filter, "When loading tar archives, use REGEX,REPLACEMENT against path names", "REGEX,REPLACEMENT" }, { "skip-if-unchanged", 0, 0, G_OPTION_ARG_NONE, &opt_skip_if_unchanged, "If the contents are unchanged from previous commit, do nothing", NULL }, { "statoverride", 0, 0, G_OPTION_ARG_FILENAME, &opt_statoverride_file, "File containing list of modifications to make to permissions", "PATH" }, { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" }, @@ -219,6 +224,28 @@ commit_filter (OstreeRepo *self, return OSTREE_REPO_COMMIT_FILTER_ALLOW; } +typedef struct { + GRegex *regex; + const char *replacement; +} TranslatePathnameData; + +/* Implement --tar-pathname-filter */ +static char * +handle_translate_pathname (OstreeRepo *repo, + const struct stat *stbuf, + const char *path, + gpointer user_data) +{ + TranslatePathnameData *tpdata = user_data; + g_autoptr(GError) tmp_error = NULL; + char *ret = + g_regex_replace (tpdata->regex, path, -1, 0, + tpdata->replacement, 0, &tmp_error); + g_assert_no_error (tmp_error); + g_assert (ret); + return ret; +} + static gboolean commit_editor (OstreeRepo *repo, const char *branch, @@ -395,6 +422,7 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError g_autoptr(GHashTable) mode_overrides = NULL; g_autoptr(GHashTable) skip_list = NULL; OstreeRepoCommitModifierFlags flags = 0; + g_autoptr(OstreeSePolicy) policy = NULL; OstreeRepoCommitModifier *modifier = NULL; OstreeRepoTransactionStats stats; struct CommitFilterData filter_data = { 0, }; @@ -459,12 +487,26 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError || opt_owner_gid >= 0 || opt_statoverride_file != NULL || opt_skiplist_file != NULL - || opt_no_xattrs) + || opt_no_xattrs + || opt_selinux_policy) { filter_data.mode_adds = mode_adds; filter_data.skip_list = skip_list; modifier = ostree_repo_commit_modifier_new (flags, commit_filter, &filter_data, NULL); + if (opt_selinux_policy) + { + glnx_fd_close int rootfs_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, opt_selinux_policy, TRUE, &rootfs_dfd, error)) + { + g_prefix_error (error, "selinux-policy: "); + goto out; + } + policy = ostree_sepolicy_new_at (rootfs_dfd, cancellable, error); + if (!policy) + goto out; + ostree_repo_commit_modifier_set_sepolicy (modifier, policy); + } } if (opt_parent) @@ -551,11 +593,50 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError } else if (strcmp (tree_type, "tar") == 0) { - object_to_commit = g_file_new_for_path (tree); - if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, - opt_tar_autocreate_parents, - cancellable, error)) - goto out; + if (!opt_tar_pathname_filter) + { + object_to_commit = g_file_new_for_path (tree); + if (!ostree_repo_write_archive_to_mtree (repo, object_to_commit, mtree, modifier, + opt_tar_autocreate_parents, + cancellable, error)) + goto out; + } + else + { +#ifdef HAVE_LIBARCHIVE + const char *comma = strchr (opt_tar_pathname_filter, ','); + if (!comma) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Missing ',' in --tar-pathname-filter"); + goto out; + } + const char *replacement = comma + 1; + g_autofree char *regexp_text = g_strndup (opt_tar_pathname_filter, comma - opt_tar_pathname_filter); + /* Use new API if we have a pathname filter */ + OstreeRepoImportArchiveOptions opts = { 0, }; + opts.autocreate_parents = opt_tar_autocreate_parents; + opts.translate_pathname = handle_translate_pathname; + g_autoptr(GRegex) regexp = g_regex_new (regexp_text, 0, 0, error); + TranslatePathnameData tpdata = { regexp, replacement }; + if (!regexp) + { + g_prefix_error (error, "--tar-pathname-filter: "); + goto out; + } + opts.translate_pathname_user_data = &tpdata; + g_autoptr(OtAutoArchiveRead) archive = ot_open_archive_read (tree, error); + if (!archive) + goto out; + if (!ostree_repo_import_archive_to_mtree (repo, &opts, archive, mtree, + modifier, cancellable, error)) + goto out; + } +#else + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "This version of ostree is not compiled with libarchive support"); + return FALSE; +#endif } else if (strcmp (tree_type, "ref") == 0) { @@ -699,7 +780,7 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError if (!ostree_repo_commit_transaction (repo, &stats, cancellable, error)) goto out; - /* The default for this option is FALSE, even for archive-z2 repos, + /* The default for this option is FALSE, even for archive repos, * because ostree supports multiple processes committing to the same * repo (but different refs) concurrently, and in fact gnome-continuous * actually does this. In that context it's best to update the summary diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c index 6163b3b1..782fee85 100644 --- a/src/ostree/ot-builtin-config.c +++ b/src/ostree/ot-builtin-config.c @@ -69,7 +69,7 @@ ostree_builtin_config (int argc, char **argv, GCancellable *cancellable, GError g_autofree char *key = NULL; GKeyFile *config = NULL; - context = g_option_context_new ("- Change configuration settings"); + context = g_option_context_new ("(get KEY|set KEY VALUE) - Change repo configuration settings"); if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c index 795fe098..ed357eca 100644 --- a/src/ostree/ot-builtin-fsck.c +++ b/src/ostree/ot-builtin-fsck.c @@ -252,6 +252,7 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError ** g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ if (!ostree_repo_list_collection_refs (repo, NULL, &all_collection_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, cancellable, error)) return FALSE; diff --git a/src/ostree/ot-builtin-init.c b/src/ostree/ot-builtin-init.c index 28f96829..c77f6972 100644 --- a/src/ostree/ot-builtin-init.c +++ b/src/ostree/ot-builtin-init.c @@ -37,7 +37,7 @@ static char *opt_collection_id = NULL; */ static GOptionEntry options[] = { - { "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, archive-z2)", NULL }, + { "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, archive)", NULL }, #ifdef OSTREE_ENABLE_EXPERIMENTAL_API { "collection-id", 0, 0, G_OPTION_ARG_STRING, &opt_collection_id, "Globally unique ID for this repository as an collection of refs for redistribution to other repositories", "COLLECTION-ID" }, diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c index 997d848d..2f66334e 100644 --- a/src/ostree/ot-builtin-prune.c +++ b/src/ostree/ot-builtin-prune.c @@ -59,57 +59,40 @@ delete_commit (OstreeRepo *repo, const char *commit_to_delete, GCancellable *can #ifdef OSTREE_ENABLE_EXPERIMENTAL_API g_autoptr(GHashTable) collection_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ - GHashTableIter hashiter; - gpointer hashkey, hashvalue; - gboolean ret = FALSE; /* Check refs which are not in a collection. */ if (!ostree_repo_list_refs (repo, NULL, &refs, cancellable, error)) - goto out; + return FALSE; - g_hash_table_iter_init (&hashiter, refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + GLNX_HASH_TABLE_FOREACH_KV(refs, const char *, ref, const char *, commit) { - const char *ref = hashkey; - const char *commit = hashvalue; if (g_strcmp0 (commit_to_delete, commit) == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Commit '%s' is referenced by '%s'", commit_to_delete, ref); - goto out; - } + return glnx_throw (error, "Commit '%s' is referenced by '%s'", commit_to_delete, ref); } #ifdef OSTREE_ENABLE_EXPERIMENTAL_API /* And check refs which *are* in a collection. */ - if (!ostree_repo_list_collection_refs (repo, NULL, &collection_refs, cancellable, error)) - goto out; + if (!ostree_repo_list_collection_refs (repo, NULL, &collection_refs, + OSTREE_REPO_LIST_REFS_EXT_EXCLUDE_REMOTES, + cancellable, error)) + return FALSE; - g_hash_table_iter_init (&hashiter, collection_refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + GLNX_HASH_TABLE_FOREACH_KV (collection_refs, const OstreeCollectionRef*, ref, + const char *, commit) { - const OstreeCollectionRef *ref = hashkey; - const char *commit = hashvalue; if (g_strcmp0 (commit_to_delete, commit) == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Commit '%s' is referenced by (%s, %s)", - commit_to_delete, ref->collection_id, ref->ref_name); - goto out; - } + return glnx_throw (error, "Commit '%s' is referenced by (%s, %s)", + commit_to_delete, ref->collection_id, ref->ref_name); } #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ if (!ot_enable_tombstone_commits (repo, error)) - goto out; + return FALSE; if (!ostree_repo_delete_object (repo, OSTREE_OBJECT_TYPE_COMMIT, commit_to_delete, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - - out: - return ret; + return TRUE; } static gboolean @@ -119,7 +102,6 @@ traverse_keep_younger_than (OstreeRepo *repo, const char *checksum, GCancellable *cancellable, GError **error) { g_autofree char *next_checksum = g_strdup (checksum); - g_autoptr(GVariant) commit = NULL; /* This is the first commit in our loop, which has a ref pointing to it. We * don't want to auto-prune it. @@ -130,16 +112,14 @@ traverse_keep_younger_than (OstreeRepo *repo, const char *checksum, while (TRUE) { - guint64 commit_timestamp; - + g_autoptr(GVariant) commit = NULL; if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_COMMIT, next_checksum, &commit, error)) return FALSE; - if (!commit) break; /* This commit was pruned, so we're done */ - commit_timestamp = ostree_commit_get_timestamp (commit); + guint64 commit_timestamp = ostree_commit_get_timestamp (commit); /* Is this commit newer than our --keep-younger-than spec? */ if (commit_timestamp >= ts->tv_sec) { @@ -165,22 +145,13 @@ traverse_keep_younger_than (OstreeRepo *repo, const char *checksum, gboolean ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GOptionContext) context = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("- Search for unreachable objects"); g_autoptr(OstreeRepo) repo = NULL; - g_autofree char *formatted_freed_size = NULL; - OstreeRepoPruneFlags pruneflags = 0; - gint n_objects_total; - gint n_objects_pruned; - guint64 objsize_total; - - context = g_option_context_new ("- Search for unreachable objects"); - if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) - goto out; + return FALSE; if (!opt_no_prune && !ostree_ensure_repo_writable (repo, error)) - goto out; + return FALSE; /* Special handling for explicit commit deletion here - we do this * first. @@ -190,17 +161,18 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * if (opt_no_prune) { ot_util_usage_error (context, "Cannot specify both --delete-commit and --no-prune", error); - goto out; + return FALSE; } if (opt_static_deltas_only) { if(!ostree_repo_prune_static_deltas (repo, opt_delete_commit, cancellable, error)) - goto out; + return FALSE; } else if (!delete_commit (repo, opt_delete_commit, cancellable, error)) - goto out; + return FALSE; } + OstreeRepoPruneFlags pruneflags = 0; if (opt_refs_only) pruneflags |= OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY; if (opt_no_prune) @@ -210,12 +182,15 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * * prune API - both to avoid code duplication, and to keep it run from the * test suite. */ + gint n_objects_total; + gint n_objects_pruned; + guint64 objsize_total; if (!(opt_retain_branch_depth || opt_keep_younger_than)) { if (!ostree_repo_prune (repo, pruneflags, opt_depth, &n_objects_total, &n_objects_pruned, &objsize_total, cancellable, error)) - goto out; + return FALSE; } else { @@ -232,11 +207,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * if (opt_keep_younger_than) { if (!parse_datetime (&keep_younger_than_ts, opt_keep_younger_than, NULL)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Could not parse '%s'", opt_keep_younger_than); - goto out; - } + return glnx_throw (error, "Could not parse '%s'", opt_keep_younger_than); } for (char **iter = opt_retain_branch_depth; iter && *iter; iter++) @@ -244,34 +215,19 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * /* bd should look like BRANCH=DEPTH where DEPTH is an int */ const char *bd = *iter; const char *eq = strchr (bd, '='); - const char *depthstr; - gint64 depth; - char *endptr; - if (!eq) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid value %s, must specify BRANCH=DEPTH", - bd); - goto out; - } - depthstr = eq + 1; + return glnx_throw (error, "Invalid value %s, must specify BRANCH=DEPTH", bd); + + const char *depthstr = eq + 1; errno = EPERM; - depth = g_ascii_strtoll (depthstr, &endptr, 10); + char *endptr; + gint64 depth = g_ascii_strtoll (depthstr, &endptr, 10); if (depth == 0) { if (errno == EINVAL) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Out of range depth %s", depthstr); - goto out; - } + return glnx_throw (error, "Out of range depth %s", depthstr); else if (endptr == depthstr) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid depth %s", depthstr); - goto out; - } + return glnx_throw (error, "Invalid depth %s", depthstr); } g_hash_table_insert (retain_branch_depth, g_strndup (bd, eq - bd), GINT_TO_POINTER ((int)depth)); @@ -302,7 +258,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * &keep_younger_than_ts, reachable, cancellable, error)) - goto out; + return FALSE; /* Okay, we handled the younger-than case; the other * two fall through to plain depth-based handling below. @@ -325,12 +281,11 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * &n_objects_pruned, &objsize_total, cancellable, error)) - goto out; + return FALSE; } } - formatted_freed_size = g_format_size_full (objsize_total, 0); - + g_autofree char *formatted_freed_size = g_format_size_full (objsize_total, 0); g_print ("Total objects: %u\n", n_objects_total); if (n_objects_pruned == 0) g_print ("No unreachable objects\n"); @@ -341,7 +296,5 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * g_print ("Deleted %u objects, %s freed\n", n_objects_pruned, formatted_freed_size); - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c index a4595768..34115a01 100644 --- a/src/ostree/ot-builtin-pull-local.c +++ b/src/ostree/ot-builtin-pull-local.c @@ -47,7 +47,7 @@ static int opt_depth = 0; static GOptionEntry options[] = { { "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" }, { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, - { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust source", NULL }, + { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not verify checksums of local sources (always enabled for HTTP pulls)", NULL }, { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, { "gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_gpg_verify, "GPG verify commits (must specify --remote)", NULL }, diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c index 37cfd143..119e6656 100644 --- a/src/ostree/ot-builtin-pull.c +++ b/src/ostree/ot-builtin-pull.c @@ -34,6 +34,7 @@ static gboolean opt_dry_run; static gboolean opt_disable_static_deltas; static gboolean opt_require_static_deltas; static gboolean opt_untrusted; +static gboolean opt_timestamp_check; static gboolean opt_bareuseronly_files; static char** opt_subpaths; static char** opt_http_headers; @@ -54,9 +55,9 @@ static GOptionEntry options[] = { { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, { "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_disable_static_deltas, "Do not use static deltas", NULL }, { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, - { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL }, + { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror and fetches all refs if none provided", NULL }, { "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL }, - { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL }, + { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not verify checksums of local sources (always enabled for HTTP pulls)", NULL }, { "bareuseronly-files", 0, 0, G_OPTION_ARG_NONE, &opt_bareuseronly_files, "Reject regular files with mode outside of 0775 (world writable, suid, etc.)", NULL }, { "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL }, { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" }, @@ -64,6 +65,7 @@ static GOptionEntry options[] = { { "http-header", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_http_headers, "Add NAME=VALUE as HTTP header to all requests", "NAME=VALUE" }, { "update-frequency", 0, 0, G_OPTION_ARG_INT, &opt_frequency, "Sets the update frequency, in milliseconds (0=1000ms) (default: 0)", "FREQUENCY" }, { "localcache-repo", 'L', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_localcache_repos, "Add REPO as local cache source for objects during this pull", "REPO" }, + { "timestamp-check", 'T', 0, G_OPTION_ARG_NONE, &opt_timestamp_check, "Require fetched commits to have newer timestamps", NULL }, { NULL } }; @@ -288,6 +290,9 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError ** g_variant_builder_add (&builder, "{s@v}", "dry-run", g_variant_new_variant (g_variant_new_boolean (opt_dry_run))); + if (opt_timestamp_check) + g_variant_builder_add (&builder, "{s@v}", "timestamp-check", + g_variant_new_variant (g_variant_new_boolean (opt_timestamp_check))); if (override_commit_ids) g_variant_builder_add (&builder, "{s@v}", "override-commit-ids", diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c index ead4ba48..3742f050 100644 --- a/src/ostree/ot-builtin-refs.c +++ b/src/ostree/ot-builtin-refs.c @@ -64,7 +64,8 @@ do_ref_with_collections (OstreeRepo *repo, if (!ostree_repo_list_collection_refs (repo, (!opt_create) ? refspec_prefix : NULL, - &refs, cancellable, error)) + &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, + cancellable, error)) goto out; if (!opt_delete && !opt_create) diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c index dd999c01..9d290d09 100644 --- a/src/ostree/ot-builtin-remote.c +++ b/src/ostree/ot-builtin-remote.c @@ -115,7 +115,8 @@ ostree_builtin_remote (int argc, char **argv, GCancellable *cancellable, GError /* This will not return for some options (e.g. --version). */ if (ostree_option_context_parse (context, NULL, &argc, &argv, - OSTREE_BUILTIN_FLAG_NONE, NULL, cancellable, error)) + OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, + error)) { if (subcommand_name == NULL) { diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c index 7fbb1c7f..c64dbbf5 100644 --- a/src/ostree/ot-builtin-static-delta.c +++ b/src/ostree/ot-builtin-static-delta.c @@ -100,48 +100,41 @@ static_delta_usage (char **argv, else print_func = g_print; - print_func ("usage: ostree static-delta\n"); - print_func ("Builtin commands:\n"); + print_func ("Usage:\n"); + print_func (" ostree static-delta [OPTION...] COMMAND\n\n"); + print_func ("Builtin \"static-delta\" Commands:\n"); while (command->name) { print_func (" %s\n", command->name); command++; } + + print_func ("\n"); } static gboolean ot_static_delta_builtin_list (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GPtrArray) delta_names = NULL; - guint i; - g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(GOptionContext) context = g_option_context_new ("- list static delta files"); + if (!ostree_option_context_parse (context, list_options, &argc, &argv, + OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) + return FALSE; - context = g_option_context_new ("LIST - list static delta files"); - - if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) - goto out; - + g_autoptr(GPtrArray) delta_names = NULL; if (!ostree_repo_list_static_delta_names (repo, &delta_names, cancellable, error)) - goto out; - + return FALSE; + if (delta_names->len == 0) - { - g_print ("(No static deltas)\n"); - } + g_print ("(No static deltas)\n"); else { - for (i = 0; i < delta_names->len; i++) - { - g_print ("%s\n", (char*)delta_names->pdata[i]); - } + for (guint i = 0; i < delta_names->len; i++) + g_print ("%s\n", (char*)delta_names->pdata[i]); } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -152,7 +145,7 @@ ot_static_delta_builtin_show (int argc, char **argv, GCancellable *cancellable, g_autoptr(OstreeRepo) repo = NULL; const char *delta_id = NULL; - context = g_option_context_new ("SHOW - Dump information on a delta"); + context = g_option_context_new ("- Dump information on a delta"); if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -182,7 +175,7 @@ ot_static_delta_builtin_delete (int argc, char **argv, GCancellable *cancellable g_autoptr(OstreeRepo) repo = NULL; const char *delta_id = NULL; - context = g_option_context_new ("DELETE - Remove a delta"); + context = g_option_context_new ("- Remove a delta"); if (!ostree_option_context_parse (context, list_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -212,7 +205,7 @@ ot_static_delta_builtin_generate (int argc, char **argv, GCancellable *cancellab g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeRepo) repo = NULL; - context = g_option_context_new ("GENERATE [TO] - Generate static delta files"); + context = g_option_context_new ("[TO] - Generate static delta files"); if (!ostree_option_context_parse (context, generate_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -363,7 +356,7 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, GCancellable *canc g_autoptr(GOptionContext) context = NULL; g_autoptr(OstreeRepo) repo = NULL; - context = g_option_context_new ("APPLY-OFFLINE - Apply static delta file"); + context = g_option_context_new ("- Apply static delta file"); if (!ostree_option_context_parse (context, apply_offline_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; @@ -397,13 +390,9 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, GCancellable *canc gboolean ostree_builtin_static_delta (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - OstreeCommand *command = NULL; - const char *cmdname = NULL; - int i; gboolean want_help = FALSE; - - for (i = 1; i < argc; i++) + const char *cmdname = NULL; + for (int i = 1; i < argc; i++) { if (argv[i][0] != '-') { @@ -420,11 +409,10 @@ ostree_builtin_static_delta (int argc, char **argv, GCancellable *cancellable, G if (!cmdname && !want_help) { static_delta_usage (argv, TRUE); - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No command specified"); - goto out; + return glnx_throw (error, "No command specified"); } + OstreeCommand *command = NULL; if (cmdname) { command = static_delta_subcommands; @@ -439,22 +427,17 @@ ostree_builtin_static_delta (int argc, char **argv, GCancellable *cancellable, G if (want_help && command == NULL) { static_delta_usage (argv, FALSE); - ret = TRUE; - goto out; + return TRUE; /* Note early return */ } if (!command->fn) { - g_autofree char *msg = g_strdup_printf ("Unknown command '%s'", cmdname); static_delta_usage (argv, TRUE); - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, msg); - goto out; + return glnx_throw (error, "Unknown \"static-delta\" subcommand '%s'", cmdname); } - if (!command->fn (argc, argv, cancellable, error)) - goto out; + g_autofree char *prgname = g_strdup_printf ("%s %s", g_get_prgname (), cmdname); + g_set_prgname (prgname); - ret = TRUE; - out: - return ret; + return command->fn (argc, argv, cancellable, error); } diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index 4d47985b..a6ddfe74 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -78,15 +78,11 @@ int ostree_usage (OstreeCommand *commands, gboolean is_error) { - g_autoptr(GOptionContext) context = NULL; - g_autofree char *help; - - context = ostree_option_context_new_with_commands (commands); - + g_autoptr(GOptionContext) context = + ostree_option_context_new_with_commands (commands); g_option_context_add_main_entries (context, global_entries, NULL); - help = g_option_context_get_help (context, FALSE, NULL); - + g_autofree char *help = g_option_context_get_help (context, FALSE, NULL); if (is_error) g_printerr ("%s", help); else @@ -185,13 +181,10 @@ ostree_run (int argc, { g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, "Unknown command '%s'", command_name); - ostree_usage (commands, TRUE); } } - help = g_option_context_get_help (context, FALSE, NULL); - g_printerr ("%s", help); - + ostree_usage (commands, TRUE); goto out; } @@ -381,9 +374,17 @@ ostree_admin_option_context_parse (GOptionContext *context, g_option_context_add_main_entries (context, global_admin_entries, NULL); - if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error)) + if (!ostree_option_context_parse (context, main_entries, argc, argv, + OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error)) return FALSE; + if (!opt_print_current_dir && (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT)) + { + g_assert_null (out_sysroot); + /* Early return if no sysroot is requested */ + return TRUE; + } + g_autoptr(GFile) sysroot_path = NULL; if (opt_sysroot != NULL) sysroot_path = g_file_new_for_path (opt_sysroot); @@ -391,12 +392,24 @@ ostree_admin_option_context_parse (GOptionContext *context, g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (sysroot_path); g_signal_connect (sysroot, "journal-msg", G_CALLBACK (on_sysroot_journal_msg), NULL); + if ((flags & OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED) == 0) + { + /* Released when sysroot is finalized, or on process exit */ + if (!ot_admin_sysroot_lock (sysroot, error)) + return FALSE; + } + + if (!ostree_sysroot_load (sysroot, cancellable, error)) + return FALSE; + if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER) { - GFile *path = ostree_sysroot_get_path (sysroot); + OstreeDeployment *booted = ostree_sysroot_get_booted_deployment (sysroot); - /* If sysroot path is "/" then user must be root. */ - if (!g_file_has_parent (path, NULL) && getuid () != 0) + /* Only require root if we're manipulating a booted sysroot. (Mostly + * useful for the test suite) + */ + if (booted && getuid () != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "You must be root to perform this command"); @@ -411,9 +424,6 @@ ostree_admin_option_context_parse (GOptionContext *context, g_autoptr(GFile) deployment_file = NULL; g_autofree char *deployment_path = NULL; - if (!ostree_sysroot_load (sysroot, cancellable, error)) - return FALSE; - deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) return glnx_throw (error, "Unable to find a deployment in sysroot"); @@ -433,13 +443,6 @@ ostree_admin_option_context_parse (GOptionContext *context, exit (EXIT_SUCCESS); } - if ((flags & OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED) == 0) - { - /* Released when sysroot is finalized, or on process exit */ - if (!ot_admin_sysroot_lock (sysroot, error)) - return FALSE; - } - if (out_sysroot) *out_sysroot = g_steal_pointer (&sysroot); diff --git a/src/ostree/ot-main.h b/src/ostree/ot-main.h index c7db4a07..ddf52959 100644 --- a/src/ostree/ot-main.h +++ b/src/ostree/ot-main.h @@ -33,8 +33,9 @@ typedef enum { typedef enum { OSTREE_ADMIN_BUILTIN_FLAG_NONE = 0, - OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER = 1 << 0, - OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED = 1 << 1 + OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER = (1 << 0), + OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED = (1 << 1), + OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT = (1 << 2), } OstreeAdminBuiltinFlags; typedef struct { diff --git a/src/rofiles-fuse/main.c b/src/rofiles-fuse/main.c index 88cdba6c..6deaa6d0 100644 --- a/src/rofiles-fuse/main.c +++ b/src/rofiles-fuse/main.c @@ -198,26 +198,42 @@ callback_link (const char *from, const char *to) return 0; } -static gboolean -stbuf_is_regfile_hardlinked (struct stat *stbuf) +/* Check whether @stbuf refers to a hardlinked regfile or symlink, and if so + * return -EROFS. Otherwise return 0. + */ +static int +can_write_stbuf (struct stat *stbuf) { - return S_ISREG (stbuf->st_mode) && stbuf->st_nlink > 1; + /* If it's not a regular file or symlink, ostree won't hardlink it, so allow + * writes - it might be a FIFO or device that somehow + * ended up underneath our mount. + */ + if (!(S_ISREG (stbuf->st_mode) || S_ISLNK (stbuf->st_mode))) + return 0; + /* If the object isn't hardlinked, it's OK to write */ + if (stbuf->st_nlink <= 1) + return 0; + /* Otherwise, it's a hardlinked file or symlink; it must be + * immutable. + */ + return -EROFS; } +/* Check whether @path refers to a hardlinked regfile or symlink, and if so + * return -EROFS. Otherwise return 0. + */ static int can_write (const char *path) { struct stat stbuf; - if (fstatat (basefd, path, &stbuf, 0) == -1) + if (fstatat (basefd, path, &stbuf, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOENT) return 0; else return -errno; } - if (stbuf_is_regfile_hardlinked (&stbuf)) - return -EROFS; - return 0; + return can_write_stbuf (&stbuf); } #define VERIFY_WRITE(path) do { \ @@ -231,6 +247,10 @@ callback_chmod (const char *path, mode_t mode) { path = ENSURE_RELPATH (path); VERIFY_WRITE(path); + /* Note we can't use AT_SYMLINK_NOFOLLOW yet; + * https://marc.info/?l=linux-kernel&m=148830147803162&w=2 + * https://marc.info/?l=linux-fsdevel&m=149193779929561&w=2 + */ if (fchmodat (basefd, path, mode, 0) != 0) return -errno; return 0; @@ -241,7 +261,7 @@ callback_chown (const char *path, uid_t uid, gid_t gid) { path = ENSURE_RELPATH (path); VERIFY_WRITE(path); - if (fchownat (basefd, path, uid, gid, 0) != 0) + if (fchownat (basefd, path, uid, gid, AT_SYMLINK_NOFOLLOW) != 0) return -errno; return 0; } @@ -254,7 +274,7 @@ callback_truncate (const char *path, off_t size) path = ENSURE_RELPATH (path); VERIFY_WRITE(path); - fd = openat (basefd, path, O_WRONLY); + fd = openat (basefd, path, O_NOFOLLOW|O_WRONLY); if (fd == -1) return -errno; @@ -312,10 +332,11 @@ do_open (const char *path, mode_t mode, struct fuse_file_info *finfo) return -errno; } - if (stbuf_is_regfile_hardlinked (&stbuf)) + int r = can_write_stbuf (&stbuf); + if (r != 0) { (void) close (fd); - return -EROFS; + return r; } /* Handle O_TRUNC here only after verifying hardlink state */ @@ -433,7 +454,7 @@ callback_access (const char *path, int mode) * before trying to do an unlink. So...we'll just lie about * writable access here. */ - if (faccessat (basefd, path, mode, 0) == -1) + if (faccessat (basefd, path, mode, AT_SYMLINK_NOFOLLOW) == -1) return -errno; return 0; } diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 55de7235..f5d33a6f 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -19,6 +19,8 @@ set -euo pipefail +echo "1..$((22 + ${extra_admin_tests:-0}))" + function validate_bootloader() { cd ${test_tmpdir}; bootloader="" @@ -33,6 +35,13 @@ function validate_bootloader() { cd - } +# Test generate_deployment_refs() +assert_ostree_deployment_refs() { + ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo refs ostree | sort > ostree-refs.txt + (for v in "$@"; do echo $v; done) | sort > ostree-refs-expected.txt + diff -u ostree-refs{-expected,}.txt +} + orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) ${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) @@ -53,6 +62,7 @@ assert_file_has_content curdir ^`pwd`/sysroot/ostree/deploy/testos/deploy/${rev} echo "ok --print-current-dir" +# Test layout of bootloader config and refs assert_not_has_dir sysroot/boot/loader.0 assert_has_dir sysroot/boot/loader.1 assert_has_dir sysroot/ostree/boot.1.1 @@ -62,9 +72,8 @@ assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'option assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 1/1/0 ${CMD_PREFIX} ostree admin status - - echo "ok layout" orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) @@ -82,6 +91,7 @@ assert_not_has_dir sysroot/ostree/boot.1.1 assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/boot.0/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 0/1/{0,1} ${CMD_PREFIX} ostree admin status validate_bootloader @@ -94,6 +104,7 @@ assert_not_has_dir sysroot/boot/loader.1 # But swap subbootversion assert_has_dir sysroot/ostree/boot.0.0 assert_not_has_dir sysroot/ostree/boot.0.1 +assert_ostree_deployment_refs 0/0/{0,1} ${CMD_PREFIX} ostree admin status validate_bootloader @@ -108,6 +119,7 @@ assert_has_file sysroot/boot/loader/entries/ostree-testos-1.conf assert_has_file sysroot/boot/loader/entries/ostree-otheros-0.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.1/etc/os-release 'NAME=TestOS' assert_file_has_content sysroot/ostree/deploy/otheros/deploy/${rev}.0/etc/os-release 'NAME=TestOS' +assert_ostree_deployment_refs 1/1/{0,1,2} ${CMD_PREFIX} ostree admin status validate_bootloader @@ -121,6 +133,7 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.2/etc/os-rele assert_has_file sysroot/boot/loader/entries/ostree-testos-2.conf assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/os-release 'NAME=TestOS' ${CMD_PREFIX} ostree admin status +assert_ostree_deployment_refs 0/1/{0,1,2,3} validate_bootloader echo "ok fourth deploy (retain)" @@ -130,6 +143,8 @@ rm -r sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/testdirectory rm sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/aconfigfile ln -s /ENOENT sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/a-new-broken-symlink ${CMD_PREFIX} ostree admin deploy --retain --os=testos testos:testos/buildmaster/x86_64-runtime +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 linktarget=$(readlink sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-broken-symlink) test "${linktarget}" = /ENOENT assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/os-release 'NAME=TestOS' @@ -138,9 +153,36 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/a-new-c assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/aconfigfile ${CMD_PREFIX} ostree admin status validate_bootloader - echo "ok deploy with modified /etc" +# we now have 5 deployments, let's bring that back down to 1 +for i in $(seq 4); do + ${CMD_PREFIX} ostree admin undeploy 0 +done +assert_has_file sysroot/boot/loader/entries/ostree-testos-0.conf +assert_not_has_file sysroot/boot/loader/entries/ostree-testos-1.conf +assert_not_has_file sysroot/boot/loader/entries/ostree-otheros-1.conf +${CMD_PREFIX} ostree admin deploy --not-as-default --os=otheros testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/loader.0 +assert_not_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-testos-0.conf +assert_has_file sysroot/boot/loader/entries/ostree-otheros-1.conf +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok deploy --not-as-default" + +${CMD_PREFIX} ostree admin deploy --retain-rollback --os=otheros testos:testos/buildmaster/x86_64-runtime +assert_not_has_dir sysroot/boot/loader.0 +assert_has_dir sysroot/boot/loader.1 +assert_has_file sysroot/boot/loader/entries/ostree-otheros-0.conf +assert_has_file sysroot/boot/loader/entries/ostree-testos-1.conf +assert_has_file sysroot/boot/loader/entries/ostree-otheros-2.conf +${CMD_PREFIX} ostree admin status +validate_bootloader + +echo "ok deploy --retain-rollback" + os_repository_new_commit ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime newrev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos:testos/buildmaster/x86_64-runtime) @@ -153,7 +195,7 @@ assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/os-r assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/a-new-default-config-file "a new default config file" assert_file_has_content sysroot/ostree/deploy/testos/deploy/${newrev}.0/etc/new-default-dir/moo "a new default dir and file" # And persist /etc changes from before -assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.3/etc/aconfigfile +assert_not_has_file sysroot/ostree/deploy/testos/deploy/${rev}.4/etc/aconfigfile ${CMD_PREFIX} ostree admin status validate_bootloader @@ -250,6 +292,15 @@ assert_not_file_has_content sysroot/ostree/repo/config remote-test-nonphysical assert_file_has_content ${deployment}/etc/ostree/remotes.d/remote-test-nonphysical.conf testos-repo echo "ok remote add nonphysical sysroot" +# Test that setting add-remotes-config-dir to false adds a remote in the +# config file rather than the remotes config dir even though this is a +# "system" repo. +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set core.add-remotes-config-dir false +${CMD_PREFIX} ostree --sysroot=${deployment} remote add --set=gpg-verify=false remote-test-config-dir file://$(pwd)/testos-repo +assert_not_has_file ${deployment}/etc/ostree/remotes.d/remote-test-config-dir.conf testos-repo +assert_file_has_content sysroot/ostree/repo/config remote-test-config-dir +echo "ok remote add nonphysical sysroot add-remotes-config-dir false" + if env OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},test-fifreeze" \ ${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime 2>err.txt; then fatal "fifreeze-test exited successfully?" diff --git a/tests/basic-test.sh b/tests/basic-test.sh index 9ae26f47..5058af1d 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -19,13 +19,14 @@ set -euo pipefail -echo "1..$((70 + ${extra_basic_tests:-0}))" +echo "1..$((72 + ${extra_basic_tests:-0}))" $CMD_PREFIX ostree --version > version.yaml python -c 'import yaml; yaml.safe_load(open("version.yaml"))' echo "ok yaml version" CHECKOUT_U_ARG="" +CHECKOUT_H_ARGS="-H" COMMIT_ARGS="" DIFF_ARGS="" if is_bare_user_only_repo repo; then @@ -36,6 +37,11 @@ if is_bare_user_only_repo repo; then DIFF_ARGS="--owner-uid=0 --owner-gid=0 --no-xattrs" # Also, since we can't check out uid=0 files we need to check out in user mode CHECKOUT_U_ARG="-U" + CHECKOUT_H_ARGS="-U -H" +else + if grep -E -q '^mode=bare-user' repo/config; then + CHECKOUT_H_ARGS="-U -H" + fi fi validate_checkout_basic() { @@ -106,19 +112,23 @@ echo "ok shortened checksum" (cd repo && ${CMD_PREFIX} ostree rev-parse test2) echo "ok repo-in-cwd" -rm test-repo -rf -ostree_repo_init test-repo --mode=bare-user -ostree_repo_init test-repo --mode=bare-user -rm test-repo -rf -echo "ok repo-init on existing repo" +if ! skip_one_without_user_xattrs; then + rm test-repo -rf + ostree_repo_init test-repo --mode=bare-user + ostree_repo_init test-repo --mode=bare-user + rm test-repo -rf + echo "ok repo-init on existing repo" +fi -rm test-repo -rf -ostree_repo_init test-repo --mode=bare-user -${CMD_PREFIX} ostree --repo=test-repo refs -rm -rf test-repo/tmp -${CMD_PREFIX} ostree --repo=test-repo refs -assert_has_dir test-repo/tmp -echo "ok autocreate tmp" +if ! skip_one_without_user_xattrs; then + rm test-repo -rf + ostree_repo_init test-repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=test-repo refs + rm -rf test-repo/tmp + ${CMD_PREFIX} ostree --repo=test-repo refs + assert_has_dir test-repo/tmp + echo "ok autocreate tmp" +fi rm checkout-test2 -rf $OSTREE checkout test2 checkout-test2 @@ -262,27 +272,31 @@ cd ${test_tmpdir} assert_file_has_content diff-test2-2 'M */four$' echo "ok diff file changing type" -cd ${test_tmpdir} -mkdir repo2 -# Use a different mode to test hardlinking metadata only -if grep -q 'mode=archive' repo/config || is_bare_user_only_repo repo; then - opposite_mode=bare-user -else - opposite_mode=archive +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + mkdir repo2 + # Use a different mode to test hardlinking metadata only + if grep -q 'mode=archive' repo/config || is_bare_user_only_repo repo; then + opposite_mode=bare-user + else + opposite_mode=archive + fi + ostree_repo_init repo2 --mode=$opposite_mode + ${CMD_PREFIX} ostree --repo=repo2 pull-local repo + test2_commitid=$(${CMD_PREFIX} ostree --repo=repo rev-parse test2) + test2_commit_relpath=/objects/${test2_commitid:0:2}/${test2_commitid:2}.commit + assert_files_hardlinked repo/${test2_commit_relpath} repo2/${test2_commit_relpath} + echo "ok pull-local (hardlinking metadata)" fi -ostree_repo_init repo2 --mode=$opposite_mode -${CMD_PREFIX} ostree --repo=repo2 pull-local repo -test2_commitid=$(${CMD_PREFIX} ostree --repo=repo rev-parse test2) -test2_commit_relpath=/objects/${test2_commitid:0:2}/${test2_commitid:2}.commit -assert_files_hardlinked repo/${test2_commit_relpath} repo2/${test2_commit_relpath} -echo "ok pull-local (hardlinking metadata)" -cd ${test_tmpdir} -rm repo2 -rf && mkdir repo2 -ostree_repo_init repo2 --mode=$opposite_mode -${CMD_PREFIX} ostree --repo=repo2 pull-local --bareuseronly-files repo test2 -${CMD_PREFIX} ostree --repo=repo2 fsck -q -echo "ok pull-local --bareuseronly-files" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo2 -rf && mkdir repo2 + ostree_repo_init repo2 --mode=$opposite_mode + ${CMD_PREFIX} ostree --repo=repo2 pull-local --bareuseronly-files repo test2 + ${CMD_PREFIX} ostree --repo=repo2 fsck -q + echo "ok pull-local --bareuseronly-files" +fi # This is mostly a copy of the suid test in test-basic-user-only.sh, # but for the `pull --bareuseronly-files` case. @@ -303,11 +317,13 @@ fi assert_file_has_content err.txt 'object.*\.file: invalid mode.*with bits 040.*' echo "ok pull-local (bareuseronly files)" -cd ${test_tmpdir} -${CMD_PREFIX} ostree --repo=repo2 checkout ${CHECKOUT_U_ARG} test2 test2-checkout-from-local-clone -cd test2-checkout-from-local-clone -assert_file_has_content yet/another/tree/green 'leaf' -echo "ok local clone checkout" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=repo2 checkout ${CHECKOUT_U_ARG} test2 test2-checkout-from-local-clone + cd test2-checkout-from-local-clone + assert_file_has_content yet/another/tree/green 'leaf' + echo "ok local clone checkout" +fi $OSTREE checkout -U test2 checkout-user-test2 echo "ok user checkout" @@ -459,6 +475,57 @@ assert_file_has_content checkout-test-union-add/union-add-test 'existing file fo assert_file_has_content checkout-test-union-add/union-add-test2 'another file for union add testing' echo "ok checkout union add" +# Test --union-identical +# Prepare data: +cd ${test_tmpdir} +for x in $(seq 3); do + mkdir -p pkg${x}/usr/{bin,share/licenses} + # Separate binaries and symlinks + echo 'binary for pkg'${x} > pkg${x}/usr/bin/pkg${x} + ln -s pkg${x} pkg${x}/usr/bin/link${x} + # But they share the GPL + echo 'this is the GPL' > pkg${x}/usr/share/licenses/COPYING + ln -s COPYING pkg${x}/usr/share/licenses/LICENSE + $OSTREE commit -b union-identical-pkg${x} --tree=dir=pkg${x} +done +rm union-identical-test -rf +for x in $(seq 3); do + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg${x} union-identical-test +done +if $OSTREE checkout ${CHECKOUT_H_ARGS/-H/} --union-identical union-identical-pkg${x} union-identical-test-tmp 2>err.txt; then + fatal "--union-identical without -H" +fi +assert_file_has_content err.txt "error:.*--union-identical requires --require-hardlinks" +for x in $(seq 3); do + for v in pkg link; do + assert_file_has_content union-identical-test/usr/bin/${v}${x} "binary for pkg"${x} + done + for v in COPYING LICENSE; do + assert_file_has_content union-identical-test/usr/share/licenses/${v} GPL + done +done +echo "ok checkout union identical merges" + +# Make conflicting packages, one with regfile, one with symlink +mkdir -p pkg-conflict1bin/usr/{bin,share/licenses} +echo 'binary for pkg-conflict1bin' > pkg-conflict1bin/usr/bin/pkg1 +echo 'this is the GPL' > pkg-conflict1bin/usr/share/licenses/COPYING +$OSTREE commit -b union-identical-conflictpkg1bin --tree=dir=pkg-conflict1bin +mkdir -p pkg-conflict1link/usr/{bin,share/licenses} +ln -s somewhere-else > pkg-conflict1link/usr/bin/pkg1 +echo 'this is the GPL' > pkg-conflict1link/usr/share/licenses/COPYING +$OSTREE commit -b union-identical-conflictpkg1link --tree=dir=pkg-conflict1link + +for v in bin link; do + rm union-identical-test -rf + $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-pkg1 union-identical-test + if $OSTREE checkout ${CHECKOUT_H_ARGS} --union-identical union-identical-conflictpkg1${v} union-identical-test 2>err.txt; then + fatal "union identical $v succeeded?" + fi + assert_file_has_content err.txt 'error:.*File exists' +done +echo "ok checkout union identical conflicts" + cd ${test_tmpdir} rm files -rf && mkdir files mkdir files/worldwritable-dir @@ -496,24 +563,28 @@ cd ${test_tmpdir} $OSTREE checkout test2 --allow-noent --subpath /enoent 2>/dev/null echo "ok subdir noent" -cd ${test_tmpdir} -mkdir repo3 -ostree_repo_init repo3 --mode=bare-user -${CMD_PREFIX} ostree --repo=repo3 pull-local --remote=aremote repo test2 -${CMD_PREFIX} ostree --repo=repo3 rev-parse aremote/test2 -echo "ok pull-local with --remote arg" - -cd ${test_tmpdir} -${CMD_PREFIX} ostree --repo=repo3 prune -find repo3/objects -name '*.commit' > objlist-before-prune -rm repo3/refs/heads/* repo3/refs/mirrors/* repo3/refs/remotes/* -rf -${CMD_PREFIX} ostree --repo=repo3 prune --refs-only -find repo3/objects -name '*.commit' > objlist-after-prune -if cmp -s objlist-before-prune objlist-after-prune; then - fatal "Prune didn't delete anything!" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + mkdir repo3 + ostree_repo_init repo3 --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo3 pull-local --remote=aremote repo test2 + ${CMD_PREFIX} ostree --repo=repo3 rev-parse aremote/test2 + echo "ok pull-local with --remote arg" +fi + +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + ${CMD_PREFIX} ostree --repo=repo3 prune + find repo3/objects -name '*.commit' > objlist-before-prune + rm repo3/refs/heads/* repo3/refs/mirrors/* repo3/refs/remotes/* -rf + ${CMD_PREFIX} ostree --repo=repo3 prune --refs-only + find repo3/objects -name '*.commit' > objlist-after-prune + if cmp -s objlist-before-prune objlist-after-prune; then + fatal "Prune didn't delete anything!" + fi + rm repo3 objlist-before-prune objlist-after-prune -rf + echo "ok prune" fi -rm repo3 objlist-before-prune objlist-after-prune -rf -echo "ok prune" cd ${test_tmpdir} rm repo3 -rf @@ -597,14 +668,16 @@ $OSTREE show --print-detached-metadata-key=SIGNATURE test2 > test2-meta assert_file_has_content test2-meta "HANCOCK" echo "ok metadata commit with strings" -cd ${test_tmpdir} -rm repo2 -rf -mkdir repo2 -ostree_repo_init repo2 --mode=bare-user -${CMD_PREFIX} ostree --repo=repo2 pull-local repo -${CMD_PREFIX} ostree --repo=repo2 show --print-detached-metadata-key=SIGNATURE test2 > test2-meta -assert_file_has_content test2-meta "HANCOCK" -echo "ok pull-local after commit metadata" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo2 -rf + mkdir repo2 + ostree_repo_init repo2 --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo2 pull-local repo + ${CMD_PREFIX} ostree --repo=repo2 show --print-detached-metadata-key=SIGNATURE test2 > test2-meta + assert_file_has_content test2-meta "HANCOCK" + echo "ok pull-local after commit metadata" +fi cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=repo remote --set=tls-permissive=true add aremote http://remote.example.com/repo testos/buildmaster/x86_64-runtime diff --git a/tests/libostreetest.c b/tests/libostreetest.c index 2fb83f51..f1a01e68 100644 --- a/tests/libostreetest.c +++ b/tests/libostreetest.c @@ -33,9 +33,7 @@ gboolean ot_test_run_libtest (const char *cmd, GError **error) { - gboolean ret = FALSE; const char *srcdir = g_getenv ("G_TEST_SRCDIR"); - int estatus; g_autoptr(GPtrArray) argv = g_ptr_array_new (); g_autoptr(GString) cmdstr = g_string_new (""); @@ -50,53 +48,39 @@ ot_test_run_libtest (const char *cmd, GError **error) g_ptr_array_add (argv, cmdstr->str); g_ptr_array_add (argv, NULL); + int estatus; if (!g_spawn_sync (NULL, (char**)argv->pdata, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, NULL, &estatus, error)) - goto out; - + return FALSE; if (!g_spawn_check_exit_status (estatus, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } OstreeRepo * ot_test_setup_repo (GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; + if (!ot_test_run_libtest ("setup_test_repository archive", error)) + return NULL; + g_autoptr(GFile) repo_path = g_file_new_for_path ("repo"); - glnx_unref_object OstreeRepo* ret_repo = NULL; - - if (!ot_test_run_libtest ("setup_test_repository archive-z2", error)) - goto out; - - ret_repo = ostree_repo_new (repo_path); - + g_autoptr(OstreeRepo) ret_repo = ostree_repo_new (repo_path); if (!ostree_repo_open (ret_repo, cancellable, error)) - goto out; + return NULL; - ret = TRUE; - out: - if (ret) - return g_steal_pointer (&ret_repo); - return NULL; + return g_steal_pointer (&ret_repo); } OstreeSysroot * ot_test_setup_sysroot (GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GFile) sysroot_path = g_file_new_for_path ("sysroot"); - glnx_unref_object OstreeSysroot *ret_sysroot = NULL; + if (!ot_test_run_libtest ("setup_os_repository \"archive\" \"syslinux\"", error)) + return FALSE; + struct statfs stbuf; - - if (!ot_test_run_libtest ("setup_os_repository \"archive-z2\" \"syslinux\"", error)) - goto out; - { g_autoptr(GString) buf = g_string_new ("mutable-deployments"); if (statfs ("/", &stbuf) < 0) return glnx_null_throw_errno (error); @@ -113,11 +97,6 @@ ot_test_setup_sysroot (GCancellable *cancellable, g_setenv ("OSTREE_SYSROOT_DEBUG", buf->str, TRUE); } - ret_sysroot = ostree_sysroot_new (sysroot_path); - - ret = TRUE; - out: - if (ret) - return g_steal_pointer (&ret_sysroot); - return NULL; + g_autoptr(GFile) sysroot_path = g_file_new_for_path ("sysroot"); + return ostree_sysroot_new (sysroot_path); } diff --git a/tests/libtest.sh b/tests/libtest.sh index ff096505..73e88891 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -366,7 +366,7 @@ setup_os_repository () { shift bootmode=$1 shift - bootdir=${1:-usr/lib/ostree-boot} + bootdir=${1:-usr/lib/modules/3.6.0} oldpwd=`pwd` @@ -381,17 +381,25 @@ setup_os_repository () { cd ${test_tmpdir} mkdir osdata cd osdata - mkdir -p usr/bin usr/lib/modules/3.6.0 usr/share usr/etc - mkdir -p ${bootdir} - echo "a kernel" > ${bootdir}/vmlinuz-3.6.0 - echo "an initramfs" > ${bootdir}/initramfs-3.6.0 - bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + kver=3.6.0 + mkdir -p usr/bin ${bootdir} usr/lib/modules/${kver} usr/share usr/etc + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs.img + # /usr/lib/modules just uses "vmlinuz", since the version is in the module + # directory name. + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img + fi + echo "a kernel" > ${kernel_path} + echo "an initramfs" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') export bootcsum # Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not # /usr/lib/modules. - if [[ $bootdir != usr/lib/modules ]]; then - mv ${bootdir}/vmlinuz-3.6.0{,-${bootcsum}} - mv ${bootdir}/initramfs-3.6.0{,-${bootcsum}} + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} fi echo "an executable" > usr/bin/sh @@ -412,7 +420,7 @@ EOF echo "a default daemon file" > usr/etc/testdirectory/test ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" - + # Ensure these commits have distinct second timestamps sleep 2 echo "a new executable" > usr/bin/sh @@ -447,7 +455,7 @@ EOF setup_os_boot_grub2 "${bootmode}" ;; esac - + cd ${test_tmpdir} mkdir ${test_tmpdir}/httpd cd httpd @@ -465,17 +473,31 @@ os_repository_new_commit () branch=${3:-testos/buildmaster/x86_64-runtime} echo "BOOT ITERATION: $boot_checksum_iteration" cd ${test_tmpdir}/osdata - bootdir=usr/lib/ostree-boot - if ! test -d ${bootdir}; then - bootdir=boot + kver=3.6.0 + if test -f usr/lib/modules/${kver}/vmlinuz; then + bootdir=usr/lib/modules/${kver} + else + if test -d usr/lib/ostree-boot; then + bootdir=usr/lib/ostree-boot + else + bootdir=boot + fi fi rm ${bootdir}/* - echo "new: a kernel ${boot_checksum_iteration}" > ${bootdir}/vmlinuz-3.6.0 - echo "new: an initramfs ${boot_checksum_iteration}" > ${bootdir}/initramfs-3.6.0 - bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + kernel_path=${bootdir}/vmlinuz + initramfs_path=${bootdir}/initramfs.img + if [[ $bootdir != usr/lib/modules/* ]]; then + kernel_path=${kernel_path}-${kver} + initramfs_path=${bootdir}/initramfs-${kver}.img + fi + echo "new: a kernel ${boot_checksum_iteration}" > ${kernel_path} + echo "new: an initramfs ${boot_checksum_iteration}" > ${initramfs_path} + bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ') export bootcsum - mv ${bootdir}/vmlinuz-3.6.0 ${bootdir}/vmlinuz-3.6.0-${bootcsum} - mv ${bootdir}/initramfs-3.6.0 ${bootdir}/initramfs-3.6.0-${bootcsum} + if [[ $bootdir != usr/lib/modules/* ]]; then + mv ${kernel_path}{,-${bootcsum}} + mv ${initramfs_path}{,-${bootcsum}} + fi echo "a new default config file" > usr/etc/a-new-default-config-file mkdir -p usr/etc/new-default-dir @@ -489,6 +511,17 @@ os_repository_new_commit () cd ${test_tmpdir} } +# Usage: if ! skip_one_without_user_xattrs; then ... more tests ...; fi +skip_one_without_user_xattrs () { + touch test-xattrs + if ! setfattr -n user.testvalue -v somevalue test-xattrs; then + echo "ok # SKIP - this test requires xattr support" + return 0 + else + return 1 + fi +} + skip_without_user_xattrs () { touch test-xattrs setfattr -n user.testvalue -v somevalue test-xattrs || \ @@ -528,6 +561,14 @@ ostree_file_path_to_checksum() { $CMD_PREFIX ostree --repo=$repo ls -C $ref $path | awk '{ print $5 }' } +# Given an object checksum, print its relative file path +ostree_checksum_to_relative_object_path() { + repo=$1 + checksum=$2 + if grep -Eq -e '^mode=archive' ${repo}/config; then suffix=z; else suffix=''; fi + echo objects/${checksum:0:2}/${checksum:2}.file${suffix} +} + # Given a path to a file in a repo for a ref, print the (relative) path to its # object ostree_file_path_to_relative_object_path() { @@ -536,7 +577,7 @@ ostree_file_path_to_relative_object_path() { path=$3 checksum=$(ostree_file_path_to_checksum $repo $ref $path) test -n "${checksum}" - echo objects/${checksum:0:2}/${checksum:2}.file + ostree_checksum_to_relative_object_path ${repo} ${checksum} } # Given a path to a file in a repo for a ref, print the path to its object diff --git a/tests/pull-test.sh b/tests/pull-test.sh index f51d4445..f44c2ced 100644 --- a/tests/pull-test.sh +++ b/tests/pull-test.sh @@ -35,7 +35,7 @@ function verify_initial_contents() { assert_file_has_content baz/cow '^moo$' } -echo "1..28" +echo "1..29" # Try both syntaxes repo_init --no-gpg-verify @@ -205,6 +205,31 @@ ${CMD_PREFIX} ostree --repo=parentpullrepo rev-parse origin:main > main.txt assert_file_has_content main.txt ${rev} echo "ok pull specific commit" +# test pull -T +cd ${test_tmpdir} +repo_init --no-gpg-verify +${CMD_PREFIX} ostree --repo=repo pull origin main +origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse main) +# Check we can pull the same commit with timestamp checking enabled +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_streq ${origrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +newrev=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +# New commit with timestamp checking +${CMD_PREFIX} ostree --repo=repo pull -T origin main +assert_not_streq "${origrev}" "${newrev}" +assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +newrev2=$(${CMD_PREFIX} ostree --timestamp="October 25 1985" --repo=ostree-srv/gnomerepo commit -b main --tree=ref=main) +${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +if ${CMD_PREFIX} ostree --repo=repo pull -T origin main 2>err.txt; then + fatal "pulled older commit with timestamp checking enabled?" +fi +assert_file_has_content err.txt "Upgrade.*is chronologically older" +assert_streq ${newrev} "$(${CMD_PREFIX} ostree --repo=repo rev-parse main)" +# But we can pull it without timestamp checking +${CMD_PREFIX} ostree --repo=repo pull origin main +echo "ok pull timestamp checking" + cd ${test_tmpdir} repo_init --no-gpg-verify ${CMD_PREFIX} ostree --repo=repo pull origin main diff --git a/tests/test-admin-deploy-2.sh b/tests/test-admin-deploy-2.sh index 79e253bb..3e00c670 100755 --- a/tests/test-admin-deploy-2.sh +++ b/tests/test-admin-deploy-2.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..3" diff --git a/tests/test-admin-deploy-bootid-gc.sh b/tests/test-admin-deploy-bootid-gc.sh index 29360e38..d96438c1 100755 --- a/tests/test-admin-deploy-bootid-gc.sh +++ b/tests/test-admin-deploy-bootid-gc.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..1" diff --git a/tests/test-admin-deploy-clean.sh b/tests/test-admin-deploy-clean.sh index 58283108..4dc19f41 100755 --- a/tests/test-admin-deploy-clean.sh +++ b/tests/test-admin-deploy-clean.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..1" diff --git a/tests/test-admin-deploy-etcmerge-cornercases.sh b/tests/test-admin-deploy-etcmerge-cornercases.sh index 10e7a438..8da6d16c 100755 --- a/tests/test-admin-deploy-etcmerge-cornercases.sh +++ b/tests/test-admin-deploy-etcmerge-cornercases.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..2" diff --git a/tests/test-admin-deploy-grub2.sh b/tests/test-admin-deploy-grub2.sh index 6f785df5..c91ba8a5 100755 --- a/tests/test-admin-deploy-grub2.sh +++ b/tests/test-admin-deploy-grub2.sh @@ -19,11 +19,11 @@ set -euo pipefail -echo "1..19" - . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "grub2 ostree-grub-generator" +setup_os_repository "archive" "grub2 ostree-grub-generator" + +extra_admin_tests=0 . $(dirname $0)/admin-test.sh diff --git a/tests/test-admin-deploy-karg.sh b/tests/test-admin-deploy-karg.sh index 643aef78..bbd7af33 100755 --- a/tests/test-admin-deploy-karg.sh +++ b/tests/test-admin-deploy-karg.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..3" diff --git a/tests/test-admin-deploy-switch.sh b/tests/test-admin-deploy-switch.sh index 0157e27b..6c27649f 100755 --- a/tests/test-admin-deploy-switch.sh +++ b/tests/test-admin-deploy-switch.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..4" diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index b19a74f0..7c1535b6 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -19,31 +19,52 @@ set -euo pipefail -echo "1..20" - . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" + +extra_admin_tests=3 . $(dirname $0)/admin-test.sh +# Test the legacy dirs +for test_bootdir in "boot" "usr/lib/ostree-boot"; do + cd ${test_tmpdir} + rm httpd osdata testos-repo sysroot -rf + setup_os_repository "archive" "syslinux" $test_bootdir + ${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) + ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime + assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' + assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' + assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' + # kernel/initrams should also be in the tree's /boot with the checksum + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/vmlinuz-3.6.0-${bootcsum} 'a kernel' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/$test_bootdir/initramfs-3.6.0.img-${bootcsum} 'an initramfs' + assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' + assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' + ${CMD_PREFIX} ostree admin status + validate_bootloader + echo "ok kernel in $test_bootdir" +done + +# And test that legacy overrides /usr/lib/modules cd ${test_tmpdir} rm httpd osdata testos-repo sysroot -rf -setup_os_repository "archive-z2" "syslinux" "boot" - +setup_os_repository "archive" "syslinux" "usr/lib/ostree-boot" +cd osdata +echo "this is a kernel without an initramfs like Fedora 26" > usr/lib/modules/3.6.0/vmlinuz +usrlib_modules_bootcsum=$(cat usr/lib/modules/3.6.0/vmlinuz | sha256sum | cut -f 1 -d ' ') +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build" +cd ${test_tmpdir} ${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) ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' -assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' -assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' -# kernel/initrams should also be in the tree's /boot with the checksum -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/vmlinuz-3.6.0-${bootcsum} 'a kernel' -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/initramfs-3.6.0-${bootcsum} 'an initramfs' -assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' -assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' -${CMD_PREFIX} ostree admin status -validate_bootloader -echo "ok kernel in tree's /boot" +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0.img 'an initramfs' +# Note this bootcsum shouldn't be the modules one +assert_not_streq "${bootcsum}" "${usrlib_modules_bootcsum}" +echo "ok kernel in /usr/lib/modules and /usr/lib/ostree-boot" diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index 3685e31e..7791360e 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -20,16 +20,17 @@ set -euo pipefail -echo "1..20" - . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "uboot" +setup_os_repository "archive" "uboot" + +extra_admin_tests=1 . $(dirname $0)/admin-test.sh cd ${test_tmpdir} +mkdir -p osdata/usr/lib/ostree-boot cat << 'EOF' > osdata/usr/lib/ostree-boot/uEnv.txt loaduimage=load mmc ${bootpart} ${loadaddr} ${kernel_image} loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}${fdtfile} @@ -41,5 +42,7 @@ ${CMD_PREFIX} ostree --repo=testos-repo commit --tree=dir=osdata/ -b testos/buil ${CMD_PREFIX} ostree admin upgrade --os=testos assert_file_has_content sysroot/boot/uEnv.txt "loadfdt=" assert_file_has_content sysroot/boot/uEnv.txt "kernel_image=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image2=" +assert_file_has_content sysroot/boot/uEnv.txt "kernel_image3=" echo "ok merging uEnv.txt files" diff --git a/tests/test-admin-instutil-set-kargs.sh b/tests/test-admin-instutil-set-kargs.sh index 132c9336..fb08c24b 100755 --- a/tests/test-admin-instutil-set-kargs.sh +++ b/tests/test-admin-instutil-set-kargs.sh @@ -23,7 +23,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..5" diff --git a/tests/test-admin-locking.sh b/tests/test-admin-locking.sh index 01814f9f..3466ce99 100755 --- a/tests/test-admin-locking.sh +++ b/tests/test-admin-locking.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" # If parallel is not installed, skip the test if ! parallel --gnu /bin/true /dev/null 2>&1; then diff --git a/tests/test-admin-pull-deploy-commit.sh b/tests/test-admin-pull-deploy-commit.sh index e1f7def6..f128fd0b 100755 --- a/tests/test-admin-pull-deploy-commit.sh +++ b/tests/test-admin-pull-deploy-commit.sh @@ -25,7 +25,7 @@ set -euo pipefail echo "1..1" -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo diff --git a/tests/test-admin-pull-deploy-split.sh b/tests/test-admin-pull-deploy-split.sh index 7a6750e2..fa10b784 100755 --- a/tests/test-admin-pull-deploy-split.sh +++ b/tests/test-admin-pull-deploy-split.sh @@ -25,7 +25,7 @@ set -euo pipefail echo "1..1" -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo diff --git a/tests/test-admin-upgrade-endoflife.sh b/tests/test-admin-upgrade-endoflife.sh index a58c64ce..c5a05da6 100755 --- a/tests/test-admin-upgrade-endoflife.sh +++ b/tests/test-admin-upgrade-endoflife.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" # This does: # - init ostree repo in testos-repo # - create system files in osdata and commit twice those contents into testos-repo diff --git a/tests/test-admin-upgrade-not-backwards.sh b/tests/test-admin-upgrade-not-backwards.sh index fd1e1108..10fd25c9 100755 --- a/tests/test-admin-upgrade-not-backwards.sh +++ b/tests/test-admin-upgrade-not-backwards.sh @@ -22,30 +22,47 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..2" +ref=testos/buildmaster/x86_64-runtime cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo -${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime -rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos ${ref} +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse ${ref}) export rev echo "rev=${rev}" -# This initial deployment gets kicked off with some kernel arguments -${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:${ref} assert_has_dir sysroot/boot/ostree/testos-${bootcsum} # This should be a no-op ${CMD_PREFIX} ostree admin upgrade --os=testos -# Now reset to an older revision -${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo reset testos/buildmaster/x86_64-runtime{,^} - +# Generate a new commit with an older timestamp that also has +# some new content, so we test timestamp checking during pull +# +origrev=$(ostree --repo=${test_tmpdir}/sysroot/ostree/repo rev-parse testos:${ref}) +cd ${test_tmpdir}/osdata +echo "new content for pull timestamp checking" > usr/share/test-pull-ts-check.txt +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=tscheck" \ + -b ${ref} --timestamp='October 25 1985' +newrev=$(ostree --repo=${test_tmpdir}/testos-repo rev-parse ${ref}) +assert_not_streq ${origrev} ${newrev} +cd ${test_tmpdir} +tscheck_checksum=$(ostree_file_path_to_checksum testos-repo ${ref} /usr/share/test-pull-ts-check.txt) +tscheck_filez_objpath=$(ostree_checksum_to_relative_object_path testos-repo ${tscheck_checksum}) +assert_has_file testos-repo/${tscheck_filez_objpath} if ${CMD_PREFIX} ostree admin upgrade --os=testos 2>upgrade-err.txt; then assert_not_reached 'upgrade unexpectedly succeeded' fi assert_file_has_content upgrade-err.txt 'chronologically older' +currev=$(ostree --repo=sysroot/ostree/repo rev-parse testos:${ref}) +assert_not_streq ${newrev} ${currev} +assert_streq ${origrev} ${currev} +tscheck_file_objpath=$(ostree_checksum_to_relative_object_path sysroot/ostree/repo ${tscheck_checksum}) +assert_not_has_file sysroot/ostree/repo/${tscheck_file_objpath} echo 'ok upgrade will not go backwards' diff --git a/tests/test-admin-upgrade-unconfigured.sh b/tests/test-admin-upgrade-unconfigured.sh index c952356e..63885642 100755 --- a/tests/test-admin-upgrade-unconfigured.sh +++ b/tests/test-admin-upgrade-unconfigured.sh @@ -22,7 +22,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh # Exports OSTREE_SYSROOT so --sysroot not needed. -setup_os_repository "archive-z2" "syslinux" +setup_os_repository "archive" "syslinux" echo "1..2" diff --git a/tests/test-archivez.sh b/tests/test-archivez.sh index 836e9180..d6faab6c 100755 --- a/tests/test-archivez.sh +++ b/tests/test-archivez.sh @@ -21,12 +21,15 @@ set -euo pipefail . $(dirname $0)/libtest.sh -echo '1..11' +echo '1..12' -setup_test_repository "archive-z2" +setup_test_repository "archive" . ${test_srcdir}/archive-test.sh +${CMD_PREFIX} ostree --repo=repo-archive-z2 init --mode=archive-z2 +echo "ok did an init with archive-z2 alias" + cd ${test_tmpdir} mkdir repo2 ostree_repo_init repo2 diff --git a/tests/test-basic-c.c b/tests/test-basic-c.c index dc6d33f2..d8800763 100644 --- a/tests/test-basic-c.c +++ b/tests/test-basic-c.c @@ -55,7 +55,7 @@ input_stream_to_bytes (GInputStream *input) } static void -test_raw_file_to_archive_z2_stream (gconstpointer data) +test_raw_file_to_archive_stream (gconstpointer data) { OstreeRepo *repo = OSTREE_REPO (data); g_autofree gchar *commit_checksum = NULL; @@ -249,7 +249,7 @@ int main (int argc, char **argv) goto out; g_test_add_data_func ("/repo-not-system", repo, test_repo_is_not_system); - g_test_add_data_func ("/raw-file-to-archive-z2-stream", repo, test_raw_file_to_archive_z2_stream); + g_test_add_data_func ("/raw-file-to-archive-stream", repo, test_raw_file_to_archive_stream); g_test_add_data_func ("/objectwrites", repo, test_object_writes); g_test_add_func ("/remotename", test_validate_remotename); diff --git a/tests/test-basic-user-only.sh b/tests/test-basic-user-only.sh index fb071fe4..ce69e49e 100755 --- a/tests/test-basic-user-only.sh +++ b/tests/test-basic-user-only.sh @@ -72,21 +72,23 @@ $CMD_PREFIX ostree --repo=repo checkout -U -H content-with-dir-world-writable di assert_file_has_mode dir-co/worldwritable-dir 775 echo "ok didn't make world-writable dir" -cd ${test_tmpdir} -rm repo-input -rf -rm repo -rf -ostree_repo_init repo init --mode=bare-user-only -ostree_repo_init repo-input init --mode=bare-user -rm files -rf && mkdir files -echo afile > files/afile -ln -s afile files/afile-link -$CMD_PREFIX ostree --repo=repo-input commit --canonical-permissions -b testtree --tree=dir=files -afile_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile) -afile_link_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile-link) -$CMD_PREFIX ostree pull-local --repo=repo repo-input -assert_files_hardlinked repo/${afile_relobjpath} repo-input/${afile_relobjpath} -if files_are_hardlinked repo/${afile_link_relobjpath} repo-input/${afile_link_relobjpath}; then - assert_not_reached "symlinks hardlinked across bare-user?" +if ! skip_one_without_user_xattrs; then + cd ${test_tmpdir} + rm repo-input -rf + rm repo -rf + ostree_repo_init repo init --mode=bare-user-only + ostree_repo_init repo-input init --mode=bare-user + rm files -rf && mkdir files + echo afile > files/afile + ln -s afile files/afile-link + $CMD_PREFIX ostree --repo=repo-input commit --canonical-permissions -b testtree --tree=dir=files + afile_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile) + afile_link_relobjpath=$(ostree_file_path_to_relative_object_path repo-input testtree /afile-link) + $CMD_PREFIX ostree pull-local --repo=repo repo-input + assert_files_hardlinked repo/${afile_relobjpath} repo-input/${afile_relobjpath} + if files_are_hardlinked repo/${afile_link_relobjpath} repo-input/${afile_link_relobjpath}; then + assert_not_reached "symlinks hardlinked across bare-user?" + fi + $OSTREE fsck -q + echo "ok hardlink pull from bare-user" fi -$OSTREE fsck -q -echo "ok hardlink pull from bare-user" diff --git a/tests/test-commit-sign.sh b/tests/test-commit-sign.sh index 96608e88..755818c8 100755 --- a/tests/test-commit-sign.sh +++ b/tests/test-commit-sign.sh @@ -33,7 +33,7 @@ oldpwd=`pwd` mkdir ostree-srv cd ostree-srv mkdir gnomerepo -ostree_repo_init gnomerepo --mode="archive-z2" +ostree_repo_init gnomerepo --mode="archive" mkdir gnomerepo-files cd gnomerepo-files echo first > firstfile diff --git a/tests/test-delta.sh b/tests/test-delta.sh index a59ee8e5..97d94391 100755 --- a/tests/test-delta.sh +++ b/tests/test-delta.sh @@ -29,7 +29,7 @@ morebindatafiles="false ls" echo '1..12' mkdir repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive mkdir files for bin in ${bindatafiles}; do diff --git a/tests/test-demo-buildsystem.sh b/tests/test-demo-buildsystem.sh index 99ddc505..4b2d86f1 100755 --- a/tests/test-demo-buildsystem.sh +++ b/tests/test-demo-buildsystem.sh @@ -68,7 +68,7 @@ packages="bash systemd" mkdir build-repo ostree_repo_init build-repo --mode=bare-user mkdir repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive # Our FUSE mount point mkdir mnt diff --git a/tests/test-export.sh b/tests/test-export.sh index 856c4073..7cba3bd7 100755 --- a/tests/test-export.sh +++ b/tests/test-export.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_test_repository "archive-z2" +setup_test_repository "archive" echo '1..5' diff --git a/tests/test-find-remotes.sh b/tests/test-find-remotes.sh index 0cf0127f..0bbe54f0 100755 --- a/tests/test-find-remotes.sh +++ b/tests/test-find-remotes.sh @@ -56,8 +56,11 @@ ${CMD_PREFIX} ostree --repo=local refs > refs assert_file_has_content refs "^apps-remote:app1$" assert_file_has_content refs "^os-remote:os/amd64/master$" -${CMD_PREFIX} ostree --repo=local refs --collections | wc -l > refscount -assert_file_has_content refscount "^0$" +${CMD_PREFIX} ostree --repo=local refs --collections > refs +cat refs | wc -l > refscount +assert_file_has_content refs "^(org.example.AppsCollection, app1)$" +assert_file_has_content refs "^(org.example.OsCollection, os/amd64/master)$" +assert_file_has_content refscount "^2$" # Create a local mirror repository where we pull the branches *in mirror mode* from the two remotes. # This should pull them into refs/mirrors, since the remotes advertise a collection ID. diff --git a/tests/test-gpg-signed-commit.sh b/tests/test-gpg-signed-commit.sh index ad022b2b..69f0cb20 100755 --- a/tests/test-gpg-signed-commit.sh +++ b/tests/test-gpg-signed-commit.sh @@ -29,7 +29,7 @@ fi echo "1..1" -setup_test_repository "archive-z2" +setup_test_repository "archive" export OSTREE_GPG_SIGN="${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME}" diff --git a/tests/test-gpg-verify-result.c b/tests/test-gpg-verify-result.c index 62b05e33..6d11fac6 100644 --- a/tests/test-gpg-verify-result.c +++ b/tests/test-gpg-verify-result.c @@ -173,7 +173,7 @@ test_attribute_basics (TestFixture *fixture, tuple = ostree_gpg_verify_result_get_all (fixture->result, ii); type_string = g_variant_get_type_string (tuple); - g_assert_cmpstr (type_string, ==, "(bbbbbsxxssss)"); + g_assert_cmpstr (type_string, ==, "(bbbbbsxxsssss)"); /* Check attributes which should be common to all signatures. */ diff --git a/tests/test-help.sh b/tests/test-help.sh index ca555b1b..75fe0c11 100755 --- a/tests/test-help.sh +++ b/tests/test-help.sh @@ -23,41 +23,66 @@ set -euo pipefail echo "1..1" -echo "Testing:" 1>&2 +test_usage_output() { + file=$1; shift + cmd=$1; shift + assert_file_has_content $file '^Usage' + # check that it didn't print twice somehow + if [ "$(grep --count '^Usage' $file)" != 1 ]; then + _fatal_print_file "$file" "File '$file' has '^Usage' more than once." + fi + assert_file_has_content $file "$cmd" +} + +# check that we found at least one command with subcommands +found_subcommands=0 + test_recursive() { local cmd=$1 - local root=$2 echo "$cmd" 1>&2 $cmd --help 1>out 2>err # --help message goes to standard output - if [ "$root" = "1" ] ; then - assert_file_has_content out "[Uu]sage" - assert_file_has_content out "$cmd" - fi + test_usage_output out "$cmd" assert_file_empty err - builtins=`sed -n '/^Builtin commands/,/^[^ ]/p' out 2>err - if [ $? = 0 ] ; then - echo 1>&2 "missing subcommand but 0 exit status"; exit 1 + rc=0 + $cmd 1>out 2>err || rc=$? + if [ $rc = 0 ] ; then + assert_not_reached "missing subcommand but 0 exit status" fi - set -euo pipefail + # error message and usage goes to standard error - assert_file_has_content err "[Uu]sage" - assert_file_has_content err "$cmd" - assert_file_has_content err "Builtin commands" + test_usage_output err "$cmd" + assert_file_has_content err 'No \("[^"]*" sub\)\?command specified' assert_file_empty out - for subcmd in $builtins ; do - test_recursive "$cmd $subcmd" 0 + rc=0 + $cmd non-existent-subcommand 1>out 2>err || rc=$? + if [ $rc = 0 ] ; then + assert_not_reached "non-existent subcommand but 0 exit status" + fi + + test_usage_output err "$cmd" + assert_file_has_content err 'Unknown \("[^"]*" sub\)\?command' + assert_file_empty out + + for subcmd in $builtins; do + test_recursive "$cmd $subcmd" done fi } -test_recursive ostree 1 +test_recursive ostree +if [ $found_subcommands != 1 ]; then + assert_not_reached "no ostree commands with subcommands found!" +fi echo "ok help option is properly supported" diff --git a/tests/test-libarchive-import.c b/tests/test-libarchive-import.c index 8f884a66..77c2dd30 100644 --- a/tests/test-libarchive-import.c +++ b/tests/test-libarchive-import.c @@ -35,6 +35,7 @@ typedef struct { int fd; int fd_empty; char *tmpd; + GError *skip_all; } TestData; static void @@ -136,7 +137,13 @@ test_data_init (TestData *td) g_assert_cmpint (0, ==, mkdir ("repo", 0755)); ostree_repo_create (td->repo, OSTREE_REPO_MODE_BARE_USER, NULL, &error); - g_assert_no_error (error); + + /* G_IO_ERROR_NOT_SUPPORTED probably means no extended attribute support */ + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) + g_propagate_prefixed_error (&td->skip_all, g_steal_pointer (&error), + "Unable to set up repository: "); + else + g_assert_no_error (error); } } @@ -169,6 +176,12 @@ test_libarchive_noautocreate_empty (gconstpointer data) OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + test_archive_setup (td->fd_empty, a); (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error); @@ -185,6 +198,12 @@ test_libarchive_autocreate_empty (gconstpointer data) OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + opts.autocreate_parents = 1; test_archive_setup (td->fd_empty, a); @@ -203,6 +222,12 @@ test_libarchive_error_device_file (gconstpointer data) OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + return; + } + test_archive_setup (td->fd, a); (void)ostree_repo_import_archive_to_mtree (td->repo, &opts, a, mtree, NULL, NULL, &error); @@ -235,34 +260,31 @@ import_write_and_ref (OstreeRepo *repo, OstreeRepoCommitModifier *modifier, GError **error) { - gboolean ret = FALSE; - glnx_unref_object GFile *root = NULL; - g_autofree char *commit_checksum = NULL; - glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); + g_autoptr(OstreeMutableTree) mtree = ostree_mutable_tree_new (); if (!ostree_repo_prepare_transaction (repo, NULL, NULL, error)) - goto out; + return FALSE; if (!ostree_repo_import_archive_to_mtree (repo, opts, a, mtree, modifier, NULL, error)) - goto out; + return FALSE; + g_autoptr(GFile) root = NULL; if (!ostree_repo_write_mtree (repo, mtree, &root, NULL, error)) - goto out; + return FALSE; + g_autofree char *commit_checksum = NULL; if (!ostree_repo_write_commit (repo, NULL, "", "", NULL, OSTREE_REPO_FILE (root), &commit_checksum, NULL, error)) - goto out; + return FALSE; ostree_repo_transaction_set_ref (repo, NULL, ref, commit_checksum); if (!ostree_repo_commit_transaction (repo, NULL, NULL, error)) - goto out; + return FALSE; - ret = TRUE; -out: - return ret; + return TRUE; } static void @@ -276,6 +298,12 @@ test_libarchive_ignore_device_file (gconstpointer data) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + test_archive_setup (td->fd, a); opts.ignore_unsupported_content = TRUE; @@ -338,6 +366,12 @@ test_libarchive_ostree_convention (gconstpointer data) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + test_archive_setup (td->fd, a); opts.autocreate_parents = TRUE; @@ -376,12 +410,18 @@ test_libarchive_xattr_callback (gconstpointer data) GError *error = NULL; g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0 }; - OstreeRepoCommitModifier *modifier = NULL; + g_autoptr(OstreeRepoCommitModifier) modifier = NULL; char buf[7] = { 0 }; if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + modifier = ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); ostree_repo_commit_modifier_set_xattr_callback (modifier, xattr_cb, NULL, NULL); @@ -409,8 +449,6 @@ test_libarchive_xattr_callback (gconstpointer data) g_assert_cmpstr (buf, ==, "mydata"); out: - if (modifier) - ostree_repo_commit_modifier_unref (modifier); g_assert_no_error (error); } @@ -437,6 +475,12 @@ entry_pathname_test_helper (gconstpointer data, gboolean on) if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + modifier = ostree_repo_commit_modifier_new (0, NULL, NULL, NULL); ostree_repo_commit_modifier_set_xattr_callback (modifier, path_cb, NULL, &met_etc_file); @@ -494,12 +538,18 @@ test_libarchive_selinux (gconstpointer data) g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0 }; glnx_unref_object OstreeSePolicy *sepol = NULL; - OstreeRepoCommitModifier *modifier = NULL; + g_autoptr(OstreeRepoCommitModifier) modifier = NULL; char buf[64] = { 0 }; if (skip_if_no_xattr (td)) goto out; + if (td->skip_all != NULL) + { + g_test_skip (td->skip_all->message); + goto out; + } + { glnx_unref_object GFile *root = g_file_new_for_path ("/"); @@ -536,8 +586,6 @@ test_libarchive_selinux (gconstpointer data) g_assert_cmpstr (buf, ==, "system_u:object_r:etc_t:s0"); out: - if (modifier) - ostree_repo_commit_modifier_unref (modifier); g_assert_no_error (error); } diff --git a/tests/test-libarchive.sh b/tests/test-libarchive.sh index 6540b94b..c839ba91 100755 --- a/tests/test-libarchive.sh +++ b/tests/test-libarchive.sh @@ -26,14 +26,14 @@ fi . $(dirname $0)/libtest.sh -echo "1..20" +echo "1..13" setup_test_repository "bare" cd ${test_tmpdir} mkdir foo cd foo -mkdir -p usr/bin +mkdir -p usr/bin usr/lib echo contents > usr/bin/foo touch usr/bin/foo0 ln usr/bin/foo usr/bin/bar @@ -45,8 +45,12 @@ 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 "a library" > usr/lib/libfoo.so +echo "another library" > usr/lib/libbar.so +# Create a tar archive tar -c -z -f ../foo.tar.gz . +# Create a cpio archive find . | cpio -o -H newc > ../foo.cpio cd .. @@ -71,10 +75,17 @@ $OSTREE commit -s "from cpio" -b test-cpio \ echo "ok cpio commit" assert_valid_checkout () { - cd ${test_tmpdir} - $OSTREE checkout test-$1 test-$1-checkout - cd test-$1-checkout + ref=$1 + rm test-${ref}-checkout -rf + $OSTREE checkout test-${ref} test-${ref}-checkout + assert_valid_content test-${ref}-checkout + rm -rf test-${ref}-checkout +} + +assert_valid_content () { + dn=$1 + cd ${dn} # basic content check assert_file_has_content usr/bin/foo contents assert_file_has_content usr/bin/bar contents @@ -82,39 +93,35 @@ assert_valid_checkout () { assert_file_empty usr/bin/foo0 assert_file_empty usr/bin/bar0 assert_file_empty usr/local/bin/baz0 - echo "ok $1 contents" + assert_file_has_content usr/lib/libfoo.so 'a library' + assert_file_has_content usr/lib/libbar.so 'another library' # hardlinks assert_files_hardlinked usr/bin/foo usr/bin/bar assert_files_hardlinked usr/bin/foo usr/local/bin/baz - echo "ok $1 hardlink" assert_files_hardlinked usr/bin/foo0 usr/bin/bar0 assert_files_hardlinked usr/bin/foo0 usr/local/bin/baz0 - echo "ok $1 hardlink to empty files" # symlinks assert_symlink_has_content usr/bin/sl foo assert_file_has_content usr/bin/sl contents - echo "ok $1 symlink" # ostree checkout doesn't care if two symlinks are actually hardlinked # together (which is fine). checking that it's also a symlink is good enough. assert_symlink_has_content usr/local/bin/slhl foo - echo "ok $1 hardlink to symlink" # stat override test -u usr/bin/setuidme - echo "ok $1 setuid" # skip list test ! -f usr/bin/skipme - echo "ok $1 file skip" cd ${test_tmpdir} - rm -rf test-$1-checkout } assert_valid_checkout tar +echo "ok tar contents" assert_valid_checkout cpio +echo "ok cpio contents" cd ${test_tmpdir} mkdir multicommit-files @@ -154,3 +161,60 @@ $OSTREE checkout partial partial-checkout cd partial-checkout assert_file_has_content subdir/original "original" echo "ok tar partial commit contents" + +uid=$(id -u) +gid=$(id -g) +autocreate_args="--tar-autocreate-parents --owner-uid=${uid} --owner-gid=${gid}" + +cd ${test_tmpdir} +tar -cf empty.tar.gz -T /dev/null +$OSTREE commit -b tar-empty ${autocreate_args} --tree=tar=empty.tar.gz +$OSTREE ls tar-empty > ls.txt +assert_file_has_content ls.txt "d00755 ${uid} ${gid} 0 /" +echo "ok tar autocreate with owner uid/gid" + +# noop pathname filter +cd ${test_tmpdir} +$OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter='^nosuchfile/,nootherfile/' \ + --statoverride=statoverride.txt \ + --skip-list=skiplist.txt \ + --tree=tar=foo.tar.gz +rm test-tar-co -rf +$OSTREE checkout test-tar test-tar-co +assert_valid_content ${test_tmpdir}/test-tar-co +echo "ok tar pathname filter prefix (noop)" + +# Add a prefix +cd ${test_tmpdir} +# Update the metadata overrides matching our pathname filter +for f in statoverride.txt skiplist.txt; do + sed -i -e 's,/usr/,/foo/usr/,' $f +done +$OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter='^,foo/' \ + --statoverride=statoverride.txt \ + --skip-list=skiplist.txt \ + --tree=tar=foo.tar.gz +rm test-tar-co -rf +$OSTREE checkout test-tar test-tar-co +assert_has_dir test-tar-co/foo +assert_valid_content ${test_tmpdir}/test-tar-co/foo +echo "ok tar pathname filter prefix" + +# Test anchored and not-anchored +for filter in '^usr/bin/,usr/sbin/' '/bin/,/sbin/'; do + cd ${test_tmpdir} + $OSTREE commit -b test-tar ${autocreate_args} \ + --tar-pathname-filter=$filter \ + --tree=tar=foo.tar.gz + rm test-tar-co -rf + $OSTREE checkout test-tar test-tar-co + cd test-tar-co + # Check that we just had usr/bin → usr/sbin + assert_not_has_file usr/bin/foo + assert_file_has_content usr/sbin/foo contents + assert_not_has_file usr/sbin/libfoo.so + assert_file_has_content usr/lib/libfoo.so 'a library' + echo "ok tar pathname filter modification: ${filter}" +done diff --git a/tests/test-local-pull-depth.sh b/tests/test-local-pull-depth.sh index fef2f2dc..2dfb735d 100755 --- a/tests/test-local-pull-depth.sh +++ b/tests/test-local-pull-depth.sh @@ -21,13 +21,13 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_test_repository "archive-z2" +setup_test_repository "archive" echo "1..1" cd ${test_tmpdir} mkdir repo2 -ostree_repo_init repo2 --mode="archive-z2" +ostree_repo_init repo2 --mode="archive" ${CMD_PREFIX} ostree --repo=repo2 pull-local repo find repo2/objects -name '*.commit' | wc -l > commitcount diff --git a/tests/test-local-pull.sh b/tests/test-local-pull.sh index 1c9767f6..f9ac63b6 100755 --- a/tests/test-local-pull.sh +++ b/tests/test-local-pull.sh @@ -28,7 +28,7 @@ skip_without_user_xattrs echo "1..8" -setup_test_repository "archive-z2" +setup_test_repository "archive" echo "ok setup" cd ${test_tmpdir} @@ -40,7 +40,7 @@ ${CMD_PREFIX} ostree --repo=repo2 fsck echo "ok pull-local z2 to bare-user" mkdir repo3 -ostree_repo_init repo3 --mode="archive-z2" +ostree_repo_init repo3 --mode="archive" ${CMD_PREFIX} ostree --repo=repo3 pull-local repo2 ${CMD_PREFIX} ostree --repo=repo3 fsck echo "ok pull-local bare-user to z2" @@ -62,7 +62,7 @@ cmp checkout1.files checkout3.files echo "ok checkouts same" mkdir repo4 -ostree_repo_init repo4 --mode="archive-z2" +ostree_repo_init repo4 --mode="archive" ${CMD_PREFIX} ostree --repo=repo4 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo if ${CMD_PREFIX} ostree --repo=repo4 pull-local --remote=origin --gpg-verify repo test2 2>&1; then assert_not_reached "GPG verification unexpectedly succeeded" @@ -72,13 +72,13 @@ echo "ok --gpg-verify with no signature" ${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME} test2 ${TEST_GPG_KEYID_1} mkdir repo5 -ostree_repo_init repo5 --mode="archive-z2" +ostree_repo_init repo5 --mode="archive" ${CMD_PREFIX} ostree --repo=repo5 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo ${CMD_PREFIX} ostree --repo=repo5 pull-local --remote=origin --gpg-verify repo test2 echo "ok --gpg-verify" mkdir repo6 -ostree_repo_init repo6 --mode="archive-z2" +ostree_repo_init repo6 --mode="archive" ${CMD_PREFIX} ostree --repo=repo6 remote add --gpg-import ${test_tmpdir}/gpghome/key1.asc origin repo if ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summary repo test2 2>&1; then assert_not_reached "GPG summary verification with no summary unexpectedly succeeded" @@ -97,7 +97,7 @@ ${CMD_PREFIX} ostree --repo=repo6 pull-local --remote=origin --gpg-verify-summar echo "ok --gpg-verify-summary" mkdir repo7 -ostree_repo_init repo7 --mode="archive-z2" +ostree_repo_init repo7 --mode="archive" ${CMD_PREFIX} ostree --repo=repo7 pull-local repo ${CMD_PREFIX} ostree --repo=repo7 fsck for src_object in `find repo/objects -name '*.filez'`; do diff --git a/tests/test-oldstyle-partial.sh b/tests/test-oldstyle-partial.sh index 08be69d3..35344c39 100755 --- a/tests/test-oldstyle-partial.sh +++ b/tests/test-oldstyle-partial.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-parent.sh b/tests/test-parent.sh index 4d5520dd..9abdcf2d 100755 --- a/tests/test-parent.sh +++ b/tests/test-parent.sh @@ -25,7 +25,7 @@ skip_without_user_xattrs echo '1..2' -setup_test_repository "archive-z2" +setup_test_repository "archive" export OSTREE_GPG_SIGN="${OSTREE} gpg-sign --gpg-homedir=${TEST_GPG_KEYHOME}" diff --git a/tests/test-prune.sh b/tests/test-prune.sh index 0781b543..afcfbb52 100755 --- a/tests/test-prune.sh +++ b/tests/test-prune.sh @@ -23,7 +23,7 @@ set -euo pipefail skip_without_user_xattrs -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..5' diff --git a/tests/test-pull-bareuser.sh b/tests/test-pull-bareuser.sh index 0729247f..2e357234 100755 --- a/tests/test-pull-bareuser.sh +++ b/tests/test-pull-bareuser.sh @@ -21,6 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh +skip_without_user_xattrs setup_fake_remote_repo1 "archive" repo_mode=bare-user diff --git a/tests/test-pull-commit-only.sh b/tests/test-pull-commit-only.sh index 0cbdebc8..ff71d487 100755 --- a/tests/test-pull-commit-only.sh +++ b/tests/test-pull-commit-only.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-pull-contenturl.sh b/tests/test-pull-contenturl.sh index 5d72fb23..8f703923 100755 --- a/tests/test-pull-contenturl.sh +++ b/tests/test-pull-contenturl.sh @@ -28,7 +28,7 @@ if has_gpgme; then COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" fi -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # create a summary ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo \ diff --git a/tests/test-pull-corruption.sh b/tests/test-pull-corruption.sh index 89d89b75..3696acc4 100755 --- a/tests/test-pull-corruption.sh +++ b/tests/test-pull-corruption.sh @@ -27,9 +27,9 @@ fi . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" -echo '1..2' +echo '1..3' repopath=${test_tmpdir}/ostree-srv/gnomerepo cp -a ${repopath} ${repopath}.orig @@ -59,3 +59,44 @@ gjs $(dirname $0)/corrupt-repo-ref.js ${repopath} main || true assert_file_has_content corrupted-status.txt 'Changed byte' do_corrupt_pull_test echo "ok corruption" + +if ! skip_one_without_user_xattrs; then + # Set up a corrupted commit object + rm ostree-srv httpd repo -rf + setup_fake_remote_repo1 "archive" + rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main) + corruptrev=$(echo ${rev} hello | sha256sum | cut -f 1 -d ' ') + assert_not_streq ${rev} ${corruptrev} + rev_path=ostree-srv/gnomerepo/objects/${rev:0:2}/${rev:2}.commit + corruptrev_path=ostree-srv/gnomerepo/objects/${corruptrev:0:2}/${corruptrev:2}.commit + mkdir -p $(dirname ${corruptrev_path}) + mv ${rev_path} ${corruptrev_path} + echo ${corruptrev} > ostree-srv/gnomerepo/refs/heads/main + ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u + if ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo fsck 2>err.txt; then + assert_not_reached "fsck with corrupted commit worked?" + fi + assert_file_has_content err.txt "corrupted object ${corruptrev}\.commit" + + # Do a pull-local; this should succeed since we don't verify checksums + # for local repos by default. + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo pull-local ostree-srv/gnomerepo main + + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + if ${CMD_PREFIX} ostree --repo=repo pull-local --untrusted ostree-srv/gnomerepo main 2>err.txt; then + assert_not_reached "pull-local --untrusted worked?" + fi + assert_file_has_content err.txt "Corrupted commit object ${corruptrev}.*actual checksum is ${rev}" + + rm repo err.txt -rf + ostree_repo_init repo --mode=bare-user + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo + if ${CMD_PREFIX} ostree --repo=repo pull origin main 2>err.txt; then + assert_not_reached "pull unexpectedly succeeded!" + fi + assert_file_has_content err.txt "Corrupted commit object ${corruptrev}.*actual checksum is ${rev}" + echo "ok pull commit corruption" +fi diff --git a/tests/test-pull-depth.sh b/tests/test-pull-depth.sh index 372bef49..2e82c3a9 100755 --- a/tests/test-pull-depth.sh +++ b/tests/test-pull-depth.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-pull-large-metadata.sh b/tests/test-pull-large-metadata.sh index 2fdf0d91..219c519e 100755 --- a/tests/test-pull-large-metadata.sh +++ b/tests/test-pull-large-metadata.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' diff --git a/tests/test-pull-metalink.sh b/tests/test-pull-metalink.sh index 171c8d4b..7dbc4bf0 100755 --- a/tests/test-pull-metalink.sh +++ b/tests/test-pull-metalink.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..9' diff --git a/tests/test-pull-mirror-summary.sh b/tests/test-pull-mirror-summary.sh index 883c0245..71f917fc 100755 --- a/tests/test-pull-mirror-summary.sh +++ b/tests/test-pull-mirror-summary.sh @@ -24,7 +24,7 @@ set -euo pipefail echo "1..5" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # Now, setup multiple branches mkdir ${test_tmpdir}/ostree-srv/other-files @@ -41,7 +41,7 @@ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u prev_dir=`pwd` cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull --mirror origin assert_has_file repo/summary @@ -69,13 +69,13 @@ cd $prev_dir cd ${test_tmpdir} rm -rf repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo echo "ok pull mirror without checking signed summary" cd ${test_tmpdir} rm -rf repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo if ${OSTREE} --repo=repo pull --mirror origin 2>err.txt; then assert_not_reached "Mirroring unexpectedly succeeded" @@ -86,7 +86,7 @@ ${OSTREE} --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u ${COMMIT_SIGN} cd ${test_tmpdir} rm -rf repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo ${OSTREE} --repo=repo pull --mirror origin assert_has_file repo/summary @@ -99,7 +99,7 @@ truncate --size=1 ${test_tmpdir}/ostree-srv/gnomerepo/summary.sig cd ${test_tmpdir} rm -rf repo mkdir repo -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo ${OSTREE} --repo=repo pull --mirror origin assert_has_file repo/summary diff --git a/tests/test-pull-mirrorlist.sh b/tests/test-pull-mirrorlist.sh index 35320506..22d3950b 100755 --- a/tests/test-pull-mirrorlist.sh +++ b/tests/test-pull-mirrorlist.sh @@ -23,7 +23,7 @@ set -euo pipefail echo "1..3" -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" setup_mirror () { name=$1; shift diff --git a/tests/test-pull-override-url.sh b/tests/test-pull-override-url.sh index 16f79a02..6b72440f 100755 --- a/tests/test-pull-override-url.sh +++ b/tests/test-pull-override-url.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..1' @@ -34,7 +34,7 @@ gnomerepo_url="$(cat httpd-address)/ostree/gnomerepo" mkdir mirror-srv cd mirror-srv mkdir gnomerepo -ostree_repo_init gnomerepo --mode "archive-z2" +ostree_repo_init gnomerepo --mode "archive" ${CMD_PREFIX} ostree --repo=gnomerepo remote add --set=gpg-verify=false origin ${gnomerepo_url} ${CMD_PREFIX} ostree --repo=gnomerepo pull --mirror --depth=-1 origin main diff --git a/tests/test-pull-repeated.sh b/tests/test-pull-repeated.sh index 108c2057..30d0e03b 100755 --- a/tests/test-pull-repeated.sh +++ b/tests/test-pull-repeated.sh @@ -24,10 +24,10 @@ set -euo pipefail echo "1..1" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" --random-500s=50 +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" --random-500s=50 cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo for x in $(seq 200); do if ${CMD_PREFIX} ostree --repo=repo pull --mirror origin main 2>err.txt; then diff --git a/tests/test-pull-resume.sh b/tests/test-pull-resume.sh index 51746b9c..c6d268f4 100755 --- a/tests/test-pull-resume.sh +++ b/tests/test-pull-resume.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" "" "--force-range-requests" +setup_fake_remote_repo1 "archive" "" "--force-range-requests" echo '1..1' diff --git a/tests/test-pull-subpath.sh b/tests/test-pull-subpath.sh index 27eb64be..eb103004 100755 --- a/tests/test-pull-subpath.sh +++ b/tests/test-pull-subpath.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..4' diff --git a/tests/test-pull-summary-sigs.sh b/tests/test-pull-summary-sigs.sh index 016ee4b9..b6b17500 100755 --- a/tests/test-pull-summary-sigs.sh +++ b/tests/test-pull-summary-sigs.sh @@ -24,7 +24,7 @@ set -euo pipefail echo "1..7" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # Now, setup multiple branches mkdir ${test_tmpdir}/ostree-srv/other-files @@ -41,7 +41,7 @@ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u prev_dir=`pwd` cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull --mirror origin assert_has_file repo/summary @@ -66,7 +66,7 @@ repo_reinit () { cd ${test_tmpdir} rm -rf repo mkdir repo - ostree_repo_init repo --mode=archive-z2 + ostree_repo_init repo --mode=archive ${OSTREE} --repo=repo remote add --set=gpg-verify-summary=true origin $(cat httpd-address)/ostree/gnomerepo } diff --git a/tests/test-refs-collections.sh b/tests/test-refs-collections.sh index 4d49247d..5e6b50d7 100755 --- a/tests/test-refs-collections.sh +++ b/tests/test-refs-collections.sh @@ -103,6 +103,35 @@ ${CMD_PREFIX} ostree --repo=repo refs --collections > refs assert_file_has_content refs "^(org.example.Collection, ctest)$" assert_file_has_content refs "^(org.example.NewCollection, ctest-mirror)$" +# Remote refs should be listed if they have collection IDs + +cd ${test_tmpdir} +mkdir collection-repo +ostree_repo_init collection-repo --collection-id org.example.RemoteCollection +mkdir -p adir +${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit + +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_file_has_content refs "^(org.example.RemoteCollection, rcommit)$" + +${CMD_PREFIX} ostree --repo=repo refs --collections org.example.RemoteCollection > refs +assert_file_has_content refs "^(org.example.RemoteCollection, rcommit)$" + +${CMD_PREFIX} ostree --repo=repo refs --collections org.example.NonexistentID > refs +assert_not_file_has_content refs "^(org.example.RemoteCollection, rcommit)$" + +cd ${test_tmpdir} +mkdir no-collection-repo +ostree_repo_init no-collection-repo +mkdir -p adir2 +${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 +${CMD_PREFIX} ostree --repo=repo refs --collections > refs +assert_not_file_has_content refs "rcommit2" + echo "ok 1 refs collections" # Test that listing, creating and deleting refs works from an old repository diff --git a/tests/test-refs.sh b/tests/test-refs.sh index e48784aa..da45605c 100755 --- a/tests/test-refs.sh +++ b/tests/test-refs.sh @@ -21,7 +21,7 @@ set -euo pipefail . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo '1..2' diff --git a/tests/test-remote-cookies.sh b/tests/test-remote-cookies.sh index 14e3dd12..352bd7f6 100755 --- a/tests/test-remote-cookies.sh +++ b/tests/test-remote-cookies.sh @@ -24,7 +24,7 @@ echo '1..4' . $(dirname $0)/libtest.sh -setup_fake_remote_repo1 "archive-z2" "" \ +setup_fake_remote_repo1 "archive" "" \ "--expected-cookies foo=bar --expected-cookies baz=badger" assert_fail (){ diff --git a/tests/test-remote-gpg-import.sh b/tests/test-remote-gpg-import.sh index a5803785..7f5423a6 100755 --- a/tests/test-remote-gpg-import.sh +++ b/tests/test-remote-gpg-import.sh @@ -24,7 +24,7 @@ set -euo pipefail # We don't want OSTREE_GPG_HOME used for these tests. unset OSTREE_GPG_HOME -setup_fake_remote_repo1 "archive-z2" +setup_fake_remote_repo1 "archive" echo "1..4" diff --git a/tests/test-remotes-config-dir.js b/tests/test-remotes-config-dir.js new file mode 100755 index 00000000..7b6585c9 --- /dev/null +++ b/tests/test-remotes-config-dir.js @@ -0,0 +1,114 @@ +#!/usr/bin/env gjs +// +// Copyright (C) 2013 Colin Walters +// Copyright (C) 2017 Dan Nicholson +// +// 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. + +const GLib = imports.gi.GLib; +const Gio = imports.gi.Gio; +const OSTree = imports.gi.OSTree; + +function assertEquals(a, b) { + if (a != b) + throw new Error("assertion failed " + JSON.stringify(a) + " == " + JSON.stringify(b)); +} + +function assertNotEquals(a, b) { + if (a == b) + throw new Error("assertion failed " + JSON.stringify(a) + " != " + JSON.stringify(b)); +} + +print('1..6') + +let remotesDir = Gio.File.new_for_path('remotes.d'); +remotesDir.make_directory(null); + +let remoteConfig = GLib.KeyFile.new() +remoteConfig.set_value('remote "foo"', 'url', 'http://foo') + +let remoteConfigFile = remotesDir.get_child('foo.conf') +remoteConfig.save_to_file(remoteConfigFile.get_path()) + +// Use the full Repo constructor to set remotes-config-dir +let repoFile = Gio.File.new_for_path('repo'); +let repo = new OSTree.Repo({path: repoFile, + remotes_config_dir: remotesDir.get_path()}); +repo.create(OSTree.RepoMode.ARCHIVE_Z2, null); +repo.open(null); + +// See if the remotes.d remote exists +let remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('foo'), -1); + +print("ok read-remotes-config-dir"); + +// Adding a remote should not go in the remotes.d dir unless this is a +// system repo or add-remotes-config-dir is set to true +repo.remote_add('bar', 'http://bar', null, null); +remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('bar'), -1); +assertEquals(remotesDir.get_child('bar.conf').query_exists(null), false); + +print("ok add-not-in-remotes-config-dir"); + +// Removing the remotes.d remote should delete the conf file +repo.remote_delete('foo', null); +remotes = repo.remote_list() +assertEquals(remotes.indexOf('foo'), -1); +assertEquals(remotesDir.get_child('foo.conf').query_exists(null), false); + +print("ok delete-in-remotes-config-dir"); + +// Set add-remotes-config-dir to true and check that a remote gets added +// in the config dir +let repoConfig = repo.copy_config(); +repoConfig.set_boolean('core', 'add-remotes-config-dir', true); +repo.write_config(repoConfig); +repo.reload_config(null); +repo.remote_add('baz', 'http://baz', null, null); +remotes = repo.remote_list() +assertNotEquals(remotes.indexOf('baz'), -1); +assertEquals(remotesDir.get_child('baz.conf').query_exists(null), true); + +print("ok add-in-remotes-config-dir"); + +// Trying to set a remote config option via write_config() for a remote +// defined in the config file should succeed +let [, gpg_verify] = repo.remote_get_gpg_verify('bar'); +assertEquals(gpg_verify, true); +repoConfig = repo.copy_config(); +repoConfig.set_boolean('remote "bar"', 'gpg-verify', false); +repo.write_config(repoConfig); +repo.reload_config(null); +[, gpg_verify] = repo.remote_get_gpg_verify('bar'); +assertEquals(gpg_verify, false); + +print("ok config-remote-in-config-file-succeeds"); + +// Trying to set a remote config option via write_config() for a remote +// defined in the config dir should fail with G_IO_ERROR_EXISTS +repoConfig = repo.copy_config(); +repoConfig.set_boolean('remote "baz"', 'gpg-verify', false); +try { + if (repo.write_config(repoConfig)) + throw new Error("config of remote in config dir should fail"); +} catch (e) { + if (!(e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS))) + throw e; +} + +print("ok config-remote-in-config-dir-fails"); diff --git a/tests/test-reset-nonlinear.sh b/tests/test-reset-nonlinear.sh index 735f1523..65e7505e 100755 --- a/tests/test-reset-nonlinear.sh +++ b/tests/test-reset-nonlinear.sh @@ -23,7 +23,7 @@ echo "1..1" . $(dirname $0)/libtest.sh -setup_test_repository "archive-z2" +setup_test_repository "archive" cd ${test_tmpdir}/files $OSTREE commit -b testx -s "Another Commit" cd ${test_tmpdir} diff --git a/tests/test-rofiles-fuse.sh b/tests/test-rofiles-fuse.sh index 56045c61..d329d765 100755 --- a/tests/test-rofiles-fuse.sh +++ b/tests/test-rofiles-fuse.sh @@ -24,13 +24,16 @@ set -euo pipefail skip_without_fuse skip_without_user_xattrs -setup_test_repository "bare-user" +setup_test_repository "bare" -echo "1..6" +echo "1..7" +cd ${test_tmpdir} mkdir mnt - -$OSTREE checkout -U test2 checkout-test2 +# The default content set amazingly doesn't have a non-broken link +ln -s firstfile files/firstfile-link +$OSTREE commit -b test2 --tree=dir=files +$OSTREE checkout -H test2 checkout-test2 rofiles-fuse checkout-test2 mnt cleanup_fuse() { @@ -40,25 +43,55 @@ trap cleanup_fuse EXIT assert_file_has_content mnt/firstfile first echo "ok mount" -if cp /dev/null mnt/firstfile 2>err.txt; then - assert_not_reached "inplace mutation" +# Test open(O_TRUNC) directly and via symlink +for path in firstfile{,-link}; do + if cp /dev/null mnt/${path} 2>err.txt; then + assert_not_reached "inplace mutation ${path}" + fi + assert_file_has_content err.txt "Read-only file system" + assert_file_has_content mnt/firstfile first + assert_file_has_content checkout-test2/firstfile first +done +echo "ok failed inplace mutation (open O_TRUNCATE)" + +# Test chmod +if chmod 0600 mnt/firstfile 2>err.txt; then + assert_not_reached "chmod inplace" fi -assert_file_has_content err.txt "Read-only file system" -assert_file_has_content mnt/firstfile first -assert_file_has_content checkout-test2/firstfile first - -echo "ok failed inplace mutation" +assert_file_has_content err.txt "chmod:.*Read-only file system" +# Test chown with regfiles and symlinks +for path in firstfile baz/alink; do + if chown -h $(id -u) mnt/${path} 2>err.txt; then + assert_not_reached "chown inplace ${path}" + fi + assert_file_has_content err.txt "chown:.*Read-only file system" +done +# And test via dereferencing a symlink +if chown $(id -u) mnt/firstfile-link 2>err.txt; then + assert_not_reached "chown inplace firstfile-link" +fi +assert_file_has_content err.txt "chown:.*Read-only file system" +echo "ok failed mutation chmod + chown" +# Test creating new files, using chown + chmod on them as well echo anewfile-for-fuse > mnt/anewfile-for-fuse assert_file_has_content mnt/anewfile-for-fuse anewfile-for-fuse assert_file_has_content checkout-test2/anewfile-for-fuse anewfile-for-fuse +ln -s anewfile-for-fuse mnt/anewfile-for-fuse-link +# And also test modifications through a symlink +echo writevialink > mnt/anewfile-for-fuse-link +for path in anewfile-for-fuse{,-link}; do + assert_file_has_content mnt/${path} writevialink +done +chown $(id -u) mnt/anewfile-for-fuse-link mkdir mnt/newfusedir for i in $(seq 5); do echo ${i}-morenewfuse-${i} > mnt/newfusedir/test-morenewfuse.${i} + chmod 0600 mnt/newfusedir/test-morenewfuse.${i} + chown $(id -u) mnt/newfusedir/test-morenewfuse.${i} done assert_file_has_content checkout-test2/newfusedir/test-morenewfuse.3 3-morenewfuse-3 - echo "ok new content" rm mnt/baz/cow @@ -73,7 +106,7 @@ ${CMD_PREFIX} ostree --repo=repo commit -b test2 -s fromfuse --link-checkout-spe echo "ok commit" ${CMD_PREFIX} ostree --repo=repo checkout -U test2 mnt/test2-checkout-copy-fallback -assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse anewfile-for-fuse +assert_file_has_content mnt/test2-checkout-copy-fallback/anewfile-for-fuse writevialink if ${CMD_PREFIX} ostree --repo=repo checkout -UH test2 mnt/test2-checkout-copy-hardlinked 2>err.txt; then assert_not_reached "Checking out via hardlinks across mountpoint unexpectedly succeeded!" diff --git a/tests/test-summary-collections.sh b/tests/test-summary-collections.sh index 989e63e8..d12100ba 100755 --- a/tests/test-summary-collections.sh +++ b/tests/test-summary-collections.sh @@ -55,4 +55,29 @@ ${CMD_PREFIX} ostree --repo=repo summary --update ${CMD_PREFIX} ostree --repo=repo summary --view > summary assert_file_has_content summary "(org.example.OtherCollection, test-1-mirror)$" +# Test that remote refs are listed, but only if they have collection IDs +cd ${test_tmpdir} +mkdir collection-repo +ostree_repo_init collection-repo --collection-id org.example.RemoteCollection +mkdir -p adir +${CMD_PREFIX} ostree --repo=collection-repo commit --branch=rcommit -m rcommit -s rcommit adir +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify --collection-id org.example.RemoteCollection collection-repo-remote "file://${test_tmpdir}/collection-repo" +${CMD_PREFIX} ostree --repo=repo pull collection-repo-remote rcommit +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_file_has_content summary "(org.example.RemoteCollection, rcommit)$" + +cd ${test_tmpdir} +mkdir no-collection-repo +ostree_repo_init no-collection-repo +mkdir -p adir2 +${CMD_PREFIX} ostree --repo=no-collection-repo commit --branch=rcommit2 -m rcommit2 -s rcommit2 adir2 +${CMD_PREFIX} ostree --repo=repo remote add --no-gpg-verify no-collection-repo-remote "file://${test_tmpdir}/no-collection-repo" +${CMD_PREFIX} ostree --repo=repo pull no-collection-repo-remote rcommit2 +${CMD_PREFIX} ostree --repo=repo summary --update + +${CMD_PREFIX} ostree --repo=repo summary --view > summary +assert_not_file_has_content summary "rcommit2" + echo "ok summary collections" diff --git a/tests/test-summary-view.sh b/tests/test-summary-view.sh index 60855eb1..52ac8926 100755 --- a/tests/test-summary-view.sh +++ b/tests/test-summary-view.sh @@ -27,7 +27,7 @@ set -euo pipefail echo "1..2" COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" -setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" +setup_fake_remote_repo1 "archive" "${COMMIT_SIGN}" # Set up a second branch. mkdir ${test_tmpdir}/ostree-srv/other-files @@ -41,7 +41,7 @@ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo summary -u # Check out the repository. prev_dir=`pwd` cd ${test_tmpdir} -ostree_repo_init repo --mode=archive-z2 +ostree_repo_init repo --mode=archive ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo ${CMD_PREFIX} ostree --repo=repo pull --mirror origin diff --git a/tests/test-symbols.sh b/tests/test-symbols.sh index b324d1bf..f54b64ee 100755 --- a/tests/test-symbols.sh +++ b/tests/test-symbols.sh @@ -52,7 +52,7 @@ echo 'ok documented symbols' # ONLY update this checksum in release commits! cat > released-sha256.txt <