diff --git a/Makefile-libostree-defines.am b/Makefile-libostree-defines.am index 1531cf8c..aff7e52b 100644 --- a/Makefile-libostree-defines.am +++ b/Makefile-libostree-defines.am @@ -38,6 +38,12 @@ libostree_public_headers = \ src/libostree/ostree-repo-deprecated.h \ $(NULL) +if ENABLE_EXPERIMENTAL_API +libostree_public_headers += \ + src/libostree/ostree-remote.h \ + $(NULL) +endif + # This one is generated via configure.ac, and the gtk-doc # code hence needs to look in the builddir. libostree_public_built_headers = src/libostree/ostree-version.h diff --git a/Makefile-libostree.am b/Makefile-libostree.am index 0a114884..7f2e2a4a 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -94,6 +94,8 @@ libostree_1_la_SOURCES = \ src/libostree/ostree-linuxfsutil.c \ src/libostree/ostree-diff.c \ src/libostree/ostree-mutable-tree.c \ + src/libostree/ostree-remote.c \ + src/libostree/ostree-remote-private.h \ src/libostree/ostree-repo.c \ src/libostree/ostree-repo-checkout.c \ src/libostree/ostree-repo-commit.c \ @@ -113,6 +115,7 @@ libostree_1_la_SOURCES = \ src/libostree/ostree-sysroot-cleanup.c \ src/libostree/ostree-sysroot-deploy.c \ src/libostree/ostree-sysroot-upgrader.c \ + src/libostree/ostree-impl-system-generator.c \ src/libostree/ostree-bootconfig-parser.c \ src/libostree/ostree-deployment.c \ src/libostree/ostree-bootloader.h \ @@ -146,6 +149,11 @@ libostree_1_la_SOURCES += \ src/libostree/ostree-tls-cert-interaction.h \ $(NULL) endif +if !ENABLE_EXPERIMENTAL_API +libostree_1_la_SOURCES += \ + src/libostree/ostree-remote.h \ + $(NULL) +endif libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/bsdiff -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -I$(builddir)/src/libostree \ $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(OT_DEP_LZMA_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) $(OT_DEP_OPENSSL_CFLAGS) \ @@ -156,7 +164,15 @@ libostree_1_la_LIBADD = libotutil.la libglnx.la libbsdiff.la libostree-kernel-ar libostree_1_la_LIBADD += $(bupsplitpath) EXTRA_libostree_1_la_DEPENDENCIES = $(top_srcdir)/src/libostree/libostree.sym -EXTRA_DIST += src/libostree/libostree.sym +EXTRA_DIST += \ + src/libostree/libostree.sym \ + src/libostree/libostree-experimental.sym \ + $(NULL) + +if ENABLE_EXPERIMENTAL_API +libostree_1_la_LDFLAGS += -Wl,--version-script=$(top_srcdir)/src/libostree/libostree-experimental.sym +EXTRA_libostree_1_la_DEPENDENCIES += $(top_srcdir)/src/libostree/libostree-experimental.sym +endif if USE_LIBARCHIVE libostree_1_la_CFLAGS += $(OT_DEP_LIBARCHIVE_CFLAGS) diff --git a/Makefile-switchroot.am b/Makefile-switchroot.am index 6fd2f820..dd24010e 100644 --- a/Makefile-switchroot.am +++ b/Makefile-switchroot.am @@ -27,6 +27,7 @@ ostree_prepare_root_SOURCES = \ src/switchroot/ostree-mount-util.h \ src/switchroot/ostree-prepare-root.c \ $(NULL) +ostree_prepare_root_CPPFLAGS = $(AM_CPPFLAGS) if BUILDOPT_USE_STATIC_COMPILER # ostree-prepare-root can be used as init in a system without a populated /lib. @@ -45,7 +46,6 @@ ostree-prepare-root : $(ostree_prepare_root_SOURCES) $(STATIC_COMPILER) -o $@ -static $(ostree_prepare_root_SOURCES) $(AM_CPPFLAGS) $(AM_CFLAGS) $(DEFAULT_INCLUDES) else ostree_boot_PROGRAMS += ostree-prepare-root - ostree_prepare_root_CFLAGS = $(AM_CFLAGS) -Isrc/switchroot endif @@ -53,4 +53,19 @@ ostree_remount_SOURCES = \ src/switchroot/ostree-mount-util.h \ src/switchroot/ostree-remount.c \ $(NULL) -ostree_remount_CFLAGS = $(AM_CFLAGS) -Isrc/switchroot +ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) -Isrc/switchroot + +# This is the "new mode" of using a generator for /var; see +# https://github.com/ostreedev/ostree/issues/855 +if BUILDOPT_SYSTEMD_AND_LIBMOUNT +ostree_prepare_root_CPPFLAGS += -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +ostree_remount_CPPFLAGS += -DHAVE_SYSTEMD_AND_LIBMOUNT=1 + +systemdsystemgenerator_PROGRAMS = ostree-system-generator +GITIGNOREFILES += $(systemdsystemgenerator_PROGRAMS) +ostree_system_generator_SOURCES = src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-system-generator.c +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) +endif diff --git a/Makefile-tests.am b/Makefile-tests.am index 8389331d..89675288 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -34,6 +34,7 @@ TESTS_ENVIRONMENT += OT_TESTS_DEBUG=1 \ GI_TYPELIB_PATH=$$(cd $(top_builddir) && pwd)$${GI_TYPELIB_PATH:+:$$GI_TYPELIB_PATH} \ 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) if BUILDOPT_ASAN TESTS_ENVIRONMENT += OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc @@ -42,12 +43,20 @@ endif uninstalled_test_data = tests/ostree-symlink-stamp tests/ostree-prepare-root-symlink-stamp \ tests/ostree-remount-symlink-stamp tests/rofiles-fuse-symlink-stamp -dist_uninstalled_test_scripts = tests/test-symbols.sh +dist_uninstalled_test_scripts = tests/test-symbols.sh tests/coccinelle.sh -dist_test_scripts = \ +# This logic implements ENABLE_INSTALLED_TESTS_EXCLUSIVE; see below. +# The goal here if installed tests are enabled, we explicitly make the +# 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) +test_programs = $(NULL) +_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 \ tests/test-archivez.sh \ tests/test-remote-add.sh \ @@ -68,7 +77,6 @@ dist_test_scripts = \ tests/test-pull-resume.sh \ tests/test-pull-repeated.sh \ tests/test-pull-untrusted.sh \ - tests/test-pull-many.sh \ tests/test-pull-override-url.sh \ tests/test-local-pull.sh \ tests/test-local-pull-depth.sh \ @@ -88,7 +96,6 @@ dist_test_scripts = \ tests/test-admin-pull-deploy-split.sh \ tests/test-admin-locking.sh \ tests/test-admin-deploy-clean.sh \ - tests/test-repo-checkout-subpath.sh \ tests/test-reset-nonlinear.sh \ tests/test-oldstyle-partial.sh \ tests/test-delta.sh \ @@ -100,23 +107,23 @@ dist_test_scripts = \ tests/test-switchroot.sh \ tests/test-pull-contenturl.sh \ tests/test-pull-mirrorlist.sh \ - tests/coccinelle.sh \ + tests/test-summary-view.sh \ $(NULL) if BUILDOPT_FUSE -dist_test_scripts += tests/test-rofiles-fuse.sh +_installed_or_uninstalled_test_scripts += tests/test-rofiles-fuse.sh else EXTRA_DIST += tests/test-rofiles-fuse.sh endif if USE_LIBSOUP -dist_test_scripts += tests/test-remote-cookies.sh +_installed_or_uninstalled_test_scripts += tests/test-remote-cookies.sh endif -# These call into gjs scripts +# These call into gjs scripts js_tests = tests/test-corruption.sh tests/test-pull-corruption.sh if BUILDOPT_GJS -dist_test_scripts += $(js_tests) +_installed_or_uninstalled_test_scripts += $(js_tests) else EXTRA_DIST += $(js_tests) endif @@ -127,9 +134,10 @@ dist_installed_test_data = tests/archive-test.sh \ tests/basic-test.sh \ tests/pre-endian-deltas-repo-big.tar.xz \ tests/pre-endian-deltas-repo-little.tar.xz \ + tests/libtest-core.sh \ $(NULL) -EXTRA_DIST += tests/libtest.sh +EXTRA_DIST += tests/libtest.sh dist_test_extra_scripts = \ tests/bootloader-entries-crosscheck.py \ @@ -179,7 +187,7 @@ if !ENABLE_INSTALLED_TESTS libreaddir_rand_la_LDFLAGS += -rpath $(abs_builddir) endif -test_programs = tests/test-varint tests/test-ot-unix-utils tests/test-bsdiff tests/test-mutable-tree \ +_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 @@ -188,7 +196,7 @@ test_programs = tests/test-varint tests/test-ot-unix-utils tests/test-bsdiff tes noinst_PROGRAMS += tests/test-rollsum-cli if USE_LIBARCHIVE -test_programs += tests/test-libarchive-import +_installed_or_uninstalled_test_programs += tests/test-libarchive-import endif common_tests_cflags = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx @@ -285,6 +293,17 @@ tests/%-symlink-stamp: % Makefile ln -sf "$${real_bin}" tests/$*; \ touch $@ +# See above comment on binding the tests to be either installed or not. +if ENABLE_INSTALLED_TESTS_EXCLUSIVE +dist_installed_test_scripts = $(_installed_or_uninstalled_test_scripts) +installed_test_programs = $(_installed_or_uninstalled_test_programs) +check-local: + echo "NOTE: Exclusive installed tests are enabled; to run them, make install, then: gnome-desktop-testing-runner -p 0 libostree/" +else +dist_test_scripts += $(_installed_or_uninstalled_test_scripts) +test_programs += $(_installed_or_uninstalled_test_programs) +endif + # Unfortunately the glib test data APIs don't actually handle # non-recursive Automake, so we change our code to canonically look # for tests/ which is just a symlink when installed. diff --git a/Makefile.am b/Makefile.am index 78cd6653..53b505e3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ include Makefile-decls.am shortened_sysconfdir = $$(echo "$(sysconfdir)" | sed -e 's|^$(prefix)||' -e 's|^/||') -OSTREE_GITREV=$(shell if command -v git >/dev/null 2>&1 && test -d $(srcdir)/.git; then git describe --abbrev=42 --tags --always HEAD; fi) +OSTREE_GITREV=$(shell cd $(srcdir) && if command -v git >/dev/null 2>&1 && test -d .git; then git describe --abbrev=42 --tags --always HEAD; fi) ACLOCAL_AMFLAGS = -I buildutil -I libglnx ${ACLOCAL_FLAGS} AM_CPPFLAGS += -DDATADIR='"$(datadir)"' -DLIBEXECDIR='"$(libexecdir)"' \ @@ -113,11 +113,11 @@ include Makefile-boot.am include Makefile-man.am release-tag: - git tag -m "Release $(VERSION)" v$(VERSION) + cd $(srcdir) && git $(srcdir) tag -m "Release $(VERSION)" v$(VERSION) embed_dependency=tar -C $(srcdir) --append --exclude='.git/*' --transform="s,^embedded-dependencies/,ostree-embeddeps-$${GITVERSION}/embedded-dependencies/," --file=$${TARFILE_TMP} -git_version_rpm = $$(git describe | sed -e 's,-,\.,g' -e 's,^v,,') +git_version_rpm = $$(cd $(srcdir) && git describe | sed -e 's,-,\.,g' -e 's,^v,,') release-tarball-embedded: set -x; \ diff --git a/Makefile.in b/Makefile.in index d17f7720..b0d766e6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -340,13 +340,13 @@ host_triplet = @host@ bin_PROGRAMS = ostree$(EXEEXT) $(am__EXEEXT_1) sbin_PROGRAMS = libexec_PROGRAMS = -pkglibexec_PROGRAMS = $(am__EXEEXT_12) -noinst_PROGRAMS = $(am__EXEEXT_9) tests/test-rollsum-cli$(EXEEXT) -ostree_boot_PROGRAMS = $(am__EXEEXT_10) $(am__EXEEXT_11) -TESTS = $(am__EXEEXT_3) $(am__EXEEXT_14) \ - $(dist_uninstalled_test_scripts) $(am__EXEEXT_6) -installed_test_PROGRAMS = $(am__EXEEXT_8) -check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) +pkglibexec_PROGRAMS = $(am__EXEEXT_16) +noinst_PROGRAMS = $(am__EXEEXT_13) tests/test-rollsum-cli$(EXEEXT) +ostree_boot_PROGRAMS = $(am__EXEEXT_14) $(am__EXEEXT_15) +TESTS = $(am__EXEEXT_6) $(am__EXEEXT_19) \ + $(dist_uninstalled_test_scripts) $(am__EXEEXT_10) +installed_test_PROGRAMS = $(am__EXEEXT_12) +check_PROGRAMS = $(am__EXEEXT_9) $(am__EXEEXT_10) $(am__EXEEXT_11) @ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__append_1 = $(all_test_ltlibs) @ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__append_2 = $(all_test_programs) @ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__append_3 = $(all_test_scripts) @@ -374,23 +374,33 @@ check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) @ENABLE_INSTALLED_TESTS_TRUE@am__append_13 = $(installed_test_meta_DATA) @ENABLE_GTK_DOC_TRUE@am__append_14 = apidoc @ENABLE_RUST_TRUE@am__append_15 = $(srcdir)/rust/Cargo.toml $(srcdir)/rust/cargo-vendor-config -@ENABLE_RUST_TRUE@am__append_16 = $(BUPSPLIT_RUST_SRCS) -@ENABLE_RUST_FALSE@am__append_17 = libbupsplit.la -@USE_LIBARCHIVE_TRUE@am__append_18 = src/libostree/ostree-libarchive-input-stream.h \ +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_16 = \ +@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-remote.h \ +@ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) + +@ENABLE_RUST_TRUE@am__append_17 = $(BUPSPLIT_RUST_SRCS) +@ENABLE_RUST_FALSE@am__append_18 = libbupsplit.la +@USE_LIBARCHIVE_TRUE@am__append_19 = src/libostree/ostree-libarchive-input-stream.h \ @USE_LIBARCHIVE_TRUE@ src/libostree/ostree-libarchive-input-stream.c \ @USE_LIBARCHIVE_TRUE@ src/libostree/ostree-libarchive-private.h \ @USE_LIBARCHIVE_TRUE@ $(NULL) -@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@am__append_19 = \ +@HAVE_LIBSOUP_CLIENT_CERTS_TRUE@am__append_20 = \ @HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ src/libostree/ostree-tls-cert-interaction.c \ @HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ src/libostree/ostree-tls-cert-interaction.h \ @HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ $(NULL) -@USE_LIBARCHIVE_TRUE@am__append_20 = $(OT_DEP_LIBARCHIVE_CFLAGS) -@USE_LIBARCHIVE_TRUE@am__append_21 = $(OT_DEP_LIBARCHIVE_LIBS) -@BUILDOPT_LIBSYSTEMD_TRUE@am__append_22 = $(LIBSYSTEMD_CFLAGS) -@BUILDOPT_LIBSYSTEMD_TRUE@am__append_23 = $(LIBSYSTEMD_LIBS) -@USE_CURL_OR_SOUP_TRUE@am__append_24 = \ +@ENABLE_EXPERIMENTAL_API_FALSE@am__append_21 = \ +@ENABLE_EXPERIMENTAL_API_FALSE@ src/libostree/ostree-remote.h \ +@ENABLE_EXPERIMENTAL_API_FALSE@ $(NULL) + +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_22 = -Wl,--version-script=$(top_srcdir)/src/libostree/libostree-experimental.sym +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_23 = $(top_srcdir)/src/libostree/libostree-experimental.sym +@USE_LIBARCHIVE_TRUE@am__append_24 = $(OT_DEP_LIBARCHIVE_CFLAGS) +@USE_LIBARCHIVE_TRUE@am__append_25 = $(OT_DEP_LIBARCHIVE_LIBS) +@BUILDOPT_LIBSYSTEMD_TRUE@am__append_26 = $(LIBSYSTEMD_CFLAGS) +@BUILDOPT_LIBSYSTEMD_TRUE@am__append_27 = $(LIBSYSTEMD_LIBS) +@USE_CURL_OR_SOUP_TRUE@am__append_28 = \ @USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-fetcher.h \ @USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-fetcher-util.h \ @USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-fetcher-util.c \ @@ -399,25 +409,25 @@ check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) @USE_CURL_OR_SOUP_TRUE@ src/libostree/ostree-metalink.c \ @USE_CURL_OR_SOUP_TRUE@ $(NULL) -@USE_CURL_TRUE@am__append_25 = src/libostree/ostree-fetcher-curl.c \ +@USE_CURL_TRUE@am__append_29 = src/libostree/ostree-fetcher-curl.c \ @USE_CURL_TRUE@ src/libostree/ostree-soup-uri.h src/libostree/ostree-soup-uri.c \ @USE_CURL_TRUE@ src/libostree/ostree-soup-form.c \ @USE_CURL_TRUE@ $(NULL) -@USE_CURL_TRUE@am__append_26 = $(OT_DEP_CURL_CFLAGS) -@USE_CURL_TRUE@am__append_27 = $(OT_DEP_CURL_LIBS) -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_28 = src/libostree/ostree-fetcher-soup.c -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_29 = $(OT_INTERNAL_SOUP_CFLAGS) -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_30 = $(OT_INTERNAL_SOUP_LIBS) -@USE_LIBMOUNT_TRUE@am__append_31 = $(OT_DEP_LIBMOUNT_CFLAGS) -@USE_LIBMOUNT_TRUE@am__append_32 = $(OT_DEP_LIBMOUNT_LIBS) -@USE_SELINUX_TRUE@am__append_33 = $(OT_DEP_SELINUX_CFLAGS) -@USE_SELINUX_TRUE@am__append_34 = $(OT_DEP_SELINUX_LIBS) -@BUILDOPT_INTROSPECTION_TRUE@am__append_35 = OSTree-1.0.gir -@BUILDOPT_INTROSPECTION_TRUE@am__append_36 = OSTree-1.0.gir -@BUILDOPT_INTROSPECTION_TRUE@am__append_37 = OSTree-1.0.typelib -@BUILDOPT_INTROSPECTION_TRUE@am__append_38 = $(gir_DATA) $(typelib_DATA) -@USE_CURL_OR_SOUP_TRUE@am__append_39 = src/ostree/ot-remote-builtin-add-cookie.c \ +@USE_CURL_TRUE@am__append_30 = $(OT_DEP_CURL_CFLAGS) +@USE_CURL_TRUE@am__append_31 = $(OT_DEP_CURL_LIBS) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_32 = src/libostree/ostree-fetcher-soup.c +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_33 = $(OT_INTERNAL_SOUP_CFLAGS) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_34 = $(OT_INTERNAL_SOUP_LIBS) +@USE_LIBMOUNT_TRUE@am__append_35 = $(OT_DEP_LIBMOUNT_CFLAGS) +@USE_LIBMOUNT_TRUE@am__append_36 = $(OT_DEP_LIBMOUNT_LIBS) +@USE_SELINUX_TRUE@am__append_37 = $(OT_DEP_SELINUX_CFLAGS) +@USE_SELINUX_TRUE@am__append_38 = $(OT_DEP_SELINUX_LIBS) +@BUILDOPT_INTROSPECTION_TRUE@am__append_39 = OSTree-1.0.gir +@BUILDOPT_INTROSPECTION_TRUE@am__append_40 = OSTree-1.0.gir +@BUILDOPT_INTROSPECTION_TRUE@am__append_41 = OSTree-1.0.typelib +@BUILDOPT_INTROSPECTION_TRUE@am__append_42 = $(gir_DATA) $(typelib_DATA) +@USE_CURL_OR_SOUP_TRUE@am__append_43 = src/ostree/ot-remote-builtin-add-cookie.c \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-builtin-delete-cookie.c \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-builtin-list-cookies.c \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ot-remote-cookie-util.h \ @@ -425,40 +435,49 @@ check_PROGRAMS = $(am__EXEEXT_5) $(am__EXEEXT_6) $(am__EXEEXT_7) @USE_CURL_OR_SOUP_TRUE@ $(NULL) src/ostree/ot-builtin-pull.c # Eventually once we stop things from using this, we should support disabling this -@USE_LIBSOUP_TRUE@am__append_40 = src/ostree/ot-builtin-trivial-httpd.c -@USE_LIBSOUP_TRUE@am__append_41 = ostree-trivial-httpd +@USE_LIBSOUP_TRUE@am__append_44 = src/ostree/ot-builtin-trivial-httpd.c +@USE_LIBSOUP_TRUE@am__append_45 = ostree-trivial-httpd # This is necessary for the cookie jar bits -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_42 = $(OT_INTERNAL_SOUP_CFLAGS) -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_43 = $(OT_INTERNAL_SOUP_LIBS) -@USE_LIBARCHIVE_TRUE@am__append_44 = $(OT_DEP_LIBARCHIVE_CFLAGS) -@USE_LIBARCHIVE_TRUE@am__append_45 = $(OT_DEP_LIBARCHIVE_LIBS) -@BUILDOPT_SYSTEMD_TRUE@am__append_46 = ostree-remount +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_46 = $(OT_INTERNAL_SOUP_CFLAGS) +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__append_47 = $(OT_INTERNAL_SOUP_LIBS) +@USE_LIBARCHIVE_TRUE@am__append_48 = $(OT_DEP_LIBARCHIVE_CFLAGS) +@USE_LIBARCHIVE_TRUE@am__append_49 = $(OT_DEP_LIBARCHIVE_LIBS) +@BUILDOPT_SYSTEMD_TRUE@am__append_50 = ostree-remount # It is built anyway as a side-effect of having the symlink in tests/, # and if we declare it here, it gets cleaned up properly -@BUILDOPT_SYSTEMD_FALSE@am__append_47 = ostree-remount -@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__append_48 = ostree-prepare-root -@BUILDOPT_FUSE_TRUE@am__append_49 = rofiles-fuse -@BUILDOPT_ASAN_TRUE@am__append_50 = OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc -@BUILDOPT_FUSE_TRUE@am__append_51 = tests/test-rofiles-fuse.sh -@BUILDOPT_FUSE_FALSE@am__append_52 = tests/test-rofiles-fuse.sh -@USE_LIBSOUP_TRUE@am__append_53 = tests/test-remote-cookies.sh -@BUILDOPT_GJS_TRUE@am__append_54 = $(js_tests) -@BUILDOPT_GJS_FALSE@am__append_55 = $(js_tests) -@BUILDOPT_GJS_FALSE@am__append_56 = $(js_installed_tests) -@ENABLE_INSTALLED_TESTS_FALSE@am__append_57 = -rpath $(abs_builddir) -@USE_LIBARCHIVE_TRUE@am__append_58 = tests/test-libarchive-import -@ENABLE_INSTALLED_TESTS_TRUE@am__append_59 = install-installed-tests-extra +@BUILDOPT_SYSTEMD_FALSE@am__append_51 = ostree-remount +@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__append_52 = ostree-prepare-root + +# This is the "new mode" of using a generator for /var; see +# https://github.com/ostreedev/ostree/issues/855 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_53 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_54 = -DHAVE_SYSTEMD_AND_LIBMOUNT=1 +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@systemdsystemgenerator_PROGRAMS = ostree-system-generator$(EXEEXT) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am__append_55 = $(systemdsystemgenerator_PROGRAMS) +@BUILDOPT_FUSE_TRUE@am__append_56 = rofiles-fuse +@BUILDOPT_ASAN_TRUE@am__append_57 = OT_SKIP_READDIR_RAND=1 G_SLICE=always-malloc +@BUILDOPT_FUSE_TRUE@am__append_58 = tests/test-rofiles-fuse.sh +@BUILDOPT_FUSE_FALSE@am__append_59 = tests/test-rofiles-fuse.sh +@USE_LIBSOUP_TRUE@am__append_60 = tests/test-remote-cookies.sh +@BUILDOPT_GJS_TRUE@am__append_61 = $(js_tests) +@BUILDOPT_GJS_FALSE@am__append_62 = $(js_tests) +@BUILDOPT_GJS_FALSE@am__append_63 = $(js_installed_tests) +@ENABLE_INSTALLED_TESTS_FALSE@am__append_64 = -rpath $(abs_builddir) +@USE_LIBARCHIVE_TRUE@am__append_65 = tests/test-libarchive-import +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_66 = $(_installed_or_uninstalled_test_scripts) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__append_67 = $(_installed_or_uninstalled_test_programs) +@ENABLE_INSTALLED_TESTS_TRUE@am__append_68 = install-installed-tests-extra # Allow the distcheck install under $prefix test to pass -@BUILDOPT_SYSTEMD_TRUE@am__append_60 = --with-systemdsystemunitdir='$${libdir}/systemd/system' +@BUILDOPT_SYSTEMD_TRUE@am__append_69 = --with-systemdsystemunitdir='$${libdir}/systemd/system' # We're using the system grub2-mkconfig generator -@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_61 = src/boot/grub2/grub2-15_ostree -@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_62 = install-grub2-config-hook -@BUILDOPT_FUSE_TRUE@@ENABLE_MAN_TRUE@am__append_63 = rofiles-fuse.1 -@ENABLE_MAN_TRUE@am__append_64 = $(man1_MANS) $(man5_MANS) $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) -@ENABLE_MAN_TRUE@am__append_65 = \ +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_70 = src/boot/grub2/grub2-15_ostree +@BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE@am__append_71 = install-grub2-config-hook +@BUILDOPT_FUSE_TRUE@@ENABLE_MAN_TRUE@am__append_72 = rofiles-fuse.1 +@ENABLE_MAN_TRUE@am__append_73 = $(man1_MANS) $(man5_MANS) $(man1_MANS:.1=.xml) $(man5_MANS:.5=.xml) +@ENABLE_MAN_TRUE@am__append_74 = \ @ENABLE_MAN_TRUE@ $(man1_MANS) \ @ENABLE_MAN_TRUE@ $(man5_MANS) \ @ENABLE_MAN_TRUE@ $(NULL) @@ -480,8 +499,8 @@ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__dist_gpginsttest_DATA_DIST) \ $(am__dist_gpginsttest_trusted_DATA_DIST) \ - $(am__dist_gpgvinsttest_DATA_DIST) $(libostreeinclude_HEADERS) \ - $(am__DIST_COMMON) + $(am__dist_gpgvinsttest_DATA_DIST) \ + $(am__libostreeinclude_HEADERS_DIST) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d @@ -521,8 +540,8 @@ am__installdirs = "$(DESTDIR)$(installed_testdir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(installed_testdir)" \ "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(ostree_bootdir)" \ "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(sbindir)" \ - "$(DESTDIR)$(bindir)" "$(DESTDIR)$(dracutmoddir)" \ - "$(DESTDIR)$(installed_testdir)" \ + "$(DESTDIR)$(systemdsystemgeneratordir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" \ "$(DESTDIR)$(mkinitcpioinstalldir)" \ "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" \ @@ -611,6 +630,8 @@ am__libostree_1_la_SOURCES_DIST = \ src/libostree/ostree-linuxfsutil.h \ src/libostree/ostree-linuxfsutil.c src/libostree/ostree-diff.c \ src/libostree/ostree-mutable-tree.c \ + src/libostree/ostree-remote.c \ + src/libostree/ostree-remote-private.h \ src/libostree/ostree-repo.c \ src/libostree/ostree-repo-checkout.c \ src/libostree/ostree-repo-commit.c \ @@ -630,6 +651,7 @@ am__libostree_1_la_SOURCES_DIST = \ src/libostree/ostree-sysroot-cleanup.c \ src/libostree/ostree-sysroot-deploy.c \ src/libostree/ostree-sysroot-upgrader.c \ + src/libostree/ostree-impl-system-generator.c \ src/libostree/ostree-bootconfig-parser.c \ src/libostree/ostree-deployment.c \ src/libostree/ostree-bootloader.h \ @@ -655,7 +677,7 @@ am__libostree_1_la_SOURCES_DIST = \ src/libostree/ostree-libarchive-private.h \ src/libostree/ostree-tls-cert-interaction.c \ src/libostree/ostree-tls-cert-interaction.h \ - src/libostree/ostree-fetcher.h \ + src/libostree/ostree-remote.h src/libostree/ostree-fetcher.h \ src/libostree/ostree-fetcher-util.h \ src/libostree/ostree-fetcher-util.c \ src/libostree/ostree-fetcher-uri.c \ @@ -670,15 +692,16 @@ am__libostree_1_la_SOURCES_DIST = \ @USE_LIBARCHIVE_TRUE@ $(am__objects_1) @HAVE_LIBSOUP_CLIENT_CERTS_TRUE@am__objects_3 = src/libostree/libostree_1_la-ostree-tls-cert-interaction.lo \ @HAVE_LIBSOUP_CLIENT_CERTS_TRUE@ $(am__objects_1) -@USE_CURL_OR_SOUP_TRUE@am__objects_4 = src/libostree/libostree_1_la-ostree-fetcher-util.lo \ +@ENABLE_EXPERIMENTAL_API_FALSE@am__objects_4 = $(am__objects_1) +@USE_CURL_OR_SOUP_TRUE@am__objects_5 = src/libostree/libostree_1_la-ostree-fetcher-util.lo \ @USE_CURL_OR_SOUP_TRUE@ src/libostree/libostree_1_la-ostree-fetcher-uri.lo \ @USE_CURL_OR_SOUP_TRUE@ src/libostree/libostree_1_la-ostree-metalink.lo \ @USE_CURL_OR_SOUP_TRUE@ $(am__objects_1) -@USE_CURL_TRUE@am__objects_5 = src/libostree/libostree_1_la-ostree-fetcher-curl.lo \ +@USE_CURL_TRUE@am__objects_6 = src/libostree/libostree_1_la-ostree-fetcher-curl.lo \ @USE_CURL_TRUE@ src/libostree/libostree_1_la-ostree-soup-uri.lo \ @USE_CURL_TRUE@ src/libostree/libostree_1_la-ostree-soup-form.lo \ @USE_CURL_TRUE@ $(am__objects_1) -@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__objects_6 = src/libostree/libostree_1_la-ostree-fetcher-soup.lo +@USE_CURL_FALSE@@USE_LIBSOUP_TRUE@am__objects_7 = src/libostree/libostree_1_la-ostree-fetcher-soup.lo am_libostree_1_la_OBJECTS = \ src/libostree/libostree_1_la-ostree-async-progress.lo \ src/libostree/libostree_1_la-ostree-cmdprivate.lo \ @@ -694,6 +717,7 @@ am_libostree_1_la_OBJECTS = \ src/libostree/libostree_1_la-ostree-linuxfsutil.lo \ src/libostree/libostree_1_la-ostree-diff.lo \ src/libostree/libostree_1_la-ostree-mutable-tree.lo \ + src/libostree/libostree_1_la-ostree-remote.lo \ src/libostree/libostree_1_la-ostree-repo.lo \ src/libostree/libostree_1_la-ostree-repo-checkout.lo \ src/libostree/libostree_1_la-ostree-repo-commit.lo \ @@ -709,6 +733,7 @@ am_libostree_1_la_OBJECTS = \ src/libostree/libostree_1_la-ostree-sysroot-cleanup.lo \ src/libostree/libostree_1_la-ostree-sysroot-deploy.lo \ src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo \ + src/libostree/libostree_1_la-ostree-impl-system-generator.lo \ src/libostree/libostree_1_la-ostree-bootconfig-parser.lo \ src/libostree/libostree_1_la-ostree-deployment.lo \ src/libostree/libostree_1_la-ostree-bootloader.lo \ @@ -722,7 +747,8 @@ am_libostree_1_la_OBJECTS = \ src/libostree/libostree_1_la-ostree-gpg-verifier.lo \ src/libostree/libostree_1_la-ostree-gpg-verify-result.lo \ $(am__objects_1) $(am__objects_2) $(am__objects_3) \ - $(am__objects_4) $(am__objects_5) $(am__objects_6) + $(am__objects_4) $(am__objects_5) $(am__objects_6) \ + $(am__objects_7) nodist_libostree_1_la_OBJECTS = \ src/libostree/libostree_1_la-ostree-enumtypes.lo \ $(am__objects_1) @@ -785,9 +811,10 @@ libreaddir_rand_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @ENABLE_INSTALLED_TESTS_TRUE@am_libreaddir_rand_la_rpath = -rpath \ @ENABLE_INSTALLED_TESTS_TRUE@ $(installed_testdir) @BUILDOPT_FUSE_TRUE@am__EXEEXT_1 = rofiles-fuse$(EXEEXT) -@USE_LIBARCHIVE_TRUE@am__EXEEXT_2 = \ +am__EXEEXT_2 = +@USE_LIBARCHIVE_TRUE@am__EXEEXT_3 = \ @USE_LIBARCHIVE_TRUE@ tests/test-libarchive-import$(EXEEXT) -am__EXEEXT_3 = tests/test-varint$(EXEEXT) \ +am__EXEEXT_4 = tests/test-varint$(EXEEXT) \ tests/test-ot-unix-utils$(EXEEXT) tests/test-bsdiff$(EXEEXT) \ tests/test-mutable-tree$(EXEEXT) \ tests/test-keyfile-utils$(EXEEXT) \ @@ -797,20 +824,26 @@ am__EXEEXT_3 = tests/test-varint$(EXEEXT) \ tests/test-checksum$(EXEEXT) tests/test-lzma$(EXEEXT) \ tests/test-rollsum$(EXEEXT) tests/test-basic-c$(EXEEXT) \ tests/test-sysroot-c$(EXEEXT) tests/test-pull-c$(EXEEXT) \ - $(am__EXEEXT_2) -am__EXEEXT_4 = $(am__EXEEXT_3) -@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__EXEEXT_5 = $(am__EXEEXT_4) -am__EXEEXT_6 = test-libglnx-xattrs$(EXEEXT) test-libglnx-fdio$(EXEEXT) \ - test-libglnx-errors$(EXEEXT) -@BUILDOPT_SYSTEMD_FALSE@am__EXEEXT_7 = ostree-remount$(EXEEXT) -@ENABLE_INSTALLED_TESTS_TRUE@am__EXEEXT_8 = $(am__EXEEXT_3) -@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__EXEEXT_9 = $(am__EXEEXT_4) -@BUILDOPT_SYSTEMD_TRUE@am__EXEEXT_10 = ostree-remount$(EXEEXT) -@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__EXEEXT_11 = ostree-prepare-root$(EXEEXT) -@USE_LIBSOUP_TRUE@am__EXEEXT_12 = ostree-trivial-httpd$(EXEEXT) + $(am__EXEEXT_3) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__EXEEXT_5 = \ +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@ $(am__EXEEXT_4) +am__EXEEXT_6 = $(am__EXEEXT_2) $(am__EXEEXT_5) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@am__EXEEXT_7 = $(am__EXEEXT_4) +am__EXEEXT_8 = $(am__EXEEXT_6) $(am__EXEEXT_7) +@ENABLE_ALWAYS_BUILD_TESTS_FALSE@am__EXEEXT_9 = $(am__EXEEXT_8) +am__EXEEXT_10 = test-libglnx-xattrs$(EXEEXT) \ + test-libglnx-fdio$(EXEEXT) test-libglnx-errors$(EXEEXT) +@BUILDOPT_SYSTEMD_FALSE@am__EXEEXT_11 = ostree-remount$(EXEEXT) +@ENABLE_INSTALLED_TESTS_TRUE@am__EXEEXT_12 = $(am__EXEEXT_6) \ +@ENABLE_INSTALLED_TESTS_TRUE@ $(am__EXEEXT_7) +@ENABLE_ALWAYS_BUILD_TESTS_TRUE@am__EXEEXT_13 = $(am__EXEEXT_8) +@BUILDOPT_SYSTEMD_TRUE@am__EXEEXT_14 = ostree-remount$(EXEEXT) +@BUILDOPT_USE_STATIC_COMPILER_FALSE@am__EXEEXT_15 = ostree-prepare-root$(EXEEXT) +@USE_LIBSOUP_TRUE@am__EXEEXT_16 = ostree-trivial-httpd$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(installed_test_PROGRAMS) \ $(libexec_PROGRAMS) $(noinst_PROGRAMS) $(ostree_boot_PROGRAMS) \ - $(pkglibexec_PROGRAMS) $(sbin_PROGRAMS) + $(pkglibexec_PROGRAMS) $(sbin_PROGRAMS) \ + $(systemdsystemgenerator_PROGRAMS) am__ostree_SOURCES_DIST = src/ostree/main.c \ src/ostree/ot-builtin-admin.c src/ostree/ot-builtins.h \ src/ostree/ot-builtin-cat.c src/ostree/ot-builtin-config.c \ @@ -863,13 +896,13 @@ am__ostree_SOURCES_DIST = src/ostree/main.c \ src/ostree/ot-remote-cookie-util.c \ src/ostree/ot-builtin-pull.c \ src/ostree/ot-builtin-trivial-httpd.c -@USE_CURL_OR_SOUP_TRUE@am__objects_7 = src/ostree/ostree-ot-remote-builtin-add-cookie.$(OBJEXT) \ +@USE_CURL_OR_SOUP_TRUE@am__objects_8 = src/ostree/ostree-ot-remote-builtin-add-cookie.$(OBJEXT) \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-remote-builtin-delete-cookie.$(OBJEXT) \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-remote-builtin-list-cookies.$(OBJEXT) \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-remote-cookie-util.$(OBJEXT) \ @USE_CURL_OR_SOUP_TRUE@ $(am__objects_1) \ @USE_CURL_OR_SOUP_TRUE@ src/ostree/ostree-ot-builtin-pull.$(OBJEXT) -@USE_LIBSOUP_TRUE@am__objects_8 = src/ostree/ostree-ot-builtin-trivial-httpd.$(OBJEXT) +@USE_LIBSOUP_TRUE@am__objects_9 = src/ostree/ostree-ot-builtin-trivial-httpd.$(OBJEXT) am_ostree_OBJECTS = src/ostree/ostree-main.$(OBJEXT) \ src/ostree/ostree-ot-builtin-admin.$(OBJEXT) \ src/ostree/ostree-ot-builtin-cat.$(OBJEXT) \ @@ -921,7 +954,7 @@ am_ostree_OBJECTS = src/ostree/ostree-main.$(OBJEXT) \ src/ostree/ostree-ot-remote-builtin-show-url.$(OBJEXT) \ src/ostree/ostree-ot-remote-builtin-refs.$(OBJEXT) \ src/ostree/ostree-ot-remote-builtin-summary.$(OBJEXT) \ - $(am__objects_1) $(am__objects_7) $(am__objects_8) + $(am__objects_1) $(am__objects_8) $(am__objects_9) ostree_OBJECTS = $(am_ostree_OBJECTS) ostree_DEPENDENCIES = $(am__DEPENDENCIES_10) libbsdiff.la \ libostree-kernel-args.la $(am__DEPENDENCIES_1) \ @@ -942,10 +975,19 @@ am_ostree_remount_OBJECTS = \ $(am__objects_1) ostree_remount_OBJECTS = $(am_ostree_remount_OBJECTS) ostree_remount_LDADD = $(LDADD) -ostree_remount_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ +am__ostree_system_generator_SOURCES_DIST = \ + src/switchroot/ostree-mount-util.h \ + src/switchroot/ostree-system-generator.c +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@am_ostree_system_generator_OBJECTS = src/switchroot/ostree_system_generator-ostree-system-generator.$(OBJEXT) +ostree_system_generator_OBJECTS = \ + $(am_ostree_system_generator_OBJECTS) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_DEPENDENCIES = \ +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ libglnx.la libostree-1.la \ +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ $(am__DEPENDENCIES_2) +ostree_system_generator_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(ostree_remount_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o \ - $@ + $(ostree_system_generator_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ am__ostree_trivial_httpd_SOURCES_DIST = \ src/ostree/ostree-trivial-httpd.c @USE_LIBSOUP_TRUE@am_ostree_trivial_httpd_OBJECTS = src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.$(OBJEXT) @@ -1172,6 +1214,7 @@ SOURCES = $(libbsdiff_la_SOURCES) $(libbupsplit_la_SOURCES) \ $(libostreetest_la_SOURCES) $(libotutil_la_SOURCES) \ $(libreaddir_rand_la_SOURCES) $(ostree_SOURCES) \ $(ostree_prepare_root_SOURCES) $(ostree_remount_SOURCES) \ + $(ostree_system_generator_SOURCES) \ $(ostree_trivial_httpd_SOURCES) $(rofiles_fuse_SOURCES) \ $(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \ $(test_libglnx_xattrs_SOURCES) tests/test-basic-c.c \ @@ -1192,6 +1235,7 @@ DIST_SOURCES = $(libbsdiff_la_SOURCES) \ $(libostreetest_la_SOURCES) $(libotutil_la_SOURCES) \ $(libreaddir_rand_la_SOURCES) $(am__ostree_SOURCES_DIST) \ $(ostree_prepare_root_SOURCES) $(ostree_remount_SOURCES) \ + $(am__ostree_system_generator_SOURCES_DIST) \ $(am__ostree_trivial_httpd_SOURCES_DIST) \ $(am__rofiles_fuse_SOURCES_DIST) \ $(test_libglnx_errors_SOURCES) $(test_libglnx_fdio_SOURCES) \ @@ -1237,6 +1281,21 @@ DATA = $(dist_gpginsttest_DATA) $(dist_gpginsttest_trusted_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 \ + src/libostree/ostree-core.h \ + src/libostree/ostree-dummy-enumtypes.h \ + src/libostree/ostree-mutable-tree.h \ + src/libostree/ostree-repo.h src/libostree/ostree-types.h \ + src/libostree/ostree-repo-file.h src/libostree/ostree-diff.h \ + src/libostree/ostree-gpg-verify-result.h \ + src/libostree/ostree-sepolicy.h src/libostree/ostree-sysroot.h \ + src/libostree/ostree-sysroot-upgrader.h \ + src/libostree/ostree-deployment.h \ + src/libostree/ostree-bootconfig-parser.h \ + src/libostree/ostree-repo-deprecated.h \ + src/libostree/ostree-remote.h src/libostree/ostree-version.h HEADERS = $(libostreeinclude_HEADERS) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive @@ -1423,22 +1482,20 @@ am__set_TESTS_bases = \ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ bases=`echo $$bases` RECHECK_LOGS = $(TEST_LOGS) -am__EXEEXT_13 = -am__EXEEXT_14 = tests/test-basic.sh tests/test-basic-user.sh \ - tests/test-basic-user-only.sh tests/test-pull-subpath.sh \ - tests/test-archivez.sh tests/test-remote-add.sh \ - tests/test-remote-headers.sh tests/test-remote-gpg-import.sh \ - tests/test-commit-sign.sh tests/test-export.sh \ - tests/test-help.sh tests/test-libarchive.sh \ - tests/test-parent.sh tests/test-pull-archive-z.sh \ - tests/test-pull-commit-only.sh tests/test-pull-depth.sh \ - tests/test-pull-mirror-summary.sh \ +am__EXEEXT_17 = 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 tests/test-archivez.sh \ + tests/test-remote-add.sh tests/test-remote-headers.sh \ + tests/test-remote-gpg-import.sh tests/test-commit-sign.sh \ + tests/test-export.sh tests/test-help.sh \ + tests/test-libarchive.sh tests/test-parent.sh \ + tests/test-pull-archive-z.sh tests/test-pull-commit-only.sh \ + tests/test-pull-depth.sh tests/test-pull-mirror-summary.sh \ tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \ tests/test-pull-summary-sigs.sh tests/test-pull-resume.sh \ tests/test-pull-repeated.sh tests/test-pull-untrusted.sh \ - tests/test-pull-many.sh tests/test-pull-override-url.sh \ - tests/test-local-pull.sh tests/test-local-pull-depth.sh \ - tests/test-gpg-signed-commit.sh \ + tests/test-pull-override-url.sh tests/test-local-pull.sh \ + tests/test-local-pull-depth.sh tests/test-gpg-signed-commit.sh \ tests/test-admin-upgrade-unconfigured.sh \ tests/test-admin-deploy-syslinux.sh \ tests/test-admin-deploy-2.sh tests/test-admin-deploy-karg.sh \ @@ -1452,15 +1509,17 @@ am__EXEEXT_14 = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-admin-pull-deploy-commit.sh \ tests/test-admin-pull-deploy-split.sh \ tests/test-admin-locking.sh tests/test-admin-deploy-clean.sh \ - tests/test-repo-checkout-subpath.sh \ tests/test-reset-nonlinear.sh tests/test-oldstyle-partial.sh \ tests/test-delta.sh tests/test-xattrs.sh \ tests/test-auto-summary.sh tests/test-prune.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/coccinelle.sh \ - $(am__EXEEXT_13) $(am__append_51) $(am__append_53) \ - $(am__append_54) + tests/test-pull-mirrorlist.sh tests/test-summary-view.sh \ + $(am__EXEEXT_2) $(am__append_58) $(am__append_60) \ + $(am__append_61) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@am__EXEEXT_18 = \ +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@ $(am__EXEEXT_17) +am__EXEEXT_19 = $(am__EXEEXT_2) $(am__EXEEXT_18) TEST_SUITE_LOG = test-suite.log TEST_EXTENSIONS = @EXEEXT@ .test LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) @@ -1727,6 +1786,7 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemdsystemgeneratordir = @systemdsystemgeneratordir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ @@ -1746,25 +1806,26 @@ AM_CPPFLAGS = -DDATADIR='"$(datadir)"' -DLIBEXECDIR='"$(libexecdir)"' \ -DSOUP_VERSION_MAX_ALLOWED=SOUP_VERSION_2_48 AM_CFLAGS = -std=gnu99 $(WARN_CFLAGS) AM_DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-man \ - --disable-maintainer-mode $(NULL) $(am__append_60) + --disable-maintainer-mode $(NULL) $(am__append_69) SUBDIRS = . $(am__append_14) NULL = BUILT_SOURCES = $(nodist_libostree_1_la_SOURCES) MANPAGES = -CLEANFILES = $(am__append_13) $(BUILT_SOURCES) $(am__append_38) \ +CLEANFILES = $(am__append_13) $(BUILT_SOURCES) $(am__append_42) \ src/ostree/parse-datetime.c tests/libreaddir-rand.so \ tests/ostree-symlink-stamp \ tests/ostree-prepare-root-symlink-stamp \ tests/ostree-remount-symlink-stamp \ tests/rofiles-fuse-symlink-stamp tests/ostree \ tests/ostree-prepare-root tests/ostree-remount \ - tests/rofiles-fuse $(am__append_65) + tests/rofiles-fuse $(am__append_74) 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) \ libglnx/Makefile-libglnx.am bsdiff/bsdiff.h bsdiff/bspatch.h \ bsdiff/LICENSE bsdiff/README.md bsdiff/Makefile-bsdiff.am \ - $(am__append_16) src/libostree/libostree.sym \ + $(am__append_17) src/libostree/libostree.sym \ + src/libostree/libostree-experimental.sym $(NULL) \ src/libostree/README-gpg src/libostree/bupsplit.h \ src/libostree/ostree-enumtypes.h.template \ src/libostree/ostree-enumtypes.c.template \ @@ -1772,29 +1833,29 @@ 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_52) $(am__append_55) \ - tests/libtest.sh $(am__append_56) tests/libostreetest.h \ + tests/ostree.supp $(NULL) $(am__append_59) $(am__append_62) \ + tests/libtest.sh $(am__append_63) 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_64) + src/boot/grub2/ostree-grub-generator $(NULL) $(am__append_73) bin_SCRIPTS = lib_LTLIBRARIES = libostree-1.la -pkglibexec_SCRIPTS = $(am__append_61) +pkglibexec_SCRIPTS = $(am__append_70) noinst_LTLIBRARIES = $(am__append_1) libglnx.la libbsdiff.la \ - libotutil.la libostree-kernel-args.la $(am__append_17) \ + libotutil.la libostree-kernel-args.la $(am__append_18) \ libostreetest.la privlibdir = $(pkglibdir) privlib_LTLIBRARIES = pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = src/libostree/ostree-1.pc -INTROSPECTION_GIRS = $(am__append_35) +INTROSPECTION_GIRS = $(am__append_39) girdir = $(datadir)/gir-1.0 -gir_DATA = $(am__append_36) +gir_DATA = $(am__append_40) typelibdir = $(libdir)/girepository-1.0 -typelib_DATA = $(am__append_37) +typelib_DATA = $(am__append_41) gsettings_SCHEMAS = ostree_bootdir = $(prefix)/lib/ostree @@ -1811,8 +1872,8 @@ TESTS_ENVIRONMENT = G_TEST_SRCDIR="$(abs_srcdir)" \ pwd)$${GI_TYPELIB_PATH:+:$$GI_TYPELIB_PATH} \ LD_LIBRARY_PATH=$$(cd $(top_builddir)/.libs && \ pwd)$${LD_LIBRARY_PATH:+:$${LD_LIBRARY_PATH}} PATH=$$(cd \ - $(top_builddir)/tests && pwd):$${PATH} $(NULL) \ - $(am__append_50) + $(top_builddir)/tests && pwd):$${PATH} \ + OSTREE_FEATURES="$(OSTREE_FEATURES)" $(NULL) $(am__append_57) 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) @@ -1852,13 +1913,14 @@ 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_59) \ - $(am__append_62) +INSTALL_DATA_HOOKS = install-mkdir-remotes-d-hook $(am__append_68) \ + $(am__append_71) ALL_LOCAL_RULES = tests/libreaddir-rand.so shortened_sysconfdir = $$(echo "$(sysconfdir)" | sed -e 's|^$(prefix)||' -e 's|^/||') -OSTREE_GITREV = $(shell if command -v git >/dev/null 2>&1 && test -d $(srcdir)/.git; then git describe --abbrev=42 --tags --always HEAD; fi) +OSTREE_GITREV = $(shell cd $(srcdir) && if command -v git >/dev/null 2>&1 && test -d .git; then git describe --abbrev=42 --tags --always HEAD; fi) ACLOCAL_AMFLAGS = -I buildutil -I libglnx ${ACLOCAL_FLAGS} -GITIGNOREFILES = aclocal.m4 build-aux/ buildutil/*.m4 config.h.in gtk-doc.make +GITIGNOREFILES = aclocal.m4 build-aux/ buildutil/*.m4 config.h.in \ + gtk-doc.make $(am__append_55) OT_INTERNAL_GIO_UNIX_CFLAGS = $(OT_DEP_GIO_UNIX_CFLAGS) OT_INTERNAL_GIO_UNIX_LIBS = $(OT_DEP_GIO_UNIX_LIBS) OT_INTERNAL_SOUP_CFLAGS = $(OT_DEP_SOUP_CFLAGS) @@ -1954,26 +2016,21 @@ libotutil_la_SOURCES = \ libotutil_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil -DLOCALEDIR=\"$(datadir)/locale\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(LIBSYSTEMD_CFLAGS) libotutil_la_LIBADD = $(OT_INTERNAL_GIO_UNIX_LIBS) $(OT_INTERNAL_GPGME_LIBS) $(LIBSYSTEMD_LIBS) -libostree_public_headers = \ - src/libostree/ostree.h \ +libostree_public_headers = src/libostree/ostree.h \ src/libostree/ostree-async-progress.h \ src/libostree/ostree-autocleanups.h \ src/libostree/ostree-core.h \ src/libostree/ostree-dummy-enumtypes.h \ src/libostree/ostree-mutable-tree.h \ - src/libostree/ostree-repo.h \ - src/libostree/ostree-types.h \ - src/libostree/ostree-repo-file.h \ - src/libostree/ostree-diff.h \ + src/libostree/ostree-repo.h src/libostree/ostree-types.h \ + src/libostree/ostree-repo-file.h src/libostree/ostree-diff.h \ src/libostree/ostree-gpg-verify-result.h \ - src/libostree/ostree-sepolicy.h \ - src/libostree/ostree-sysroot.h \ + src/libostree/ostree-sepolicy.h src/libostree/ostree-sysroot.h \ src/libostree/ostree-sysroot-upgrader.h \ src/libostree/ostree-deployment.h \ src/libostree/ostree-bootconfig-parser.h \ - src/libostree/ostree-repo-deprecated.h \ - $(NULL) - + src/libostree/ostree-repo-deprecated.h $(NULL) \ + $(am__append_16) # This one is generated via configure.ac, and the gtk-doc # code hence needs to look in the builddir. @@ -2018,6 +2075,8 @@ libostree_1_la_SOURCES = src/libostree/ostree-async-progress.c \ src/libostree/ostree-linuxfsutil.h \ src/libostree/ostree-linuxfsutil.c src/libostree/ostree-diff.c \ src/libostree/ostree-mutable-tree.c \ + src/libostree/ostree-remote.c \ + src/libostree/ostree-remote-private.h \ src/libostree/ostree-repo.c \ src/libostree/ostree-repo-checkout.c \ src/libostree/ostree-repo-commit.c \ @@ -2037,6 +2096,7 @@ libostree_1_la_SOURCES = src/libostree/ostree-async-progress.c \ src/libostree/ostree-sysroot-cleanup.c \ src/libostree/ostree-sysroot-deploy.c \ src/libostree/ostree-sysroot-upgrader.c \ + src/libostree/ostree-impl-system-generator.c \ src/libostree/ostree-bootconfig-parser.c \ src/libostree/ostree-deployment.c \ src/libostree/ostree-bootloader.h \ @@ -2056,9 +2116,9 @@ libostree_1_la_SOURCES = src/libostree/ostree-async-progress.c \ src/libostree/ostree-gpg-verifier.h \ src/libostree/ostree-gpg-verify-result.c \ src/libostree/ostree-gpg-verify-result-private.h \ - src/libostree/ostree-autocleanups.h $(NULL) $(am__append_18) \ - $(am__append_19) $(am__append_24) $(am__append_25) \ - $(am__append_28) + src/libostree/ostree-autocleanups.h $(NULL) $(am__append_19) \ + $(am__append_20) $(am__append_21) $(am__append_28) \ + $(am__append_29) $(am__append_32) libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/bsdiff \ -I$(srcdir)/libglnx -I$(srcdir)/src/libotutil \ -I$(srcdir)/src/libostree -I$(builddir)/src/libostree \ @@ -2066,16 +2126,19 @@ libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/bsdiff \ $(OT_DEP_LZMA_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) \ $(OT_DEP_OPENSSL_CFLAGS) -fvisibility=hidden \ '-D_OSTREE_PUBLIC=__attribute__((visibility("default"))) \ - extern' $(am__append_20) $(am__append_22) $(am__append_26) \ - $(am__append_29) $(am__append_31) $(am__append_33) -libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions -Wl,--version-script=$(top_srcdir)/src/libostree/libostree.sym + extern' $(am__append_24) $(am__append_26) $(am__append_30) \ + $(am__append_33) $(am__append_35) $(am__append_37) +libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions \ + -Wl,--version-script=$(top_srcdir)/src/libostree/libostree.sym \ + $(am__append_22) libostree_1_la_LIBADD = libotutil.la libglnx.la libbsdiff.la \ libostree-kernel-args.la $(OT_INTERNAL_GIO_UNIX_LIBS) \ $(OT_INTERNAL_GPGME_LIBS) $(OT_DEP_LZMA_LIBS) \ $(OT_DEP_ZLIB_LIBS) $(OT_DEP_OPENSSL_LIBS) $(bupsplitpath) \ - $(am__append_21) $(am__append_23) $(am__append_27) \ - $(am__append_30) $(am__append_32) $(am__append_34) -EXTRA_libostree_1_la_DEPENDENCIES = $(top_srcdir)/src/libostree/libostree.sym + $(am__append_25) $(am__append_27) $(am__append_31) \ + $(am__append_34) $(am__append_36) $(am__append_38) +EXTRA_libostree_1_la_DEPENDENCIES = \ + $(top_srcdir)/src/libostree/libostree.sym $(am__append_23) @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_EXPORT_PACKAGES = ostree-1 @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_INCLUDES = Gio-2.0 @BUILDOPT_INTROSPECTION_TRUE@OSTree_1_0_gir_CFLAGS = $(libostree_1_la_CFLAGS) @@ -2133,7 +2196,7 @@ ostree_SOURCES = src/ostree/main.c src/ostree/ot-builtin-admin.c \ src/ostree/ot-remote-builtin-show-url.c \ src/ostree/ot-remote-builtin-refs.c \ src/ostree/ot-remote-builtin-summary.c $(NULL) \ - $(am__append_39) $(am__append_40) + $(am__append_43) $(am__append_44) ostree_bin_shared_cflags = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree \ -I$(builddir)/src/libostree -I$(srcdir)/src/ostree -I$(srcdir)/libglnx $(OT_INTERNAL_GIO_UNIX_CFLAGS) \ -DPKGLIBEXECDIR=\"$(pkglibexecdir)\" @@ -2141,11 +2204,11 @@ ostree_bin_shared_cflags = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/sr ostree_bin_shared_ldadd = $(AM_LDFLAGS) libglnx.la libotutil.la libostree-1.la \ $(OT_INTERNAL_GIO_UNIX_LIBS) -ostree_CFLAGS = $(ostree_bin_shared_cflags) $(am__append_42) \ - $(am__append_44) +ostree_CFLAGS = $(ostree_bin_shared_cflags) $(am__append_46) \ + $(am__append_48) ostree_LDADD = $(ostree_bin_shared_ldadd) libbsdiff.la \ - libostree-kernel-args.la $(LIBSYSTEMD_LIBS) $(am__append_43) \ - $(am__append_45) + libostree-kernel-args.la $(LIBSYSTEMD_LIBS) $(am__append_47) \ + $(am__append_49) @USE_LIBSOUP_TRUE@ostree_trivial_httpd_SOURCES = src/ostree/ostree-trivial-httpd.c @USE_LIBSOUP_TRUE@ostree_trivial_httpd_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_SOUP_CFLAGS) @USE_LIBSOUP_TRUE@ostree_trivial_httpd_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_SOUP_LIBS) @@ -2154,6 +2217,7 @@ ostree_prepare_root_SOURCES = \ src/switchroot/ostree-prepare-root.c \ $(NULL) +ostree_prepare_root_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_53) # We're using our internal generator @BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE@ostree_boot_SCRIPTS = src/boot/grub2/ostree-grub-generator @@ -2174,16 +2238,32 @@ ostree_remount_SOURCES = \ src/switchroot/ostree-remount.c \ $(NULL) -ostree_remount_CFLAGS = $(AM_CFLAGS) -Isrc/switchroot +ostree_remount_CPPFLAGS = $(AM_CPPFLAGS) -Isrc/switchroot \ + $(am__append_54) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_SOURCES = src/switchroot/ostree-mount-util.h \ +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ src/switchroot/ostree-system-generator.c + +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/libglnx -I$(srcdir)/src/libostree +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) +@BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE@ostree_system_generator_LDADD = $(AM_LDFLAGS) libglnx.la libostree-1.la $(OT_INTERNAL_GIO_UNIX_LIBS) @BUILDOPT_FUSE_TRUE@rofiles_fuse_SOURCES = src/rofiles-fuse/main.c @BUILDOPT_FUSE_TRUE@rofiles_fuse_CFLAGS = $(AM_CFLAGS) -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 $(BUILDOPT_FUSE_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx $(NULL) @BUILDOPT_FUSE_TRUE@rofiles_fuse_LDADD = libglnx.la $(BUILDOPT_FUSE_LIBS) $(OT_INTERNAL_GIO_UNIX_LIBS) uninstalled_test_data = tests/ostree-symlink-stamp tests/ostree-prepare-root-symlink-stamp \ tests/ostree-remount-symlink-stamp tests/rofiles-fuse-symlink-stamp -dist_uninstalled_test_scripts = tests/test-symbols.sh -dist_test_scripts = tests/test-basic.sh tests/test-basic-user.sh \ - tests/test-basic-user-only.sh tests/test-pull-subpath.sh \ +dist_uninstalled_test_scripts = tests/test-symbols.sh tests/coccinelle.sh + +# This logic implements ENABLE_INSTALLED_TESTS_EXCLUSIVE; see below. +# The goal here if installed tests are enabled, we explicitly make the +# 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_66) +test_programs = $(NULL) $(am__append_67) +_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 \ tests/test-archivez.sh tests/test-remote-add.sh \ tests/test-remote-headers.sh tests/test-remote-gpg-import.sh \ tests/test-commit-sign.sh tests/test-export.sh \ @@ -2194,9 +2274,8 @@ dist_test_scripts = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-pull-large-metadata.sh tests/test-pull-metalink.sh \ tests/test-pull-summary-sigs.sh tests/test-pull-resume.sh \ tests/test-pull-repeated.sh tests/test-pull-untrusted.sh \ - tests/test-pull-many.sh tests/test-pull-override-url.sh \ - tests/test-local-pull.sh tests/test-local-pull-depth.sh \ - tests/test-gpg-signed-commit.sh \ + tests/test-pull-override-url.sh tests/test-local-pull.sh \ + tests/test-local-pull-depth.sh tests/test-gpg-signed-commit.sh \ tests/test-admin-upgrade-unconfigured.sh \ tests/test-admin-deploy-syslinux.sh \ tests/test-admin-deploy-2.sh tests/test-admin-deploy-karg.sh \ @@ -2210,16 +2289,15 @@ dist_test_scripts = tests/test-basic.sh tests/test-basic-user.sh \ tests/test-admin-pull-deploy-commit.sh \ tests/test-admin-pull-deploy-split.sh \ tests/test-admin-locking.sh tests/test-admin-deploy-clean.sh \ - tests/test-repo-checkout-subpath.sh \ tests/test-reset-nonlinear.sh tests/test-oldstyle-partial.sh \ tests/test-delta.sh tests/test-xattrs.sh \ tests/test-auto-summary.sh tests/test-prune.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/coccinelle.sh $(NULL) \ - $(am__append_51) $(am__append_53) $(am__append_54) + tests/test-pull-mirrorlist.sh tests/test-summary-view.sh \ + $(NULL) $(am__append_58) $(am__append_60) $(am__append_61) -# These call into gjs scripts +# These call into gjs scripts js_tests = tests/test-corruption.sh tests/test-pull-corruption.sh dist_installed_test_data = tests/archive-test.sh \ tests/pull-test.sh \ @@ -2227,6 +2305,7 @@ dist_installed_test_data = tests/archive-test.sh \ tests/basic-test.sh \ tests/pre-endian-deltas-repo-big.tar.xz \ tests/pre-endian-deltas-repo-little.tar.xz \ + tests/libtest-core.sh \ $(NULL) dist_test_extra_scripts = \ @@ -2259,6 +2338,9 @@ js_installed_tests = \ $(NULL) @BUILDOPT_GJS_TRUE@dist_installed_test_scripts = $(js_installed_tests) + +# See above comment on binding the tests to be either installed or not. +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@dist_installed_test_scripts = $(_installed_or_uninstalled_test_scripts) test_ltlibraries = libreaddir-rand.la libreaddir_rand_la_SOURCES = tests/readdir-rand.c libreaddir_rand_la_CFLAGS = $(AM_CFLAGS) $(OT_INTERNAL_GIO_UNIX_CFLAGS) @@ -2268,14 +2350,14 @@ libreaddir_rand_la_LIBADD = \ $(NULL) libreaddir_rand_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version \ - $(am__append_57) -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_58) + $(am__append_64) +_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_65) 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 @@ -2327,6 +2409,7 @@ tests_test_gpg_verify_result_SOURCES = \ tests_test_gpg_verify_result_CFLAGS = $(TESTS_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@installed_test_programs = $(_installed_or_uninstalled_test_programs) # Not using $(libdir) here is intentional, dracut modules go in prefix/lib @BUILDOPT_DRACUT_TRUE@dracutmoddir = $(prefix)/lib/dracut/modules.d/98ostree @@ -2359,7 +2442,7 @@ tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) @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 ostree-trivial-httpd.1 \ -@ENABLE_MAN_TRUE@ $(am__append_63) +@ENABLE_MAN_TRUE@ $(am__append_72) @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)) @@ -2374,7 +2457,7 @@ tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) @ENABLE_MAN_TRUE@XSLTPROC_MAN = $(XSLTPROC) $(XSLTPROC_FLAGS) embed_dependency = tar -C $(srcdir) --append --exclude='.git/*' --transform="s,^embedded-dependencies/,ostree-embeddeps-$${GITVERSION}/embedded-dependencies/," --file=$${TARFILE_TMP} -git_version_rpm = $$(git describe | sed -e 's,-,\.,g' -e 's,^v,,') +git_version_rpm = $$(cd $(srcdir) && git describe | sed -e 's,-,\.,g' -e 's,^v,,') all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -2653,6 +2736,9 @@ src/libostree/libostree_1_la-ostree-diff.lo: \ src/libostree/libostree_1_la-ostree-mutable-tree.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-remote.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) src/libostree/libostree_1_la-ostree-repo.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) @@ -2698,6 +2784,9 @@ src/libostree/libostree_1_la-ostree-sysroot-deploy.lo: \ src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) +src/libostree/libostree_1_la-ostree-impl-system-generator.lo: \ + src/libostree/$(am__dirstamp) \ + src/libostree/$(DEPDIR)/$(am__dirstamp) src/libostree/libostree_1_la-ostree-bootconfig-parser.lo: \ src/libostree/$(am__dirstamp) \ src/libostree/$(DEPDIR)/$(am__dirstamp) @@ -3145,6 +3234,55 @@ clean-sbinPROGRAMS: list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list +install-systemdsystemgeneratorPROGRAMS: $(systemdsystemgenerator_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(systemdsystemgenerator_PROGRAMS)'; test -n "$(systemdsystemgeneratordir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemgeneratordir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemdsystemgeneratordir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(systemdsystemgeneratordir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(systemdsystemgeneratordir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-systemdsystemgeneratorPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(systemdsystemgenerator_PROGRAMS)'; test -n "$(systemdsystemgeneratordir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(systemdsystemgeneratordir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(systemdsystemgeneratordir)" && rm -f $$files + +clean-systemdsystemgeneratorPROGRAMS: + @list='$(systemdsystemgenerator_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list src/ostree/$(am__dirstamp): @$(MKDIR_P) src/ostree @: > src/ostree/$(am__dirstamp) @@ -3337,7 +3475,14 @@ src/switchroot/ostree_remount-ostree-remount.$(OBJEXT): \ ostree-remount$(EXEEXT): $(ostree_remount_OBJECTS) $(ostree_remount_DEPENDENCIES) $(EXTRA_ostree_remount_DEPENDENCIES) @rm -f ostree-remount$(EXEEXT) - $(AM_V_CCLD)$(ostree_remount_LINK) $(ostree_remount_OBJECTS) $(ostree_remount_LDADD) $(LIBS) + $(AM_V_CCLD)$(LINK) $(ostree_remount_OBJECTS) $(ostree_remount_LDADD) $(LIBS) +src/switchroot/ostree_system_generator-ostree-system-generator.$(OBJEXT): \ + src/switchroot/$(am__dirstamp) \ + src/switchroot/$(DEPDIR)/$(am__dirstamp) + +ostree-system-generator$(EXEEXT): $(ostree_system_generator_OBJECTS) $(ostree_system_generator_DEPENDENCIES) $(EXTRA_ostree_system_generator_DEPENDENCIES) + @rm -f ostree-system-generator$(EXEEXT) + $(AM_V_CCLD)$(ostree_system_generator_LINK) $(ostree_system_generator_OBJECTS) $(ostree_system_generator_LDADD) $(LIBS) src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.$(OBJEXT): \ src/ostree/$(am__dirstamp) \ src/ostree/$(DEPDIR)/$(am__dirstamp) @@ -3768,6 +3913,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-fetcher-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verifier.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-gpg-verify-result.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-libarchive-input-stream.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-linuxfsutil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-common.Plo@am__quote@ @@ -3775,6 +3921,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-lzma-decompressor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-metalink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-mutable-tree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-checkout.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-commit.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo-file-enumerator.Plo@am__quote@ @@ -3879,6 +4026,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/rofiles-fuse/$(DEPDIR)/rofiles_fuse-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/libostreetest_la-libostreetest.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/libreaddir_rand_la-readdir-rand.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tests/$(DEPDIR)/tests_test_basic_c-test-basic-c.Po@am__quote@ @@ -4097,6 +4245,13 @@ src/libostree/libostree_1_la-ostree-mutable-tree.lo: src/libostree/ostree-mutabl @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-mutable-tree.lo `test -f 'src/libostree/ostree-mutable-tree.c' || echo '$(srcdir)/'`src/libostree/ostree-mutable-tree.c +src/libostree/libostree_1_la-ostree-remote.lo: src/libostree/ostree-remote.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-remote.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Tpo -c -o src/libostree/libostree_1_la-ostree-remote.lo `test -f 'src/libostree/ostree-remote.c' || echo '$(srcdir)/'`src/libostree/ostree-remote.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-remote.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-remote.c' object='src/libostree/libostree_1_la-ostree-remote.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-remote.lo `test -f 'src/libostree/ostree-remote.c' || echo '$(srcdir)/'`src/libostree/ostree-remote.c + src/libostree/libostree_1_la-ostree-repo.lo: src/libostree/ostree-repo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-repo.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Tpo -c -o src/libostree/libostree_1_la-ostree-repo.lo `test -f 'src/libostree/ostree-repo.c' || echo '$(srcdir)/'`src/libostree/ostree-repo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-repo.Plo @@ -4202,6 +4357,13 @@ src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo: src/libostree/ostree-sy @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-sysroot-upgrader.lo `test -f 'src/libostree/ostree-sysroot-upgrader.c' || echo '$(srcdir)/'`src/libostree/ostree-sysroot-upgrader.c +src/libostree/libostree_1_la-ostree-impl-system-generator.lo: src/libostree/ostree-impl-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-impl-system-generator.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Tpo -c -o src/libostree/libostree_1_la-ostree-impl-system-generator.lo `test -f 'src/libostree/ostree-impl-system-generator.c' || echo '$(srcdir)/'`src/libostree/ostree-impl-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-impl-system-generator.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libostree/ostree-impl-system-generator.c' object='src/libostree/libostree_1_la-ostree-impl-system-generator.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -c -o src/libostree/libostree_1_la-ostree-impl-system-generator.lo `test -f 'src/libostree/ostree-impl-system-generator.c' || echo '$(srcdir)/'`src/libostree/ostree-impl-system-generator.c + src/libostree/libostree_1_la-ostree-bootconfig-parser.lo: src/libostree/ostree-bootconfig-parser.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libostree_1_la_CFLAGS) $(CFLAGS) -MT src/libostree/libostree_1_la-ostree-bootconfig-parser.lo -MD -MP -MF src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Tpo -c -o src/libostree/libostree_1_la-ostree-bootconfig-parser.lo `test -f 'src/libostree/ostree-bootconfig-parser.c' || echo '$(srcdir)/'`src/libostree/ostree-bootconfig-parser.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Tpo src/libostree/$(DEPDIR)/libostree_1_la-ostree-bootconfig-parser.Plo @@ -5246,32 +5408,46 @@ src/ostree/ostree-ot-builtin-trivial-httpd.obj: src/ostree/ot-builtin-trivial-ht @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_CFLAGS) $(CFLAGS) -c -o src/ostree/ostree-ot-builtin-trivial-httpd.obj `if test -f 'src/ostree/ot-builtin-trivial-httpd.c'; then $(CYGPATH_W) 'src/ostree/ot-builtin-trivial-httpd.c'; else $(CYGPATH_W) '$(srcdir)/src/ostree/ot-builtin-trivial-httpd.c'; fi` src/switchroot/ostree_prepare_root-ostree-prepare-root.o: src/switchroot/ostree-prepare-root.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_prepare_root-ostree-prepare-root.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.o `test -f 'src/switchroot/ostree-prepare-root.c' || echo '$(srcdir)/'`src/switchroot/ostree-prepare-root.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_prepare_root-ostree-prepare-root.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.o `test -f 'src/switchroot/ostree-prepare-root.c' || echo '$(srcdir)/'`src/switchroot/ostree-prepare-root.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-prepare-root.c' object='src/switchroot/ostree_prepare_root-ostree-prepare-root.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.o `test -f 'src/switchroot/ostree-prepare-root.c' || echo '$(srcdir)/'`src/switchroot/ostree-prepare-root.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.o `test -f 'src/switchroot/ostree-prepare-root.c' || echo '$(srcdir)/'`src/switchroot/ostree-prepare-root.c src/switchroot/ostree_prepare_root-ostree-prepare-root.obj: src/switchroot/ostree-prepare-root.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_prepare_root-ostree-prepare-root.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.obj `if test -f 'src/switchroot/ostree-prepare-root.c'; then $(CYGPATH_W) 'src/switchroot/ostree-prepare-root.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-prepare-root.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_prepare_root-ostree-prepare-root.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.obj `if test -f 'src/switchroot/ostree-prepare-root.c'; then $(CYGPATH_W) 'src/switchroot/ostree-prepare-root.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-prepare-root.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Tpo src/switchroot/$(DEPDIR)/ostree_prepare_root-ostree-prepare-root.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-prepare-root.c' object='src/switchroot/ostree_prepare_root-ostree-prepare-root.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.obj `if test -f 'src/switchroot/ostree-prepare-root.c'; then $(CYGPATH_W) 'src/switchroot/ostree-prepare-root.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-prepare-root.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_prepare_root_CPPFLAGS) $(CPPFLAGS) $(ostree_prepare_root_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_prepare_root-ostree-prepare-root.obj `if test -f 'src/switchroot/ostree-prepare-root.c'; then $(CYGPATH_W) 'src/switchroot/ostree-prepare-root.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-prepare-root.c'; fi` src/switchroot/ostree_remount-ostree-remount.o: src/switchroot/ostree-remount.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_remount_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_remount-ostree-remount.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo -c -o src/switchroot/ostree_remount-ostree-remount.o `test -f 'src/switchroot/ostree-remount.c' || echo '$(srcdir)/'`src/switchroot/ostree-remount.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_remount-ostree-remount.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo -c -o src/switchroot/ostree_remount-ostree-remount.o `test -f 'src/switchroot/ostree-remount.c' || echo '$(srcdir)/'`src/switchroot/ostree-remount.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-remount.c' object='src/switchroot/ostree_remount-ostree-remount.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_remount_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_remount-ostree-remount.o `test -f 'src/switchroot/ostree-remount.c' || echo '$(srcdir)/'`src/switchroot/ostree-remount.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_remount-ostree-remount.o `test -f 'src/switchroot/ostree-remount.c' || echo '$(srcdir)/'`src/switchroot/ostree-remount.c src/switchroot/ostree_remount-ostree-remount.obj: src/switchroot/ostree-remount.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_remount_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_remount-ostree-remount.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo -c -o src/switchroot/ostree_remount-ostree-remount.obj `if test -f 'src/switchroot/ostree-remount.c'; then $(CYGPATH_W) 'src/switchroot/ostree-remount.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-remount.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_remount-ostree-remount.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo -c -o src/switchroot/ostree_remount-ostree-remount.obj `if test -f 'src/switchroot/ostree-remount.c'; then $(CYGPATH_W) 'src/switchroot/ostree-remount.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-remount.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Tpo src/switchroot/$(DEPDIR)/ostree_remount-ostree-remount.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-remount.c' object='src/switchroot/ostree_remount-ostree-remount.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_remount_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_remount-ostree-remount.obj `if test -f 'src/switchroot/ostree-remount.c'; then $(CYGPATH_W) 'src/switchroot/ostree-remount.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-remount.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_remount_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_remount-ostree-remount.obj `if test -f 'src/switchroot/ostree-remount.c'; then $(CYGPATH_W) 'src/switchroot/ostree-remount.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-remount.c'; fi` + +src/switchroot/ostree_system_generator-ostree-system-generator.o: src/switchroot/ostree-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_system_generator-ostree-system-generator.o -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo -c -o src/switchroot/ostree_system_generator-ostree-system-generator.o `test -f 'src/switchroot/ostree-system-generator.c' || echo '$(srcdir)/'`src/switchroot/ostree-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-system-generator.c' object='src/switchroot/ostree_system_generator-ostree-system-generator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_system_generator-ostree-system-generator.o `test -f 'src/switchroot/ostree-system-generator.c' || echo '$(srcdir)/'`src/switchroot/ostree-system-generator.c + +src/switchroot/ostree_system_generator-ostree-system-generator.obj: src/switchroot/ostree-system-generator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -MT src/switchroot/ostree_system_generator-ostree-system-generator.obj -MD -MP -MF src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo -c -o src/switchroot/ostree_system_generator-ostree-system-generator.obj `if test -f 'src/switchroot/ostree-system-generator.c'; then $(CYGPATH_W) 'src/switchroot/ostree-system-generator.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-system-generator.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Tpo src/switchroot/$(DEPDIR)/ostree_system_generator-ostree-system-generator.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/switchroot/ostree-system-generator.c' object='src/switchroot/ostree_system_generator-ostree-system-generator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(ostree_system_generator_CPPFLAGS) $(CPPFLAGS) $(ostree_system_generator_CFLAGS) $(CFLAGS) -c -o src/switchroot/ostree_system_generator-ostree-system-generator.obj `if test -f 'src/switchroot/ostree-system-generator.c'; then $(CYGPATH_W) 'src/switchroot/ostree-system-generator.c'; else $(CYGPATH_W) '$(srcdir)/src/switchroot/ostree-system-generator.c'; fi` src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o: src/ostree/ostree-trivial-httpd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ostree_trivial_httpd_CFLAGS) $(CFLAGS) -MT src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o -MD -MP -MF src/ostree/$(DEPDIR)/ostree_trivial_httpd-ostree-trivial-httpd.Tpo -c -o src/ostree/ostree_trivial_httpd-ostree-trivial-httpd.o `test -f 'src/ostree/ostree-trivial-httpd.c' || echo '$(srcdir)/'`src/ostree/ostree-trivial-httpd.c @@ -6431,6 +6607,13 @@ tests/test-basic-user-only.sh.log: tests/test-basic-user-only.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/test-basic-root.sh.log: tests/test-basic-root.sh + @p='tests/test-basic-root.sh'; \ + b='tests/test-basic-root.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) tests/test-pull-subpath.sh.log: tests/test-pull-subpath.sh @p='tests/test-pull-subpath.sh'; \ b='tests/test-pull-subpath.sh'; \ @@ -6571,13 +6754,6 @@ tests/test-pull-untrusted.sh.log: tests/test-pull-untrusted.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) -tests/test-pull-many.sh.log: tests/test-pull-many.sh - @p='tests/test-pull-many.sh'; \ - b='tests/test-pull-many.sh'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) tests/test-pull-override-url.sh.log: tests/test-pull-override-url.sh @p='tests/test-pull-override-url.sh'; \ b='tests/test-pull-override-url.sh'; \ @@ -6711,13 +6887,6 @@ tests/test-admin-deploy-clean.sh.log: tests/test-admin-deploy-clean.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) -tests/test-repo-checkout-subpath.sh.log: tests/test-repo-checkout-subpath.sh - @p='tests/test-repo-checkout-subpath.sh'; \ - b='tests/test-repo-checkout-subpath.sh'; \ - $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ - --log-file $$b.log --trs-file $$b.trs \ - $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ - "$$tst" $(AM_TESTS_FD_REDIRECT) tests/test-reset-nonlinear.sh.log: tests/test-reset-nonlinear.sh @p='tests/test-reset-nonlinear.sh'; \ b='tests/test-reset-nonlinear.sh'; \ @@ -6795,9 +6964,9 @@ tests/test-pull-mirrorlist.sh.log: tests/test-pull-mirrorlist.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) -tests/coccinelle.sh.log: tests/coccinelle.sh - @p='tests/coccinelle.sh'; \ - b='tests/coccinelle.sh'; \ +tests/test-summary-view.sh.log: tests/test-summary-view.sh + @p='tests/test-summary-view.sh'; \ + b='tests/test-summary-view.sh'; \ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ @@ -6837,6 +7006,13 @@ tests/test-symbols.sh.log: tests/test-symbols.sh --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +tests/coccinelle.sh.log: tests/coccinelle.sh + @p='tests/coccinelle.sh'; \ + b='tests/coccinelle.sh'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) test-libglnx-xattrs.log: test-libglnx-xattrs$(EXEEXT) @p='test-libglnx-xattrs$(EXEEXT)'; \ b='test-libglnx-xattrs'; \ @@ -7064,7 +7240,7 @@ distcleancheck: distclean || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 -@ENABLE_RUST_FALSE@check-local: +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE@@ENABLE_RUST_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) $(check_LTLIBRARIES) $(check_PROGRAMS) \ $(check_SCRIPTS) $(check_DATA) @@ -7077,7 +7253,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)$(bindir)" "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(mkinitcpioinstalldir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(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)$(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 \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) @@ -7143,7 +7319,8 @@ clean-am: clean-binPROGRAMS clean-checkLTLIBRARIES clean-checkPROGRAMS \ clean-libexecPROGRAMS clean-libtool clean-local \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ clean-ostree_bootPROGRAMS clean-pkglibexecPROGRAMS \ - clean-privlibLTLIBRARIES clean-sbinPROGRAMS mostlyclean-am + clean-privlibLTLIBRARIES clean-sbinPROGRAMS \ + clean-systemdsystemgeneratorPROGRAMS mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) @@ -7175,8 +7352,9 @@ install-data-am: install-dist_gpginsttestDATA \ install-mkinitcpioconfDATA install-mkinitcpioinstallSCRIPTS \ install-nobase_installed_testDATA install-ostree_bootPROGRAMS \ install-ostree_bootSCRIPTS install-pkgconfigDATA \ - install-privlibLTLIBRARIES install-systemdsystemunitDATA \ - install-typelibDATA + install-privlibLTLIBRARIES \ + install-systemdsystemgeneratorPROGRAMS \ + install-systemdsystemunitDATA install-typelibDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-data-hook install-dvi: install-dvi-recursive @@ -7245,8 +7423,9 @@ uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ uninstall-ostree_bootPROGRAMS uninstall-ostree_bootSCRIPTS \ uninstall-pkgconfigDATA uninstall-pkglibexecPROGRAMS \ uninstall-pkglibexecSCRIPTS uninstall-privlibLTLIBRARIES \ - uninstall-sbinPROGRAMS uninstall-systemdsystemunitDATA \ - uninstall-typelibDATA + uninstall-sbinPROGRAMS \ + uninstall-systemdsystemgeneratorPROGRAMS \ + uninstall-systemdsystemunitDATA uninstall-typelibDATA uninstall-man: uninstall-man1 uninstall-man5 @@ -7261,15 +7440,16 @@ uninstall-man: uninstall-man1 uninstall-man5 clean-libexecPROGRAMS clean-libtool clean-local \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ clean-ostree_bootPROGRAMS clean-pkglibexecPROGRAMS \ - clean-privlibLTLIBRARIES clean-sbinPROGRAMS cscope \ - cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ - dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \ - dist-zip distcheck distclean distclean-compile \ - distclean-generic distclean-hdr distclean-libtool \ - distclean-tags distcleancheck distdir distuninstallcheck dvi \ - dvi-am html html-am info info-am install install-am \ - install-binPROGRAMS install-binSCRIPTS install-data \ - install-data-am install-data-hook install-dist_gpginsttestDATA \ + clean-privlibLTLIBRARIES clean-sbinPROGRAMS \ + clean-systemdsystemgeneratorPROGRAMS cscope cscopelist-am \ + ctags ctags-am dist dist-all dist-bzip2 dist-gzip dist-hook \ + dist-lzip dist-shar dist-tarZ dist-xz dist-zip distcheck \ + distclean distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-binSCRIPTS \ + install-data install-data-am install-data-hook \ + install-dist_gpginsttestDATA \ install-dist_gpginsttest_trustedDATA \ install-dist_gpgvinsttestDATA install-dracutconfDATA \ install-dracutmodSCRIPTS install-dvi install-dvi-am \ @@ -7287,6 +7467,7 @@ uninstall-man: uninstall-man1 uninstall-man5 install-pkgconfigDATA install-pkglibexecPROGRAMS \ install-pkglibexecSCRIPTS install-privlibLTLIBRARIES \ install-ps install-ps-am install-sbinPROGRAMS install-strip \ + install-systemdsystemgeneratorPROGRAMS \ install-systemdsystemunitDATA install-typelibDATA installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ @@ -7310,8 +7491,9 @@ uninstall-man: uninstall-man1 uninstall-man5 uninstall-ostree_bootPROGRAMS uninstall-ostree_bootSCRIPTS \ uninstall-pkgconfigDATA uninstall-pkglibexecPROGRAMS \ uninstall-pkglibexecSCRIPTS uninstall-privlibLTLIBRARIES \ - uninstall-sbinPROGRAMS uninstall-systemdsystemunitDATA \ - uninstall-typelibDATA + uninstall-sbinPROGRAMS \ + uninstall-systemdsystemgeneratorPROGRAMS \ + uninstall-systemdsystemunitDATA uninstall-typelibDATA .PRECIOUS: Makefile @@ -7376,6 +7558,8 @@ tests/%-symlink-stamp: % Makefile fi; \ ln -sf "$${real_bin}" tests/$*; \ touch $@ +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@check-local: +@ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE@ echo "NOTE: Exclusive installed tests are enabled; to run them, make install, then: gnome-desktop-testing-runner -p 0 libostree/" # Unfortunately the glib test data APIs don't actually handle # non-recursive Automake, so we change our code to canonically look @@ -7398,7 +7582,7 @@ tests/%-symlink-stamp: % Makefile @ENABLE_MAN_TRUE@ $(AM_V_GEN) $(XSLTPROC_MAN) --output $@ $(XSLT_STYLESHEET) $< release-tag: - git tag -m "Release $(VERSION)" v$(VERSION) + cd $(srcdir) && git $(srcdir) tag -m "Release $(VERSION)" v$(VERSION) release-tarball-embedded: set -x; \ diff --git a/apidoc/Makefile.am b/apidoc/Makefile.am index 730a4c33..f3405fb0 100644 --- a/apidoc/Makefile.am +++ b/apidoc/Makefile.am @@ -120,6 +120,7 @@ include $(top_srcdir)/gtk-doc.make EXTRA_DIST += \ version.xml \ ostree-sections.txt \ + ostree-experimental-sections.txt \ $(NULL) -include $(top_srcdir)/git.mk diff --git a/apidoc/Makefile.in b/apidoc/Makefile.in index 8000f3b4..22ad83e0 100644 --- a/apidoc/Makefile.in +++ b/apidoc/Makefile.in @@ -130,6 +130,10 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ +@ENABLE_EXPERIMENTAL_API_TRUE@am__append_1 = \ +@ENABLE_EXPERIMENTAL_API_TRUE@ src/libostree/ostree-remote.h \ +@ENABLE_EXPERIMENTAL_API_TRUE@ $(NULL) + subdir = apidoc ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/buildutil/attributes.m4 \ @@ -352,31 +356,26 @@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ +systemdsystemgeneratordir = @systemdsystemgeneratordir@ systemdsystemunitdir = @systemdsystemunitdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -libostree_public_headers = \ - src/libostree/ostree.h \ +libostree_public_headers = src/libostree/ostree.h \ src/libostree/ostree-async-progress.h \ src/libostree/ostree-autocleanups.h \ src/libostree/ostree-core.h \ src/libostree/ostree-dummy-enumtypes.h \ src/libostree/ostree-mutable-tree.h \ - src/libostree/ostree-repo.h \ - src/libostree/ostree-types.h \ - src/libostree/ostree-repo-file.h \ - src/libostree/ostree-diff.h \ + src/libostree/ostree-repo.h src/libostree/ostree-types.h \ + src/libostree/ostree-repo-file.h src/libostree/ostree-diff.h \ src/libostree/ostree-gpg-verify-result.h \ - src/libostree/ostree-sepolicy.h \ - src/libostree/ostree-sysroot.h \ + src/libostree/ostree-sepolicy.h src/libostree/ostree-sysroot.h \ src/libostree/ostree-sysroot-upgrader.h \ src/libostree/ostree-deployment.h \ src/libostree/ostree-bootconfig-parser.h \ - src/libostree/ostree-repo-deprecated.h \ - $(NULL) - + src/libostree/ostree-repo-deprecated.h $(NULL) $(am__append_1) # This one is generated via configure.ac, and the gtk-doc # code hence needs to look in the builddir. @@ -499,7 +498,7 @@ SETUP_FILES = \ # This includes the standard gtk-doc make rules, copied by gtkdocize. EXTRA_DIST = $(HTML_IMAGES) $(SETUP_FILES) version.xml \ - ostree-sections.txt $(NULL) + ostree-sections.txt ostree-experimental-sections.txt $(NULL) DOC_STAMPS = setup-build.stamp scan-build.stamp sgml-build.stamp \ html-build.stamp pdf-build.stamp \ sgml.stamp html.stamp pdf.stamp diff --git a/apidoc/html/index.html b/apidoc/html/index.html index e8784b1e..f4d3d764 100644 --- a/apidoc/html/index.html +++ b/apidoc/html/index.html @@ -14,7 +14,7 @@
-

for OSTree 2017.4

+

for OSTree 2017.6


diff --git a/apidoc/html/ostree-Content-addressed-object-store.html b/apidoc/html/ostree-Content-addressed-object-store.html index 0761497c..31c45644 100644 --- a/apidoc/html/ostree-Content-addressed-object-store.html +++ b/apidoc/html/ostree-Content-addressed-object-store.html @@ -881,7 +881,7 @@ -OstreeRepoCommitIterResult +OstreeRepoCommitIterResult ostree_repo_commit_traverse_iter_next () @@ -1044,6 +1044,18 @@ enum +OstreeRepoResolveRevExtFlags + + +enum +OstreeRepoListRefsExtFlags + + +enum +OstreeRepoCommitState + + +enum OstreeRepoCommitFilterResult @@ -1076,6 +1088,14 @@ enum +OstreeRepoCommitTraverseFlags + + +enum +OstreeRepoCommitIterResult + + +enum OstreeRepoPruneFlags @@ -1971,7 +1991,10 @@ ostree_repo_remote_fetch_summary_with_options GError **error);

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

-
+

Parameters

@@ -2504,8 +2527,8 @@ arguments.

- - + +

checksum

The checksum to point it to

 

The checksum to point it to.

[nullable]
@@ -2558,8 +2581,8 @@ be made to the repository.

checksum

-

The checksum to point it to

-  +

The checksum to point it to.

+[nullable]
@@ -3349,7 +3372,7 @@ is true and it does not exist.

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 @@ -3461,7 +3484,7 @@ refspecs which have refspec_prefix 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 @@ -3621,11 +3644,11 @@ result in out_variant 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, 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

@@ -5734,7 +5757,7 @@ 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 +only be called if OSTREE_REPO_COMMIT_ITER_RESULT_DIR was returned from ostree_repo_commit_traverse_iter_next().

Parameters

@@ -5778,7 +5801,7 @@ 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 +called if OSTREE_REPO_COMMIT_ITER_RESULT_FILE was returned from ostree_repo_commit_traverse_iter_next().

Parameters

@@ -5816,7 +5839,7 @@ ostree_repo_commit_traverse_iter_init_commit (OstreeRepoCommitTraverseIter *iter, OstreeRepo *repo, GVariant *commit, - OstreeRepoCommitTraverseFlags flags, + OstreeRepoCommitTraverseFlags flags, GError **error);

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

@@ -5865,7 +5888,7 @@ ostree_repo_commit_traverse_iter_init_dirtree (OstreeRepoCommitTraverseIter *iter, OstreeRepo *repo, GVariant *dirtree, - OstreeRepoCommitTraverseFlags flags, + OstreeRepoCommitTraverseFlags flags, GError **error);

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

@@ -5909,19 +5932,19 @@ 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, +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_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 +

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().

@@ -6314,7 +6337,7 @@ The following are currently defined:

  • override-commit-ids (as): Array of specific commit IDs to fetch for refs

  • dry-run (b): Only print information on what will be downloaded (requires static deltas)

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

  • -
  • inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do mutliple pulls in one transaction.

  • +
  • inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do multiple pulls in one transaction.

  • http-headers (a(ss)): Additional headers to add to all HTTP requests

  • update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid

  • @@ -6882,6 +6905,10 @@ ostree_repo_regenerate_summary (GError **error);

    An OSTree repository can contain a high level "summary" file that describes the available branches and other metadata.

    +

    If the timetable for making commits and updating the summary file is fairly +regular, setting the ostree.summary.expires key in additional_metadata + +will aid clients in working out when to check for updates.

    It is regenerated automatically after a commit if core/commit-update-summary is set.

    @@ -7099,6 +7126,67 @@ in bytes, counting only content objects.


    +

    enum OstreeRepoResolveRevExtFlags

    +
    +

    Members

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

    OSTREE_REPO_RESOLVE_REV_EXT_NONE

    +

    No flags.

    +
     
    +
    +
    +
    +
    +

    enum OstreeRepoListRefsExtFlags

    +
    +

    Members

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

    OSTREE_REPO_LIST_REFS_EXT_NONE

    +

    No flags.

    +
     
    +
    +
    +
    +
    +

    enum OstreeRepoCommitState

    +
    +

    Members

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

    OSTREE_REPO_COMMIT_STATE_PARTIAL

      
    +
    +
    +
    +

    enum OstreeRepoCommitFilterResult

    Members

    @@ -7337,6 +7425,61 @@ as - List of pack file checksums in which this object appears


    +

    enum OstreeRepoCommitTraverseFlags

    +
    +

    Members

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

    OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE

      
    +
    +
    +
    +
    +

    enum OstreeRepoCommitIterResult

    +
    +

    Members

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

    OSTREE_REPO_COMMIT_ITER_RESULT_ERROR

      

    OSTREE_REPO_COMMIT_ITER_RESULT_END

      

    OSTREE_REPO_COMMIT_ITER_RESULT_FILE

      

    OSTREE_REPO_COMMIT_ITER_RESULT_DIR

      
    +
    +
    +
    +

    enum OstreeRepoPruneFlags

    Members

    diff --git a/apidoc/html/ostree-Core-repository-independent-functions.html b/apidoc/html/ostree-Core-repository-independent-functions.html index c4afe12a..8bf4efcf 100644 --- a/apidoc/html/ostree-Core-repository-independent-functions.html +++ b/apidoc/html/ostree-Core-repository-independent-functions.html @@ -2289,9 +2289,9 @@ content, the other types are metadata.

    #define OSTREE_DIRMETA_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_DIRMETA_GVARIANT_STRING)
     
      -
    • u - uid

    • -
    • u - gid

    • -
    • u - mode

    • +
    • u - uid (big-endian)

    • +
    • u - gid (big-endian)

    • +
    • u - mode (big-endian)

    • a(ayay) - xattrs

    @@ -2311,9 +2311,9 @@ in bare-user repositories. This allows us to store metadata information that we can't store in the real filesystem but we can still use a regular .file object that we can hardlink to in the case of a user-mode checkout.

      -
    • u - uid

    • -
    • u - gid

    • -
    • u - mode

    • +
    • u - uid (big-endian)

    • +
    • u - gid (big-endian)

    • +
    • u - mode (big-endian)

    • a(ayay) - xattrs

    @@ -2350,7 +2350,7 @@ that we can hardlink to in the case of a user-mode checkout.

  • a(say) - Related objects

  • s - subject

  • s - body

  • -
  • t - Timestamp in seconds since the epoch (UTC)

  • +
  • t - Timestamp in seconds since the epoch (UTC, big-endian)

  • ay - Root tree contents

  • ay - Root tree metadata

  • @@ -2370,9 +2370,21 @@ that we can hardlink to in the case of a user-mode checkout.

  • a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name

  • a{sv} - Additional metadata, at the current time the following are defined:

    -
    • key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum

    +
      +
    • key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum

    • +
    • key: "ostree.summary.last-modified", value: t, timestamp (seconds since +the Unix epoch in UTC, big-endian) when the summary was last regenerated +(similar to the HTTP Last-Modified header)

    • +
    • key: "ostree.summary.expires", value: t, timestamp (seconds since the +Unix epoch in UTC, big-endian) after which the summary is considered +stale and should be re-downloaded if possible (similar to the HTTP +Expires header)

    • +
  • +

    The currently defined keys for the a{sv} of additional metadata for each commit are:

    +
    • key: ostree.commit.timestamp, value: t, timestamp (seconds since the +Unix epoch in UTC, big-endian) when the commit was committed

    diff --git a/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html b/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html index 588132f6..60efeb05 100644 --- a/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html +++ b/apidoc/html/ostree-Progress-notification-system-for-asynchronous-operations.html @@ -65,6 +65,22 @@ +void + + +ostree_async_progress_get () + + + + +GVariant * + + +ostree_async_progress_get_variant () + + + + guint @@ -92,6 +108,22 @@ void +ostree_async_progress_set () + + + + +void + + +ostree_async_progress_set_variant () + + + + +void + + ostree_async_progress_set_uint () @@ -138,6 +170,10 @@ operations to communicate back with callers. It transparently handles thread safety, ensuring that the progress change notification occurs in the thread-default context of the calling operation.

    +

    The ostree_async_progress_get_status() and ostree_async_progress_set_status() +methods get and set a well-known status key of type G_VARIANT_TYPE_STRING. +This key may be accessed using the other OstreeAsyncProgress methods, but it +must always have the correct type.

    Functions

    @@ -163,6 +199,141 @@ ostree_async_progress_new_and_connect (

    ostree_async_progress_get_status ()

    char *
     ostree_async_progress_get_status (OstreeAsyncProgress *self);
    +

    Get the human-readable status string from the OstreeAsyncProgress. This +operation is thread-safe. The retuned value may be NULL if no status is +set.

    +

    This is a convenience function to get the well-known status key.

    +
    +

    Parameters

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

    self

    an OstreeAsyncProgress

     
    +
    +
    +

    Returns

    +

    the current status, or NULL if none is set.

    +

    [transfer full][nullable]

    +
    +

    Since: 2017.6

    +
    +
    +
    +

    ostree_async_progress_get ()

    +
    void
    +ostree_async_progress_get (OstreeAsyncProgress *self,
    +                           ...);
    +

    Get the values corresponding to zero or more keys from the +OstreeAsyncProgress. Each key is specified in @... as the key name, followed +by a GVariant format string, followed by the necessary arguments for that +format string, just as for g_variant_get(). After those arguments is the +next key name. The varargs list must be NULL-terminated.

    +

    Each format string must make deep copies of its value, as the values stored +in the OstreeAsyncProgress may be freed from another thread after this +function returns.

    +

    This operation is thread-safe, and all the keys are queried atomically.

    +
    + + + + + + + +
    1
    +2
    +3
    +4
    +5
    +6
    +7
    +8
    +9
    +10
    +11
    guint32 outstanding_fetches;
    +guint64 bytes_received;
    +g_autofree gchar *status = NULL;
    +g_autoptr(GVariant) refs_variant = NULL;
    +
    +ostree_async_progress_get (progress,
    +                           "outstanding-fetches", "u", &outstanding_fetches,
    +                           "bytes-received", "t", &bytes_received,
    +                           "status", "s", &status,
    +                           "refs", "@a{ss}", &refs_variant,
    +                           NULL);
    +
    + +

    +
    +

    Parameters

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

    self

    an OstreeAsyncProgress

     

    ...

    key name, format string, GVariant return locations, …, followed by NULL

     
    +
    +

    Since: 2017.6

    +
    +
    +
    +

    ostree_async_progress_get_variant ()

    +
    GVariant *
    +ostree_async_progress_get_variant (OstreeAsyncProgress *self,
    +                                   const char *key);
    +

    Look up a key in the OstreeAsyncProgress and return the GVariant associated +with it. The lookup is thread-safe.

    +
    +

    Parameters

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

    self

    an OstreeAsyncProgress

     

    key

    a key to look up

     
    +
    +
    +

    Returns

    +

    value for the given key +, or NULL if +it was not set.

    +

    [transfer full][nullable]

    +
    +

    Since: 2017.6


    @@ -184,6 +355,145 @@ ostree_async_progress_get_uint64 (void ostree_async_progress_set_status (OstreeAsyncProgress *self, const char *status); +

    Set the human-readable status string for the OstreeAsyncProgress. This +operation is thread-safe. NULL may be passed to clear the status.

    +

    This is a convenience function to set the well-known status key.

    +
    +

    Parameters

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

    self

    an OstreeAsyncProgress

     

    status

    new status string, or NULL to clear the status.

    [nullable]
    +
    +

    Since: 2017.6

    +
    +
    +
    +

    ostree_async_progress_set ()

    +
    void
    +ostree_async_progress_set (OstreeAsyncProgress *self,
    +                           ...);
    +

    Set the values for zero or more keys in the OstreeAsyncProgress. Each key is +specified in @... as the key name, followed by a GVariant format string, +followed by the necessary arguments for that format string, just as for +g_variant_new(). After those arguments is the next key name. The varargs list +must be NULL-terminated.

    +

    g_variant_ref_sink() will be called as appropriate on the GVariant +parameters, so they may be floating.

    +

    This operation is thread-safe, and all the keys are set atomically.

    +
    + + + + + + + +
    1
    +2
    +3
    +4
    +5
    +6
    +7
    +8
    +9
    guint32 outstanding_fetches = 15;
    +guint64 bytes_received = 1000;
    +
    +ostree_async_progress_set (progress,
    +                           "outstanding-fetches", "u", outstanding_fetches,
    +                           "bytes-received", "t", bytes_received,
    +                           "status", "s", "Updated status",
    +                           "refs", "@a{ss}", g_variant_new_parsed ("@a{ss} {}"),
    +                           NULL);
    +
    + +

    +
    +

    Parameters

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

    self

    an OstreeAsyncProgress

     

    ...

    key name, format string, GVariant parameters, …, followed by NULL

     
    +
    +

    Since: 2017.6

    +
    +
    +
    +

    ostree_async_progress_set_variant ()

    +
    void
    +ostree_async_progress_set_variant (OstreeAsyncProgress *self,
    +                                   const char *key,
    +                                   GVariant *value);
    +

    Assign a new value + to the given key +, replacing any existing value. The +operation is thread-safe. value + may be a floating reference; +g_variant_ref_sink() will be called on it.

    +

    Any watchers of the OstreeAsyncProgress will be notified of the change if +value + differs from the existing value for key +.

    +
    +

    Parameters

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

    self

    an OstreeAsyncProgress

     

    key

    a key to set

     

    value

    the value to assign to key +

     
    +
    +

    Since: 2017.6


    diff --git a/apidoc/html/ostree.devhelp2 b/apidoc/html/ostree.devhelp2 index 5cbabaca..665a92b1 100644 --- a/apidoc/html/ostree.devhelp2 +++ b/apidoc/html/ostree.devhelp2 @@ -207,6 +207,9 @@ + + + @@ -215,6 +218,8 @@ + + @@ -268,10 +273,14 @@ - + + + - + + + @@ -379,6 +388,9 @@ + + + @@ -397,6 +409,11 @@ + + + + + diff --git a/apidoc/html/reference.html b/apidoc/html/reference.html index d0e784be..c0365130 100644 --- a/apidoc/html/reference.html +++ b/apidoc/html/reference.html @@ -80,6 +80,10 @@
    +ostree_async_progress_get, function in Progress notification system for asynchronous operations +
    +
    +
    ostree_async_progress_get_status, function in Progress notification system for asynchronous operations
    @@ -92,6 +96,10 @@
    +ostree_async_progress_get_variant, function in Progress notification system for asynchronous operations +
    +
    +
    ostree_async_progress_new, function in Progress notification system for asynchronous operations
    @@ -100,6 +108,10 @@
    +ostree_async_progress_set, function in Progress notification system for asynchronous operations +
    +
    +
    ostree_async_progress_set_status, function in Progress notification system for asynchronous operations
    @@ -111,6 +123,10 @@ ostree_async_progress_set_uint64, function in Progress notification system for asynchronous operations
    +
    +ostree_async_progress_set_variant, function in Progress notification system for asynchronous operations +
    +

    B

    OstreeBootconfigParser, struct in ostree-bootconfig-parser @@ -598,6 +614,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
    +OstreeRepoCommitIterResult, enum in Content-addressed object store +
    +
    +
    OstreeRepoCommitModifier, typedef in Content-addressed object store
    @@ -610,6 +630,14 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
    +OstreeRepoCommitState, enum in Content-addressed object store +
    +
    +
    +OstreeRepoCommitTraverseFlags, enum in Content-addressed object store +
    +
    +
    OstreeRepoFile, typedef in ostree-repo-file
    @@ -618,6 +646,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
    +OstreeRepoListRefsExtFlags, enum in Content-addressed object store +
    +
    +
    OstreeRepoMode, enum in Content-addressed object store
    @@ -634,6 +666,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
    +OstreeRepoResolveRevExtFlags, enum in Content-addressed object store +
    +
    +
    OstreeRepoTransactionStats, struct in Content-addressed object store
    diff --git a/apidoc/ostree-experimental-sections.txt b/apidoc/ostree-experimental-sections.txt new file mode 100644 index 00000000..790feb33 --- /dev/null +++ b/apidoc/ostree-experimental-sections.txt @@ -0,0 +1,6 @@ +
    +ostree-remote +OstreeRemote +ostree_remote_ref +ostree_remote_unref +
    diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index 07dbaf1f..adc2dfd7 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -4,9 +4,13 @@ OstreeAsyncProgress ostree_async_progress_new ostree_async_progress_new_and_connect ostree_async_progress_get_status +ostree_async_progress_get +ostree_async_progress_get_variant ostree_async_progress_get_uint ostree_async_progress_get_uint64 ostree_async_progress_set_status +ostree_async_progress_set +ostree_async_progress_set_variant ostree_async_progress_set_uint ostree_async_progress_set_uint64 ostree_async_progress_finish @@ -316,11 +320,14 @@ ostree_repo_write_content_trusted ostree_repo_write_content_async ostree_repo_write_content_finish ostree_repo_resolve_rev +OstreeRepoResolveRevExtFlags ostree_repo_resolve_rev_ext ostree_repo_list_refs +OstreeRepoListRefsExtFlags ostree_repo_list_refs_ext ostree_repo_remote_list_refs ostree_repo_load_variant +OstreeRepoCommitState ostree_repo_load_commit ostree_repo_load_variant_if_exists ostree_repo_load_file @@ -376,8 +383,10 @@ ostree_repo_commit_traverse_iter_cleanup ostree_repo_commit_traverse_iter_clear ostree_repo_commit_traverse_iter_get_dir ostree_repo_commit_traverse_iter_get_file +OstreeRepoCommitTraverseFlags ostree_repo_commit_traverse_iter_init_commit ostree_repo_commit_traverse_iter_init_dirtree +OstreeRepoCommitIterResult ostree_repo_commit_traverse_iter_next OstreeRepoPruneFlags ostree_repo_prune diff --git a/apidoc/ostree.types b/apidoc/ostree.types index d6bbf69d..b229e7da 100644 --- a/apidoc/ostree.types +++ b/apidoc/ostree.types @@ -6,6 +6,7 @@ ostree_deployment_get_type ostree_diff_item_get_type ostree_gpg_verify_result_get_type ostree_mutable_tree_get_type +ostree_remote_get_type ostree_repo_commit_modifier_get_type ostree_repo_devino_cache_get_type ostree_repo_file_get_type diff --git a/apidoc/version.xml b/apidoc/version.xml index 719d04cc..f7cc504e 100644 --- a/apidoc/version.xml +++ b/apidoc/version.xml @@ -1 +1 @@ -2017.4 \ No newline at end of file +2017.6 \ No newline at end of file diff --git a/buildutil/glibtests.m4 b/buildutil/glibtests.m4 index 27e90246..108c8478 100644 --- a/buildutil/glibtests.m4 +++ b/buildutil/glibtests.m4 @@ -1,17 +1,21 @@ dnl GLIB_TESTS -dnl +dnl NOTE: this file has been modified from upstream glib; see +dnl https://github.com/ostreedev/ostree/pull/837 AC_DEFUN([GLIB_TESTS], [ AC_ARG_ENABLE(installed-tests, AS_HELP_STRING([--enable-installed-tests], [Enable installation of some test cases]), - [case ${enableval} in + [enable_installed_tests=${enableval}; + case ${enableval} in yes) ENABLE_INSTALLED_TESTS="1" ;; + exclusive) ENABLE_INSTALLED_TESTS="1"; ENABLE_INSTALLED_TESTS_EXCLUSIVE=1 ;; no) ENABLE_INSTALLED_TESTS="" ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-installed-tests]) ;; esac]) AM_CONDITIONAL([ENABLE_INSTALLED_TESTS], test "$ENABLE_INSTALLED_TESTS" = "1") + AM_CONDITIONAL([ENABLE_INSTALLED_TESTS_EXCLUSIVE], test "$ENABLE_INSTALLED_TESTS_EXCLUSIVE" = "1") AC_ARG_ENABLE(always-build-tests, AS_HELP_STRING([--enable-always-build-tests], [Enable always building tests during 'make all']), diff --git a/config.h.in b/config.h.in index 72d72cda..3cc2f9e0 100644 --- a/config.h.in +++ b/config.h.in @@ -3,6 +3,9 @@ /* Define if we are enabling ostree trivial-httpd entrypoint */ #undef BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE +/* Define if systemd and libmount */ +#undef BUILDOPT_LIBSYSTEMD_AND_LIBMOUNT + /* Define if we should avoid using O_TMPFILE */ #undef DISABLE_OTMPFILE @@ -85,6 +88,9 @@ /* Define to the sub-directory where libtool stores uninstalled libraries. */ #undef LT_OBJDIR +/* Define if experimental API should be enabled */ +#undef OSTREE_ENABLE_EXPERIMENTAL_API + /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT diff --git a/configure b/configure index 0a2b349e..c8350804 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.5. +# Generated by GNU Autoconf 2.69 for libostree 2017.6. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libostree' PACKAGE_TARNAME='libostree' -PACKAGE_VERSION='2017.5' -PACKAGE_STRING='libostree 2017.5' +PACKAGE_VERSION='2017.6' +PACKAGE_STRING='libostree 2017.6' PACKAGE_BUGREPORT='walters@verbum.org' PACKAGE_URL='' @@ -635,6 +635,8 @@ ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS +ENABLE_EXPERIMENTAL_API_FALSE +ENABLE_EXPERIMENTAL_API_TRUE BUILDOPT_GJS_FALSE BUILDOPT_GJS_TRUE GJS @@ -644,8 +646,11 @@ BUILDOPT_USE_STATIC_COMPILER_TRUE GRUB2_MKCONFIG BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE +BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE +BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE BUILDOPT_SYSTEMD_FALSE BUILDOPT_SYSTEMD_TRUE +systemdsystemgeneratordir systemdsystemunitdir BUILDOPT_LIBSYSTEMD_FALSE BUILDOPT_LIBSYSTEMD_TRUE @@ -758,6 +763,8 @@ installed_testdir installed_test_metadir ENABLE_ALWAYS_BUILD_TESTS_FALSE ENABLE_ALWAYS_BUILD_TESTS_TRUE +ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE +ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE ENABLE_INSTALLED_TESTS_FALSE ENABLE_INSTALLED_TESTS_TRUE OSTREE_FEATURES @@ -926,9 +933,11 @@ enable_rofiles_fuse with_dracut with_mkinitcpio with_systemdsystemunitdir +with_systemdsystemgeneratordir with_builtin_grub2_mkconfig with_grub2_mkconfig_path with_static_compiler +enable_experimental_api ' ac_precious_vars='build_alias host_alias @@ -1513,7 +1522,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.5 to adapt to many kinds of systems. +\`configure' configures libostree 2017.6 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1583,7 +1592,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libostree 2017.5:";; + short | recursive ) echo "Configuration of libostree 2017.6:";; esac cat <<\_ACEOF @@ -1631,6 +1640,9 @@ Optional Features: --enable-rust-debug Build Rust code with debugging information [default=no] --enable-rofiles-fuse generate rofiles-fuse helper [default=yes] + --enable-experimental-api + Enable unstable experimental API in libostree + [default=no] Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] @@ -1656,6 +1668,8 @@ Optional Packages: --with-mkinitcpio Install mkinitcpio module (default: no) --with-systemdsystemunitdir=DIR Directory for systemd service files + --with-systemdsystemgeneratordir=DIR + Directory for systemd generators --with-builtin-grub2-mkconfig Use a builtin minimal grub2-mkconfig to generate a GRUB2 configuration file (default: no) @@ -1809,7 +1823,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libostree configure 2017.5 +libostree configure 2017.6 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2224,7 +2238,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.5, which was +It was created by libostree $as_me 2017.6, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3091,7 +3105,7 @@ fi # Define the identity of the package. PACKAGE='libostree' - VERSION='2017.5' + VERSION='2017.6' # Some tools Automake needs. @@ -5825,9 +5839,9 @@ test -n "$YACC" || YACC="yacc" YEAR_VERSION=2017 -RELEASE_VERSION=5 +RELEASE_VERSION=6 -PACKAGE_VERSION=2017.5 +PACKAGE_VERSION=2017.6 @@ -13584,8 +13598,10 @@ OSTREE_FEATURES="" # Check whether --enable-installed-tests was given. if test "${enable_installed_tests+set}" = set; then : - enableval=$enable_installed_tests; case ${enableval} in + enableval=$enable_installed_tests; enable_installed_tests=${enableval}; + case ${enableval} in yes) ENABLE_INSTALLED_TESTS="1" ;; + exclusive) ENABLE_INSTALLED_TESTS="1"; ENABLE_INSTALLED_TESTS_EXCLUSIVE=1 ;; no) ENABLE_INSTALLED_TESTS="" ;; *) as_fn_error $? "bad value ${enableval} for --enable-installed-tests" "$LINENO" 5 ;; esac @@ -13599,6 +13615,14 @@ else ENABLE_INSTALLED_TESTS_FALSE= fi + if test "$ENABLE_INSTALLED_TESTS_EXCLUSIVE" = "1"; then + ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE= + ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE='#' +else + ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE='#' + ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE= +fi + # Check whether --enable-always-build-tests was given. if test "${enable_always_build_tests+set}" = set; then : enableval=$enable_always_build_tests; case ${enableval} in @@ -16820,6 +16844,20 @@ fi systemdsystemunitdir=$with_systemdsystemunitdir +fi + +# Check whether --with-systemdsystemgeneratordir was given. +if test "${with_systemdsystemgeneratordir+set}" = set; then : + withval=$with_systemdsystemgeneratordir; +else + with_systemdsystemgeneratordir=$($PKG_CONFIG --variable=systemdsystemgeneratordir systemd) +fi + + if test "x$with_systemdsystemgeneratordir" != "xno"; then : + + systemdsystemgeneratordir=$with_systemdsystemgeneratordir + + fi fi @@ -16831,6 +16869,19 @@ else BUILDOPT_SYSTEMD_FALSE= fi + if test x$with_systemd = xyes && test x$with_libmount = xyes; then + BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE= + BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE='#' +else + BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE='#' + BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE= +fi + +if test -z "$BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE"; then : + +$as_echo "#define BUILDOPT_LIBSYSTEMD_AND_LIBMOUNT 1" >>confdefs.h + +fi # Check whether --with-builtin-grub2-mkconfig was given. @@ -16993,6 +17044,35 @@ else fi +# Do we enable building experimental (non-stable) API? +# The OSTREE_ENABLE_EXPERIMENTAL_API #define is used internally and in public +# headers, so any consumer of libostree who wants to use experimental API must +# #define OSTREE_ENABLE_EXPERIMENTAL_API 1 +# before including libostree headers. This means the name in the AC_DEFINE below +# is public API. +# Check whether --enable-experimental-api was given. +if test "${enable_experimental_api+set}" = set; then : + enableval=$enable_experimental_api; +else + enable_experimental_api=no +fi + +if test x$enable_experimental_api = xyes; then : + +$as_echo "#define OSTREE_ENABLE_EXPERIMENTAL_API 1" >>confdefs.h + + OSTREE_FEATURES="$OSTREE_FEATURES experimental" + +fi + if test x$enable_experimental_api = xyes; then + ENABLE_EXPERIMENTAL_API_TRUE= + ENABLE_EXPERIMENTAL_API_FALSE='#' +else + ENABLE_EXPERIMENTAL_API_TRUE='#' + ENABLE_EXPERIMENTAL_API_FALSE= +fi + + ac_config_files="$ac_config_files Makefile apidoc/Makefile src/libostree/ostree-1.pc src/libostree/ostree-version.h" cat >confcache <<\_ACEOF @@ -17144,6 +17224,10 @@ if test -z "${ENABLE_INSTALLED_TESTS_TRUE}" && test -z "${ENABLE_INSTALLED_TESTS as_fn_error $? "conditional \"ENABLE_INSTALLED_TESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${ENABLE_INSTALLED_TESTS_EXCLUSIVE_TRUE}" && test -z "${ENABLE_INSTALLED_TESTS_EXCLUSIVE_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_INSTALLED_TESTS_EXCLUSIVE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${ENABLE_ALWAYS_BUILD_TESTS_TRUE}" && test -z "${ENABLE_ALWAYS_BUILD_TESTS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_ALWAYS_BUILD_TESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -17252,6 +17336,10 @@ if test -z "${BUILDOPT_SYSTEMD_TRUE}" && test -z "${BUILDOPT_SYSTEMD_FALSE}"; th as_fn_error $? "conditional \"BUILDOPT_SYSTEMD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${BUILDOPT_SYSTEMD_AND_LIBMOUNT_TRUE}" && test -z "${BUILDOPT_SYSTEMD_AND_LIBMOUNT_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_SYSTEMD_AND_LIBMOUNT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${BUILDOPT_BUILTIN_GRUB2_MKCONFIG_TRUE}" && test -z "${BUILDOPT_BUILTIN_GRUB2_MKCONFIG_FALSE}"; then as_fn_error $? "conditional \"BUILDOPT_BUILTIN_GRUB2_MKCONFIG\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -17264,6 +17352,10 @@ if test -z "${BUILDOPT_GJS_TRUE}" && test -z "${BUILDOPT_GJS_FALSE}"; then as_fn_error $? "conditional \"BUILDOPT_GJS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${ENABLE_EXPERIMENTAL_API_TRUE}" && test -z "${ENABLE_EXPERIMENTAL_API_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_EXPERIMENTAL_API\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 @@ -17661,7 +17753,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.5, which was +This file was extended by libostree $as_me 2017.6, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -17727,7 +17819,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.5 +libostree config.status 2017.6 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" @@ -19436,10 +19528,12 @@ echo " wrpseudo-compat: $enable_wrpseudo_compat man pages (xsltproc): $enable_man api docs (gtk-doc): $enable_gtk_doc + installed tests: $enable_installed_tests gjs-based tests: $have_gjs dracut: $with_dracut mkinitcpio: $with_mkinitcpio - Static compiler for ostree-prepare-root: $with_static_compiler" + Static compiler for ostree-prepare-root: $with_static_compiler + Experimental API $enable_experimental_api" if test x$with_builtin_grub2_mkconfig = xyes; then : echo " builtin grub2-mkconfig (instead of system): $with_builtin_grub2_mkconfig" diff --git a/configure.ac b/configure.ac index c8e02930..a6abee85 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ AC_PREREQ([2.63]) dnl If incrementing the version here, remember to update libostree.sym too m4_define([year_version], [2017]) -m4_define([release_version], [5]) +m4_define([release_version], [6]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) @@ -389,8 +389,19 @@ AS_IF([test "x$have_libsystemd" = "xyes"], [ AS_IF([test "x$with_systemdsystemunitdir" != "xno"], [ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) ]) + AC_ARG_WITH([systemdsystemgeneratordir], + AS_HELP_STRING([--with-systemdsystemgeneratordir=DIR], [Directory for systemd generators]), + [], + [with_systemdsystemgeneratordir=$($PKG_CONFIG --variable=systemdsystemgeneratordir systemd)]) + AS_IF([test "x$with_systemdsystemgeneratordir" != "xno"], [ + AC_SUBST([systemdsystemgeneratordir], [$with_systemdsystemgeneratordir]) + ]) ]) AM_CONDITIONAL(BUILDOPT_SYSTEMD, test x$with_systemd = xyes) +dnl If we have both, we use the "new /var" model with ostree-system-generator +AM_CONDITIONAL(BUILDOPT_SYSTEMD_AND_LIBMOUNT,[test x$with_systemd = xyes && test x$with_libmount = xyes]) +AM_COND_IF(BUILDOPT_SYSTEMD_AND_LIBMOUNT, + AC_DEFINE([BUILDOPT_LIBSYSTEMD_AND_LIBMOUNT], 1, [Define if systemd and libmount])) AC_ARG_WITH(builtin-grub2-mkconfig, AS_HELP_STRING([--with-builtin-grub2-mkconfig], @@ -429,6 +440,22 @@ AS_IF([test "x$found_introspection" = xyes && test x$using_asan != xyes], [ ], [have_gjs=no]) AM_CONDITIONAL(BUILDOPT_GJS, test x$have_gjs = xyes) +# Do we enable building experimental (non-stable) API? +# The OSTREE_ENABLE_EXPERIMENTAL_API #define is used internally and in public +# headers, so any consumer of libostree who wants to use experimental API must +# #define OSTREE_ENABLE_EXPERIMENTAL_API 1 +# before including libostree headers. This means the name in the AC_DEFINE below +# is public API. +AC_ARG_ENABLE([experimental-api], + [AS_HELP_STRING([--enable-experimental-api], + [Enable unstable experimental API in libostree [default=no]])],, + [enable_experimental_api=no]) +AS_IF([test x$enable_experimental_api = xyes], + [AC_DEFINE([OSTREE_ENABLE_EXPERIMENTAL_API],[1],[Define if experimental API should be enabled]) + OSTREE_FEATURES="$OSTREE_FEATURES experimental"] +) +AM_CONDITIONAL([ENABLE_EXPERIMENTAL_API],[test x$enable_experimental_api = xyes]) + AC_CONFIG_FILES([ Makefile apidoc/Makefile @@ -457,10 +484,12 @@ echo " wrpseudo-compat: $enable_wrpseudo_compat man pages (xsltproc): $enable_man api docs (gtk-doc): $enable_gtk_doc + installed tests: $enable_installed_tests gjs-based tests: $have_gjs dracut: $with_dracut mkinitcpio: $with_mkinitcpio - Static compiler for ostree-prepare-root: $with_static_compiler" + Static compiler for ostree-prepare-root: $with_static_compiler + Experimental API $enable_experimental_api" AS_IF([test x$with_builtin_grub2_mkconfig = xyes], [ echo " builtin grub2-mkconfig (instead of system): $with_builtin_grub2_mkconfig" ], [ diff --git a/libglnx/glnx-dirfd.c b/libglnx/glnx-dirfd.c index 08d90071..12b983c1 100644 --- a/libglnx/glnx-dirfd.c +++ b/libglnx/glnx-dirfd.c @@ -209,13 +209,12 @@ glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; struct dirent *ret_dent; g_return_val_if_fail (out_dent, FALSE); if (!glnx_dirfd_iterator_next_dent (dfd_iter, out_dent, cancellable, error)) - goto out; + return FALSE; ret_dent = *out_dent; @@ -226,17 +225,12 @@ glnx_dirfd_iterator_next_dent_ensure_dtype (GLnxDirFdIterator *dfd_iter, { struct stat stbuf; if (TEMP_FAILURE_RETRY (fstatat (dfd_iter->fd, ret_dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW)) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); ret_dent->d_type = IFTODT (stbuf.st_mode); } } - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -348,3 +342,70 @@ glnx_mkdtempat (int dfd, "mkstempat ran out of combinations to try."); return FALSE; } + +/** + * glnx_mkdtempat_open: + * @dfd: Directory FD + * @tmpl: (type filename): template directory name, last 6 characters will be replaced + * @mode: permissions to create the temporary directory with + * @out_dfd: (out caller-allocates): Return location for an FD for the new + * temporary directory, or `-1` on error + * @error: Return location for a #GError, or %NULL + * + * Similar to glnx_mkdtempat(), except it will open the resulting temporary + * directory and return a directory FD to it. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +gboolean +glnx_mkdtempat_open (int dfd, + gchar *tmpl, + int mode, + int *out_dfd, + GError **error) +{ + /* FIXME: Ideally we could use openat(O_DIRECTORY | O_CREAT | O_EXCL) here + * to create and open the directory atomically, but that’s not supported by + * current kernel versions: http://www.openwall.com/lists/oss-security/2014/11/26/14 + * (Tested on kernel 4.10.10-200.fc25.x86_64). For the moment, accept a + * TOCTTOU race here. */ + *out_dfd = -1; + + if (!glnx_mkdtempat (dfd, tmpl, mode, error)) + return FALSE; + + return glnx_opendirat (dfd, tmpl, FALSE, out_dfd, error); +} + +/** + * glnx_mkdtempat_open_in_system: + * @tmpl: (type filename): template directory name, last 6 characters will be replaced + * @mode: permissions to create the temporary directory with + * @out_dfd: (out caller-allocates): Return location for an FD for the new + * temporary directory, or `-1` on error + * @error: Return location for a #GError, or %NULL + * + * Similar to glnx_mkdtempat_open(), except it will use the system temporary + * directory (from g_get_tmp_dir()) as the parent directory to @tmpl. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +gboolean +glnx_mkdtempat_open_in_system (gchar *tmpl, + int mode, + int *out_dfd, + GError **error) +{ + glnx_fd_close int tmp_dfd = -1; + + *out_dfd = -1; + + if (!glnx_opendirat (-1, g_get_tmp_dir (), TRUE, &tmp_dfd, error)) + return FALSE; + + return glnx_mkdtempat_open (tmp_dfd, tmpl, mode, out_dfd, error); +} + + diff --git a/libglnx/glnx-dirfd.h b/libglnx/glnx-dirfd.h index 3a766952..0cb79e69 100644 --- a/libglnx/glnx-dirfd.h +++ b/libglnx/glnx-dirfd.h @@ -88,4 +88,15 @@ gboolean glnx_mkdtempat (int dfd, int mode, GError **error); +gboolean glnx_mkdtempat_open (int dfd, + gchar *tmpl, + int mode, + int *out_dfd, + GError **error); + +gboolean glnx_mkdtempat_open_in_system (gchar *tmpl, + int mode, + int *out_dfd, + GError **error); + G_END_DECLS diff --git a/libglnx/glnx-errors.c b/libglnx/glnx-errors.c index edbce205..48008733 100644 --- a/libglnx/glnx-errors.c +++ b/libglnx/glnx-errors.c @@ -23,6 +23,22 @@ #include #include +void +glnx_real_set_prefix_error_va (GError *error, + const char *format, + va_list args) +{ + if (error == NULL) + return; + + g_autofree char *old_msg = g_steal_pointer (&error->message); + g_autoptr(GString) buf = g_string_new (""); + g_string_append_vprintf (buf, format, args); + g_string_append (buf, ": "); + g_string_append (buf, old_msg); + error->message = g_string_free (g_steal_pointer (&buf), FALSE); +} + void glnx_real_set_prefix_error_from_errno_va (GError **error, gint errsv, @@ -32,13 +48,9 @@ glnx_real_set_prefix_error_from_errno_va (GError **error, if (!error) return; - /* TODO - enhance GError to have a "set and take ownership" API */ - g_autoptr(GString) buf = g_string_new (""); - g_string_append_vprintf (buf, format, args); - g_string_append (buf, ": "); - g_string_append (buf, g_strerror (errsv)); g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv), - buf->str); + g_strerror (errsv)); + glnx_real_set_prefix_error_va (*error, format, args); } diff --git a/libglnx/glnx-errors.h b/libglnx/glnx-errors.h index 8f9cad81..e26a513e 100644 --- a/libglnx/glnx-errors.h +++ b/libglnx/glnx-errors.h @@ -30,7 +30,7 @@ G_BEGIN_DECLS * This function returns %FALSE so it can be used conveniently in a single * statement: * - * `` + * ``` * if (strcmp (foo, "somevalue") != 0) * return glnx_throw (error, "key must be somevalue, not '%s'", foo); * ``` @@ -49,13 +49,47 @@ glnx_throw (GError **error, const char *fmt, ...) return FALSE; } +/* Like `glnx_throw ()`, but returns %NULL. */ +#define glnx_null_throw(error, args...) \ + ({glnx_throw (error, args); NULL;}) + +/* Implementation detail of glnx_throw_prefix() */ +void glnx_real_set_prefix_error_va (GError *error, + const char *format, + va_list args) G_GNUC_PRINTF (2,0); + +/* Prepend to @error's message by `$prefix: ` where `$prefix` is computed via + * printf @fmt. Returns %FALSE so it can be used conveniently in a single + * statement: + * + * ``` + * if (!function_that_fails (s, error)) + * return glnx_throw_prefix (error, "while handling '%s'", s); + * ``` + * */ +static inline gboolean G_GNUC_PRINTF (2,3) +glnx_prefix_error (GError **error, const char *fmt, ...) +{ + if (error == NULL) + return FALSE; + + va_list args; + va_start (args, fmt); + glnx_real_set_prefix_error_va (*error, fmt, args); + va_end (args); + return FALSE; +} + +/* Like `glnx_prefix_error ()`, but returns %NULL. */ +#define glnx_prefix_error_null(error, args...) \ + ({glnx_prefix_error (error, args); NULL;}) /* Set @error using the value of `g_strerror (errno)`. * * This function returns %FALSE so it can be used conveniently in a single * statement: * - * `` + * ``` * if (unlinkat (fd, somepathname) < 0) * return glnx_throw_errno (error); * ``` @@ -79,6 +113,10 @@ glnx_throw_errno (GError **error) return FALSE; } +/* Like glnx_throw_errno(), but yields a NULL pointer. */ +#define glnx_null_throw_errno(error) \ + ({glnx_throw_errno (error); NULL;}) + /* Implementation detail of glnx_throw_errno_prefix() */ void glnx_real_set_prefix_error_from_errno_va (GError **error, gint errsv, @@ -108,6 +146,10 @@ glnx_throw_errno_prefix (GError **error, const char *fmt, ...) return FALSE; } +/* Like glnx_throw_errno_prefix(), but yields a NULL pointer. */ +#define glnx_null_throw_errno_prefix(error, args...) \ + ({glnx_throw_errno_prefix (error, args); NULL;}) + /* BEGIN LEGACY APIS */ #define glnx_set_error_from_errno(error) \ @@ -117,9 +159,7 @@ glnx_throw_errno_prefix (GError **error, const char *fmt, ...) #define glnx_set_prefix_error_from_errno(error, format, args...) \ do { \ - glnx_set_error_from_errno (error); \ - g_prefix_error (error, format, args); \ + glnx_throw_errno_prefix (error, format, args); \ } while (0); - G_END_DECLS diff --git a/libglnx/glnx-fdio.c b/libglnx/glnx-fdio.c index 68704cb1..df4c8518 100644 --- a/libglnx/glnx-fdio.c +++ b/libglnx/glnx-fdio.c @@ -102,10 +102,7 @@ rename_file_noreplace_at (int olddirfd, const char *oldpath, return TRUE; } else - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno (error); } return TRUE; } @@ -172,10 +169,7 @@ glnx_open_tmpfile_linkable_at (int dfd, #if defined(O_TMPFILE) && !defined(DISABLE_OTMPFILE) && !defined(ENABLE_WRPSEUDO_COMPAT) fd = openat (dfd, subpath, O_TMPFILE|flags, 0600); if (fd == -1 && !(errno == ENOSYS || errno == EISDIR || errno == EOPNOTSUPP)) - { - glnx_set_prefix_error_from_errno (error, "%s", "open(O_TMPFILE)"); - return FALSE; - } + return glnx_throw_errno_prefix (error, "open(O_TMPFILE)"); if (fd != -1) { *out_fd = fd; @@ -199,10 +193,7 @@ glnx_open_tmpfile_linkable_at (int dfd, if (errno == EEXIST) continue; else - { - glnx_set_prefix_error_from_errno (error, "%s", "Creating temp file"); - return FALSE; - } + return glnx_throw_errno_prefix (error, "Creating temp file"); } else { @@ -246,9 +237,10 @@ glnx_link_tmpfile_at (int dfd, */ if (renameat (dfd, tmpfile_path, target_dfd, target) < 0) { + int errsv = errno; (void) unlinkat (dfd, tmpfile_path, 0); - glnx_set_error_from_errno (error); - return FALSE; + errno = errsv; + return glnx_throw_errno_prefix (error, "renameat"); } } else @@ -293,10 +285,7 @@ glnx_link_tmpfile_at (int dfd, if (errno == EEXIST) continue; else - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno_prefix (error, "linkat"); } else break; @@ -311,9 +300,10 @@ glnx_link_tmpfile_at (int dfd, /* This is currently the only case where we need to have * a cleanup unlinkat() still with O_TMPFILE. */ + int errsv = errno; (void) unlinkat (target_dfd, tmpname_buf, 0); - glnx_set_error_from_errno (error); - return FALSE; + errno = errsv; + return glnx_throw_errno_prefix (error, "renameat"); } } else @@ -323,10 +313,7 @@ glnx_link_tmpfile_at (int dfd, if (errno == EEXIST && mode == GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST) ; else - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno_prefix (error, "linkat"); } } @@ -341,49 +328,37 @@ glnx_fd_readall_malloc (int fd, GCancellable *cancellable, GError **error) { - gboolean success = FALSE; const guint maxreadlen = 4096; - int res; + struct stat stbuf; - guint8* buf = NULL; + if (TEMP_FAILURE_RETRY (fstat (fd, &stbuf)) < 0) + return glnx_null_throw_errno (error); + gsize buf_allocated; - gsize buf_size = 0; - gssize bytes_read; - - do - res = fstat (fd, &stbuf); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) - { - glnx_set_error_from_errno (error); - goto out; - } - if (S_ISREG (stbuf.st_mode) && stbuf.st_size > 0) buf_allocated = stbuf.st_size; else buf_allocated = 16; - - buf = g_malloc (buf_allocated); + g_autofree guint8* buf = g_malloc (buf_allocated); + + gsize buf_size = 0; while (TRUE) { gsize readlen = MIN (buf_allocated - buf_size, maxreadlen); - - if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto out; + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return FALSE; + + gssize bytes_read; do bytes_read = read (fd, buf + buf_size, readlen); while (G_UNLIKELY (bytes_read == -1 && errno == EINTR)); if (G_UNLIKELY (bytes_read == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_null_throw_errno (error); if (bytes_read == 0) break; - + buf_size += bytes_read; if (buf_allocated - buf_size < maxreadlen) buf = g_realloc (buf, buf_allocated *= 2); @@ -396,15 +371,8 @@ glnx_fd_readall_malloc (int fd, buf[buf_size] = '\0'; } - success = TRUE; - out: - if (success) - { - *out_len = buf_size; - return buf; - } - g_free (buf); - return NULL; + *out_len = buf_size; + return g_steal_pointer (&buf); } /** @@ -423,13 +391,10 @@ glnx_fd_readall_bytes (int fd, GCancellable *cancellable, GError **error) { - guint8 *buf; gsize len; - - buf = glnx_fd_readall_malloc (fd, &len, FALSE, cancellable, error); + guint8 *buf = glnx_fd_readall_malloc (fd, &len, FALSE, cancellable, error); if (!buf) return NULL; - return g_bytes_new_take (buf, len); } @@ -451,13 +416,10 @@ glnx_fd_readall_utf8 (int fd, GCancellable *cancellable, GError **error) { - gboolean success = FALSE; - guint8 *buf; gsize len; - - buf = glnx_fd_readall_malloc (fd, &len, TRUE, cancellable, error); + g_autofree guint8 *buf = glnx_fd_readall_malloc (fd, &len, TRUE, cancellable, error); if (!buf) - goto out; + return FALSE; if (!g_utf8_validate ((char*)buf, len, NULL)) { @@ -465,19 +427,12 @@ glnx_fd_readall_utf8 (int fd, G_IO_ERROR, G_IO_ERROR_INVALID_DATA, "Invalid UTF-8"); - goto out; + return FALSE; } - success = TRUE; - out: - if (success) - { - if (out_len) - *out_len = len; - return (char*)buf; - } - g_free (buf); - return NULL; + if (out_len) + *out_len = len; + return (char*)g_steal_pointer (&buf); } /** @@ -501,36 +456,20 @@ glnx_file_get_contents_utf8_at (int dfd, GCancellable *cancellable, GError **error) { - gboolean success = FALSE; - glnx_fd_close int fd = -1; - char *buf = NULL; - gsize len; - dfd = glnx_dirfd_canonicalize (dfd); - do - fd = openat (dfd, subpath, O_RDONLY | O_NOCTTY | O_CLOEXEC); - while (G_UNLIKELY (fd == -1 && errno == EINTR)); + glnx_fd_close int fd = TEMP_FAILURE_RETRY (openat (dfd, subpath, O_RDONLY | O_NOCTTY | O_CLOEXEC)); if (G_UNLIKELY (fd == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_null_throw_errno_prefix (error, "open(%s)", subpath); - buf = glnx_fd_readall_utf8 (fd, &len, cancellable, error); + gsize len; + g_autofree char *buf = glnx_fd_readall_utf8 (fd, &len, cancellable, error); if (G_UNLIKELY(!buf)) - goto out; - - success = TRUE; - out: - if (success) - { - if (out_len) - *out_len = len; - return buf; - } - g_free (buf); - return NULL; + return FALSE; + + if (out_len) + *out_len = len; + return g_steal_pointer (&buf); } /** @@ -555,25 +494,20 @@ glnx_readlinkat_malloc (int dfd, for (;;) { - char *c; + g_autofree char *c = NULL; ssize_t n; c = g_malloc (l); n = TEMP_FAILURE_RETRY (readlinkat (dfd, subpath, c, l-1)); if (n < 0) - { - glnx_set_error_from_errno (error); - g_free (c); - return FALSE; - } + return glnx_null_throw_errno (error); if ((size_t) n < l-1) { c[n] = 0; - return c; + return g_steal_pointer (&c); } - g_free (c); l *= 2; } @@ -590,158 +524,171 @@ copy_symlink_at (int src_dfd, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autofree char *buf = NULL; - - buf = glnx_readlinkat_malloc (src_dfd, src_subpath, cancellable, error); + g_autofree char *buf = glnx_readlinkat_malloc (src_dfd, src_subpath, cancellable, error); if (!buf) - goto out; + return FALSE; if (TEMP_FAILURE_RETRY (symlinkat (buf, dest_dfd, dest_subpath)) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } - + return glnx_throw_errno_prefix (error, "symlinkat"); + if (!(copyflags & GLNX_FILE_COPY_NOXATTRS)) { g_autoptr(GVariant) xattrs = NULL; if (!glnx_dfd_name_get_all_xattrs (src_dfd, src_subpath, &xattrs, cancellable, error)) - goto out; + return FALSE; if (!glnx_dfd_name_set_all_xattrs (dest_dfd, dest_subpath, xattrs, cancellable, error)) - goto out; + return FALSE; } - + if (TEMP_FAILURE_RETRY (fchownat (dest_dfd, dest_subpath, src_stbuf->st_uid, src_stbuf->st_gid, AT_SYMLINK_NOFOLLOW)) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); - ret = TRUE; - out: - return ret; + return TRUE; } #define COPY_BUFFER_SIZE (16*1024) -/* From systemd */ +/* Most of the code below is from systemd, but has been reindented to GNU style, + * and changed to use POSIX error conventions (return -1, set errno) to more + * conveniently fit in with the rest of libglnx. + */ static int btrfs_reflink(int infd, int outfd) { - int r; - g_return_val_if_fail(infd >= 0, -1); g_return_val_if_fail(outfd >= 0, -1); - r = ioctl(outfd, BTRFS_IOC_CLONE, infd); - if (r < 0) - return -errno; - - return 0; + return ioctl (outfd, BTRFS_IOC_CLONE, infd); } -int glnx_loop_write(int fd, const void *buf, size_t nbytes) { - const uint8_t *p = buf; +/* Like write(), but loop until @nbytes are written, or an error + * occurs. + * + * On error, -1 is returned an @errno is set. NOTE: This is an + * API change from previous versions of this function. + */ +int +glnx_loop_write(int fd, const void *buf, size_t nbytes) +{ + const uint8_t *p = buf; - g_return_val_if_fail(fd >= 0, -1); - g_return_val_if_fail(buf, -1); + g_return_val_if_fail(fd >= 0, -1); + g_return_val_if_fail(buf, -1); - errno = 0; + errno = 0; - while (nbytes > 0) { - ssize_t k; + while (nbytes > 0) + { + ssize_t k; - k = write(fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; + k = write(fd, p, nbytes); + if (k < 0) + { + if (errno == EINTR) + continue; - return -errno; - } - - if (k == 0) /* Can't really happen */ - return -EIO; - - p += k; - nbytes -= k; + return -1; } - return 0; + if (k == 0) /* Can't really happen */ + { + errno = EIO; + return -1; + } + + p += k; + nbytes -= k; + } + + return 0; } -static int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { - bool try_sendfile = true; - int r; +/* Read from @fdf until EOF, writing to @fdt. If @try_reflink is %TRUE, + * attempt to use any "reflink" functionality; see e.g. https://lwn.net/Articles/331808/ + * + * The file descriptor @fdf must refer to a regular file. + * + * If provided, @max_bytes specifies the maximum number of bytes to read from @fdf. + * On error, this function returns `-1` and @errno will be set. + */ +int +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink) +{ + bool try_sendfile = true; + int r; - g_return_val_if_fail (fdf >= 0, -1); - g_return_val_if_fail (fdt >= 0, -1); - - /* Try btrfs reflinks first. */ - if (try_reflink && max_bytes == (off_t) -1) { - r = btrfs_reflink(fdf, fdt); - if (r >= 0) - return r; - } - - for (;;) { - size_t m = COPY_BUFFER_SIZE; - ssize_t n; - - if (max_bytes != (off_t) -1) { - - if (max_bytes <= 0) - return -EFBIG; - - if ((off_t) m > max_bytes) - m = (size_t) max_bytes; - } - - /* First try sendfile(), unless we already tried */ - if (try_sendfile) { - - n = sendfile(fdt, fdf, NULL, m); - if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) - return -errno; - - try_sendfile = false; - /* use fallback below */ - } else if (n == 0) /* EOF */ - break; - else if (n > 0) - /* Succcess! */ - goto next; - } - - /* As a fallback just copy bits by hand */ - { - char buf[m]; - - n = read(fdf, buf, m); - if (n < 0) - return -errno; - if (n == 0) /* EOF */ - break; - - r = glnx_loop_write(fdt, buf, (size_t) n); - if (r < 0) - return r; - } - - next: - if (max_bytes != (off_t) -1) { - g_assert(max_bytes >= n); - max_bytes -= n; - } - } + g_return_val_if_fail (fdf >= 0, -1); + g_return_val_if_fail (fdt >= 0, -1); + g_return_val_if_fail (max_bytes >= -1, -1); + /* Try btrfs reflinks first. */ + if (try_reflink && max_bytes == (off_t) -1) + { + r = btrfs_reflink(fdf, fdt); + if (r >= 0) return 0; + /* Fall through */ + } + + while (TRUE) + { + size_t m = COPY_BUFFER_SIZE; + ssize_t n; + + if (max_bytes != (off_t) -1) + { + if ((off_t) m > max_bytes) + m = (size_t) max_bytes; + } + + /* First try sendfile(), unless we already tried */ + if (try_sendfile) + { + n = sendfile (fdt, fdf, NULL, m); + if (n < 0) + { + if (errno != EINVAL && errno != ENOSYS) + return -1; + + try_sendfile = false; + /* use fallback below */ + } + else if (n == 0) /* EOF */ + break; + else if (n > 0) + /* Succcess! */ + goto next; + } + + /* As a fallback just copy bits by hand */ + { char buf[m]; + + n = read (fdf, buf, m); + if (n < 0) + return -1; + if (n == 0) /* EOF */ + break; + + if (glnx_loop_write (fdt, buf, (size_t) n) < 0) + return -1; + } + + next: + if (max_bytes != (off_t) -1) + { + g_assert(max_bytes >= n); + max_bytes -= n; + if (max_bytes == 0) + break; + } + } + + return 0; } /** @@ -829,10 +776,9 @@ glnx_file_copy_at (int src_dfd, goto out; } - r = copy_bytes (src_fd, dest_fd, (off_t) -1, TRUE); + r = glnx_regfile_copy_bytes (src_fd, dest_fd, (off_t) -1, TRUE); if (r < 0) { - errno = -r; glnx_set_error_from_errno (error); goto out; } @@ -921,7 +867,6 @@ glnx_file_replace_contents_at (int dfd, return glnx_file_replace_contents_with_perms_at (dfd, subpath, buf, len, (mode_t) -1, (uid_t) -1, (gid_t) -1, flags, cancellable, error); - } /** @@ -953,8 +898,6 @@ glnx_file_replace_contents_with_perms_at (int dfd, int r; char *dnbuf = strdupa (subpath); const char *dn = dirname (dnbuf); - g_autofree char *tmpfile_path = NULL; - glnx_fd_close int fd = -1; dfd = glnx_dirfd_canonicalize (dfd); @@ -964,6 +907,8 @@ glnx_file_replace_contents_with_perms_at (int dfd, if (mode == (mode_t) -1) mode = 0644; + glnx_fd_close int fd = -1; + g_autofree char *tmpfile_path = NULL; if (!glnx_open_tmpfile_linkable_at (dfd, dn, O_WRONLY | O_CLOEXEC, &fd, &tmpfile_path, error)) @@ -979,30 +924,22 @@ glnx_file_replace_contents_with_perms_at (int dfd, if (r != 0) { errno = r; - glnx_set_error_from_errno (error); - return FALSE; + return glnx_throw_errno_prefix (error, "fallocate"); } } - if ((r = glnx_loop_write (fd, buf, len)) != 0) - { - errno = -r; - glnx_set_error_from_errno (error); - return FALSE; - } - + if (glnx_loop_write (fd, buf, len) < 0) + return glnx_throw_errno (error); + if (!(flags & GLNX_FILE_REPLACE_NODATASYNC)) { struct stat stbuf; gboolean do_sync; - + if (fstatat (dfd, subpath, &stbuf, AT_SYMLINK_NOFOLLOW) != 0) { if (errno != ENOENT) - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno (error); do_sync = (flags & GLNX_FILE_REPLACE_DATASYNC_NEW) > 0; } else @@ -1011,27 +948,18 @@ glnx_file_replace_contents_with_perms_at (int dfd, if (do_sync) { if (fdatasync (fd) != 0) - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno_prefix (error, "fdatasync"); } } if (uid != (uid_t) -1) { if (fchown (fd, uid, gid) != 0) - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno (error); } if (fchmod (fd, mode) != 0) - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno (error); if (!glnx_link_tmpfile_at (dfd, GLNX_LINK_TMPFILE_REPLACE, fd, tmpfile_path, dfd, subpath, error)) @@ -1060,10 +988,7 @@ glnx_stream_fstat (GFileDescriptorBased *stream, int fd = g_file_descriptor_based_get_fd (stream); if (fstat (fd, stbuf) == -1) - { - glnx_set_prefix_error_from_errno (error, "%s", "fstat"); - return FALSE; - } + return glnx_throw_errno_prefix (error, "fstat"); return TRUE; } diff --git a/libglnx/glnx-fdio.h b/libglnx/glnx-fdio.h index c3e7573c..deff22b2 100644 --- a/libglnx/glnx-fdio.h +++ b/libglnx/glnx-fdio.h @@ -35,6 +35,8 @@ #include #undef basename +#include + G_BEGIN_DECLS /* Irritatingly, g_basename() which is what we want @@ -129,6 +131,9 @@ glnx_readlinkat_malloc (int dfd, int glnx_loop_write (int fd, const void *buf, size_t nbytes); +int +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink); + typedef enum { GLNX_FILE_COPY_OVERWRITE = (1 << 0), GLNX_FILE_COPY_NOXATTRS = (1 << 1), @@ -155,5 +160,54 @@ int glnx_renameat2_noreplace (int olddirfd, const char *oldpath, int glnx_renameat2_exchange (int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +/** + * glnx_fstat: + * @fd: FD to stat + * @buf: (out caller-allocates): Return location for stat details + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fstat() which adds #GError support and ensures that it retries + * on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstat (int fd, + struct stat *buf, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fstat (fd, buf)) != 0) + return glnx_throw_errno (error); + + return TRUE; +} + +/** + * glnx_fstatat: + * @dfd: Directory FD to stat beneath + * @path: Path to stat beneath @dfd + * @buf: (out caller-allocates): Return location for stat details + * @flags: Flags to pass to fstatat() + * @error: Return location for a #GError, or %NULL + * + * Wrapper around fstatat() which adds #GError support and ensures that it + * retries on %EINTR. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +static inline gboolean +glnx_fstatat (int dfd, + const gchar *path, + struct stat *buf, + int flags, + GError **error) +{ + if (TEMP_FAILURE_RETRY (fstatat (dfd, path, buf, flags)) != 0) + return glnx_throw_errno (error); + + return TRUE; +} G_END_DECLS diff --git a/libglnx/glnx-local-alloc.h b/libglnx/glnx-local-alloc.h index f628b61c..8c1914cf 100644 --- a/libglnx/glnx-local-alloc.h +++ b/libglnx/glnx-local-alloc.h @@ -199,9 +199,9 @@ glnx_cleanup_close_fdp (int *fdp) int fd, errsv; g_assert (fdp); - + fd = *fdp; - if (fd != -1) + if (fd >= 0) { errsv = errno; (void) close (fd); diff --git a/libglnx/glnx-lockfile.c b/libglnx/glnx-lockfile.c index 7dd69e91..c1cfc6b2 100644 --- a/libglnx/glnx-lockfile.c +++ b/libglnx/glnx-lockfile.c @@ -61,7 +61,6 @@ */ gboolean glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_lock, GError **error) { - gboolean ret = FALSE; glnx_fd_close int fd = -1; g_autofree char *t = NULL; int r; @@ -89,10 +88,8 @@ glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_loc struct stat st; fd = openat(dfd, p, O_CREAT|O_RDWR|O_NOFOLLOW|O_CLOEXEC|O_NOCTTY, 0600); - if (fd < 0) { - glnx_set_error_from_errno(error); - goto out; - } + if (fd < 0) + return glnx_throw_errno(error); /* Unfortunately, new locks are not in RHEL 7.1 glibc */ #ifdef F_OFD_SETLK @@ -107,10 +104,8 @@ glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_loc if (errno == EINVAL) r = flock(fd, operation); - if (r < 0) { - glnx_set_error_from_errno(error); - goto out; - } + if (r < 0) + return glnx_throw_errno(error); } /* If we acquired the lock, let's check if the file @@ -120,10 +115,8 @@ glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_loc * hence try again. */ r = fstat(fd, &st); - if (r < 0) { - glnx_set_error_from_errno(error); - goto out; - } + if (r < 0) + return glnx_throw_errno(error); if (st.st_nlink > 0) break; @@ -142,9 +135,7 @@ glnx_make_lock_file(int dfd, const char *p, int operation, GLnxLockFile *out_loc fd = -1; t = NULL; - ret = TRUE; - out: - return ret; + return TRUE; } void glnx_release_lock_file(GLnxLockFile *f) { diff --git a/libglnx/glnx-shutil.c b/libglnx/glnx-shutil.c index 6ff9fa68..6a1cdd4a 100644 --- a/libglnx/glnx-shutil.c +++ b/libglnx/glnx-shutil.c @@ -31,14 +31,12 @@ glnx_shutil_rm_rf_children (GLnxDirFdIterator *dfd_iter, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; struct dirent *dent; while (TRUE) { if (!glnx_dirfd_iterator_next_dent_ensure_dtype (dfd_iter, &dent, cancellable, error)) - goto out; - + return FALSE; if (dent == NULL) break; @@ -48,33 +46,25 @@ glnx_shutil_rm_rf_children (GLnxDirFdIterator *dfd_iter, if (!glnx_dirfd_iterator_init_at (dfd_iter->fd, dent->d_name, FALSE, &child_dfd_iter, error)) - goto out; + return FALSE; if (!glnx_shutil_rm_rf_children (&child_dfd_iter, cancellable, error)) - goto out; + return FALSE; if (unlinkat (dfd_iter->fd, dent->d_name, AT_REMOVEDIR) == -1) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "unlinkat"); } else { if (unlinkat (dfd_iter->fd, dent->d_name, 0) == -1) { if (errno != ENOENT) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "unlinkat"); } } } - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -94,7 +84,6 @@ glnx_shutil_rm_rf_at (int dfd, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; glnx_fd_close int target_dfd = -1; g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; @@ -114,40 +103,28 @@ glnx_shutil_rm_rf_at (int dfd, else if (errsv == ENOTDIR || errsv == ELOOP) { if (unlinkat (dfd, path, 0) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "unlinkat"); } else - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "open(%s)", path); } else { if (!glnx_dirfd_iterator_init_take_fd (target_dfd, &dfd_iter, error)) - goto out; + return FALSE; target_dfd = -1; if (!glnx_shutil_rm_rf_children (&dfd_iter, cancellable, error)) - goto out; + return FALSE; if (unlinkat (dfd, path, AT_REMOVEDIR) == -1) { - int errsv = errno; - if (errsv != ENOENT) - { - glnx_set_error_from_errno (error); - goto out; - } + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "unlinkat"); } } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -157,11 +134,10 @@ mkdir_p_at_internal (int dfd, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; gboolean did_recurse = FALSE; if (g_cancellable_set_error_if_cancelled (cancellable, error)) - goto out; + return FALSE; again: if (mkdirat (dfd, path, mode) == -1) @@ -179,7 +155,7 @@ mkdir_p_at_internal (int dfd, if (!glnx_shutil_mkdir_p_at (dfd, path, mode, cancellable, error)) - goto out; + return FALSE; /* Now restore it for another mkdir attempt */ *lastslash = '/'; @@ -194,15 +170,10 @@ mkdir_p_at_internal (int dfd, */ } else - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "mkdir(%s)", path); } - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -223,26 +194,58 @@ glnx_shutil_mkdir_p_at (int dfd, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; struct stat stbuf; char *buf; /* Fast path stat to see whether it already exists */ if (fstatat (dfd, path, &stbuf, AT_SYMLINK_NOFOLLOW) == 0) { + /* Note early return */ if (S_ISDIR (stbuf.st_mode)) - { - ret = TRUE; - goto out; - } + return TRUE; } buf = strdupa (path); if (!mkdir_p_at_internal (dfd, buf, mode, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; +} + +/** + * glnx_shutil_mkdir_p_at_open: + * @dfd: Directory fd + * @path: Directory path to be created + * @mode: Mode for newly created directories + * @out_dfd: (out caller-allocates): Return location for an FD to @dfd/@path, + * or `-1` on error + * @cancellable: (nullable): Cancellable, or %NULL + * @error: Return location for a #GError, or %NULL + * + * Similar to glnx_shutil_mkdir_p_at(), except it opens the resulting directory + * and returns a directory FD to it. Currently, this is not guaranteed to be + * race-free. + * + * Returns: %TRUE on success, %FALSE otherwise + * Since: UNRELEASED + */ +gboolean +glnx_shutil_mkdir_p_at_open (int dfd, + const char *path, + int mode, + int *out_dfd, + GCancellable *cancellable, + GError **error) +{ + /* FIXME: It’s not possible to eliminate the race here until + * openat(O_DIRECTORY | O_CREAT) works (and returns a directory rather than a + * file). It appears to be not supported in current kernels. (Tested with + * 4.10.10-200.fc25.x86_64.) */ + *out_dfd = -1; + + if (!glnx_shutil_mkdir_p_at (dfd, path, mode, cancellable, error)) + return FALSE; + + return glnx_opendirat (dfd, path, TRUE, out_dfd, error); } diff --git a/libglnx/glnx-shutil.h b/libglnx/glnx-shutil.h index 8cc732c3..56a99fa2 100644 --- a/libglnx/glnx-shutil.h +++ b/libglnx/glnx-shutil.h @@ -37,4 +37,12 @@ glnx_shutil_mkdir_p_at (int dfd, GCancellable *cancellable, GError **error); +gboolean +glnx_shutil_mkdir_p_at_open (int dfd, + const char *path, + int mode, + int *out_dfd, + GCancellable *cancellable, + GError **error); + G_END_DECLS diff --git a/libglnx/tests/test-libglnx-errors.c b/libglnx/tests/test-libglnx-errors.c index 8d109cd1..721818ba 100644 --- a/libglnx/tests/test-libglnx-errors.c +++ b/libglnx/tests/test-libglnx-errors.c @@ -33,6 +33,19 @@ test_error_throw (void) g_assert (!glnx_throw (&error, "foo: %s %d", "hello", 42)); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); g_assert_cmpstr (error->message, ==, "foo: hello 42"); + g_clear_error (&error); + + gpointer dummy = glnx_null_throw (&error, "literal foo"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "literal foo"); + g_clear_error (&error); + + gpointer dummy2 = glnx_null_throw (&error, "foo: %s %d", "hola", 24); + g_assert (dummy2 == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_cmpstr (error->message, ==, "foo: hola 24"); + g_clear_error (&error); } static void @@ -47,6 +60,9 @@ test_error_errno (void) { g_assert (!glnx_throw_errno (&error)); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (!glnx_prefix_error (&error, "myprefix")); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "myprefix: ")); g_clear_error (&error); } else @@ -55,8 +71,53 @@ test_error_errno (void) fd = open (noent_path, O_RDONLY); if (fd < 0) { + gpointer dummy = glnx_null_throw_errno (&error); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + dummy = glnx_prefix_error_null (&error, "myprefix"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "myprefix: ")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + g_autofree char *expected_prefix = g_strdup_printf ("Failed to open %s", noent_path); g_assert (!glnx_throw_errno_prefix (&error, "Failed to open %s", noent_path)); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, expected_prefix)); + g_clear_error (&error); + /* And test the legacy wrapper */ + glnx_set_prefix_error_from_errno (&error, "Failed to open %s", noent_path); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, expected_prefix)); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open file"); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); + g_assert (g_str_has_prefix (error->message, "Failed to open file")); + g_clear_error (&error); + } + else + g_assert_cmpint (fd, ==, -1); + + fd = open (noent_path, O_RDONLY); + if (fd < 0) + { + gpointer dummy = glnx_null_throw_errno_prefix (&error, "Failed to open %s", noent_path); + g_assert (dummy == NULL); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND); g_assert (g_str_has_prefix (error->message, glnx_strjoina ("Failed to open ", noent_path))); g_clear_error (&error); } diff --git a/libglnx/tests/test-libglnx-xattrs.c b/libglnx/tests/test-libglnx-xattrs.c index 0b21133a..b6f0ac69 100644 --- a/libglnx/tests/test-libglnx-xattrs.c +++ b/libglnx/tests/test-libglnx-xattrs.c @@ -244,6 +244,21 @@ test_xattr_races (void) if (!glnx_opendirat (AT_FDCWD, tmpdir, TRUE, &dfd, error)) goto out; + /* Support people building/testing on tmpfs https://github.com/flatpak/flatpak/issues/686 */ + if (fsetxattr (dfd, "user.test", "novalue", strlen ("novalue"), 0) < 0) + { + if (errno == EOPNOTSUPP) + { + g_test_skip ("no xattr support"); + return; + } + else + { + glnx_set_error_from_errno (error); + goto out; + } + } + for (guint i = 0; i < nprocs; i++) { struct XattrWorker *worker = &wdata[i]; diff --git a/man/ostree-admin-cleanup.1 b/man/ostree-admin-cleanup.1 index 4fb7bd71..50ba5195 100644 --- a/man/ostree-admin-cleanup.1 +++ b/man/ostree-admin-cleanup.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin cleanup .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin cleanup .\" Source: OSTree .\" Language: English diff --git a/man/ostree-admin-config-diff.1 b/man/ostree-admin-config-diff.1 index 1891b90f..f3661b09 100644 --- a/man/ostree-admin-config-diff.1 +++ b/man/ostree-admin-config-diff.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin config-diff .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/14/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin config-diff .\" Source: OSTree .\" Language: English @@ -37,9 +37,9 @@ ostree-admin-config-diff \- Diff current /etc configuration versus default Prints the differences between the current /etc directory and the default configuration in /usr/etc\&. Newly added files (present in /etc but not in /usr/etc) will be prefixed with \*(AqA\*(Aq\&. Modified files will be prefixed with \*(AqM\*(Aq, and deleted files with \*(AqD\*(Aq\&. .SH "OPTIONS" .PP -\fB\-\-os\fR="OSNAME" +\fB\-\-os\fR="STATEROOT" .RS 4 -Use a different operating system root than the current one\&. +Use a different operating system stateroot than the current one\&. .RE .SH "EXAMPLE" .PP diff --git a/man/ostree-admin-config-diff.xml b/man/ostree-admin-config-diff.xml index 69209e49..256b02fe 100644 --- a/man/ostree-admin-config-diff.xml +++ b/man/ostree-admin-config-diff.xml @@ -66,10 +66,10 @@ Boston, MA 02111-1307, USA. - ="OSNAME" + ="STATEROOT" - Use a different operating system root than the current one. + Use a different operating system stateroot than the current one. diff --git a/man/ostree-admin-deploy.1 b/man/ostree-admin-deploy.1 index 838aa181..0c07738e 100644 --- a/man/ostree-admin-deploy.1 +++ b/man/ostree-admin-deploy.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin deploy .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/14/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin deploy .\" Source: OSTree .\" Language: English @@ -37,7 +37,7 @@ ostree-admin-deploy \- Checkout a revision as the new default deployment Takes a commit or revision REFSPEC, and queues the new deployment as default upon reboot\&. .SH "OPTIONS" .PP -\fB\-\-os\fR="OSNAME" +\fB\-\-os\fR="STATEROOT" .RS 4 Use a different operating system root than the current one\&. .RE diff --git a/man/ostree-admin-deploy.xml b/man/ostree-admin-deploy.xml index ef96203c..347a4ba9 100644 --- a/man/ostree-admin-deploy.xml +++ b/man/ostree-admin-deploy.xml @@ -66,7 +66,7 @@ Boston, MA 02111-1307, USA. - ="OSNAME" + ="STATEROOT" Use a different operating system root than the current one. diff --git a/man/ostree-admin-init-fs.1 b/man/ostree-admin-init-fs.1 index 785f55ef..fcb7302f 100644 --- a/man/ostree-admin-init-fs.1 +++ b/man/ostree-admin-init-fs.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin init-fs .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin init-fs .\" Source: OSTree .\" Language: English diff --git a/man/ostree-admin-instutil.1 b/man/ostree-admin-instutil.1 index f6c90952..cc0f52b7 100644 --- a/man/ostree-admin-instutil.1 +++ b/man/ostree-admin-instutil.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin instutil .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin instutil .\" Source: OSTree .\" Language: English diff --git a/man/ostree-admin-os-init.1 b/man/ostree-admin-os-init.1 index 5b14d45f..4f2f7cbe 100644 --- a/man/ostree-admin-os-init.1 +++ b/man/ostree-admin-os-init.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin os-init .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/14/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin os-init .\" Source: OSTree .\" Language: English @@ -31,21 +31,21 @@ ostree-admin-os-init \- Initialize empty state for a given operating system .SH "SYNOPSIS" .HP \w'\fBostree\ admin\ os\-init\fR\ 'u -\fBostree admin os\-init\fR {OSNAME} +\fBostree admin os\-init\fR {STATEROOT} .SH "DESCRIPTION" .PP -Initializes an new state for an operating system\&. Ensures that the core subdirectories of /var (/tmp, /lib, /run, and /lock) exist and initialize the given OSNAME as OSTree root\&. Each deployment location is comprised of a single shared +Initializes an new stateroot (AKA "osname") for an operating system\&. Ensures that the core subdirectories of /var (/tmp, /lib, /run, and /lock) exist and initialize the given STATEROOT as OSTree stateroot\&. Each deployment location is comprised of a single shared var and a set of deployments (chroots)\&. .SH "EXAMPLE" .PP -\fB$ ostree admin os\-init gnome\-ostree\fR +\fB$ ostree admin os\-init exampleos\fR .sp .if n \{\ .RS 4 .\} .nf - ostree/deploy/gnome\-ostree initialized as OSTree root + ostree/deploy/exampleos initialized as OSTree root .fi .if n \{\ diff --git a/man/ostree-admin-os-init.xml b/man/ostree-admin-os-init.xml index 77bd126a..10f02ad6 100644 --- a/man/ostree-admin-os-init.xml +++ b/man/ostree-admin-os-init.xml @@ -49,7 +49,7 @@ Boston, MA 02111-1307, USA. - ostree admin os-init OSNAME + ostree admin os-init STATEROOT @@ -57,15 +57,19 @@ Boston, MA 02111-1307, USA. Description - Initializes an new state for an operating system. Ensures that the core subdirectories of /var (/tmp, /lib, /run, and /lock) exist and initialize the given OSNAME as OSTree root. Each deployment location is comprised of a single shared var and a set of deployments (chroots). + Initializes an new stateroot (AKA "osname") for an operating system. + Ensures that the core subdirectories of /var (/tmp, /lib, /run, and + /lock) exist and initialize the given STATEROOT as OSTree stateroot. + Each deployment location is comprised of a single shared + var and a set of deployments (chroots). Example - $ ostree admin os-init gnome-ostree + $ ostree admin os-init exampleos - ostree/deploy/gnome-ostree initialized as OSTree root + ostree/deploy/exampleos initialized as OSTree root diff --git a/man/ostree-admin-set-origin.1 b/man/ostree-admin-set-origin.1 index fe1db02d..33d6720f 100644 --- a/man/ostree-admin-set-origin.1 +++ b/man/ostree-admin-set-origin.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin set-origin .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin set-origin .\" Source: OSTree .\" Language: English diff --git a/man/ostree-admin-status.1 b/man/ostree-admin-status.1 index 5a14d3e5..9ac88f20 100644 --- a/man/ostree-admin-status.1 +++ b/man/ostree-admin-status.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin status .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin status .\" Source: OSTree .\" Language: English diff --git a/man/ostree-admin-switch.1 b/man/ostree-admin-switch.1 index 1df9f953..f7761162 100644 --- a/man/ostree-admin-switch.1 +++ b/man/ostree-admin-switch.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin switch .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/14/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin switch .\" Source: OSTree .\" Language: English @@ -38,7 +38,7 @@ Choose a different REF forom the current remote to track\&. This is the ref that \fBostree admin upgrade\fR\&. Like an upgrade, the operating system state will be preserved\&. .SH "OPTIONS" .PP -\fB\-\-os\fR="OSNAME" +\fB\-\-os\fR="STATEROOT" .RS 4 Use a different operating system root than the current one\&. .RE diff --git a/man/ostree-admin-switch.xml b/man/ostree-admin-switch.xml index 8072d6b9..86f9be40 100644 --- a/man/ostree-admin-switch.xml +++ b/man/ostree-admin-switch.xml @@ -66,7 +66,7 @@ Boston, MA 02111-1307, USA. - ="OSNAME" + ="STATEROOT" Use a different operating system root than the current one. diff --git a/man/ostree-admin-undeploy.1 b/man/ostree-admin-undeploy.1 index 88a7ba41..5a0253f2 100644 --- a/man/ostree-admin-undeploy.1 +++ b/man/ostree-admin-undeploy.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin undeploy .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin undeploy .\" Source: OSTree .\" Language: English diff --git a/man/ostree-admin-unlock.1 b/man/ostree-admin-unlock.1 index 68145e27..141656c5 100644 --- a/man/ostree-admin-unlock.1 +++ b/man/ostree-admin-unlock.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin unlock .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin unlock .\" Source: OSTree .\" Language: English diff --git a/man/ostree-admin-upgrade.1 b/man/ostree-admin-upgrade.1 index 768f24ef..50734f26 100644 --- a/man/ostree-admin-upgrade.1 +++ b/man/ostree-admin-upgrade.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin upgrade .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/14/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin upgrade .\" Source: OSTree .\" Language: English @@ -40,7 +40,7 @@ and \fB\-\-deploy\-only\fR\&. .SH "OPTIONS" .PP -\fB\-\-os\fR="OSNAME" +\fB\-\-os\fR="STATEROOT" .RS 4 Use a different operating system root than the current one\&. .RE diff --git a/man/ostree-admin-upgrade.xml b/man/ostree-admin-upgrade.xml index 7766c66e..51900b85 100644 --- a/man/ostree-admin-upgrade.xml +++ b/man/ostree-admin-upgrade.xml @@ -69,7 +69,7 @@ Boston, MA 02111-1307, USA. - ="OSNAME" + ="STATEROOT" Use a different operating system root than the current one. diff --git a/man/ostree-admin.1 b/man/ostree-admin.1 index 2de6a630..4f149829 100644 --- a/man/ostree-admin.1 +++ b/man/ostree-admin.1 @@ -2,7 +2,7 @@ .\" Title: ostree admin .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree admin .\" Source: OSTree .\" Language: English diff --git a/man/ostree-cat.1 b/man/ostree-cat.1 index c068668a..c771a90a 100644 --- a/man/ostree-cat.1 +++ b/man/ostree-cat.1 @@ -2,7 +2,7 @@ .\" Title: ostree cat .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree cat .\" Source: OSTree .\" Language: English diff --git a/man/ostree-checkout.1 b/man/ostree-checkout.1 index 80420983..44dc90a8 100644 --- a/man/ostree-checkout.1 +++ b/man/ostree-checkout.1 @@ -2,7 +2,7 @@ .\" Title: ostree checkout .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree checkout .\" Source: OSTree .\" Language: English diff --git a/man/ostree-checksum.1 b/man/ostree-checksum.1 index 7d2d56bc..fa8abeaf 100644 --- a/man/ostree-checksum.1 +++ b/man/ostree-checksum.1 @@ -2,7 +2,7 @@ .\" Title: ostree checksum .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree checksum .\" Source: OSTree .\" Language: English diff --git a/man/ostree-commit.1 b/man/ostree-commit.1 index d3ce3286..0bc038db 100644 --- a/man/ostree-commit.1 +++ b/man/ostree-commit.1 @@ -2,7 +2,7 @@ .\" Title: ostree commit .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree commit .\" Source: OSTree .\" Language: English diff --git a/man/ostree-config.1 b/man/ostree-config.1 index 2a820647..9e927d46 100644 --- a/man/ostree-config.1 +++ b/man/ostree-config.1 @@ -2,7 +2,7 @@ .\" Title: ostree config .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree config .\" Source: OSTree .\" Language: English diff --git a/man/ostree-diff.1 b/man/ostree-diff.1 index d91442ab..abbb8b80 100644 --- a/man/ostree-diff.1 +++ b/man/ostree-diff.1 @@ -2,7 +2,7 @@ .\" Title: ostree diff .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/11/2017 +.\" Date: 05/17/2017 .\" Manual: ostree diff .\" Source: OSTree .\" Language: English diff --git a/man/ostree-export.1 b/man/ostree-export.1 index b642a026..f40c257e 100644 --- a/man/ostree-export.1 +++ b/man/ostree-export.1 @@ -2,7 +2,7 @@ .\" Title: ostree export .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree export .\" Source: OSTree .\" Language: English diff --git a/man/ostree-fsck.1 b/man/ostree-fsck.1 index c7cf826b..6ee29ddd 100644 --- a/man/ostree-fsck.1 +++ b/man/ostree-fsck.1 @@ -2,7 +2,7 @@ .\" Title: ostree fsck .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree fsck .\" Source: OSTree .\" Language: English diff --git a/man/ostree-gpg-sign.1 b/man/ostree-gpg-sign.1 index 150e488a..621af5cb 100644 --- a/man/ostree-gpg-sign.1 +++ b/man/ostree-gpg-sign.1 @@ -2,7 +2,7 @@ .\" Title: ostree gpg-sign .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree gpg-sign .\" Source: OSTree .\" Language: English diff --git a/man/ostree-init.1 b/man/ostree-init.1 index 303f9ebe..8a33ac92 100644 --- a/man/ostree-init.1 +++ b/man/ostree-init.1 @@ -2,7 +2,7 @@ .\" Title: ostree init .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree init .\" Source: OSTree .\" Language: English diff --git a/man/ostree-log.1 b/man/ostree-log.1 index 8b6bbb50..5dee34cd 100644 --- a/man/ostree-log.1 +++ b/man/ostree-log.1 @@ -2,7 +2,7 @@ .\" Title: ostree log .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree log .\" Source: OSTree .\" Language: English diff --git a/man/ostree-ls.1 b/man/ostree-ls.1 index 9488f2a4..aefbb97c 100644 --- a/man/ostree-ls.1 +++ b/man/ostree-ls.1 @@ -2,7 +2,7 @@ .\" Title: ostree ls .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree ls .\" Source: OSTree .\" Language: English diff --git a/man/ostree-prune.1 b/man/ostree-prune.1 index d474c1cf..30a42239 100644 --- a/man/ostree-prune.1 +++ b/man/ostree-prune.1 @@ -2,7 +2,7 @@ .\" Title: ostree prune .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree prune .\" Source: OSTree .\" Language: English diff --git a/man/ostree-pull-local.1 b/man/ostree-pull-local.1 index af5e740c..9abae9a9 100644 --- a/man/ostree-pull-local.1 +++ b/man/ostree-pull-local.1 @@ -2,7 +2,7 @@ .\" Title: ostree pull-local .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree pull-local .\" Source: OSTree .\" Language: English diff --git a/man/ostree-pull.1 b/man/ostree-pull.1 index 17d9fcbd..ff57eb3c 100644 --- a/man/ostree-pull.1 +++ b/man/ostree-pull.1 @@ -2,7 +2,7 @@ .\" Title: ostree pull .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree pull .\" Source: OSTree .\" Language: English diff --git a/man/ostree-refs.1 b/man/ostree-refs.1 index 0734d0f2..7898ba25 100644 --- a/man/ostree-refs.1 +++ b/man/ostree-refs.1 @@ -2,7 +2,7 @@ .\" Title: ostree refs .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree refs .\" Source: OSTree .\" Language: English diff --git a/man/ostree-remote.1 b/man/ostree-remote.1 index 20278e44..eb9cbd55 100644 --- a/man/ostree-remote.1 +++ b/man/ostree-remote.1 @@ -2,7 +2,7 @@ .\" Title: ostree remote .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree remote .\" Source: OSTree .\" Language: English diff --git a/man/ostree-reset.1 b/man/ostree-reset.1 index b009d9e9..b2ce450b 100644 --- a/man/ostree-reset.1 +++ b/man/ostree-reset.1 @@ -2,7 +2,7 @@ .\" Title: ostree reset .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree reset .\" Source: OSTree .\" Language: English diff --git a/man/ostree-rev-parse.1 b/man/ostree-rev-parse.1 index 3da7374b..78af805b 100644 --- a/man/ostree-rev-parse.1 +++ b/man/ostree-rev-parse.1 @@ -2,7 +2,7 @@ .\" Title: ostree rev-parse .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree rev-parse .\" Source: OSTree .\" Language: English diff --git a/man/ostree-show.1 b/man/ostree-show.1 index 5fb6c675..ef36f4a2 100644 --- a/man/ostree-show.1 +++ b/man/ostree-show.1 @@ -2,7 +2,7 @@ .\" Title: ostree show .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree show .\" Source: OSTree .\" Language: English diff --git a/man/ostree-static-delta.1 b/man/ostree-static-delta.1 index 5d2ed8e9..660983ff 100644 --- a/man/ostree-static-delta.1 +++ b/man/ostree-static-delta.1 @@ -2,7 +2,7 @@ .\" Title: ostree static-delta .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree static-delta .\" Source: OSTree .\" Language: English diff --git a/man/ostree-summary.1 b/man/ostree-summary.1 index 6e258f0b..6f2b1622 100644 --- a/man/ostree-summary.1 +++ b/man/ostree-summary.1 @@ -2,7 +2,7 @@ .\" Title: ostree summary .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree summary .\" Source: OSTree .\" Language: English diff --git a/man/ostree-trivial-httpd.1 b/man/ostree-trivial-httpd.1 index a6a7cafe..9a021cc9 100644 --- a/man/ostree-trivial-httpd.1 +++ b/man/ostree-trivial-httpd.1 @@ -2,7 +2,7 @@ .\" Title: ostree trivial-httpd .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree trivial-httpd .\" Source: OSTree .\" Language: English diff --git a/man/ostree.1 b/man/ostree.1 index 6c58dccc..58434378 100644 --- a/man/ostree.1 +++ b/man/ostree.1 @@ -2,7 +2,7 @@ .\" Title: ostree .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/14/2017 +.\" Date: 05/17/2017 .\" Manual: ostree .\" Source: OSTree .\" Language: English @@ -37,8 +37,10 @@ ostree \- Manage multiple bootable versioned filesystem trees OSTree is a tool for managing multiple bootable versioned filesystem trees, or just "tree" for short\&. In the OSTree model, operating systems no longer live in the physical "/" root directory\&. Instead, they parallel install to the new toplevel /ostree directory\&. Each installed system gets its own -/ostree/deploy/\fIosname\fR -directory\&. +/ostree/deploy/\fIstateroot\fR +directory\&. (stateroot +is the newer term for +osname)\&. .PP Unlike rpm diff --git a/man/ostree.repo-config.5 b/man/ostree.repo-config.5 index 7d84d39b..de7302a3 100644 --- a/man/ostree.repo-config.5 +++ b/man/ostree.repo-config.5 @@ -2,7 +2,7 @@ .\" Title: ostree.repo-config .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree.repo-config .\" Source: OSTree .\" Language: English diff --git a/man/ostree.repo.5 b/man/ostree.repo.5 index 9d630fa1..07f0d904 100644 --- a/man/ostree.repo.5 +++ b/man/ostree.repo.5 @@ -2,7 +2,7 @@ .\" Title: ostree.repo .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: ostree.repo .\" Source: OSTree .\" Language: English diff --git a/man/ostree.xml b/man/ostree.xml index e31d58b2..940d81d7 100644 --- a/man/ostree.xml +++ b/man/ostree.xml @@ -65,8 +65,9 @@ Boston, MA 02111-1307, USA. Instead, they parallel install to the new toplevel /ostree directory. Each installed system gets its own - /ostree/deploy/osname - directory. + /ostree/deploy/stateroot + directory. (stateroot is the + newer term for osname). Unlike rpm or diff --git a/man/rofiles-fuse.1 b/man/rofiles-fuse.1 index 4c6de299..59591a05 100644 --- a/man/rofiles-fuse.1 +++ b/man/rofiles-fuse.1 @@ -2,7 +2,7 @@ .\" Title: rofiles-fuse .\" Author: Colin Walters .\" Generator: DocBook XSL Stylesheets v1.79.1 -.\" Date: 04/05/2017 +.\" Date: 05/17/2017 .\" Manual: rofiles-fuse .\" Source: rofiles-fuse .\" Language: English diff --git a/src/libostree/libostree-experimental.sym b/src/libostree/libostree-experimental.sym new file mode 100644 index 00000000..e2ab4ea8 --- /dev/null +++ b/src/libostree/libostree-experimental.sym @@ -0,0 +1,31 @@ +/* + * Copyright © 2017 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Philip Withnall + */ + +/* Symbols in this file are added to the build if OSTree is configured with + * --enable-experimental-api. They are not stable or officially supported, and + * might disappear or change in future releases. */ + +LIBOSTREE_2017.6_EXPERIMENTAL { +global: + ostree_remote_ref; + ostree_remote_unref; +} LIBOSTREE_2017.6; diff --git a/src/libostree/libostree.sym b/src/libostree/libostree.sym index d9339bf2..e2a7c3d9 100644 --- a/src/libostree/libostree.sym +++ b/src/libostree/libostree.sym @@ -389,17 +389,24 @@ global: ostree_sysroot_write_deployments_with_options; } LIBOSTREE_2017.3; +LIBOSTREE_2017.6 { +global: + ostree_async_progress_get; + ostree_async_progress_set; + ostree_async_progress_get_variant; + ostree_async_progress_set_variant; +} LIBOSTREE_2017.4; + /* NOTE NOTE NOTE * Versions above here are released. Only add symbols below this line. * NOTE NOTE NOTE */ -/* Uncomment when adding the first new symbol */ /* LIBOSTREE_2017.$NEWVERSION { global: someostree_symbol_deleteme; -} LIBOSTREE_2017.4; +} LIBOSTREE_2017.6; */ /* Stub section for the stable release *after* this development one; don't diff --git a/src/libostree/ostree-1.pc.in b/src/libostree/ostree-1.pc.in index d777c597..9a4debce 100644 --- a/src/libostree/ostree-1.pc.in +++ b/src/libostree/ostree-1.pc.in @@ -2,6 +2,7 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ +features=@OSTREE_FEATURES@ Name: OSTree Description: Git for operating system binaries diff --git a/src/libostree/ostree-async-progress.c b/src/libostree/ostree-async-progress.c index 0851fd86..b879559e 100644 --- a/src/libostree/ostree-async-progress.c +++ b/src/libostree/ostree-async-progress.c @@ -22,6 +22,8 @@ #include "ostree-async-progress.h" +#include "libglnx.h" + /** * SECTION:ostree-async-progress * @title: Progress notification system for asynchronous operations @@ -37,14 +39,13 @@ * handles thread safety, ensuring that the progress change * notification occurs in the thread-default context of the calling * operation. + * + * The ostree_async_progress_get_status() and ostree_async_progress_set_status() + * methods get and set a well-known `status` key of type %G_VARIANT_TYPE_STRING. + * This key may be accessed using the other #OstreeAsyncProgress methods, but it + * must always have the correct type. */ -#if GLIB_SIZEOF_VOID_P == 8 -#define _OSTREE_HAVE_LP64 1 -#else -#define _OSTREE_HAVE_LP64 0 -#endif - enum { CHANGED, LAST_SIGNAL @@ -59,12 +60,9 @@ struct OstreeAsyncProgress GMutex lock; GMainContext *maincontext; GSource *idle_source; - GHashTable *uint_values; - GHashTable *uint64_values; + GHashTable *values; /* (element-type uint GVariant) */ gboolean dead; - - char *status; }; G_DEFINE_TYPE (OstreeAsyncProgress, ostree_async_progress, G_TYPE_OBJECT) @@ -79,9 +77,7 @@ ostree_async_progress_finalize (GObject *object) g_mutex_clear (&self->lock); g_clear_pointer (&self->maincontext, g_main_context_unref); g_clear_pointer (&self->idle_source, g_source_unref); - g_hash_table_unref (self->uint_values); - g_hash_table_unref (self->uint64_values); - g_free (self->status); + g_hash_table_unref (self->values); G_OBJECT_CLASS (ostree_async_progress_parent_class)->finalize (object); } @@ -114,46 +110,115 @@ ostree_async_progress_init (OstreeAsyncProgress *self) { g_mutex_init (&self->lock); self->maincontext = g_main_context_ref_thread_default (); - self->uint_values = g_hash_table_new (NULL, NULL); -#if _OSTREE_HAVE_LP64 - self->uint64_values = g_hash_table_new (NULL, NULL); -#else - self->uint64_values = g_hash_table_new_full (NULL, NULL, - NULL, g_free); -#endif + self->values = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) g_variant_unref); +} + +/** + * ostree_async_progress_get_variant: + * @self: an #OstreeAsyncProgress + * @key: a key to look up + * + * Look up a key in the #OstreeAsyncProgress and return the #GVariant associated + * with it. The lookup is thread-safe. + * + * Returns: (transfer full) (nullable): value for the given @key, or %NULL if + * it was not set + * Since: 2017.6 + */ +GVariant * +ostree_async_progress_get_variant (OstreeAsyncProgress *self, + const char *key) +{ + GVariant *rval; + + g_return_val_if_fail (OSTREE_IS_ASYNC_PROGRESS (self), NULL); + g_return_val_if_fail (key != NULL, NULL); + + g_mutex_lock (&self->lock); + rval = g_hash_table_lookup (self->values, GUINT_TO_POINTER (g_quark_from_string (key))); + if (rval != NULL) + g_variant_ref (rval); + g_mutex_unlock (&self->lock); + + return rval; } guint ostree_async_progress_get_uint (OstreeAsyncProgress *self, const char *key) { - guint rval; - g_mutex_lock (&self->lock); - rval = GPOINTER_TO_UINT (g_hash_table_lookup (self->uint_values, - GUINT_TO_POINTER (g_quark_from_string (key)))); - g_mutex_unlock (&self->lock); - return rval; + g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, key); + return (rval != NULL) ? g_variant_get_uint32 (rval) : 0; } guint64 ostree_async_progress_get_uint64 (OstreeAsyncProgress *self, const char *key) { -#if _OSTREE_HAVE_LP64 - guint64 rval; + g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, key); + return (rval != NULL) ? g_variant_get_uint64 (rval) : 0; +} + +/** + * ostree_async_progress_get: + * @self: an #OstreeAsyncProgress + * @...: key name, format string, #GVariant return locations, …, followed by %NULL + * + * Get the values corresponding to zero or more keys from the + * #OstreeAsyncProgress. Each key is specified in @... as the key name, followed + * by a #GVariant format string, followed by the necessary arguments for that + * format string, just as for g_variant_get(). After those arguments is the + * next key name. The varargs list must be %NULL-terminated. + * + * Each format string must make deep copies of its value, as the values stored + * in the #OstreeAsyncProgress may be freed from another thread after this + * function returns. + * + * This operation is thread-safe, and all the keys are queried atomically. + * + * |[ + * guint32 outstanding_fetches; + * guint64 bytes_received; + * g_autofree gchar *status = NULL; + * g_autoptr(GVariant) refs_variant = NULL; + * + * ostree_async_progress_get (progress, + * "outstanding-fetches", "u", &outstanding_fetches, + * "bytes-received", "t", &bytes_received, + * "status", "s", &status, + * "refs", "@a{ss}", &refs_variant, + * NULL); + * ]| + * + * Since: 2017.6 + */ +void +ostree_async_progress_get (OstreeAsyncProgress *self, + ...) +{ + va_list ap; + const char *key, *format_string; + g_mutex_lock (&self->lock); - rval = (guint64) g_hash_table_lookup (self->uint64_values, GUINT_TO_POINTER (g_quark_from_string (key))); + va_start (ap, self); + + for (key = va_arg (ap, const char *), format_string = va_arg (ap, const char *); + key != NULL; + key = va_arg (ap, const char *), format_string = va_arg (ap, const char *)) + { + GVariant *variant; + + g_assert (format_string != NULL); + + variant = g_hash_table_lookup (self->values, GUINT_TO_POINTER (g_quark_from_string (key))); + g_assert (variant != NULL); + g_assert (g_variant_check_format_string (variant, format_string, TRUE)); + + g_variant_get_va (variant, format_string, NULL, &ap); + } + + va_end (ap); g_mutex_unlock (&self->lock); - return rval; -#else - guint64 *rval; - g_mutex_lock (&self->lock); - rval = g_hash_table_lookup (self->uint64_values, (gpointer)g_quark_from_string (key)); - g_mutex_unlock (&self->lock); - if (rval) - return *rval; - return 0; -#endif } static gboolean @@ -180,50 +245,162 @@ ensure_callback_locked (OstreeAsyncProgress *self) g_source_attach (self->idle_source, self->maincontext); } +/** + * ostree_async_progress_set_status: + * @self: an #OstreeAsyncProgress + * @status: (nullable): new status string, or %NULL to clear the status + * + * Set the human-readable status string for the #OstreeAsyncProgress. This + * operation is thread-safe. %NULL may be passed to clear the status. + * + * This is a convenience function to set the well-known `status` key. + * + * Since: 2017.6 + */ void ostree_async_progress_set_status (OstreeAsyncProgress *self, const char *status) { - g_mutex_lock (&self->lock); - if (!self->dead) - { - g_free (self->status); - self->status = g_strdup (status); - ensure_callback_locked (self); - } - g_mutex_unlock (&self->lock); + ostree_async_progress_set_variant (self, "status", + g_variant_new_string ((status != NULL) ? status : "")); } +/** + * ostree_async_progress_get_status: + * @self: an #OstreeAsyncProgress + * + * Get the human-readable status string from the #OstreeAsyncProgress. This + * operation is thread-safe. The retuned value may be %NULL if no status is + * set. + * + * This is a convenience function to get the well-known `status` key. + * + * Returns: (transfer full) (nullable): the current status, or %NULL if none is set + * Since: 2017.6 + */ char * ostree_async_progress_get_status (OstreeAsyncProgress *self) { - char *ret; - g_mutex_lock (&self->lock); - ret = g_strdup (self->status); - g_mutex_unlock (&self->lock); - return ret; + g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, "status"); + const gchar *status = (rval != NULL) ? g_variant_get_string (rval, NULL) : NULL; + if (status != NULL && *status == '\0') + status = NULL; + return g_strdup (status); } -static void -update_key (OstreeAsyncProgress *self, - GHashTable *hash, - const char *key, - gpointer value) +/** + * ostree_async_progress_set: + * @self: an #OstreeAsyncProgress + * @...: key name, format string, #GVariant parameters, …, followed by %NULL + * + * Set the values for zero or more keys in the #OstreeAsyncProgress. Each key is + * specified in @... as the key name, followed by a #GVariant format string, + * followed by the necessary arguments for that format string, just as for + * g_variant_new(). After those arguments is the next key name. The varargs list + * must be %NULL-terminated. + * + * g_variant_ref_sink() will be called as appropriate on the #GVariant + * parameters, so they may be floating. + * + * This operation is thread-safe, and all the keys are set atomically. + * + * |[ + * guint32 outstanding_fetches = 15; + * guint64 bytes_received = 1000; + * + * ostree_async_progress_set (progress, + * "outstanding-fetches", "u", outstanding_fetches, + * "bytes-received", "t", bytes_received, + * "status", "s", "Updated status", + * "refs", "@a{ss}", g_variant_new_parsed ("@a{ss} {}"), + * NULL); + * ]| + * + * Since: 2017.6 + */ +void +ostree_async_progress_set (OstreeAsyncProgress *self, + ...) { - gpointer orig_value; - gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key)); + va_list ap; + const char *key, *format_string; + gboolean changed; g_mutex_lock (&self->lock); if (self->dead) goto out; - if (g_hash_table_lookup_extended (hash, qkey, NULL, &orig_value)) + changed = FALSE; + + va_start (ap, self); + + for (key = va_arg (ap, const char *), format_string = va_arg (ap, const char *); + key != NULL; + key = va_arg (ap, const char *), format_string = va_arg (ap, const char *)) { - if (orig_value == value) + GVariant *orig_value; + g_autoptr(GVariant) new_value = NULL; + gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key)); + + new_value = g_variant_ref_sink (g_variant_new_va (format_string, NULL, &ap)); + + if (g_hash_table_lookup_extended (self->values, qkey, NULL, (gpointer *) &orig_value) && + g_variant_equal (orig_value, new_value)) + continue; + + g_hash_table_replace (self->values, qkey, g_steal_pointer (&new_value)); + changed = TRUE; + } + + va_end (ap); + + if (changed) + ensure_callback_locked (self); + +out: + g_mutex_unlock (&self->lock); +} + +/** + * ostree_async_progress_set_variant: + * @self: an #OstreeAsyncProgress + * @key: a key to set + * @value: the value to assign to @key + * + * Assign a new @value to the given @key, replacing any existing value. The + * operation is thread-safe. @value may be a floating reference; + * g_variant_ref_sink() will be called on it. + * + * Any watchers of the #OstreeAsyncProgress will be notified of the change if + * @value differs from the existing value for @key. + * + * Since: 2017.6 + */ +void +ostree_async_progress_set_variant (OstreeAsyncProgress *self, + const char *key, + GVariant *value) +{ + GVariant *orig_value; + g_autoptr(GVariant) new_value = g_variant_ref_sink (value); + gpointer qkey = GUINT_TO_POINTER (g_quark_from_string (key)); + + g_return_if_fail (OSTREE_IS_ASYNC_PROGRESS (self)); + g_return_if_fail (key != NULL); + g_return_if_fail (value != NULL); + + g_mutex_lock (&self->lock); + + if (self->dead) + goto out; + + if (g_hash_table_lookup_extended (self->values, qkey, NULL, (gpointer *) &orig_value)) + { + if (g_variant_equal (orig_value, new_value)) goto out; } - g_hash_table_replace (hash, qkey, value); + g_hash_table_replace (self->values, qkey, g_steal_pointer (&new_value)); ensure_callback_locked (self); out: @@ -235,7 +412,7 @@ ostree_async_progress_set_uint (OstreeAsyncProgress *self, const char *key, guint value) { - update_key (self, self->uint_values, key, GUINT_TO_POINTER (value)); + ostree_async_progress_set_variant (self, key, g_variant_new_uint32 (value)); } void @@ -243,18 +420,7 @@ ostree_async_progress_set_uint64 (OstreeAsyncProgress *self, const char *key, guint64 value) { - gpointer valuep; - -#if _OSTREE_HAVE_LP64 - valuep = (gpointer)value; -#else - { - guint64 *boxed = g_malloc (sizeof (guint64)); - *boxed = value; - valuep = boxed; - } -#endif - update_key (self, self->uint64_values, key, valuep); + ostree_async_progress_set_variant (self, key, g_variant_new_uint64 (value)); } /** diff --git a/src/libostree/ostree-async-progress.h b/src/libostree/ostree-async-progress.h index ae0e5faa..55ac591c 100644 --- a/src/libostree/ostree-async-progress.h +++ b/src/libostree/ostree-async-progress.h @@ -53,17 +53,28 @@ OstreeAsyncProgress *ostree_async_progress_new_and_connect (void (*changed) (Ost _OSTREE_PUBLIC char *ostree_async_progress_get_status (OstreeAsyncProgress *self); +_OSTREE_PUBLIC +void ostree_async_progress_get (OstreeAsyncProgress *self, + ...) G_GNUC_NULL_TERMINATED; + _OSTREE_PUBLIC guint ostree_async_progress_get_uint (OstreeAsyncProgress *self, const char *key); _OSTREE_PUBLIC guint64 ostree_async_progress_get_uint64 (OstreeAsyncProgress *self, const char *key); +_OSTREE_PUBLIC +GVariant *ostree_async_progress_get_variant (OstreeAsyncProgress *self, + const char *key); _OSTREE_PUBLIC void ostree_async_progress_set_status (OstreeAsyncProgress *self, const char *status); +_OSTREE_PUBLIC +void ostree_async_progress_set (OstreeAsyncProgress *self, + ...) G_GNUC_NULL_TERMINATED; + _OSTREE_PUBLIC void ostree_async_progress_set_uint (OstreeAsyncProgress *self, const char *key, @@ -72,6 +83,10 @@ _OSTREE_PUBLIC void ostree_async_progress_set_uint64 (OstreeAsyncProgress *self, const char *key, guint64 value); +_OSTREE_PUBLIC +void ostree_async_progress_set_variant (OstreeAsyncProgress *self, + const char *key, + GVariant *value); _OSTREE_PUBLIC void ostree_async_progress_finish (OstreeAsyncProgress *self); diff --git a/src/libostree/ostree-autocleanups.h b/src/libostree/ostree-autocleanups.h index f030b50e..1fdb50ad 100644 --- a/src/libostree/ostree-autocleanups.h +++ b/src/libostree/ostree-autocleanups.h @@ -59,6 +59,10 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeSysrootUpgrader, g_object_unref) G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (OstreeRepoCommitTraverseIter, ostree_repo_commit_traverse_iter_clear) +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRemote, ostree_remote_unref) +#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ + #endif G_END_DECLS diff --git a/src/libostree/ostree-bootconfig-parser.c b/src/libostree/ostree-bootconfig-parser.c index 8031334e..a7c473dd 100644 --- a/src/libostree/ostree-bootconfig-parser.c +++ b/src/libostree/ostree-bootconfig-parser.c @@ -79,23 +79,18 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autofree char *contents = NULL; - char **lines = NULL; - char **iter = NULL; - g_return_val_if_fail (!self->parsed, FALSE); - contents = glnx_file_get_contents_utf8_at (dfd, path, NULL, cancellable, error); + g_autofree char *contents = glnx_file_get_contents_utf8_at (dfd, path, NULL, cancellable, error); if (!contents) - goto out; + return FALSE; - lines = g_strsplit (contents, "\n", -1); - for (iter = lines; *iter; iter++) + g_auto(GStrv) lines = g_strsplit (contents, "\n", -1); + for (char **iter = lines; *iter; iter++) { const char *line = *iter; char *keyname = ""; - + if (g_ascii_isalpha (*line)) { char **items = NULL; @@ -115,11 +110,8 @@ ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self, } self->parsed = TRUE; - - ret = TRUE; - out: - g_strfreev (lines); - return ret; + + return TRUE; } gboolean @@ -166,16 +158,10 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - GHashTableIter hashiter; - gpointer hashkey, hashvalue; - GString *buf = g_string_new (""); - guint i; - g_autoptr(GHashTable) written_overrides = NULL; + g_autoptr(GString) buf = g_string_new (""); + g_autoptr(GHashTable) written_overrides = g_hash_table_new (g_str_hash, g_str_equal); - written_overrides = g_hash_table_new (g_str_hash, g_str_equal); - - for (i = 0; i < self->lines->len; i++) + for (guint i = 0; i < self->lines->len; i++) { GVariant *linedata = self->lines->pdata[i]; const char *key; @@ -197,6 +183,8 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self, } } + GHashTableIter hashiter; + gpointer hashkey, hashvalue; g_hash_table_iter_init (&hashiter, self->options); while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) { @@ -208,15 +196,11 @@ ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self, if (!glnx_file_replace_contents_at (dfd, path, (guint8*)buf->str, buf->len, GLNX_FILE_REPLACE_NODATASYNC, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - if (buf) - g_string_free (buf, TRUE); - return ret; + return TRUE; } - + gboolean ostree_bootconfig_parser_write (OstreeBootconfigParser *self, GFile *output, diff --git a/src/libostree/ostree-bootloader-grub2.c b/src/libostree/ostree-bootloader-grub2.c index 2cd02287..63e4b968 100644 --- a/src/libostree/ostree-bootloader-grub2.c +++ b/src/libostree/ostree-bootloader-grub2.c @@ -148,7 +148,7 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot GError **error) { gboolean ret = FALSE; - GString *output = g_string_new (""); + g_autoptr(GString) output = g_string_new (""); g_autoptr(GOutputStream) out_stream = NULL; g_autoptr(GPtrArray) loader_configs = NULL; guint i; @@ -260,8 +260,6 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot ret = TRUE; out: - if (output) - g_string_free (output, TRUE); return ret; } diff --git a/src/libostree/ostree-cmdprivate.c b/src/libostree/ostree-cmdprivate.c index 4367b497..bade7431 100644 --- a/src/libostree/ostree-cmdprivate.c +++ b/src/libostree/ostree-cmdprivate.c @@ -45,6 +45,7 @@ const OstreeCmdPrivateVTable * ostree_cmd__private__ (void) { static OstreeCmdPrivateVTable table = { + _ostree_impl_system_generator, impl_ostree_generate_grub2_config, _ostree_repo_static_delta_dump, _ostree_repo_static_delta_query_exists, diff --git a/src/libostree/ostree-cmdprivate.h b/src/libostree/ostree-cmdprivate.h index 8d1c653e..63c427cd 100644 --- a/src/libostree/ostree-cmdprivate.h +++ b/src/libostree/ostree-cmdprivate.h @@ -24,7 +24,10 @@ G_BEGIN_DECLS +gboolean _ostree_impl_system_generator (const char *ostree_cmdline, const char *normal_dir, const char *early_dir, const char *late_dir, GError **error); + typedef struct { + gboolean (* ostree_system_generator) (const char *ostree_cmdline, const char *normal_dir, const char *early_dir, const char *late_dir, GError **error); gboolean (* ostree_generate_grub2_config) (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error); gboolean (* ostree_static_delta_dump) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error); gboolean (* ostree_static_delta_query_exists) (OstreeRepo *repo, const char *delta_id, gboolean *out_exists, GCancellable *cancellable, GError **error); diff --git a/src/libostree/ostree-core-private.h b/src/libostree/ostree-core-private.h index a66a068f..72b88aba 100644 --- a/src/libostree/ostree-core-private.h +++ b/src/libostree/ostree-core-private.h @@ -90,6 +90,14 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd, GFileInfo * _ostree_header_gfile_info_new (mode_t mode, uid_t uid, gid_t gid); +static inline void +_ostree_checksum_inplace_from_bytes_v (GVariant *csum_v, char *buf) +{ + const guint8*csum = ostree_checksum_bytes_peek (csum_v); + g_assert (csum); + ostree_checksum_inplace_from_bytes (csum, buf); +} + /* XX/checksum-2.extension, but let's just use 256 for a * bit of overkill. */ diff --git a/src/libostree/ostree-core.c b/src/libostree/ostree-core.c index bab2ab33..7d2ed3c6 100644 --- a/src/libostree/ostree-core.c +++ b/src/libostree/ostree-core.c @@ -579,57 +579,45 @@ ostree_content_stream_parse (gboolean compressed, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; guint32 archive_header_size; guchar dummy[4]; gsize bytes_read; - g_autoptr(GInputStream) ret_input = NULL; - g_autoptr(GFileInfo) ret_file_info = NULL; - g_autoptr(GVariant) ret_xattrs = NULL; - g_autoptr(GVariant) file_header = NULL; - g_autofree guchar *buf = NULL; if (!g_input_stream_read_all (input, &archive_header_size, 4, &bytes_read, cancellable, error)) - goto out; + return FALSE; archive_header_size = GUINT32_FROM_BE (archive_header_size); if (archive_header_size > input_length) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "File header size %u exceeds size %" G_GUINT64_FORMAT, - (guint)archive_header_size, input_length); - goto out; - } - if (archive_header_size == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "File header size is zero"); - goto out; - } + return glnx_throw (error, "File header size %u exceeds size %" G_GUINT64_FORMAT, + (guint)archive_header_size, input_length); + else if (archive_header_size == 0) + return glnx_throw (error, "File header size is zero"); /* Skip over padding */ if (!g_input_stream_read_all (input, dummy, 4, &bytes_read, cancellable, error)) - goto out; + return FALSE; - buf = g_malloc (archive_header_size); + g_autofree guchar *buf = g_malloc (archive_header_size); if (!g_input_stream_read_all (input, buf, archive_header_size, &bytes_read, cancellable, error)) - goto out; - file_header = g_variant_new_from_data (compressed ? _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT : _OSTREE_FILE_HEADER_GVARIANT_FORMAT, - buf, archive_header_size, trusted, - g_free, buf); + return FALSE; + g_autoptr(GVariant) file_header = + g_variant_new_from_data (compressed ? _OSTREE_ZLIB_FILE_HEADER_GVARIANT_FORMAT : _OSTREE_FILE_HEADER_GVARIANT_FORMAT, + buf, archive_header_size, trusted, + g_free, buf); buf = NULL; - + g_autoptr(GFileInfo) ret_file_info = NULL; + g_autoptr(GVariant) ret_xattrs = NULL; if (compressed) { if (!zlib_file_header_parse (file_header, out_file_info ? &ret_file_info : NULL, out_xattrs ? &ret_xattrs : NULL, error)) - goto out; + return FALSE; } else { @@ -637,11 +625,12 @@ ostree_content_stream_parse (gboolean compressed, out_file_info ? &ret_file_info : NULL, out_xattrs ? &ret_xattrs : NULL, error)) - goto out; + return FALSE; if (ret_file_info) g_file_info_set_size (ret_file_info, input_length - archive_header_size - 8); } - + + g_autoptr(GInputStream) ret_input = NULL; if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR && out_input) { @@ -658,12 +647,10 @@ ostree_content_stream_parse (gboolean compressed, ret_input = g_object_ref (input); } - ret = TRUE; ot_transfer_out_value (out_input, &ret_input); ot_transfer_out_value (out_file_info, &ret_file_info); ot_transfer_out_value (out_xattrs, &ret_xattrs); - out: - return ret; + return TRUE; } /** @@ -820,43 +807,39 @@ ostree_checksum_file (GFile *f, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GFileInfo) file_info = NULL; - g_autoptr(GInputStream) in = NULL; - g_autoptr(GVariant) xattrs = NULL; - g_autofree guchar *ret_csum = NULL; - if (g_cancellable_set_error_if_cancelled (cancellable, error)) return FALSE; - file_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, error); + g_autoptr(GFileInfo) file_info = + g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, error); if (!file_info) - goto out; + return FALSE; + g_autoptr(GInputStream) in = NULL; if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { in = (GInputStream*)g_file_read (f, cancellable, error); if (!in) - goto out; + return FALSE; } + g_autoptr(GVariant) xattrs = NULL; if (objtype == OSTREE_OBJECT_TYPE_FILE) { if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f), &xattrs, cancellable, error)) - goto out; + return FALSE; } + g_autofree guchar *ret_csum = NULL; if (!ostree_checksum_file_from_input (file_info, xattrs, in, objtype, &ret_csum, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; ot_transfer_out_value(out_csum, &ret_csum); - out: - return ret; + return TRUE; } typedef struct { @@ -1623,27 +1606,21 @@ file_header_parse (GVariant *metadata, GVariant **out_xattrs, GError **error) { - gboolean ret = FALSE; guint32 uid, gid, mode, rdev; const char *symlink_target; - g_autoptr(GFileInfo) ret_file_info = NULL; g_autoptr(GVariant) ret_xattrs = NULL; g_variant_get (metadata, "(uuuu&s@a(ayay))", &uid, &gid, &mode, &rdev, &symlink_target, &ret_xattrs); if (rdev != 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev)); - goto out; - } + return glnx_throw (error, "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev)); uid = GUINT32_FROM_BE (uid); gid = GUINT32_FROM_BE (gid); mode = GUINT32_FROM_BE (mode); - ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid); + g_autoptr(GFileInfo) ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid); if (S_ISREG (mode)) { @@ -1655,16 +1632,12 @@ file_header_parse (GVariant *metadata, } else { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Corrupted archive file; invalid mode %u", mode); - goto out; + return glnx_throw (error, "Corrupted archive file; invalid mode %u", mode); } - ret = TRUE; ot_transfer_out_value(out_file_info, &ret_file_info); ot_transfer_out_value(out_xattrs, &ret_xattrs); - out: - return ret; + return TRUE; } /* @@ -1683,28 +1656,21 @@ zlib_file_header_parse (GVariant *metadata, GVariant **out_xattrs, GError **error) { - gboolean ret = FALSE; guint64 size; guint32 uid, gid, mode, rdev; const char *symlink_target; - g_autoptr(GFileInfo) ret_file_info = NULL; g_autoptr(GVariant) ret_xattrs = NULL; g_variant_get (metadata, "(tuuuu&s@a(ayay))", &size, &uid, &gid, &mode, &rdev, &symlink_target, &ret_xattrs); if (rdev != 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev)); - goto out; - } + return glnx_throw (error, "Corrupted archive file; invalid rdev %u", GUINT32_FROM_BE (rdev)); uid = GUINT32_FROM_BE (uid); gid = GUINT32_FROM_BE (gid); mode = GUINT32_FROM_BE (mode); - ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid); - + g_autoptr(GFileInfo) ret_file_info = _ostree_header_gfile_info_new (mode, uid, gid); g_file_info_set_size (ret_file_info, GUINT64_FROM_BE (size)); if (S_ISREG (mode)) @@ -1717,16 +1683,12 @@ zlib_file_header_parse (GVariant *metadata, } else { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Corrupted archive file; invalid mode %u", mode); - goto out; + return glnx_throw (error, "Corrupted archive file; invalid mode %u", mode); } - ret = TRUE; ot_transfer_out_value(out_file_info, &ret_file_info); ot_transfer_out_value(out_xattrs, &ret_xattrs); - out: - return ret; + return TRUE; } /** @@ -1829,34 +1791,30 @@ gboolean ostree_validate_structureof_commit (GVariant *commit, GError **error) { - gboolean ret = FALSE; - g_autoptr(GVariant) parent_csum_v = NULL; - g_autoptr(GVariant) content_csum_v = NULL; - g_autoptr(GVariant) metadata_csum_v = NULL; - gsize n_elts; - if (!validate_variant (commit, OSTREE_COMMIT_GVARIANT_FORMAT, error)) - goto out; + return FALSE; + g_autoptr(GVariant) parent_csum_v = NULL; g_variant_get_child (commit, 1, "@ay", &parent_csum_v); + gsize n_elts; (void) g_variant_get_fixed_array (parent_csum_v, &n_elts, 1); if (n_elts > 0) { if (!ostree_validate_structureof_csum_v (parent_csum_v, error)) - goto out; + return FALSE; } + g_autoptr(GVariant) content_csum_v = NULL; g_variant_get_child (commit, 6, "@ay", &content_csum_v); if (!ostree_validate_structureof_csum_v (content_csum_v, error)) - goto out; + return FALSE; + g_autoptr(GVariant) metadata_csum_v = NULL; g_variant_get_child (commit, 7, "@ay", &metadata_csum_v); if (!ostree_validate_structureof_csum_v (metadata_csum_v, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -1873,14 +1831,13 @@ gboolean ostree_validate_structureof_dirtree (GVariant *dirtree, GError **error) { - gboolean ret = FALSE; const char *filename; g_autoptr(GVariant) content_csum_v = NULL; g_autoptr(GVariant) meta_csum_v = NULL; - GVariantIter *contents_iter = NULL; + g_autoptr(GVariantIter) contents_iter = NULL; if (!validate_variant (dirtree, OSTREE_TREE_GVARIANT_FORMAT, error)) - goto out; + return FALSE; g_variant_get_child (dirtree, 0, "a(say)", &contents_iter); @@ -1888,10 +1845,13 @@ ostree_validate_structureof_dirtree (GVariant *dirtree, &filename, &content_csum_v)) { if (!ot_util_filename_validate (filename, error)) - goto out; + return FALSE; if (!ostree_validate_structureof_csum_v (content_csum_v, error)) - goto out; + return FALSE; } + /* Note we only use autoptr in case we broke out of the loop early; + * g_variant_iter_loop() has special semantics. + */ content_csum_v = NULL; g_variant_iter_free (contents_iter); @@ -1901,68 +1861,49 @@ ostree_validate_structureof_dirtree (GVariant *dirtree, &filename, &content_csum_v, &meta_csum_v)) { if (!ot_util_filename_validate (filename, error)) - goto out; + return FALSE; if (!ostree_validate_structureof_csum_v (content_csum_v, error)) - goto out; + return FALSE; if (!ostree_validate_structureof_csum_v (meta_csum_v, error)) - goto out; + return FALSE; } content_csum_v = NULL; meta_csum_v = NULL; - ret = TRUE; - out: - if (contents_iter) - g_variant_iter_free (contents_iter); - return ret; + return TRUE; } static gboolean validate_stat_mode_perms (guint32 mode, GError **error) { - gboolean ret = FALSE; guint32 otherbits = (~S_IFMT & ~S_IRWXU & ~S_IRWXG & ~S_IRWXO & ~S_ISUID & ~S_ISGID & ~S_ISVTX); if (mode & otherbits) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid mode %u; invalid bits in mode", mode); - goto out; - } + return glnx_throw (error, "Invalid mode %u; invalid bits in mode", mode); - ret = TRUE; - out: - return ret; + return TRUE; } /** * ostree_validate_structureof_file_mode: * @mode: A Unix filesystem mode * @error: Error - * + * * Returns: %TRUE if @mode represents a valid file type and permissions */ gboolean ostree_validate_structureof_file_mode (guint32 mode, GError **error) { - gboolean ret = FALSE; - if (!(S_ISREG (mode) || S_ISLNK (mode))) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid file metadata mode %u; not a valid file type", mode); - goto out; - } + return glnx_throw (error, "Invalid file metadata mode %u; not a valid file type", mode); if (!validate_stat_mode_perms (mode, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -1978,28 +1919,21 @@ gboolean ostree_validate_structureof_dirmeta (GVariant *dirmeta, GError **error) { - gboolean ret = FALSE; guint32 mode; if (!validate_variant (dirmeta, OSTREE_DIRMETA_GVARIANT_FORMAT, error)) - goto out; + return FALSE; g_variant_get_child (dirmeta, 2, "u", &mode); mode = GUINT32_FROM_BE (mode); if (!S_ISDIR (mode)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid directory metadata mode %u; not a directory", mode); - goto out; - } + return glnx_throw (error, "Invalid directory metadata mode %u; not a directory", mode); if (!validate_stat_mode_perms (mode, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } /** diff --git a/src/libostree/ostree-core.h b/src/libostree/ostree-core.h index b25112db..c530cea3 100644 --- a/src/libostree/ostree-core.h +++ b/src/libostree/ostree-core.h @@ -104,9 +104,9 @@ typedef enum { /** * OSTREE_DIRMETA_GVARIANT_FORMAT: * - * - u - uid - * - u - gid - * - u - mode + * - u - uid (big-endian) + * - u - gid (big-endian) + * - u - mode (big-endian) * - a(ayay) - xattrs */ #define OSTREE_DIRMETA_GVARIANT_STRING "(uuua(ayay))" @@ -120,9 +120,9 @@ typedef enum { * can't store in the real filesystem but we can still use a regular .file object * that we can hardlink to in the case of a user-mode checkout. * - * - u - uid - * - u - gid - * - u - mode + * - u - uid (big-endian) + * - u - gid (big-endian) + * - u - mode (big-endian) * - a(ayay) - xattrs */ #define OSTREE_FILEMETA_GVARIANT_STRING "(uuua(ayay))" @@ -145,7 +145,7 @@ typedef enum { * - a(say) - Related objects * - s - subject * - s - body - * - t - Timestamp in seconds since the epoch (UTC) + * - t - Timestamp in seconds since the epoch (UTC, big-endian) * - ay - Root tree contents * - ay - Root tree metadata */ @@ -158,6 +158,17 @@ typedef enum { * - a(s(taya{sv})) - Map of ref name -> (latest commit size, latest commit checksum, additional metadata), sorted by ref name * - a{sv} - Additional metadata, at the current time the following are defined: * - key: "ostree.static-deltas", value: a{sv}, static delta name -> 32 bytes of checksum + * - key: "ostree.summary.last-modified", value: t, timestamp (seconds since + * the Unix epoch in UTC, big-endian) when the summary was last regenerated + * (similar to the HTTP `Last-Modified` header) + * - key: "ostree.summary.expires", value: t, timestamp (seconds since the + * Unix epoch in UTC, big-endian) after which the summary is considered + * stale and should be re-downloaded if possible (similar to the HTTP + * `Expires` header) + * + * The currently defined keys for the `a{sv}` of additional metadata for each commit are: + * - key: `ostree.commit.timestamp`, value: `t`, timestamp (seconds since the + * Unix epoch in UTC, big-endian) when the commit was committed */ #define OSTREE_SUMMARY_GVARIANT_STRING "(a(s(taya{sv}))a{sv})" #define OSTREE_SUMMARY_GVARIANT_FORMAT G_VARIANT_TYPE (OSTREE_SUMMARY_GVARIANT_STRING) diff --git a/src/libostree/ostree-deployment.c b/src/libostree/ostree-deployment.c index 67e896bf..8bdc9b57 100644 --- a/src/libostree/ostree-deployment.c +++ b/src/libostree/ostree-deployment.c @@ -39,6 +39,12 @@ ostree_deployment_get_bootcsum (OstreeDeployment *self) return self->bootcsum; } +/* + * ostree_deployment_get_osname: + * @self: Deployemnt + * + * Returns: The "stateroot" name, also known as an "osname" + */ const char * ostree_deployment_get_osname (OstreeDeployment *self) { diff --git a/src/libostree/ostree-diff.c b/src/libostree/ostree-diff.c index b428fb44..f21b0302 100644 --- a/src/libostree/ostree-diff.c +++ b/src/libostree/ostree-diff.c @@ -35,9 +35,7 @@ get_file_checksum (OstreeDiffFlags flags, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autofree char *ret_checksum = NULL; - g_autofree guchar *csum = NULL; if (OSTREE_IS_REPO_FILE (f)) { @@ -52,27 +50,26 @@ get_file_checksum (OstreeDiffFlags flags, { if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f), &xattrs, cancellable, error)) - goto out; + return FALSE; } if (g_file_info_get_file_type (f_info) == G_FILE_TYPE_REGULAR) { in = (GInputStream*)g_file_read (f, cancellable, error); if (!in) - goto out; + return FALSE; } + g_autofree guchar *csum = NULL; if (!ostree_checksum_file_from_input (f_info, xattrs, in, OSTREE_OBJECT_TYPE_FILE, &csum, cancellable, error)) - goto out; + return FALSE; ret_checksum = ostree_checksum_from_bytes (csum); } - ret = TRUE; ot_transfer_out_value(out_checksum, &ret_checksum); - out: - return ret; + return TRUE; } OstreeDiffItem * @@ -130,28 +127,22 @@ diff_files (OstreeDiffFlags flags, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autofree char *checksum_a = NULL; g_autofree char *checksum_b = NULL; - OstreeDiffItem *ret_item = NULL; - if (!get_file_checksum (flags, a, a_info, &checksum_a, cancellable, error)) - goto out; + return FALSE; if (!get_file_checksum (flags, b, b_info, &checksum_b, cancellable, error)) - goto out; + return FALSE; + g_autoptr(OstreeDiffItem) ret_item = NULL; if (strcmp (checksum_a, checksum_b) != 0) { ret_item = diff_item_new (a, a_info, b, b_info, checksum_a, checksum_b); } - ret = TRUE; ot_transfer_out_value(out_item, &ret_item); - out: - if (ret_item) - ostree_diff_item_unref (ret_item); - return ret; + return TRUE; } static gboolean @@ -160,47 +151,38 @@ diff_add_dir_recurse (GFile *d, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - GError *temp_error = NULL; - g_autoptr(GFileEnumerator) dir_enum = NULL; - g_autoptr(GFile) child = NULL; - g_autoptr(GFileInfo) child_info = NULL; - - dir_enum = g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, - error); + g_autoptr(GFileEnumerator) dir_enum = + g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, + error); if (!dir_enum) - goto out; + return FALSE; - while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL) + while (TRUE) { + GFileInfo *child_info; const char *name; + if (!g_file_enumerator_iterate (dir_enum, &child_info, NULL, + cancellable, error)) + return FALSE; + if (child_info == NULL) + break; + name = g_file_info_get_name (child_info); - g_clear_object (&child); - child = g_file_get_child (d, name); - + g_autoptr(GFile) child = g_file_get_child (d, name); g_ptr_array_add (added, g_object_ref (child)); if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY) { if (!diff_add_dir_recurse (child, added, cancellable, error)) - goto out; + return FALSE; } - - g_clear_object (&child_info); - } - if (temp_error != NULL) - { - g_propagate_error (error, temp_error); - goto out; } - ret = TRUE; - out: - return ret; + return TRUE; } /** diff --git a/src/libostree/ostree-fetcher-curl.c b/src/libostree/ostree-fetcher-curl.c index 829f4447..f6893fd0 100644 --- a/src/libostree/ostree-fetcher-curl.c +++ b/src/libostree/ostree-fetcher-curl.c @@ -272,7 +272,7 @@ ensure_tmpfile (FetcherRequest *req, GError **error) if (req->out_tmpfile_fd == -1) { if (!glnx_open_tmpfile_linkable_at (req->fetcher->tmpdir_dfd, ".", - O_WRONLY, &req->out_tmpfile_fd, + O_WRONLY | O_CLOEXEC, &req->out_tmpfile_fd, &req->out_tmpfile, error)) return FALSE; diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c index eda05e9a..59028821 100644 --- a/src/libostree/ostree-gpg-verifier.c +++ b/src/libostree/ostree-gpg-verifier.c @@ -116,7 +116,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, if (result == NULL) goto out; - if (!ot_gpgme_ctx_tmp_home_dir (result->context, NULL, + if (!ot_gpgme_ctx_tmp_home_dir (result->context, &tmp_dir, &target_stream, cancellable, error)) goto out; diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c index 73fbfeed..cd709b7c 100644 --- a/src/libostree/ostree-gpg-verify-result.c +++ b/src/libostree/ostree-gpg-verify-result.c @@ -562,6 +562,14 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, key_id = (len > 16) ? fingerprint + len - 16 : fingerprint; date_time_utc = g_date_time_new_from_unix_utc (timestamp); + if (date_time_utc == NULL) + { + g_string_append_printf (output_buffer, + "Can't check signature: timestamp %" G_GINT64_FORMAT " is invalid\n", + timestamp); + return; + } + date_time_local = g_date_time_to_local (date_time_utc); formatted_date_time = g_date_time_format (date_time_local, "%c"); @@ -606,6 +614,14 @@ ostree_gpg_verify_result_describe_variant (GVariant *variant, if (exp_timestamp > 0) { date_time_utc = g_date_time_new_from_unix_utc (exp_timestamp); + if (date_time_utc == NULL) + { + g_string_append_printf (output_buffer, + "Signature expiry timestamp (%" G_GINT64_FORMAT ") is invalid\n", + exp_timestamp); + return; + } + date_time_local = g_date_time_to_local (date_time_utc); formatted_date_time = g_date_time_format (date_time_local, "%c"); diff --git a/src/libostree/ostree-impl-system-generator.c b/src/libostree/ostree-impl-system-generator.c new file mode 100644 index 00000000..72f52bc5 --- /dev/null +++ b/src/libostree/ostree-impl-system-generator.c @@ -0,0 +1,229 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * 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. + */ + +#include "config.h" + +#include +#include +#include +#include +#ifdef HAVE_LIBMOUNT +#include +#endif +#include +#include "otutil.h" + +#include "ostree.h" +#include "ostree-core-private.h" +#include "ostree-cmdprivate.h" + +#ifdef HAVE_LIBMOUNT +typedef FILE OtLibMountFile; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtLibMountFile, endmntent); + +/* Taken from systemd path-util.c */ +static bool +is_path (const char *p) +{ + return !!strchr (p, '/'); +} + +/* Taken from systemd path-util.c */ +static char* +path_kill_slashes (char *path) +{ + char *f, *t; + bool slash = false; + + /* Removes redundant inner and trailing slashes. Modifies the + * passed string in-place. + * + * For example: ///foo///bar/ becomes /foo/bar + */ + + for (f = path, t = path; *f; f++) + { + if (*f == '/') + { + slash = true; + continue; + } + + if (slash) + { + slash = false; + *(t++) = '/'; + } + + *(t++) = *f; + } + + /* Special rule, if we are talking of the root directory, a + trailing slash is good */ + + if (t == path && slash) + *(t++) = '/'; + + *t = 0; + return path; +} + +/* Written by ostree-sysroot-deploy.c. We parse out the stateroot here since we + * need to know it to mount /var. Unfortunately we can't easily use the + * libostree API to find the booted deployment since /boot might not have been + * mounted yet. + */ +static char * +stateroot_from_ostree_cmdline (const char *ostree_cmdline, + GError **error) +{ + static GRegex *regex; + static gsize regex_initialized; + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^/ostree/boot.[01]/([^/]+)/", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + g_autoptr(GMatchInfo) match = NULL; + if (!g_regex_match (regex, ostree_cmdline, 0, &match)) + return glnx_null_throw (error, "Failed to parse %s", ostree_cmdline); + + return g_match_info_fetch (match, 1); +} +#endif + +/* Implementation of ostree-system-generator */ +gboolean +_ostree_impl_system_generator (const char *ostree_cmdline, + const char *normal_dir, + const char *early_dir, + const char *late_dir, + GError **error) +{ +#ifdef HAVE_LIBMOUNT + /* Not currently cancellable, but define a var in case we care later */ + GCancellable *cancellable = NULL; + /* Some path constants to avoid typos */ + static const char fstab_path[] = "/etc/fstab"; + static const char var_path[] = "/var"; + + /* ostree-prepare-root was patched to write the stateroot to this file */ + g_autofree char *stateroot = stateroot_from_ostree_cmdline (ostree_cmdline, error); + if (!stateroot) + return FALSE; + + /* Load /etc/fstab if it exists, and look for a /var mount */ + g_autoptr(OtLibMountFile) fstab = setmntent (fstab_path, "re"); + gboolean found_var_mnt = FALSE; + if (!fstab) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "Reading %s", fstab_path); + } + else + { + /* Parse it */ + struct mntent *me; + while ((me = getmntent (fstab))) + { + g_autofree char *where = g_strdup (me->mnt_dir); + if (is_path (where)) + path_kill_slashes (where); + + /* We're only looking for /var here */ + if (strcmp (where, var_path) != 0) + continue; + + found_var_mnt = TRUE; + break; + } + } + + /* If we found /var, we're done */ + if (found_var_mnt) + return TRUE; + + /* Prepare to write to the output unit dir; we use the "normal" dir + * that overrides /usr, but not /etc. + */ + glnx_fd_close int normal_dir_dfd = -1; + if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error)) + return FALSE; + + /* Generate our bind mount unit */ + const char *stateroot_var_path = glnx_strjoina ("/sysroot/ostree/deploy/", stateroot, "/var"); + + glnx_fd_close int tmpfd = -1; + g_autofree char *tmppath = NULL; + if (!glnx_open_tmpfile_linkable_at (normal_dir_dfd, ".", O_WRONLY | O_CLOEXEC, + &tmpfd, &tmppath, error)) + return FALSE; + g_autoptr(GOutputStream) outstream = g_unix_output_stream_new (tmpfd, FALSE); + gsize bytes_written; + /* This code is inspired by systemd's fstab-generator.c. + * + * Note that our unit doesn't run if systemd.volatile is enabled; + * see https://github.com/ostreedev/ostree/pull/856 + */ + if (!g_output_stream_printf (outstream, &bytes_written, cancellable, error, + "##\n# Automatically generated by ostree-system-generator\n##\n\n" + "[Unit]\n" + "Documentation=man:ostree(1)\n" + "ConditionKernelCommandLine=!systemd.volatile\n" + /* We need /sysroot mounted writable first */ + "After=ostree-remount.service\n" + "Before=local-fs.target\n" + "\n" + "[Mount]\n" + "Where=%s\n" + "What=%s\n" + "Options=bind\n", + var_path, + stateroot_var_path)) + return FALSE; + if (!g_output_stream_flush (outstream, cancellable, error)) + return FALSE; + g_clear_object (&outstream); + /* It should be readable */ + if (fchmod (tmpfd, 0644) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + /* Error out if somehow it already exists, that'll help us debug conflicts */ + if (!glnx_link_tmpfile_at (normal_dir_dfd, GLNX_LINK_TMPFILE_NOREPLACE, + tmpfd, tmppath, normal_dir_dfd, + "var.mount", error)) + return FALSE; + + /* And ensure it's required; newer systemd will auto-inject fs dependencies + * via RequiresMountsFor and the like, but on older versions (e.g. CentOS) we + * need this. It's what the fstab generator does. And my mother always said, + * listen to the fstab generator. + */ + if (!glnx_shutil_mkdir_p_at (normal_dir_dfd, "local-fs.target.requires", 0755, cancellable, error)) + return FALSE; + if (symlinkat ("../var.mount", normal_dir_dfd, "local-fs.target.requires/var.mount") < 0) + return glnx_throw_errno_prefix (error, "symlinkat"); + + return TRUE; +#else + return glnx_throw (error, "Not implemented"); +#endif +} diff --git a/src/libostree/ostree-remote-private.h b/src/libostree/ostree-remote-private.h new file mode 100644 index 00000000..e207ed4c --- /dev/null +++ b/src/libostree/ostree-remote-private.h @@ -0,0 +1,59 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2011 Colin Walters + * Copyright © 2015 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Colin Walters + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "libglnx.h" +#include "ostree-remote.h" +#include "ostree-types.h" + +G_BEGIN_DECLS + +struct OstreeRemote { + volatile int ref_count; + char *name; + char *group; /* group name in options */ + char *keyring; /* keyring name (NAME.trustedkeys.gpg) */ + GFile *file; /* NULL if remote defined in repo/config */ + GKeyFile *options; +}; + +G_GNUC_INTERNAL +OstreeRemote *ostree_remote_new (void); + +G_GNUC_INTERNAL +OstreeRemote *ostree_remote_new_from_keyfile (GKeyFile *keyfile, + const gchar *group); + +#if (defined(OSTREE_COMPILATION) || GLIB_CHECK_VERSION(2, 44, 0)) && !defined(OSTREE_ENABLE_EXPERIMENTAL_API) +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeRemote, ostree_remote_unref) +#endif + +G_END_DECLS diff --git a/src/libostree/ostree-remote.c b/src/libostree/ostree-remote.c new file mode 100644 index 00000000..86fae8d8 --- /dev/null +++ b/src/libostree/ostree-remote.c @@ -0,0 +1,150 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2011 Colin Walters + * Copyright © 2015 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Colin Walters + * - Philip Withnall + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-remote.h" +#include "ostree-remote-private.h" +#include "ot-keyfile-utils.h" + +/** + * SECTION:remote + * + * The #OstreeRemote structure represents the configuration for a single remote + * repository. Currently, all configuration is handled internally, and + * #OstreeRemote objects are represented by their textual name handle, or by an + * opaque pointer (which can be reference counted if needed). + * + * #OstreeRemote provides configuration for accessing a remote, but does not + * provide the results of accessing a remote, such as information about what + * refs are currently on a remote, or the commits they currently point to. Use + * #OstreeRepo in combination with an #OstreeRemote to query that information. + * + * Since: 2017.6 + */ + +OstreeRemote * +ostree_remote_new (void) +{ + OstreeRemote *remote; + + remote = g_slice_new0 (OstreeRemote); + remote->ref_count = 1; + remote->options = g_key_file_new (); + + return remote; +} + +OstreeRemote * +ostree_remote_new_from_keyfile (GKeyFile *keyfile, + const gchar *group) +{ + g_autoptr(GMatchInfo) match = NULL; + OstreeRemote *remote; + + static gsize regex_initialized; + static GRegex *regex; + + if (g_once_init_enter (®ex_initialized)) + { + regex = g_regex_new ("^remote \"(.+)\"$", 0, 0, NULL); + g_assert (regex); + g_once_init_leave (®ex_initialized, 1); + } + + /* Sanity check */ + g_return_val_if_fail (g_key_file_has_group (keyfile, group), NULL); + + /* If group name doesn't fit the pattern, fail. */ + if (!g_regex_match (regex, group, 0, &match)) + return NULL; + + remote = ostree_remote_new (); + remote->name = g_match_info_fetch (match, 1); + remote->group = g_strdup (group); + remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", remote->name); + + ot_keyfile_copy_group (keyfile, remote->options, group); + + return remote; +} + +/** + * ostree_remote_ref: + * @remote: an #OstreeRemote + * + * Increase the reference count on the given @remote. + * + * Returns: (transfer full): a copy of @remote, for convenience + * Since: 2017.6 + */ +OstreeRemote * +ostree_remote_ref (OstreeRemote *remote) +{ + gint refcount; + g_return_val_if_fail (remote != NULL, NULL); + refcount = g_atomic_int_add (&remote->ref_count, 1); + g_assert (refcount > 0); + return remote; +} + +/** + * ostree_remote_unref: + * @remote: (transfer full): an #OstreeRemote + * + * Decrease the reference count on the given @remote and free it if the + * reference count reaches 0. + * + * Since: 2017.6 + */ +void +ostree_remote_unref (OstreeRemote *remote) +{ + g_return_if_fail (remote != NULL); + g_return_if_fail (remote->ref_count > 0); + + if (g_atomic_int_dec_and_test (&remote->ref_count)) + { + g_clear_pointer (&remote->name, g_free); + g_clear_pointer (&remote->group, g_free); + g_clear_pointer (&remote->keyring, g_free); + g_clear_object (&remote->file); + g_clear_pointer (&remote->options, g_key_file_free); + g_slice_free (OstreeRemote, remote); + } +} + +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +G_DEFINE_BOXED_TYPE(OstreeRemote, ostree_remote, + ostree_remote_ref, + ostree_remote_unref); +#endif diff --git a/src/libostree/ostree-remote.h b/src/libostree/ostree-remote.h new file mode 100644 index 00000000..8e96213c --- /dev/null +++ b/src/libostree/ostree-remote.h @@ -0,0 +1,63 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright © 2011 Colin Walters + * Copyright © 2015 Red Hat, Inc. + * Copyright © 2017 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: + * - Colin Walters + * - Philip Withnall + */ + +#pragma once + +#include +#include +#include + +#include "ostree-types.h" + +G_BEGIN_DECLS + +/** + * OstreeRemote: + * + * This represents the configuration for a single remote repository. Currently, + * remotes can only be passed around as (reference counted) opaque handles. In + * future, more API may be added to create and interrogate them. + * + * Since: 2016.7 + */ +#ifndef OSTREE_ENABLE_EXPERIMENTAL_API +/* This is in ostree-types.h otherwise */ +typedef struct OstreeRemote OstreeRemote; +#endif + +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +_OSTREE_PUBLIC +GType ostree_remote_get_type (void) G_GNUC_CONST; +#else +#ifndef __GI_SCANNER__ +_OSTREE_PUBLIC +OstreeRemote *ostree_remote_ref (OstreeRemote *remote); +_OSTREE_PUBLIC +void ostree_remote_unref (OstreeRemote *remote); +#endif /* GI_SCANNER */ +#endif + +G_END_DECLS diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 71511824..f6e91498 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -29,11 +29,25 @@ #include "otutil.h" #include "ostree-repo-file.h" +#include "ostree-sepolicy-private.h" #include "ostree-core-private.h" #include "ostree-repo-private.h" #define WHITEOUT_PREFIX ".wh." +/* Per-checkout call state/caching */ +typedef struct { + GString *selabel_path_buf; +} CheckoutState; + +static void +checkout_state_clear (CheckoutState *state) +{ + if (state->selabel_path_buf) + g_string_free (state->selabel_path_buf, TRUE); +} +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(CheckoutState, checkout_state_clear); + static gboolean checkout_object_for_uncompressed_cache (OstreeRepo *self, const char *loose_path, @@ -42,64 +56,48 @@ checkout_object_for_uncompressed_cache (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autofree char *temp_filename = NULL; - g_autoptr(GOutputStream) temp_out = NULL; - glnx_fd_close int fd = -1; - int res; - guint32 file_mode; - /* Don't make setuid files in uncompressed cache */ - file_mode = g_file_info_get_attribute_uint32 (src_info, "unix::mode"); + guint32 file_mode = g_file_info_get_attribute_uint32 (src_info, "unix::mode"); file_mode &= ~(S_ISUID|S_ISGID); + glnx_fd_close int fd = -1; + g_autofree char *temp_filename = NULL; if (!glnx_open_tmpfile_linkable_at (self->tmp_dir_fd, ".", O_WRONLY | O_CLOEXEC, &fd, &temp_filename, error)) - goto out; - temp_out = g_unix_output_stream_new (fd, FALSE); + return FALSE; + g_autoptr(GOutputStream) temp_out = g_unix_output_stream_new (fd, FALSE); if (g_output_stream_splice (temp_out, content, 0, cancellable, error) < 0) - goto out; + return FALSE; if (!g_output_stream_flush (temp_out, cancellable, error)) - goto out; + return FALSE; if (!self->disable_fsync) { - do - res = fsync (fd); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } + if (TEMP_FAILURE_RETRY (fsync (fd)) < 0) + return glnx_throw_errno (error); } if (!g_output_stream_close (temp_out, cancellable, error)) - goto out; + return FALSE; if (fchmod (fd, file_mode) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); if (!_ostree_repo_ensure_loose_objdir_at (self->uncompressed_objects_dir_fd, loose_path, cancellable, error)) - goto out; + return FALSE; if (!glnx_link_tmpfile_at (self->tmp_dir_fd, GLNX_LINK_TMPFILE_NOREPLACE_IGNORE_EXIST, fd, temp_filename, self->uncompressed_objects_dir_fd, loose_path, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -112,209 +110,151 @@ fsync_is_enabled (OstreeRepo *self, static gboolean write_regular_file_content (OstreeRepo *self, OstreeRepoCheckoutAtOptions *options, - GOutputStream *output, + int outfd, GFileInfo *file_info, GVariant *xattrs, GInputStream *input, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; const OstreeRepoCheckoutMode mode = options->mode; - int fd; - int res; + g_autoptr(GOutputStream) outstream = NULL; - if (g_output_stream_splice (output, input, 0, - cancellable, error) < 0) - goto out; + if (G_IS_FILE_DESCRIPTOR_BASED (input)) + { + int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input); + guint64 len = g_file_info_get_size (file_info); - if (!g_output_stream_flush (output, cancellable, error)) - goto out; + if (glnx_regfile_copy_bytes (infd, outfd, (off_t)len, TRUE) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); + } + else + { + outstream = g_unix_output_stream_new (outfd, FALSE); + if (g_output_stream_splice (outstream, input, 0, + cancellable, error) < 0) + return FALSE; - fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)output); + if (!g_output_stream_flush (outstream, cancellable, error)) + return FALSE; + } if (mode != OSTREE_REPO_CHECKOUT_MODE_USER) { - do - res = fchown (fd, - g_file_info_get_attribute_uint32 (file_info, "unix::uid"), - g_file_info_get_attribute_uint32 (file_info, "unix::gid")); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } + if (TEMP_FAILURE_RETRY (fchown (outfd, g_file_info_get_attribute_uint32 (file_info, "unix::uid"), + g_file_info_get_attribute_uint32 (file_info, "unix::gid"))) < 0) + return glnx_throw_errno (error); + + if (TEMP_FAILURE_RETRY (fchmod (outfd, g_file_info_get_attribute_uint32 (file_info, "unix::mode"))) < 0) + return glnx_throw_errno (error); - do - res = fchmod (fd, g_file_info_get_attribute_uint32 (file_info, "unix::mode")); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } - if (xattrs) { - if (!glnx_fd_set_all_xattrs (fd, xattrs, cancellable, error)) - goto out; + if (!glnx_fd_set_all_xattrs (outfd, xattrs, cancellable, error)) + return FALSE; } } - + if (fsync_is_enabled (self, options)) { - if (fsync (fd) == -1) - { - glnx_set_error_from_errno (error); - goto out; - } + if (fsync (outfd) == -1) + return glnx_throw_errno (error); } - - if (!g_output_stream_close (output, cancellable, error)) - goto out; - ret = TRUE; - out: - return ret; -} - -static gboolean -checkout_file_from_input_at (OstreeRepo *self, - OstreeRepoCheckoutAtOptions *options, - GFileInfo *file_info, - GVariant *xattrs, - GInputStream *input, - int destination_dfd, - const char *destination_name, - GCancellable *cancellable, - GError **error) -{ - gboolean ret = FALSE; - int res; - - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) + if (outstream) { - do - res = symlinkat (g_file_info_get_symlink_target (file_info), - destination_dfd, destination_name); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) - { - if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES) - { - ret = TRUE; - goto out; - } - else - { - glnx_set_error_from_errno (error); - goto out; - } - } - - if (options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) - { - if (G_UNLIKELY (fchownat (destination_dfd, destination_name, - g_file_info_get_attribute_uint32 (file_info, "unix::uid"), - g_file_info_get_attribute_uint32 (file_info, "unix::gid"), - AT_SYMLINK_NOFOLLOW) == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } - - if (xattrs) - { - if (!glnx_dfd_name_set_all_xattrs (destination_dfd, destination_name, - xattrs, cancellable, error)) - goto out; - } - } + if (!g_output_stream_close (outstream, cancellable, error)) + return FALSE; } - else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) - { - g_autoptr(GOutputStream) temp_out = NULL; - int fd; - guint32 file_mode; - file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); - /* Don't make setuid files on checkout when we're doing --user */ - if (options->mode == OSTREE_REPO_CHECKOUT_MODE_USER) - file_mode &= ~(S_ISUID|S_ISGID); - - do - fd = openat (destination_dfd, destination_name, O_WRONLY | O_CREAT | O_EXCL, file_mode); - while (G_UNLIKELY (fd == -1 && errno == EINTR)); - if (fd == -1) - { - if (errno == EEXIST && options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_ADD_FILES) - { - ret = TRUE; - goto out; - } - glnx_set_error_from_errno (error); - goto out; - } - temp_out = g_unix_output_stream_new (fd, TRUE); - fd = -1; /* Transfer ownership */ - - if (!write_regular_file_content (self, options, temp_out, file_info, xattrs, input, - cancellable, error)) - goto out; - } - else - g_assert_not_reached (); - - ret = TRUE; - out: - return ret; + return TRUE; } /* - * This function creates a file under a temporary name, then rename()s - * it into place. This implements union-like behavior. + * Create a copy of a file, supporting optional union/add behavior. */ static gboolean -checkout_file_unioning_from_input_at (OstreeRepo *repo, - OstreeRepoCheckoutAtOptions *options, - GFileInfo *file_info, - GVariant *xattrs, - GInputStream *input, - int destination_dfd, - const char *destination_name, - GCancellable *cancellable, - GError **error) +create_file_copy_from_input_at (OstreeRepo *repo, + OstreeRepoCheckoutAtOptions *options, + CheckoutState *state, + GFileInfo *file_info, + GVariant *xattrs, + GInputStream *input, + int destination_dfd, + const char *destination_name, + GCancellable *cancellable, + GError **error) { - gboolean ret = FALSE; g_autofree char *temp_filename = NULL; + 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; + + /* If we're doing SELinux labeling, prepare it */ + if (sepolicy_enabled) + { + /* If doing sepolicy path-based labeling, we don't want to set the + * security.selinux attr via the generic xattr paths in either the symlink + * or regfile cases, so filter it out. + */ + modified_xattrs = _ostree_filter_selinux_xattr (xattrs); + xattrs = modified_xattrs; + } if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_SYMBOLIC_LINK) { - if (!_ostree_make_temporary_symlink_at (destination_dfd, - g_file_info_get_symlink_target (file_info), - &temp_filename, - cancellable, error)) - goto out; - - if (xattrs) + g_auto(OstreeSepolicyFsCreatecon) fscreatecon = { 0, }; + + if (sepolicy_enabled) { - if (!glnx_dfd_name_set_all_xattrs (destination_dfd, temp_filename, - xattrs, cancellable, error)) - goto out; + /* For symlinks, since we don't have O_TMPFILE, we use setfscreatecon() */ + if (!_ostree_sepolicy_preparefscreatecon (&fscreatecon, options->sepolicy, + state->selabel_path_buf->str, + g_file_info_get_attribute_uint32 (file_info, "unix::mode"), + error)) + return FALSE; } - if (G_UNLIKELY (renameat (destination_dfd, temp_filename, - destination_dfd, destination_name) == -1)) + + if (symlinkat (g_file_info_get_symlink_target (file_info), + destination_dfd, destination_name) < 0) { - glnx_set_error_from_errno (error); - goto out; + /* Handle union/add behaviors if we get EEXIST */ + if (errno == EEXIST && union_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); + } + 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 */ + if (options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) + { + if (TEMP_FAILURE_RETRY (fchownat (destination_dfd, destination_name, + g_file_info_get_attribute_uint32 (file_info, "unix::uid"), + g_file_info_get_attribute_uint32 (file_info, "unix::gid"), + AT_SYMLINK_NOFOLLOW)) == -1) + return glnx_throw_errno_prefix (error, "fchownat"); + + if (xattrs != NULL && + !glnx_dfd_name_set_all_xattrs (destination_dfd, destination_name, + xattrs, cancellable, error)) + return FALSE; } } else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { glnx_fd_close int temp_fd = -1; - g_autoptr(GOutputStream) temp_out = NULL; guint32 file_mode; + GLnxLinkTmpfileReplaceMode replace_mode; file_mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); /* Don't make setuid files on checkout when we're doing --user */ @@ -324,25 +264,42 @@ checkout_file_unioning_from_input_at (OstreeRepo *repo, if (!glnx_open_tmpfile_linkable_at (destination_dfd, ".", O_WRONLY | O_CLOEXEC, &temp_fd, &temp_filename, error)) - goto out; - temp_out = g_unix_output_stream_new (temp_fd, FALSE); + return FALSE; - if (!write_regular_file_content (repo, options, temp_out, file_info, xattrs, input, + if (sepolicy_enabled) + { + g_autofree char *label = NULL; + if (!ostree_sepolicy_get_label (options->sepolicy, + state->selabel_path_buf->str, + g_file_info_get_attribute_uint32 (file_info, "unix::mode"), + &label, cancellable, error)) + return FALSE; + if (fsetxattr (temp_fd, "security.selinux", label, strlen (label), 0) < 0) + return glnx_throw_errno_prefix (error, "Setting security.selinux"); + } + + if (!write_regular_file_content (repo, options, temp_fd, file_info, xattrs, input, cancellable, error)) - goto out; + return FALSE; - if (!glnx_link_tmpfile_at (destination_dfd, GLNX_LINK_TMPFILE_REPLACE, + /* 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; + + if (!glnx_link_tmpfile_at (destination_dfd, replace_mode, temp_fd, temp_filename, destination_dfd, destination_name, error)) - goto out; + return FALSE; } else g_assert_not_reached (); - ret = TRUE; - out: - return ret; + return TRUE; } typedef enum { @@ -386,7 +343,7 @@ checkout_file_hardlink (OstreeRepo *self, 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 @@ -400,9 +357,7 @@ checkout_file_hardlink (OstreeRepo *self, } else { - g_prefix_error (error, "Hardlinking %s to %s: ", loose_path, destination_name); - glnx_set_error_from_errno (error); - return FALSE; + return glnx_throw_errno_prefix (error, "Hardlinking %s to %s", loose_path, destination_name); } if (out_result) @@ -413,29 +368,26 @@ checkout_file_hardlink (OstreeRepo *self, static gboolean checkout_one_file_at (OstreeRepo *repo, OstreeRepoCheckoutAtOptions *options, - GFile *source, - GFileInfo *source_info, + CheckoutState *state, + const char *checksum, int destination_dfd, const char *destination_name, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *checksum; - gboolean is_symlink; - gboolean is_bare_user_symlink = FALSE; - gboolean can_cache; gboolean need_copy = TRUE; + gboolean is_bare_user_symlink = FALSE; char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; - g_autoptr(GInputStream) input = NULL; - g_autoptr(GVariant) xattrs = NULL; - gboolean is_whiteout; - is_symlink = g_file_info_get_file_type (source_info) == G_FILE_TYPE_SYMBOLIC_LINK; - checksum = ostree_repo_file_get_checksum ((OstreeRepoFile*)source); + /* FIXME - avoid the GFileInfo here */ + g_autoptr(GFileInfo) source_info = NULL; + if (!ostree_repo_load_file (repo, checksum, NULL, &source_info, NULL, + cancellable, error)) + return FALSE; - is_whiteout = !is_symlink && options->process_whiteouts && - g_str_has_prefix (destination_name, WHITEOUT_PREFIX); + const gboolean is_symlink = (g_file_info_get_file_type (source_info) == G_FILE_TYPE_SYMBOLIC_LINK); + const gboolean is_whiteout = (!is_symlink && options->process_whiteouts && + g_str_has_prefix (destination_name, WHITEOUT_PREFIX)); /* First, see if it's a Docker whiteout, * https://github.com/docker/docker/blob/1a714e76a2cb9008cd19609059e9988ff1660b78/pkg/archive/whiteouts.go @@ -445,20 +397,16 @@ checkout_one_file_at (OstreeRepo *repo, const char *name = destination_name + (sizeof (WHITEOUT_PREFIX) - 1); if (!name[0]) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid empty whiteout '%s'", name); - goto out; - } + return glnx_throw (error, "Invalid empty whiteout '%s'", name); g_assert (name[0] != '/'); /* Sanity */ if (!glnx_shutil_rm_rf_at (destination_dfd, name, cancellable, error)) - goto out; + return FALSE; need_copy = FALSE; } - else + else if (!options->force_copy) { HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED; /* Try to do a hardlink first, if it's a regular file. This also @@ -496,13 +444,10 @@ checkout_one_file_at (OstreeRepo *repo, * special exception for bare-user symlinks. */ if (options->no_copy_fallback && !is_hardlinkable && !is_bare_user_symlink) - { - glnx_throw (error, - repo_is_usermode ? - "User repository mode requires user checkout mode to hardlink" : - "Bare repository mode cannot hardlink in user checkout mode"); - goto out; - } + return glnx_throw (error, + repo_is_usermode ? + "User repository mode requires user checkout mode to hardlink" : + "Bare repository mode cannot hardlink in user checkout mode"); /* But only under these conditions */ if (is_bare || is_archive_z2_with_cache) @@ -516,24 +461,21 @@ checkout_one_file_at (OstreeRepo *repo, destination_dfd, destination_name, TRUE, &hardlink_res, cancellable, error)) - goto out; + return FALSE; if (hardlink_res == HARDLINK_RESULT_LINKED && options->devino_to_csum_cache) { struct stat stbuf; OstreeDevIno *key; - + if (TEMP_FAILURE_RETRY (fstatat (destination_dfd, destination_name, &stbuf, AT_SYMLINK_NOFOLLOW)) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } - + return glnx_throw_errno (error); + key = g_new (OstreeDevIno, 1); key->dev = stbuf.st_dev; key->ino = stbuf.st_ino; memcpy (key->checksum, checksum, OSTREE_SHA256_STRING_LEN+1); - + g_hash_table_add ((GHashTable*)options->devino_to_csum_cache, key); } @@ -546,8 +488,11 @@ checkout_one_file_at (OstreeRepo *repo, need_copy = (hardlink_res == HARDLINK_RESULT_NOT_SUPPORTED); } - can_cache = (options->enable_uncompressed_cache - && repo->enable_uncompressed_cache); + const gboolean can_cache = (options->enable_uncompressed_cache + && repo->enable_uncompressed_cache); + + g_autoptr(GInputStream) input = NULL; + g_autoptr(GVariant) xattrs = NULL; /* Ok, if we're archive-z2 and we didn't find an object, uncompress * it now, stick it in the cache, and then hardlink to that. @@ -560,10 +505,10 @@ checkout_one_file_at (OstreeRepo *repo, && options->mode == OSTREE_REPO_CHECKOUT_MODE_USER) { HardlinkResult hardlink_res = HARDLINK_RESULT_NOT_SUPPORTED; - + if (!ostree_repo_load_file (repo, checksum, &input, NULL, NULL, cancellable, error)) - goto out; + return FALSE; /* Overwrite any parent repo from earlier */ _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, OSTREE_REPO_MODE_BARE); @@ -571,11 +516,8 @@ checkout_one_file_at (OstreeRepo *repo, if (!checkout_object_for_uncompressed_cache (repo, loose_path_buf, source_info, input, cancellable, error)) - { - g_prefix_error (error, "Unpacking loose object %s: ", checksum); - goto out; - } - + return glnx_prefix_error (error, "Unpacking loose object %s", checksum); + g_clear_object (&input); /* Store the 2-byte objdir prefix (e.g. e3) in a set. The basic @@ -607,10 +549,7 @@ checkout_one_file_at (OstreeRepo *repo, destination_dfd, destination_name, FALSE, &hardlink_res, cancellable, error)) - { - g_prefix_error (error, "Using new cached uncompressed hardlink of %s to %s: ", checksum, destination_name); - goto out; - } + return glnx_prefix_error (error, "Using new cached uncompressed hardlink of %s to %s", checksum, destination_name); need_copy = (hardlink_res == HARDLINK_RESULT_NOT_SUPPORTED); } @@ -627,47 +566,28 @@ checkout_one_file_at (OstreeRepo *repo, g_assert (is_bare_user_symlink); if (!ostree_repo_load_file (repo, checksum, &input, NULL, &xattrs, cancellable, error)) - goto out; + return FALSE; - if (options->overwrite_mode == OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES) - { - if (!checkout_file_unioning_from_input_at (repo, options, source_info, xattrs, input, - destination_dfd, - destination_name, - cancellable, error)) - { - g_prefix_error (error, "Union checkout of %s to %s: ", checksum, destination_name); - goto out; - } - } - else - { - if (!checkout_file_from_input_at (repo, options, source_info, xattrs, input, - destination_dfd, - destination_name, - cancellable, error)) - { - g_prefix_error (error, "Checkout of %s to %s: ", checksum, destination_name); - goto out; - } - } + if (!create_file_copy_from_input_at (repo, options, state, source_info, xattrs, input, + destination_dfd, destination_name, + cancellable, error)) + return glnx_prefix_error (error, "Copy checkout of %s to %s", checksum, destination_name); if (input) { if (!g_input_stream_close (input, cancellable, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; + return TRUE; } /* * checkout_tree_at: * @self: Repo * @mode: Options controlling all files + * @state: Any state we're carrying through * @overwrite_mode: Whether or not to overwrite files * @destination_parent_fd: Place tree here * @destination_name: Use this name for tree @@ -680,6 +600,192 @@ checkout_one_file_at (OstreeRepo *repo, * relative @destination_name, located by @destination_parent_fd. */ static gboolean +checkout_tree_at_recurse (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options, + CheckoutState *state, + int destination_parent_fd, + const char *destination_name, + const char *dirtree_checksum, + const char *dirmeta_checksum, + GCancellable *cancellable, + GError **error) +{ + gboolean did_exist = FALSE; + const gboolean sepolicy_enabled = options->sepolicy && !self->disable_xattrs; + g_autoptr(GVariant) dirtree = NULL; + g_autoptr(GVariant) dirmeta = NULL; + g_autoptr(GVariant) xattrs = NULL; + g_autoptr(GVariant) modified_xattrs = NULL; + + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_DIR_TREE, + dirtree_checksum, &dirtree, error)) + return FALSE; + if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_DIR_META, + dirmeta_checksum, &dirmeta, error)) + return FALSE; + + /* Parse OSTREE_OBJECT_TYPE_DIR_META */ + guint32 uid, gid, mode; + g_variant_get (dirmeta, "(uuu@a(ayay))", + &uid, &gid, &mode, + options->mode != OSTREE_REPO_CHECKOUT_MODE_USER ? &xattrs : NULL); + uid = GUINT32_FROM_BE (uid); + gid = GUINT32_FROM_BE (gid); + mode = GUINT32_FROM_BE (mode); + + /* First, make the directory. Push a new scope in case we end up using + * setfscreatecon(). + */ + { + g_auto(OstreeSepolicyFsCreatecon) fscreatecon = { 0, }; + + /* If we're doing SELinux labeling, prepare it */ + if (sepolicy_enabled) + { + /* We'll set the xattr via setfscreatecon(), so don't do it via generic xattrs below. */ + modified_xattrs = _ostree_filter_selinux_xattr (xattrs); + xattrs = modified_xattrs; + + if (!_ostree_sepolicy_preparefscreatecon (&fscreatecon, options->sepolicy, + state->selabel_path_buf->str, + mode, error)) + return FALSE; + } + + /* Create initially with mode 0700, then chown/chmod only when we're + * done. This avoids anyone else being able to operate on partially + * constructed dirs. + */ + 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); + } + } + + glnx_fd_close int destination_dfd = -1; + if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE, + &destination_dfd, error)) + return FALSE; + + struct stat repo_dfd_stat; + if (fstat (self->repo_dir_fd, &repo_dfd_stat) < 0) + return glnx_throw_errno (error); + struct stat destination_stat; + if (fstat (destination_dfd, &destination_stat) < 0) + return glnx_throw_errno (error); + + if (options->no_copy_fallback && repo_dfd_stat.st_dev != destination_stat.st_dev) + return glnx_throw (error, "Unable to do hardlink checkout across devices (src=%"G_GUINT64_FORMAT" destination=%"G_GUINT64_FORMAT")", + (guint64)repo_dfd_stat.st_dev, (guint64)destination_stat.st_dev); + + /* Set the xattrs if we created the dir */ + if (!did_exist && xattrs) + { + if (!glnx_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error)) + return FALSE; + } + + GString *selabel_path_buf = state->selabel_path_buf; + /* Process files in this subdir */ + { g_autoptr(GVariant) dir_file_contents = g_variant_get_child_value (dirtree, 0); + GVariantIter viter; + g_variant_iter_init (&viter, dir_file_contents); + const char *fname; + g_autoptr(GVariant) contents_csum_v = NULL; + while (g_variant_iter_loop (&viter, "(&s@ay)", &fname, &contents_csum_v)) + { + const size_t namelen = strlen (fname); + if (selabel_path_buf) + g_string_append_len (selabel_path_buf, fname, namelen); + + char tmp_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (contents_csum_v, tmp_checksum); + + if (!checkout_one_file_at (self, options, state, + tmp_checksum, + destination_dfd, fname, + cancellable, error)) + return FALSE; + + if (selabel_path_buf) + g_string_truncate (selabel_path_buf, selabel_path_buf->len - namelen); + } + contents_csum_v = NULL; /* iter_loop freed it */ + } + + /* Process subdirectories */ + { g_autoptr(GVariant) dir_subdirs = g_variant_get_child_value (dirtree, 1); + const char *dname; + g_autoptr(GVariant) subdirtree_csum_v = NULL; + g_autoptr(GVariant) subdirmeta_csum_v = NULL; + GVariantIter viter; + g_variant_iter_init (&viter, dir_subdirs); + while (g_variant_iter_loop (&viter, "(&s@ay@ay)", &dname, + &subdirtree_csum_v, &subdirmeta_csum_v)) + { + const size_t namelen = strlen (dname); + if (selabel_path_buf) + { + g_string_append_len (selabel_path_buf, dname, namelen); + g_string_append_c (selabel_path_buf, '/'); + } + + char subdirtree_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (subdirtree_csum_v, subdirtree_checksum); + char subdirmeta_checksum[OSTREE_SHA256_STRING_LEN+1]; + _ostree_checksum_inplace_from_bytes_v (subdirmeta_csum_v, subdirmeta_checksum); + if (!checkout_tree_at_recurse (self, options, state, + destination_dfd, dname, + subdirtree_checksum, subdirmeta_checksum, + cancellable, error)) + return FALSE; + + if (selabel_path_buf) + g_string_truncate (selabel_path_buf, selabel_path_buf->len - namelen); + } + } + + /* We do fchmod/fchown last so that no one else could access the + * partially created directory and change content we're laying out. + */ + if (!did_exist) + { + if (TEMP_FAILURE_RETRY (fchmod (destination_dfd, mode)) < 0) + return glnx_throw_errno (error); + } + + if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) + { + if (TEMP_FAILURE_RETRY (fchown (destination_dfd, uid, gid)) < 0) + return glnx_throw_errno (error); + } + + /* Set directory mtime to OSTREE_TIMESTAMP, so that it is constant for all checkouts. + * Must be done after setting permissions and creating all children. + */ + if (!did_exist) + { + const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} }; + if (TEMP_FAILURE_RETRY (futimens (destination_dfd, times)) < 0) + return glnx_throw_errno (error); + } + + if (fsync_is_enabled (self, options)) + { + if (fsync (destination_dfd) == -1) + return glnx_throw_errno (error); + } + + return TRUE; +} + +/* Begin a checkout process */ +static gboolean checkout_tree_at (OstreeRepo *self, OstreeRepoCheckoutAtOptions *options, int destination_parent_fd, @@ -689,179 +795,75 @@ checkout_tree_at (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - gboolean did_exist = FALSE; - glnx_fd_close int destination_dfd = -1; - int res; - struct stat repo_dfd_stat; - struct stat destination_stat; - g_autoptr(GVariant) xattrs = NULL; - g_autoptr(GFileEnumerator) dir_enum = NULL; - - /* Create initially with mode 0700, then chown/chmod only when we're - * done. This avoids anyone else being able to operate on partially - * constructed dirs. - */ - do - res = mkdirat (destination_parent_fd, destination_name, 0700); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) + g_auto(CheckoutState) state = { 0, }; + // If SELinux labeling is enabled, we need to keep track of the full path string + if (options->sepolicy) { - 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 - { - glnx_set_error_from_errno (error); - goto out; - } - } - - if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE, - &destination_dfd, error)) - goto out; - - if (fstat (self->repo_dir_fd, &repo_dfd_stat) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } - if (fstat (destination_dfd, &destination_stat) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } - - if (options->no_copy_fallback && repo_dfd_stat.st_dev != destination_stat.st_dev) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Unable to do hardlink checkout across devices (src=%"G_GUINT64_FORMAT" destination=%"G_GUINT64_FORMAT")", - (guint64)repo_dfd_stat.st_dev, (guint64)destination_stat.st_dev); - goto out; - } - - /* Set the xattrs now, so any derived labeling works */ - if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) - { - if (!ostree_repo_file_get_xattrs (source, &xattrs, NULL, error)) - goto out; - - if (xattrs) - { - if (!glnx_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error)) - goto out; - } + GString *buf = g_string_new (options->sepolicy_prefix ?: options->subpath); + g_assert_cmpint (buf->len, >, 0); + // Ensure it ends with / + if (buf->str[buf->len-1] != '/') + g_string_append_c (buf, '/'); + state.selabel_path_buf = buf; + + /* Otherwise it'd just be corrupting things, and there's no use case */ + g_assert (options->force_copy); } + /* Special case handling for subpath of a non-directory */ if (g_file_info_get_file_type (source_info) != G_FILE_TYPE_DIRECTORY) { - ret = checkout_one_file_at (self, options, - (GFile *) source, - source_info, - destination_dfd, - g_file_info_get_name (source_info), - cancellable, error); - goto out; - } - dir_enum = g_file_enumerate_children ((GFile*)source, - OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, - error); - if (!dir_enum) - goto out; - - while (TRUE) - { - GFileInfo *file_info; - GFile *src_child; - const char *name; - - if (!g_file_enumerator_iterate (dir_enum, &file_info, &src_child, - cancellable, error)) - goto out; - if (file_info == NULL) - break; - - name = g_file_info_get_name (file_info); - - if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) + /* For backwards compat reasons, we do a mkdir() here. However, as a + * special case to allow callers to directly check out files without an + * intermediate root directory, we will skip mkdirat() if + * `destination_name` == `.`, since obviously the current directory + * exists. + */ + int destination_dfd = destination_parent_fd; + glnx_fd_close int destination_dfd_owned = -1; + if (strcmp (destination_name, ".") != 0) { - if (!checkout_tree_at (self, options, - destination_dfd, name, - (OstreeRepoFile*)src_child, file_info, - cancellable, error)) - goto out; - } - else - { - if (!checkout_one_file_at (self, options, - src_child, file_info, - destination_dfd, name, - cancellable, error)) - goto out; + if (mkdirat (destination_parent_fd, destination_name, 0700) < 0 + && errno != EEXIST) + return glnx_throw_errno_prefix (error, "mkdirat"); + if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE, + &destination_dfd_owned, error)) + return FALSE; + destination_dfd = destination_dfd_owned; } + return checkout_one_file_at (self, options, &state, + ostree_repo_file_get_checksum (source), + destination_dfd, + g_file_info_get_name (source_info), + cancellable, error); } - /* We do fchmod/fchown last so that no one else could access the - * partially created directory and change content we're laying out. + /* Cache any directory metadata we read during this operation; + * see commit b7afe91e21143d7abb0adde440683a52712aa246 */ - if (!did_exist) - { - do - res = fchmod (destination_dfd, - g_file_info_get_attribute_uint32 (source_info, "unix::mode")); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } - } + g_auto(OstreeRepoMemoryCacheRef) memcache_ref; + _ostree_repo_memory_cache_ref_init (&memcache_ref, self); - if (!did_exist && options->mode != OSTREE_REPO_CHECKOUT_MODE_USER) - { - do - res = fchown (destination_dfd, - g_file_info_get_attribute_uint32 (source_info, "unix::uid"), - g_file_info_get_attribute_uint32 (source_info, "unix::gid")); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } - } + g_assert_cmpint (g_file_info_get_file_type (source_info), ==, G_FILE_TYPE_DIRECTORY); + const char *dirtree_checksum = ostree_repo_file_tree_get_contents_checksum (source); + const char *dirmeta_checksum = ostree_repo_file_tree_get_metadata_checksum (source); + return checkout_tree_at_recurse (self, options, &state, destination_parent_fd, + destination_name, + dirtree_checksum, dirmeta_checksum, + cancellable, error); +} - /* Set directory mtime to OSTREE_TIMESTAMP, so that it is constant for all checkouts. - * Must be done after setting permissions and creating all children. - */ - if (!did_exist) - { - const struct timespec times[2] = { { OSTREE_TIMESTAMP, UTIME_OMIT }, { OSTREE_TIMESTAMP, 0} }; - do - res = futimens (destination_dfd, times); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_error_from_errno (error); - goto out; - } - } +static void +canonicalize_options (OstreeRepo *self, + OstreeRepoCheckoutAtOptions *options) +{ + /* Canonicalize subpath to / */ + if (!options->subpath) + options->subpath = "/"; - if (fsync_is_enabled (self, options)) - { - if (fsync (destination_dfd) == -1) - { - glnx_set_error_from_errno (error); - goto out; - } - } - - ret = TRUE; - out: - return ret; + /* Force USER mode for BARE_USER_ONLY always - nothing else makes sense */ + if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY) + options->mode = OSTREE_REPO_CHECKOUT_MODE_USER; } /** @@ -891,14 +893,11 @@ ostree_repo_checkout_tree (OstreeRepo *self, GError **error) { OstreeRepoCheckoutAtOptions options = { 0, }; - - if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY) - mode = OSTREE_REPO_CHECKOUT_MODE_USER; - options.mode = mode; options.overwrite_mode = overwrite_mode; /* Backwards compatibility */ options.enable_uncompressed_cache = TRUE; + canonicalize_options (self, &options); return checkout_tree_at (self, &options, AT_FDCWD, gs_file_get_path_cached (destination), @@ -992,9 +991,10 @@ ostree_repo_checkout_at (OstreeRepo *self, /* Make a copy so we can modify the options */ real_options = *options; options = &real_options; + canonicalize_options (self, options); - if (ostree_repo_get_mode (self) == OSTREE_REPO_MODE_BARE_USER_ONLY) - options->mode = OSTREE_REPO_CHECKOUT_MODE_USER; + g_return_val_if_fail (!(options->force_copy && options->no_copy_fallback), FALSE); + g_return_val_if_fail (!options->sepolicy || options->force_copy, FALSE); g_autoptr(GFile) commit_root = (GFile*) _ostree_repo_file_new_for_commit (self, commit, error); if (!commit_root) @@ -1004,7 +1004,8 @@ ostree_repo_checkout_at (OstreeRepo *self, return FALSE; g_autoptr(GFile) target_dir = NULL; - if (options->subpath && strcmp (options->subpath, "/") != 0) + + if (strcmp (options->subpath, "/") != 0) target_dir = g_file_get_child (commit_root, options->subpath); else target_dir = g_object_ref (commit_root); @@ -1111,7 +1112,7 @@ ostree_repo_checkout_gc (OstreeRepo *self, glnx_set_error_from_errno (error); return FALSE; } - + if (stbuf.st_nlink == 1) { if (unlinkat (dfd_iter.fd, dent->d_name, 0) != 0) diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 45577373..ce45a911 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -433,7 +433,7 @@ add_size_index_to_metadata (OstreeRepo *self, { guint8 csum[OSTREE_SHA256_DIGEST_LEN]; const char *e_checksum = sorted_keys->pdata[i]; - GString *buffer = g_string_new (NULL); + g_autoptr(GString) buffer = g_string_new (NULL); ostree_checksum_inplace_to_bytes (e_checksum, csum); g_string_append_len (buffer, (char*)csum, sizeof (csum)); @@ -444,7 +444,6 @@ add_size_index_to_metadata (OstreeRepo *self, g_variant_builder_add (&index_builder, "@ay", ot_gvariant_new_bytearray ((guint8*)buffer->str, buffer->len)); - g_string_free (buffer, TRUE); } g_variant_builder_add (builder, "{sv}", "ostree.sizes", @@ -459,29 +458,19 @@ add_size_index_to_metadata (OstreeRepo *self, } static gboolean -fallocate_stream (GFileDescriptorBased *stream, - goffset size, - GCancellable *cancellable, - GError **error) +ot_fallocate (int fd, goffset size, GError **error) { - gboolean ret = FALSE; - int fd = g_file_descriptor_based_get_fd (stream); + if (size == 0) + return TRUE; - if (size > 0) + int r = posix_fallocate (fd, 0, size); + if (r != 0) { - int r = posix_fallocate (fd, 0, size); - if (r != 0) - { - /* posix_fallocate is a weird deviation from errno standards */ - errno = r; - glnx_set_error_from_errno (error); - goto out; - } + /* posix_fallocate is a weird deviation from errno standards */ + errno = r; + return glnx_throw_errno_prefix (error, "fallocate"); } - - ret = TRUE; - out: - return ret; + return TRUE; } gboolean @@ -511,11 +500,10 @@ _ostree_repo_open_content_bare (OstreeRepo *self, &fd, &temp_filename, error)) goto out; - ret_stream = g_unix_output_stream_new (fd, TRUE); - - if (!fallocate_stream ((GFileDescriptorBased*)ret_stream, content_len, - cancellable, error)) + if (!ot_fallocate (fd, content_len, error)) goto out; + + ret_stream = g_unix_output_stream_new (fd, TRUE); } ret = TRUE; @@ -570,7 +558,6 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self, GCancellable *cancellable, GError **error) { - g_autoptr(GOutputStream) temp_out = NULL; glnx_fd_close int temp_fd = -1; g_autofree char *temp_filename = NULL; @@ -578,20 +565,27 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self, &temp_fd, &temp_filename, error)) return FALSE; - temp_out = g_unix_output_stream_new (temp_fd, FALSE); - if (!fallocate_stream ((GFileDescriptorBased*)temp_out, length, - cancellable, error)) + if (!ot_fallocate (temp_fd, length, error)) return FALSE; - if (g_output_stream_splice (temp_out, input, 0, - cancellable, error) < 0) - return FALSE; - if (fchmod (temp_fd, 0644) < 0) + if (G_IS_FILE_DESCRIPTOR_BASED (input)) { - glnx_set_error_from_errno (error); - return FALSE; + int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input); + if (glnx_regfile_copy_bytes (infd, temp_fd, (off_t)length, TRUE) < 0) + return glnx_throw_errno_prefix (error, "regfile copy"); } + else + { + g_autoptr(GOutputStream) temp_out = g_unix_output_stream_new (temp_fd, FALSE); + if (g_output_stream_splice (temp_out, input, 0, + cancellable, error) < 0) + return FALSE; + } + + if (fchmod (temp_fd, 0644) < 0) + return glnx_throw_errno_prefix (error, "fchmod"); + *out_fd = temp_fd; temp_fd = -1; *out_path = g_steal_pointer (&temp_filename); return TRUE; @@ -608,7 +602,8 @@ write_object (OstreeRepo *self, GError **error) { gboolean ret = FALSE; - const char *actual_checksum; + const char *actual_checksum = NULL; + g_autofree char *actual_checksum_owned = NULL; gboolean do_commit; OstreeRepoMode repo_mode; g_autofree char *temp_filename = NULL; @@ -773,7 +768,7 @@ write_object (OstreeRepo *self, actual_checksum = expected_checksum; else { - actual_checksum = ot_checksum_instream_get_string (checksum_input); + actual_checksum = actual_checksum_owned = ot_checksum_instream_get_string (checksum_input); if (expected_checksum && strcmp (actual_checksum, expected_checksum) != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, @@ -1306,7 +1301,7 @@ ensure_txn_refs (OstreeRepo *self) * ostree_repo_transaction_set_refspec: * @self: An #OstreeRepo * @refspec: The refspec to write - * @checksum: The checksum to point it to + * @checksum: (nullable): The checksum to point it to * * Like ostree_repo_transaction_set_ref(), but takes concatenated * @refspec format as input instead of separate remote and name @@ -1329,7 +1324,7 @@ ostree_repo_transaction_set_refspec (OstreeRepo *self, * @self: An #OstreeRepo * @remote: (allow-none): A remote for the ref * @ref: The ref to write - * @checksum: The checksum to point it to + * @checksum: (nullable): The checksum to point it to * * If @checksum is not %NULL, then record it as the target of ref named * @ref; if @remote is provided, the ref will appear to originate from that @@ -2014,13 +2009,13 @@ ostree_repo_read_commit_detached_metadata (OstreeRepo *self, !ot_util_variant_map_at (self->commit_stagedir_fd, buf, G_VARIANT_TYPE ("a{sv}"), OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error)) - return g_prefix_error (error, "Unable to read existing detached metadata: "), FALSE; + return glnx_prefix_error (error, "Unable to read existing detached metadata"); if (ret_metadata == NULL && !ot_util_variant_map_at (self->objects_dir_fd, buf, G_VARIANT_TYPE ("a{sv}"), OT_VARIANT_MAP_ALLOW_NOENT | OT_VARIANT_MAP_TRUSTED, &ret_metadata, error)) - return g_prefix_error (error, "Unable to read existing detached metadata: "), FALSE; + return glnx_prefix_error (error, "Unable to read existing detached metadata"); if (ret_metadata == NULL && self->parent_repo) return ostree_repo_read_commit_detached_metadata (self->parent_repo, diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index b1a58d61..2a518d4f 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -21,6 +21,7 @@ #pragma once #include "ostree-repo.h" +#include "ostree-remote-private.h" #include "libglnx.h" G_BEGIN_DECLS @@ -43,6 +44,14 @@ G_BEGIN_DECLS * */ #define _OSTREE_MAX_OUTSTANDING_WRITE_REQUESTS 16 +/* Well-known keys for the additional metadata field in a summary file. */ +#define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified" +#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires" + +/* Well-known keys for the additional metadata field in a commit in a ref entry + * in a summary file. */ +#define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp" + typedef enum { OSTREE_REPO_TEST_ERROR_PRE_COMMIT = (1 << 0) } OstreeRepoTestErrorFlags; @@ -78,7 +87,6 @@ struct OstreeRepo { GFile *repodir; int repo_dir_fd; - GFile *tmp_dir; int tmp_dir_fd; int cache_dir_fd; char *cache_dir; @@ -92,8 +100,9 @@ struct OstreeRepo { OstreeRepoTransactionStats txn_stats; GMutex cache_lock; - GPtrArray *cached_meta_indexes; - GPtrArray *cached_content_indexes; + guint dirmeta_cache_refcount; + /* char * checksum → GVariant * for dirmeta objects, used in the checkout path */ + GHashTable *dirmeta_cache; gboolean inited; gboolean writable; @@ -128,6 +137,24 @@ typedef struct { char checksum[OSTREE_SHA256_STRING_LEN+1]; } OstreeDevIno; +/* A MemoryCacheRef is an in-memory cache of objects (currently just DIRMETA). This can + * be used when performing an operation that traverses a repository in someway. Currently, + * the primary use case is ostree_repo_checkout_at() avoiding lots of duplicate dirmeta + * lookups. + */ +typedef struct { + OstreeRepo *repo; +} OstreeRepoMemoryCacheRef; + + +void +_ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state, + OstreeRepo *repo); + +void +_ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy); + #define OSTREE_REPO_TMPDIR_STAGING "staging-" #define OSTREE_REPO_TMPDIR_FETCHER "fetcher-" @@ -324,4 +351,16 @@ gboolean _ostree_repo_update_mtime (OstreeRepo *self, GError **error); +void +_ostree_repo_add_remote (OstreeRepo *self, + OstreeRemote *remote); +OstreeRemote * +_ostree_repo_get_remote (OstreeRepo *self, + const char *name, + GError **error); +OstreeRemote * +_ostree_repo_get_remote_inherited (OstreeRepo *self, + const char *name, + GError **error); + G_END_DECLS diff --git a/src/libostree/ostree-repo-prune.c b/src/libostree/ostree-repo-prune.c index 1b2a8257..bf0a2530 100644 --- a/src/libostree/ostree-repo-prune.c +++ b/src/libostree/ostree-repo-prune.c @@ -42,21 +42,14 @@ prune_commitpartial_file (OstreeRepo *repo, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autofree char *path = _ostree_get_commitpartial_path (checksum); - if (unlinkat (repo->repo_dir_fd, path, 0) != 0) { if (errno != ENOENT) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "unlinkat"); } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -67,7 +60,6 @@ maybe_prune_loose_object (OtPruneData *data, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GVariant) key = NULL; key = ostree_object_name_serialize (checksum, objtype); @@ -83,16 +75,16 @@ maybe_prune_loose_object (OtPruneData *data, if (objtype == OSTREE_OBJECT_TYPE_COMMIT) { if (!prune_commitpartial_file (data->repo, checksum, cancellable, error)) - goto out; + return FALSE; } if (!ostree_repo_query_object_storage_size (data->repo, objtype, checksum, &storage_size, cancellable, error)) - goto out; + return FALSE; if (!ostree_repo_delete_object (data->repo, objtype, checksum, cancellable, error)) - goto out; + return FALSE; data->freed_bytes += storage_size; } @@ -111,9 +103,7 @@ maybe_prune_loose_object (OtPruneData *data, data->n_reachable_content++; } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -121,25 +111,17 @@ _ostree_repo_prune_tmp (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; - glnx_fd_close int fd = -1; - if (self->cache_dir_fd == -1) return TRUE; - fd = glnx_opendirat_with_errno (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, FALSE); - if (fd < 0) - { - if (errno == ENOENT) - ret = TRUE; - else - glnx_set_error_from_errno (error); - goto out; - } - - if (!glnx_dirfd_iterator_init_take_fd (dup (fd), &dfd_iter, error)) - goto out; + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (self->cache_dir_fd, _OSTREE_SUMMARY_CACHE_DIR, + &dfd_iter, &exists, error)) + return FALSE; + /* Note early return */ + if (!exists) + return TRUE; while (TRUE) { @@ -148,8 +130,7 @@ _ostree_repo_prune_tmp (OstreeRepo *self, struct dirent *dent; if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) - goto out; - + return FALSE; if (dent == NULL) break; @@ -166,18 +147,12 @@ _ostree_repo_prune_tmp (OstreeRepo *self, if (has_sig_suffix) dent->d_name[len - 4] = '.'; - if (unlinkat (fd, dent->d_name, 0) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + if (unlinkat (dfd_iter.fd, dent->d_name, 0) < 0) + return glnx_throw_errno_prefix (error, "unlinkat"); } } - ret = TRUE; - - out: - return ret; + return TRUE; } @@ -198,22 +173,17 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GPtrArray) deltas = NULL; - guint i; - if (!ostree_repo_list_static_delta_names (self, &deltas, cancellable, error)) - goto out; + return FALSE; - for (i = 0; i < deltas->len; i++) + for (guint i = 0; i < deltas->len; i++) { const char *deltaname = deltas->pdata[i]; const char *dash = strchr (deltaname, '-'); const char *to = NULL; - gboolean have_commit; g_autofree char *from = NULL; - g_autofree char *deltadir = NULL; if (!dash) { @@ -232,26 +202,24 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit, } else { + gboolean have_commit; if (!ostree_repo_has_object (self, OSTREE_OBJECT_TYPE_COMMIT, to, &have_commit, cancellable, error)) - goto out; + return FALSE; if (have_commit) continue; } g_debug ("Trying to prune static delta %s", deltaname); - deltadir = _ostree_get_relative_static_delta_path (from, to, NULL); - + g_autofree char *deltadir = _ostree_get_relative_static_delta_path (from, to, NULL); if (!glnx_shutil_rm_rf_at (self->repo_dir_fd, deltadir, - cancellable, error)) - goto out; + cancellable, error)) + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -264,13 +232,14 @@ repo_prune_internal (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; GHashTableIter hash_iter; gpointer key, value; OtPruneData data = { 0, }; data.repo = self; - data.reachable = g_hash_table_ref (options->reachable); + /* We unref this when we're done */ + g_autoptr(GHashTable) reachable_owned = g_hash_table_ref (options->reachable); + data.reachable = reachable_owned; g_hash_table_iter_init (&hash_iter, objects); while (g_hash_table_iter_next (&hash_iter, &key, &value)) @@ -289,24 +258,20 @@ repo_prune_internal (OstreeRepo *self, if (!maybe_prune_loose_object (&data, options->flags, checksum, objtype, cancellable, error)) - goto out; + return FALSE; } if (!ostree_repo_prune_static_deltas (self, NULL, cancellable, error)) - goto out; + return FALSE; if (!_ostree_repo_prune_tmp (self, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; *out_objects_total = (data.n_reachable_meta + data.n_unreachable_meta + data.n_reachable_content + data.n_unreachable_content); *out_objects_pruned = (data.n_unreachable_meta + data.n_unreachable_content); *out_pruned_object_size_total = data.freed_bytes; - out: - if (data.reachable) - g_hash_table_unref (data.reachable); - return ret; + return TRUE; } /** diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index a7a3a5b0..f1dae995 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -68,6 +68,7 @@ typedef struct { gboolean gpg_verify; gboolean require_static_deltas; + gboolean disable_static_deltas; gboolean gpg_verify_summary; gboolean has_tombstone_commits; @@ -210,38 +211,38 @@ update_progress (gpointer user_data) n_scanned_metadata = pull_data->n_scanned_metadata; start_time = pull_data->start_time; - ostree_async_progress_set_uint (pull_data->progress, "outstanding-fetches", outstanding_fetches); - ostree_async_progress_set_uint (pull_data->progress, "outstanding-writes", outstanding_writes); - ostree_async_progress_set_uint (pull_data->progress, "fetched", fetched); - ostree_async_progress_set_uint (pull_data->progress, "requested", requested); - ostree_async_progress_set_uint (pull_data->progress, "scanning", g_queue_is_empty (&pull_data->scan_object_queue) ? 0 : 1); - ostree_async_progress_set_uint (pull_data->progress, "scanned-metadata", n_scanned_metadata); - ostree_async_progress_set_uint64 (pull_data->progress, "bytes-transferred", bytes_transferred); - ostree_async_progress_set_uint64 (pull_data->progress, "start-time", start_time); - - /* Deltas */ - ostree_async_progress_set_uint (pull_data->progress, "fetched-delta-parts", - pull_data->n_fetched_deltaparts); - ostree_async_progress_set_uint (pull_data->progress, "total-delta-parts", - pull_data->n_total_deltaparts); - ostree_async_progress_set_uint (pull_data->progress, "fetched-delta-fallbacks", - pull_data->n_fetched_deltapart_fallbacks); - ostree_async_progress_set_uint (pull_data->progress, "total-delta-fallbacks", - pull_data->n_total_delta_fallbacks); - ostree_async_progress_set_uint64 (pull_data->progress, "fetched-delta-part-size", - pull_data->fetched_deltapart_size); - ostree_async_progress_set_uint64 (pull_data->progress, "total-delta-part-size", - pull_data->total_deltapart_size); - ostree_async_progress_set_uint64 (pull_data->progress, "total-delta-part-usize", - pull_data->total_deltapart_usize); - ostree_async_progress_set_uint (pull_data->progress, "total-delta-superblocks", - pull_data->static_delta_superblocks->len); - - /* We fetch metadata before content. These allow us to report metadata fetch progress specifically. */ - ostree_async_progress_set_uint (pull_data->progress, "outstanding-metadata-fetches", pull_data->n_outstanding_metadata_fetches); - ostree_async_progress_set_uint (pull_data->progress, "metadata-fetched", pull_data->n_fetched_metadata); - - ostree_async_progress_set_status (pull_data->progress, NULL); + ostree_async_progress_set (pull_data->progress, + "outstanding-fetches", "u", outstanding_fetches, + "outstanding-writes", "u", outstanding_writes, + "fetched", "u", fetched, + "requested", "u", requested, + "scanning", "u", g_queue_is_empty (&pull_data->scan_object_queue) ? 0 : 1, + "scanned-metadata", "u", n_scanned_metadata, + "bytes-transferred", "t", bytes_transferred, + "start-time", "t", start_time, + /* Deltas */ + "fetched-delta-parts", + "u", pull_data->n_fetched_deltaparts, + "total-delta-parts", + "u", pull_data->n_total_deltaparts, + "fetched-delta-fallbacks", + "u", pull_data->n_fetched_deltapart_fallbacks, + "total-delta-fallbacks", + "u", pull_data->n_total_delta_fallbacks, + "fetched-delta-part-size", + "t", pull_data->fetched_deltapart_size, + "total-delta-part-size", + "t", pull_data->total_deltapart_size, + "total-delta-part-usize", + "t", pull_data->total_deltapart_usize, + "total-delta-superblocks", + "u", pull_data->static_delta_superblocks->len, + /* We fetch metadata before content. These allow us to report metadata fetch progress specifically. */ + "outstanding-metadata-fetches", "u", pull_data->n_outstanding_metadata_fetches, + "metadata-fetched", "u", pull_data->n_fetched_metadata, + /* Overall status. */ + "status", "s", "", + NULL); if (pull_data->dry_run) pull_data->dry_run_emitted_progress = TRUE; @@ -436,32 +437,22 @@ fetch_mirrored_uri_contents_utf8_sync (OstreeFetcher *fetcher, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GBytes) bytes = NULL; - g_autofree char *ret_contents = NULL; - gsize len; - if (!_ostree_fetcher_mirrored_request_to_membuf (fetcher, mirrorlist, filename, TRUE, FALSE, &bytes, OSTREE_MAX_METADATA_SIZE, cancellable, error)) - goto out; + return FALSE; - ret_contents = g_bytes_unref_to_data (bytes, &len); - bytes = NULL; + gsize len; + g_autofree char *ret_contents = g_bytes_unref_to_data (g_steal_pointer (&bytes), &len); if (!g_utf8_validate (ret_contents, -1, NULL)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid UTF-8"); - goto out; - } + return glnx_throw (error, "Invalid UTF-8"); - ret = TRUE; ot_transfer_out_value (out_contents, &ret_contents); - out: - return ret; + return TRUE; } static gboolean @@ -484,16 +475,11 @@ write_commitpartial_for (OtPullData *pull_data, GError **error) { g_autofree char *commitpartial_path = _ostree_get_commitpartial_path (checksum); - glnx_fd_close int fd = -1; - - fd = openat (pull_data->repo->repo_dir_fd, commitpartial_path, O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644); + glnx_fd_close int fd = openat (pull_data->repo->repo_dir_fd, commitpartial_path, O_EXCL | O_CREAT | O_WRONLY | O_CLOEXEC | O_NOCTTY, 0644); if (fd == -1) { if (errno != EEXIST) - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno_prefix (error, "open(%s)", commitpartial_path); } return TRUE; } @@ -554,15 +540,12 @@ pull_matches_subdir (OtPullData *pull_data, const char *basename, gboolean basename_is_dir) { - int i; - g_autofree char *file = NULL; - if (pull_data->dirs == NULL) return TRUE; - file = g_strconcat (path, basename, NULL); + g_autofree char *file = g_strconcat (path, basename, NULL); - for (i = 0; i < pull_data->dirs->len; i++) + for (guint i = 0; i < pull_data->dirs->len; i++) { const char *pull_dir = g_ptr_array_index (pull_data->dirs, i); if (matches_pull_dir (file, pull_dir, basename_is_dir)) @@ -580,30 +563,18 @@ scan_dirtree_object (OtPullData *pull_data, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - int i, n; - g_autoptr(GVariant) tree = NULL; - g_autoptr(GVariant) files_variant = NULL; - g_autoptr(GVariant) dirs_variant = NULL; - const char *dirname = NULL; - if (recursion_depth > OSTREE_MAX_RECURSION) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Exceeded maximum recursion"); - goto out; - } + return glnx_throw (error, "Exceeded maximum recursion"); + g_autoptr(GVariant) tree = NULL; if (!ostree_repo_load_variant (pull_data->repo, OSTREE_OBJECT_TYPE_DIR_TREE, checksum, &tree, error)) - goto out; + return FALSE; /* PARSE OSTREE_SERIALIZED_TREE_VARIANT */ - files_variant = g_variant_get_child_value (tree, 0); - dirs_variant = g_variant_get_child_value (tree, 1); - - n = g_variant_n_children (files_variant); - for (i = 0; i < n; i++) + g_autoptr(GVariant) files_variant = g_variant_get_child_value (tree, 0); + const guint n = g_variant_n_children (files_variant); + for (guint i = 0; i < n; i++) { const char *filename; gboolean file_is_stored; @@ -613,7 +584,7 @@ scan_dirtree_object (OtPullData *pull_data, g_variant_get_child (files_variant, i, "(&s@ay)", &filename, &csum); if (!ot_util_filename_validate (filename, error)) - goto out; + return FALSE; /* Skip files if we're traversing a request only directory, unless it exactly * matches the path */ @@ -624,14 +595,14 @@ scan_dirtree_object (OtPullData *pull_data, if (!ostree_repo_has_object (pull_data->repo, OSTREE_OBJECT_TYPE_FILE, file_checksum, &file_is_stored, cancellable, error)) - goto out; + return FALSE; if (!file_is_stored && pull_data->remote_repo_local) { if (!ostree_repo_import_object_from_with_trust (pull_data->repo, pull_data->remote_repo_local, OSTREE_OBJECT_TYPE_FILE, file_checksum, !pull_data->is_untrusted, cancellable, error)) - goto out; + return FALSE; } else if (!file_is_stored && !g_hash_table_lookup (pull_data->requested_content, file_checksum)) { @@ -641,44 +612,38 @@ scan_dirtree_object (OtPullData *pull_data, } } - n = g_variant_n_children (dirs_variant); - - for (i = 0; i < n; i++) + g_autoptr(GVariant) dirs_variant = g_variant_get_child_value (tree, 1); + const guint m = g_variant_n_children (dirs_variant); + for (guint i = 0; i < m; i++) { + const char *dirname = NULL; g_autoptr(GVariant) tree_csum = NULL; g_autoptr(GVariant) meta_csum = NULL; - const guchar *tree_csum_bytes; - const guchar *meta_csum_bytes; - g_autofree char *subpath = NULL; - g_variant_get_child (dirs_variant, i, "(&s@ay@ay)", &dirname, &tree_csum, &meta_csum); if (!ot_util_filename_validate (dirname, error)) - goto out; + return FALSE; if (!pull_matches_subdir (pull_data, path, dirname, TRUE)) continue; - tree_csum_bytes = ostree_checksum_bytes_peek_validate (tree_csum, error); + const guchar *tree_csum_bytes = ostree_checksum_bytes_peek_validate (tree_csum, error); if (tree_csum_bytes == NULL) - goto out; + return FALSE; - meta_csum_bytes = ostree_checksum_bytes_peek_validate (meta_csum, error); + const guchar *meta_csum_bytes = ostree_checksum_bytes_peek_validate (meta_csum, error); if (meta_csum_bytes == NULL) - goto out; - - subpath = g_strconcat (path, dirname, "/", NULL); + return FALSE; + g_autofree char *subpath = g_strconcat (path, dirname, "/", NULL); queue_scan_one_metadata_object_c (pull_data, tree_csum_bytes, OSTREE_OBJECT_TYPE_DIR_TREE, subpath, recursion_depth + 1); queue_scan_one_metadata_object_c (pull_data, meta_csum_bytes, OSTREE_OBJECT_TYPE_DIR_META, subpath, recursion_depth + 1); } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -688,27 +653,21 @@ fetch_ref_contents (OtPullData *pull_data, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; + g_autofree char *filename = g_build_filename ("refs", "heads", ref, NULL); g_autofree char *ret_contents = NULL; - g_autofree char *filename = NULL; - - filename = g_build_filename ("refs", "heads", ref, NULL); - if (!fetch_mirrored_uri_contents_utf8_sync (pull_data->fetcher, pull_data->meta_mirrorlist, filename, &ret_contents, cancellable, error)) - goto out; + return FALSE; g_strchomp (ret_contents); if (!ostree_validate_checksum_string (ret_contents, error)) - goto out; + return FALSE; - ret = TRUE; ot_transfer_out_value (out_contents, &ret_contents); - out: - return ret; + return TRUE; } static gboolean @@ -718,34 +677,23 @@ lookup_commit_checksum_from_summary (OtPullData *pull_data, gsize *out_size, GError **error) { - gboolean ret = FALSE; g_autoptr(GVariant) refs = g_variant_get_child_value (pull_data->summary, 0); - g_autoptr(GVariant) refdata = NULL; - g_autoptr(GVariant) reftargetdata = NULL; + int i; + if (!ot_variant_bsearch_str (refs, ref, &i)) + return glnx_throw (error, "No such branch '%s' in repository summary", ref); + + g_autoptr(GVariant) refdata = g_variant_get_child_value (refs, i); + g_autoptr(GVariant) reftargetdata = g_variant_get_child_value (refdata, 1); guint64 commit_size; g_autoptr(GVariant) commit_csum_v = NULL; - int i; - - if (!ot_variant_bsearch_str (refs, ref, &i)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No such branch '%s' in repository summary", - ref); - goto out; - } - - refdata = g_variant_get_child_value (refs, i); - reftargetdata = g_variant_get_child_value (refdata, 1); g_variant_get (reftargetdata, "(t@ay@a{sv})", &commit_size, &commit_csum_v, NULL); if (!ostree_validate_structureof_csum_v (commit_csum_v, error)) - goto out; + return FALSE; - ret = TRUE; *out_checksum = ostree_checksum_from_bytes_v (commit_csum_v); *out_size = commit_size; - out: - return ret; + return TRUE; } static void @@ -771,7 +719,7 @@ content_fetch_on_write_complete (GObject *object, g_autofree char *checksum = NULL; g_autofree char *checksum_obj = NULL; - if (!ostree_repo_write_content_finish ((OstreeRepo*)object, result, + if (!ostree_repo_write_content_finish ((OstreeRepo*)object, result, &csum, error)) goto out; @@ -1879,10 +1827,15 @@ process_one_static_delta (OtPullData *pull_data, /* Loop over the static delta data we got from the summary, * and find the newest commit for @out_from_revision that * goes to @to_revision. + * + * Additionally, @out_have_scratch_delta will be set to %TRUE + * if there is a %NULL → @to_revision delta, also known as + * a "from scratch" delta. */ static gboolean get_best_static_delta_start_for (OtPullData *pull_data, const char *to_revision, + gboolean *out_have_scratch_delta, char **out_from_revision, GCancellable *cancellable, GError **error) @@ -1897,6 +1850,8 @@ get_best_static_delta_start_for (OtPullData *pull_data, g_assert (pull_data->summary_deltas_checksums != NULL); g_hash_table_iter_init (&hiter, pull_data->summary_deltas_checksums); + *out_have_scratch_delta = FALSE; + /* Loop over all deltas known from the summary file, * finding ones which go to to_revision */ while (g_hash_table_iter_next (&hiter, &hkey, &hvalue)) @@ -1915,6 +1870,8 @@ get_best_static_delta_start_for (OtPullData *pull_data, if (cur_from_rev) g_ptr_array_add (candidates, g_steal_pointer (&cur_from_rev)); + else + *out_have_scratch_delta = TRUE; } /* Loop over our candidates, find the newest one */ @@ -1963,6 +1920,16 @@ typedef struct { char *to_revision; } FetchDeltaSuperData; +static void +set_required_deltas_error (GError **error, + const char *from_revision, + const char *to_revision) +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Static deltas required, but none found for %s to %s", + from_revision, to_revision); +} + static void on_superblock_fetched (GObject *src, GAsyncResult *res, @@ -1984,14 +1951,11 @@ on_superblock_fetched (GObject *src, { if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) goto out; - g_clear_error (&local_error); if (pull_data->require_static_deltas) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Static deltas required, but none found for %s to %s", - from_revision, to_revision); + set_required_deltas_error (error, from_revision, to_revision); goto out; } @@ -2442,11 +2406,15 @@ repo_remote_fetch_summary (OstreeRepo *self, g_autoptr(GMainContext) mainctx = NULL; gboolean ret = FALSE; gboolean from_cache = FALSE; - g_autofree char *url_override = NULL; + const char *url_override = NULL; + g_autoptr(GVariant) extra_headers = NULL; g_autoptr(GPtrArray) mirrorlist = NULL; if (options) - (void) g_variant_lookup (options, "override-url", "&s", &url_override); + { + (void) g_variant_lookup (options, "override-url", "&s", &url_override); + (void) g_variant_lookup (options, "http-headers", "@a(ss)", &extra_headers); + } mainctx = g_main_context_new (); g_main_context_push_thread_default (mainctx); @@ -2455,6 +2423,9 @@ repo_remote_fetch_summary (OstreeRepo *self, if (fetcher == NULL) goto out; + if (extra_headers) + _ostree_fetcher_set_extra_headers (fetcher, extra_headers); + { g_autofree char *url_string = NULL; if (metalink_url_string) @@ -2566,6 +2537,117 @@ reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **e return TRUE; } +/* Start a request for a static delta */ +static void +initiate_delta_request (OtPullData *pull_data, + const char *from_revision, + const char *to_revision) +{ + g_autofree char *delta_name = + _ostree_get_relative_static_delta_superblock_path (from_revision, to_revision); + FetchDeltaSuperData *fdata = g_new0(FetchDeltaSuperData, 1); + fdata->pull_data = pull_data; + fdata->from_revision = g_strdup (from_revision); + fdata->to_revision = g_strdup (to_revision); + + _ostree_fetcher_request_to_membuf (pull_data->fetcher, + pull_data->content_mirrorlist, + delta_name, 0, + OSTREE_MAX_METADATA_SIZE, + 0, pull_data->cancellable, + on_superblock_fetched, fdata); + pull_data->n_outstanding_metadata_fetches++; + pull_data->n_requested_metadata++; +} + +/* @ref - Optional ref name + * @to_revision: Target commit revision we want to fetch + * + * Start a request for either a ref or a commit. In the + * ref case, we know both the name and the target commit. + * + * This function primarily handles the semantics around + * `disable_static_deltas` and `require_static_deltas`. + */ +static gboolean +initiate_request (OtPullData *pull_data, + const char *ref, + const char *to_revision, + GError **error) +{ + g_autofree char *delta_from_revision = NULL; + + /* Are deltas disabled? OK, just start an object fetch and be done */ + if (pull_data->disable_static_deltas) + { + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0); + return TRUE; + } + + /* If we have a summary, we can use the newer logic */ + if (pull_data->summary) + { + gboolean have_scratch_delta = FALSE; + + /* Look for a delta to @to_revision in the summary data */ + if (!get_best_static_delta_start_for (pull_data, to_revision, + &have_scratch_delta, &delta_from_revision, + pull_data->cancellable, error)) + return FALSE; + + if (delta_from_revision) /* Did we find a delta FROM commit? */ + initiate_delta_request (pull_data, delta_from_revision, to_revision); + else if (have_scratch_delta) /* No delta FROM, do we have a scratch? */ + initiate_delta_request (pull_data, NULL, to_revision); + else if (pull_data->require_static_deltas) /* No deltas found; are they required? */ + { + set_required_deltas_error (error, ref, to_revision); + return FALSE; + } + else /* No deltas, fall back to object fetches. */ + queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0); + } + else if (ref != NULL) + { + /* Are we doing a delta via a ref? In that case we can fall back to the older + * logic of just using the current tip of the ref as a delta FROM source. */ + if (!ostree_repo_resolve_rev (pull_data->repo, ref, TRUE, + &delta_from_revision, error)) + return FALSE; + + /* Determine whether the from revision we have is partial; this + * can happen if e.g. one uses `ostree pull --commit-metadata-only`. + * This mirrors the logic in get_best_static_delta_start_for(). + */ + if (delta_from_revision) + { + OstreeRepoCommitState from_commitstate; + + if (!ostree_repo_load_commit (pull_data->repo, delta_from_revision, NULL, + &from_commitstate, error)) + return FALSE; + + /* Was it partial? Then we can't use it. */ + if (commitstate_is_partial (pull_data, from_commitstate)) + g_clear_pointer (&delta_from_revision, g_free); + } + + /* This is similar to the below, except we *might* use the previous + * commit, or we might do a scratch delta first. + */ + initiate_delta_request (pull_data, delta_from_revision ?: NULL, to_revision); + } + else + { + /* Legacy path without a summary file - let's try a scratch delta, if that + * doesn't work, it'll drop down to object requests. + */ + initiate_delta_request (pull_data, NULL, to_revision); + } + + return TRUE; +} + /* ------------------------------------------------------------------------------------------ * Below is the libsoup-invariant API; these should match * the stub functions in the #else clause @@ -2597,7 +2679,7 @@ reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **e * * override-commit-ids (as): Array of specific commit IDs to fetch for refs * * dry-run (b): Only print information on what will be downloaded (requires static deltas) * * override-url (s): Fetch objects from this URL if remote specifies no metalink in options - * * inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do mutliple pulls in one transaction. + * * inherit-transaction (b): Don't initiate, finish or abort a transaction, usefult to do multiple pulls in one transaction. * * http-headers (a(ss)): Additional headers to add to all HTTP requests * * update-frequency (u): Frequency to call the async progress callback in milliseconds, if any; only values higher than 0 are valid */ @@ -2631,7 +2713,6 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_autofree char **refs_to_fetch = NULL; g_autofree char **override_commit_ids = NULL; GSource *update_timeout = NULL; - gboolean disable_static_deltas = FALSE; gboolean opt_gpg_verify_set = FALSE; gboolean opt_gpg_verify_summary_set = FALSE; const char *url_override = NULL; @@ -2653,7 +2734,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, opt_gpg_verify_summary_set = g_variant_lookup (options, "gpg-verify-summary", "b", &pull_data->gpg_verify_summary); (void) g_variant_lookup (options, "depth", "i", &pull_data->maxdepth); - (void) g_variant_lookup (options, "disable-static-deltas", "b", &disable_static_deltas); + (void) g_variant_lookup (options, "disable-static-deltas", "b", &pull_data->disable_static_deltas); (void) g_variant_lookup (options, "require-static-deltas", "b", &pull_data->require_static_deltas); (void) g_variant_lookup (options, "override-commit-ids", "^a&s", &override_commit_ids); (void) g_variant_lookup (options, "dry-run", "b", &pull_data->dry_run); @@ -2673,7 +2754,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, for (i = 0; dirs_to_pull != NULL && dirs_to_pull[i] != NULL; i++) g_return_val_if_fail (dirs_to_pull[i][0] == '/', FALSE); - g_return_val_if_fail (!(disable_static_deltas && pull_data->require_static_deltas), FALSE); + g_return_val_if_fail (!(pull_data->disable_static_deltas && pull_data->require_static_deltas), FALSE); /* We only do dry runs with static deltas, because we don't really have any * in-advance information for bare fetches. @@ -2952,7 +3033,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, * exact object files are copied. */ if (pull_data->remote_repo_local && !pull_data->require_static_deltas) - disable_static_deltas = TRUE; + pull_data->disable_static_deltas = TRUE; /* We can't use static deltas if pulling into an archive-z2 repo. */ if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2) @@ -2963,13 +3044,13 @@ ostree_repo_pull_with_options (OstreeRepo *self, "Can't use static deltas in an archive repo"); goto out; } - disable_static_deltas = TRUE; + pull_data->disable_static_deltas = TRUE; } /* It's not efficient to use static deltas if all we want is the commit * metadata. */ if (pull_data->is_commit_only) - disable_static_deltas = TRUE; + pull_data->disable_static_deltas = TRUE; pull_data->static_delta_superblocks = g_ptr_array_new_with_free_func ((GDestroyNotify)g_variant_unref); @@ -3239,78 +3320,23 @@ ostree_repo_pull_with_options (OstreeRepo *self, if (pull_data->legacy_transaction_resuming) g_debug ("resuming legacy transaction"); + /* Initiate requests for explicit commit revisions */ g_hash_table_iter_init (&hash_iter, commits_to_fetch); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { const char *commit = value; - queue_scan_one_metadata_object (pull_data, commit, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0); + if (!initiate_request (pull_data, NULL, commit, error)) + goto out; } + /* Initiate requests for refs */ g_hash_table_iter_init (&hash_iter, requested_refs_to_fetch); while (g_hash_table_iter_next (&hash_iter, &key, &value)) { - g_autofree char *from_revision = NULL; const char *ref = key; const char *to_revision = value; - gboolean have_valid_from_commit = TRUE; - - /* If we have a summary, find the latest local commit we have - * to use as a from revision for static deltas. - */ - if (pull_data->summary) - { - if (!get_best_static_delta_start_for (pull_data, to_revision, &from_revision, - cancellable, error)) - goto out; - } - else - { - if (!ostree_repo_resolve_rev (pull_data->repo, ref, TRUE, - &from_revision, error)) - goto out; - - /* Determine whether the from revision we have is partial; this - * can happen if e.g. one uses `ostree pull --commit-metadata-only`. - * This mirrors the logic in get_best_static_delta_start_for(). - */ - if (from_revision) - { - OstreeRepoCommitState from_commitstate; - - if (!ostree_repo_load_commit (pull_data->repo, from_revision, NULL, - &from_commitstate, error)) - goto out; - - /* Was it partial? OK, we can't use it. */ - if (commitstate_is_partial (pull_data, from_commitstate)) - have_valid_from_commit = FALSE; - } - } - - if (!disable_static_deltas && - have_valid_from_commit && - (from_revision == NULL || g_strcmp0 (from_revision, to_revision) != 0)) - { - g_autofree char *delta_name = - _ostree_get_relative_static_delta_superblock_path (from_revision, to_revision); - FetchDeltaSuperData *fdata = g_new0(FetchDeltaSuperData, 1); - fdata->pull_data = pull_data; - fdata->from_revision = g_strdup (from_revision); - fdata->to_revision = g_strdup (to_revision); - - _ostree_fetcher_request_to_membuf (pull_data->fetcher, - pull_data->content_mirrorlist, - delta_name, 0, - OSTREE_MAX_METADATA_SIZE, - 0, pull_data->cancellable, - on_superblock_fetched, fdata); - pull_data->n_outstanding_metadata_fetches++; - pull_data->n_requested_metadata++; - } - else - { - queue_scan_one_metadata_object (pull_data, to_revision, OSTREE_OBJECT_TYPE_COMMIT, NULL, 0); - } + if (!initiate_request (pull_data, ref, to_revision, error)) + goto out; } if (pull_data->progress) @@ -3402,8 +3428,11 @@ ostree_repo_pull_with_options (OstreeRepo *self, bytes_transferred = _ostree_fetcher_bytes_transferred (pull_data->fetcher); if (bytes_transferred > 0 && pull_data->progress) { - guint shift; - GString *buf = g_string_new (""); + guint shift; + g_autoptr(GString) buf = g_string_new (""); + + /* Ensure the rest of the progress keys are set appropriately. */ + update_progress (pull_data); if (bytes_transferred < 1024) shift = 1; @@ -3424,7 +3453,6 @@ ostree_repo_pull_with_options (OstreeRepo *self, (guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC)); ostree_async_progress_set_status (pull_data->progress, buf->str); - g_string_free (buf, TRUE); } /* iterate over commits fetched and delete any commitpartial files */ @@ -3510,6 +3538,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, * The following are currently defined: * * - override-url (s): Fetch summary from this URL if remote specifies no metalink in options + * - http-headers (a(ss)): Additional headers to add to all HTTP requests * * Returns: %TRUE on success, %FALSE on failure */ diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c index 21ed081d..3a14f8bb 100644 --- a/src/libostree/ostree-repo-static-delta-core.c +++ b/src/libostree/ostree-repo-static-delta-core.c @@ -73,99 +73,89 @@ ostree_repo_list_static_delta_names (OstreeRepo *self, GCancellable *cancellable, GError **error) { - g_autoptr(GPtrArray) ret_deltas = NULL; - glnx_fd_close int dfd = -1; + g_autoptr(GPtrArray) ret_deltas = g_ptr_array_new_with_free_func (g_free); - ret_deltas = g_ptr_array_new_with_free_func (g_free); - - dfd = glnx_opendirat_with_errno (self->repo_dir_fd, "deltas", TRUE); - if (dfd < 0) + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, "deltas", &dfd_iter, + &exists, error)) + return FALSE; + if (!exists) { - if (errno != ENOENT) - { - glnx_set_error_from_errno (error); - return FALSE; - } + /* Note early return */ + ot_transfer_out_value (out_deltas, &ret_deltas); + return TRUE; } - else - { - g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; - if (!glnx_dirfd_iterator_init_take_fd (dfd, &dfd_iter, error)) + while (TRUE) + { + g_auto(GLnxDirFdIterator) sub_dfd_iter = { 0, }; + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + if (dent->d_type != DT_DIR) + continue; + + if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE, + &sub_dfd_iter, error)) return FALSE; - dfd = -1; while (TRUE) { - g_auto(GLnxDirFdIterator) sub_dfd_iter = { 0, }; - struct dirent *dent; + struct dirent *sub_dent; + const char *name1; + const char *name2; + g_autofree char *superblock_subpath = NULL; + struct stat stbuf; - if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent, + cancellable, error)) return FALSE; - if (dent == NULL) + if (sub_dent == NULL) break; if (dent->d_type != DT_DIR) continue; - if (!glnx_dirfd_iterator_init_at (dfd_iter.fd, dent->d_name, FALSE, - &sub_dfd_iter, error)) - return FALSE; + name1 = dent->d_name; + name2 = sub_dent->d_name; - while (TRUE) + superblock_subpath = g_strconcat (name2, "/superblock", NULL); + if (fstatat (sub_dfd_iter.fd, superblock_subpath, &stbuf, 0) < 0) { - struct dirent *sub_dent; - const char *name1; - const char *name2; - g_autofree char *superblock_subpath = NULL; - struct stat stbuf; - - if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&sub_dfd_iter, &sub_dent, - cancellable, error)) - return FALSE; - if (sub_dent == NULL) - break; - if (dent->d_type != DT_DIR) - continue; - - name1 = dent->d_name; - name2 = sub_dent->d_name; - - superblock_subpath = g_strconcat (name2, "/superblock", NULL); - if (fstatat (sub_dfd_iter.fd, superblock_subpath, &stbuf, 0) < 0) + if (errno != ENOENT) { - if (errno != ENOENT) - { - glnx_set_error_from_errno (error); - return FALSE; - } + glnx_set_error_from_errno (error); + return FALSE; } - else - { - g_autofree char *buf = g_strconcat (name1, name2, NULL); - GString *out = g_string_new (""); - char checksum[OSTREE_SHA256_STRING_LEN+1]; - guchar csum[OSTREE_SHA256_DIGEST_LEN]; - const char *dash = strchr (buf, '-'); + } + else + { + g_autofree char *buf = g_strconcat (name1, name2, NULL); + GString *out = g_string_new (""); + char checksum[OSTREE_SHA256_STRING_LEN+1]; + guchar csum[OSTREE_SHA256_DIGEST_LEN]; + const char *dash = strchr (buf, '-'); - ostree_checksum_b64_inplace_to_bytes (buf, csum); + ostree_checksum_b64_inplace_to_bytes (buf, csum); + ostree_checksum_inplace_from_bytes (csum, checksum); + g_string_append (out, checksum); + if (dash) + { + g_string_append_c (out, '-'); + ostree_checksum_b64_inplace_to_bytes (dash+1, csum); ostree_checksum_inplace_from_bytes (csum, checksum); g_string_append (out, checksum); - if (dash) - { - g_string_append_c (out, '-'); - ostree_checksum_b64_inplace_to_bytes (dash+1, csum); - ostree_checksum_inplace_from_bytes (csum, checksum); - g_string_append (out, checksum); - } - - g_ptr_array_add (ret_deltas, g_string_free (out, FALSE)); } + + g_ptr_array_add (ret_deltas, g_string_free (out, FALSE)); } } } - if (out_deltas) - *out_deltas = g_steal_pointer (&ret_deltas); + ot_transfer_out_value (out_deltas, &ret_deltas); return TRUE; } diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index c8a12543..2ef64ec0 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -32,6 +32,7 @@ #include #include "ostree-core-private.h" +#include "ostree-remote-private.h" #include "ostree-repo-private.h" #include "ostree-repo-file.h" #include "ostree-repo-file-enumerator.h" @@ -104,94 +105,10 @@ G_DEFINE_TYPE (OstreeRepo, ostree_repo, G_TYPE_OBJECT) #define SYSCONF_REMOTES SHORTENED_SYSCONFDIR "/ostree/remotes.d" -typedef struct { - volatile int ref_count; - char *name; - char *group; /* group name in options */ - char *keyring; /* keyring name (NAME.trustedkeys.gpg) */ - GFile *file; /* NULL if remote defined in repo/config */ - GKeyFile *options; -} OstreeRemote; - -static OstreeRemote * -ost_remote_new (void) -{ - OstreeRemote *remote; - - remote = g_slice_new0 (OstreeRemote); - remote->ref_count = 1; - remote->options = g_key_file_new (); - - return remote; -} - -static OstreeRemote * -ost_remote_new_from_keyfile (GKeyFile *keyfile, - const gchar *group) -{ - g_autoptr(GMatchInfo) match = NULL; - OstreeRemote *remote; - - static gsize regex_initialized; - static GRegex *regex; - - if (g_once_init_enter (®ex_initialized)) - { - regex = g_regex_new ("^remote \"(.+)\"$", 0, 0, NULL); - g_assert (regex); - g_once_init_leave (®ex_initialized, 1); - } - - /* Sanity check */ - g_return_val_if_fail (g_key_file_has_group (keyfile, group), NULL); - - /* If group name doesn't fit the pattern, fail. */ - if (!g_regex_match (regex, group, 0, &match)) - return NULL; - - remote = ost_remote_new (); - remote->name = g_match_info_fetch (match, 1); - remote->group = g_strdup (group); - remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", remote->name); - - ot_keyfile_copy_group (keyfile, remote->options, group); - - return remote; -} - -static OstreeRemote * -ost_remote_ref (OstreeRemote *remote) -{ - gint refcount; - g_return_val_if_fail (remote != NULL, NULL); - refcount = g_atomic_int_add (&remote->ref_count, 1); - g_assert (refcount > 0); - return remote; -} - -static void -ost_remote_unref (OstreeRemote *remote) -{ - g_return_if_fail (remote != NULL); - g_return_if_fail (remote->ref_count > 0); - - if (g_atomic_int_dec_and_test (&remote->ref_count)) - { - g_clear_pointer (&remote->name, g_free); - g_clear_pointer (&remote->group, g_free); - g_clear_pointer (&remote->keyring, g_free); - g_clear_object (&remote->file); - g_clear_pointer (&remote->options, g_key_file_free); - g_slice_free (OstreeRemote, remote); - } -} - -G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeRemote, ost_remote_unref) - -static OstreeRemote * -ost_repo_get_remote (OstreeRepo *self, - const char *name, - GError **error) +OstreeRemote * +_ostree_repo_get_remote (OstreeRepo *self, + const char *name, + GError **error) { OstreeRemote *remote = NULL; @@ -202,7 +119,7 @@ ost_repo_get_remote (OstreeRepo *self, remote = g_hash_table_lookup (self->remotes, name); if (remote != NULL) - ost_remote_ref (remote); + ostree_remote_ref (remote); else g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Remote \"%s\" not found", name); @@ -212,19 +129,19 @@ ost_repo_get_remote (OstreeRepo *self, return remote; } -static OstreeRemote * -ost_repo_get_remote_inherited (OstreeRepo *self, - const char *name, - GError **error) +OstreeRemote * +_ostree_repo_get_remote_inherited (OstreeRepo *self, + const char *name, + GError **error) { g_autoptr(OstreeRemote) remote = NULL; g_autoptr(GError) temp_error = NULL; - remote = ost_repo_get_remote (self, name, &temp_error); + remote = _ostree_repo_get_remote (self, name, &temp_error); if (remote == NULL) { if (self->parent_repo != NULL) - return ost_repo_get_remote_inherited (self->parent_repo, name, error); + return _ostree_repo_get_remote_inherited (self->parent_repo, name, error); g_propagate_error (error, g_steal_pointer (&temp_error)); return NULL; @@ -233,9 +150,9 @@ ost_repo_get_remote_inherited (OstreeRepo *self, return g_steal_pointer (&remote); } -static void -ost_repo_add_remote (OstreeRepo *self, - OstreeRemote *remote) +void +_ostree_repo_add_remote (OstreeRepo *self, + OstreeRemote *remote) { g_return_if_fail (self != NULL); g_return_if_fail (remote != NULL); @@ -243,7 +160,7 @@ ost_repo_add_remote (OstreeRepo *self, g_mutex_lock (&self->remotes_lock); - g_hash_table_replace (self->remotes, remote->name, ost_remote_ref (remote)); + g_hash_table_replace (self->remotes, remote->name, ostree_remote_ref (remote)); g_mutex_unlock (&self->remotes_lock); } @@ -308,7 +225,7 @@ ostree_repo_get_remote_option (OstreeRepo *self, return TRUE; } - remote = ost_repo_get_remote (self, remote_name, &temp_error); + remote = _ostree_repo_get_remote (self, remote_name, &temp_error); if (remote != NULL) { value = g_key_file_get_string (remote->options, remote->group, option_name, &temp_error); @@ -385,7 +302,7 @@ ostree_repo_get_remote_list_option (OstreeRepo *self, return TRUE; } - remote = ost_repo_get_remote (self, remote_name, &temp_error); + remote = _ostree_repo_get_remote (self, remote_name, &temp_error); if (remote != NULL) { value = g_key_file_get_string_list (remote->options, @@ -461,7 +378,7 @@ ostree_repo_get_remote_boolean_option (OstreeRepo *self, return TRUE; } - remote = ost_repo_get_remote (self, remote_name, &temp_error); + remote = _ostree_repo_get_remote (self, remote_name, &temp_error); if (remote != NULL) { value = g_key_file_get_boolean (remote->options, remote->group, option_name, &temp_error); @@ -517,7 +434,6 @@ ostree_repo_finalize (GObject *object) (void) close (self->commit_stagedir_fd); g_free (self->commit_stagedir_name); glnx_release_lock_file (&self->commit_stagedir_lock); - g_clear_object (&self->tmp_dir); if (self->tmp_dir_fd != -1) (void) close (self->tmp_dir_fd); if (self->cache_dir_fd != -1) @@ -536,10 +452,9 @@ ostree_repo_finalize (GObject *object) if (self->config) g_key_file_free (self->config); g_clear_pointer (&self->txn_refs, g_hash_table_destroy); - g_clear_pointer (&self->cached_meta_indexes, (GDestroyNotify) g_ptr_array_unref); - g_clear_pointer (&self->cached_content_indexes, (GDestroyNotify) g_ptr_array_unref); g_clear_error (&self->writable_error); g_clear_pointer (&self->object_sizes, (GDestroyNotify) g_hash_table_unref); + g_clear_pointer (&self->dirmeta_cache, (GDestroyNotify) g_hash_table_unref); g_mutex_clear (&self->cache_lock); g_mutex_clear (&self->txn_stats_lock); @@ -606,8 +521,6 @@ ostree_repo_constructed (GObject *object) g_assert (self->repodir != NULL); - self->tmp_dir = g_file_resolve_relative_path (self->repodir, "tmp"); - /* Ensure the "sysroot-path" property is set. */ if (self->sysroot_dir == NULL) self->sysroot_dir = g_object_ref (_ostree_get_default_sysroot_path ()); @@ -696,7 +609,7 @@ ostree_repo_init (OstreeRepo *self) self->remotes = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) NULL, - (GDestroyNotify) ost_remote_unref); + (GDestroyNotify) ostree_remote_unref); g_mutex_init (&self->remotes_lock); self->repo_dir_fd = -1; @@ -956,7 +869,7 @@ impl_repo_remote_add (OstreeRepo *self, if (strchr (name, '/') != NULL) return glnx_throw (error, "Invalid character '/' in remote name: %s", name); - g_autoptr(OstreeRemote) remote = ost_repo_get_remote (self, name, NULL); + g_autoptr(OstreeRemote) remote = _ostree_repo_get_remote (self, name, NULL); if (remote != NULL && if_not_exists) { /* Note early return */ @@ -969,7 +882,7 @@ impl_repo_remote_add (OstreeRepo *self, name, remote->file ? gs_file_get_path_cached (remote->file) : "(in config)"); } - remote = ost_remote_new (); + remote = ostree_remote_new (); remote->name = g_strdup (name); remote->group = g_strdup_printf ("remote \"%s\"", name); remote->keyring = g_strdup_printf ("%s.trustedkeys.gpg", name); @@ -1040,7 +953,7 @@ impl_repo_remote_add (OstreeRepo *self, return FALSE; } - ost_repo_add_remote (self, remote); + _ostree_repo_add_remote (self, remote); return TRUE; } @@ -1091,7 +1004,7 @@ impl_repo_remote_delete (OstreeRepo *self, g_autoptr(OstreeRemote) remote = NULL; if (if_exists) { - remote = ost_repo_get_remote (self, name, NULL); + remote = _ostree_repo_get_remote (self, name, NULL); if (!remote) { /* Note early return */ @@ -1099,7 +1012,7 @@ impl_repo_remote_delete (OstreeRepo *self, } } else - remote = ost_repo_get_remote (self, name, error); + remote = _ostree_repo_get_remote (self, name, error); if (remote == NULL) return FALSE; @@ -1402,7 +1315,6 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, ot_auto_gpgme_data gpgme_data_t data_buffer = NULL; gpgme_import_result_t import_result; gpgme_import_status_t import_status; - const char *tmp_dir = NULL; g_autofree char *source_tmp_dir = NULL; g_autofree char *target_tmp_dir = NULL; glnx_fd_close int target_temp_fd = -1; @@ -1410,27 +1322,17 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, struct stat stbuf; gpgme_error_t gpg_error; gboolean ret = FALSE; + const GLnxFileCopyFlags copyflags = self->disable_xattrs ? GLNX_FILE_COPY_NOXATTRS : 0; g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); g_return_val_if_fail (name != NULL, FALSE); /* First make sure the remote name is valid. */ - remote = ost_repo_get_remote_inherited (self, name, error); + remote = _ostree_repo_get_remote_inherited (self, name, error); if (remote == NULL) goto out; - /* Use OstreeRepo's "tmp" directory so the keyring files remain - * under one mount point. Necessary for renameat() below. */ - - /* XXX This produces a path under "/proc/self/fd/" which won't - * work in a child process so I had to resort to the GFile. - * I was trying to avoid the GFile so we can get rid of it. - * - * tmp_dir = glnx_fdrel_abspath (self->repo_dir_fd, "tmp"); - */ - tmp_dir = gs_file_get_path_cached (self->tmp_dir); - /* Prepare the source GPGME context. If reading GPG keys from an input * stream, point the OpenPGP engine at a temporary directory and import * the keys to a new pubring.gpg file. If the key data format is ASCII @@ -1444,7 +1346,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, { data_buffer = ot_gpgme_data_input (source_stream); - if (!ot_gpgme_ctx_tmp_home_dir (source_context, tmp_dir, &source_tmp_dir, + if (!ot_gpgme_ctx_tmp_home_dir (source_context, &source_tmp_dir, NULL, cancellable, error)) { g_prefix_error (error, "Unable to configure context: "); @@ -1527,7 +1429,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, goto out; /* No need for an output stream since we copy in a pubring.gpg. */ - if (!ot_gpgme_ctx_tmp_home_dir (target_context, tmp_dir, &target_tmp_dir, + if (!ot_gpgme_ctx_tmp_home_dir (target_context, &target_tmp_dir, NULL, cancellable, error)) { g_prefix_error (error, "Unable to configure context: "); @@ -1542,10 +1444,9 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, if (fstatat (self->repo_dir_fd, remote->keyring, &stbuf, AT_SYMLINK_NOFOLLOW) == 0) { - GLnxFileCopyFlags copyflags = self->disable_xattrs ? GLNX_FILE_COPY_NOXATTRS : 0; if (!glnx_file_copy_at (self->repo_dir_fd, remote->keyring, - &stbuf, target_temp_fd, "pubring.gpg", copyflags, - cancellable, error)) + &stbuf, target_temp_fd, "pubring.gpg", + copyflags, cancellable, error)) { g_prefix_error (error, "Unable to copy remote's keyring: "); goto out; @@ -1627,13 +1528,11 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, /* Import successful; replace the remote's old keyring with the * updated keyring in the target context's temporary directory. */ - - if (renameat (target_temp_fd, "pubring.gpg", - self->repo_dir_fd, remote->keyring) == -1) - { - glnx_set_prefix_error_from_errno (error, "%s", "Unable to rename keyring"); - goto out; - } + if (!glnx_file_copy_at (target_temp_fd, "pubring.gpg", NULL, + self->repo_dir_fd, remote->keyring, + copyflags | GLNX_FILE_COPY_OVERWRITE, + cancellable, error)) + goto out; if (out_imported != NULL) *out_imported = (guint) import_result->imported; @@ -1642,7 +1541,7 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, out: if (remote != NULL) - ost_remote_unref (remote); + ostree_remote_unref (remote); if (source_tmp_dir != NULL) (void) glnx_shutil_rm_rf_at (AT_FDCWD, source_tmp_dir, NULL, NULL); @@ -1875,7 +1774,7 @@ add_remotes_from_keyfile (OstreeRepo *self, { OstreeRemote *remote; - remote = ost_remote_new_from_keyfile (keyfile, groups[ii]); + remote = ostree_remote_new_from_keyfile (keyfile, groups[ii]); if (remote != NULL) { @@ -1906,7 +1805,7 @@ add_remotes_from_keyfile (OstreeRepo *self, out: while (!g_queue_is_empty (&queue)) - ost_remote_unref (g_queue_pop_head (&queue)); + ostree_remote_unref (g_queue_pop_head (&queue)); g_mutex_unlock (&self->remotes_lock); @@ -2365,39 +2264,41 @@ ostree_repo_get_parent (OstreeRepo *self) static gboolean list_loose_objects_at (OstreeRepo *self, GHashTable *inout_objects, - const char *prefix, int dfd, + const char *prefix, const char *commit_starting_with, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - DIR *d = NULL; - struct dirent *dent; GVariant *key, *value; - d = fdopendir (dfd); - if (!d) - { - glnx_set_error_from_errno (error); - goto out; - } + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (dfd, prefix, &dfd_iter, &exists, error)) + return FALSE; + /* Note early return */ + if (!exists) + return TRUE; - while ((dent = readdir (d)) != NULL) + while (TRUE) { + struct dirent *dent; + + if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) + break; + const char *name = dent->d_name; - const char *dot; - OstreeObjectType objtype; - char buf[OSTREE_SHA256_STRING_LEN+1]; - if (strcmp (name, ".") == 0 || strcmp (name, "..") == 0) continue; - dot = strrchr (name, '.'); + const char *dot = strrchr (name, '.'); if (!dot) continue; + OstreeObjectType objtype; if ((self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2 && strcmp (dot, ".filez") == 0) || ((_ostree_repo_mode_is_bare (self->mode)) @@ -2415,6 +2316,8 @@ list_loose_objects_at (OstreeRepo *self, if ((dot - name) != 62) continue; + char buf[OSTREE_SHA256_STRING_LEN+1]; + memcpy (buf, prefix, 2); memcpy (buf + 2, name, 62); buf[sizeof(buf)-1] = '\0'; @@ -2441,11 +2344,7 @@ list_loose_objects_at (OstreeRepo *self, g_variant_ref_sink (value)); } - ret = TRUE; - out: - if (d) - (void) closedir (d); - return ret; + return TRUE; } static gboolean @@ -2455,28 +2354,17 @@ list_loose_objects (OstreeRepo *self, GCancellable *cancellable, GError **error) { - guint c; - int dfd = -1; static const gchar hexchars[] = "0123456789abcdef"; - for (c = 0; c < 256; c++) + for (guint c = 0; c < 256; c++) { char buf[3]; buf[0] = hexchars[c >> 4]; buf[1] = hexchars[c & 0xF]; buf[2] = '\0'; - dfd = ot_opendirat (self->objects_dir_fd, buf, FALSE); - if (dfd == -1) - { - if (errno == ENOENT) - continue; - else - return glnx_throw_errno (error); - } - /* Takes ownership of dfd */ - if (!list_loose_objects_at (self, inout_objects, buf, dfd, - commit_starting_with, - cancellable, error)) + if (!list_loose_objects_at (self, inout_objects, self->objects_dir_fd, buf, + commit_starting_with, + cancellable, error)) return FALSE; } @@ -2502,6 +2390,26 @@ load_metadata_internal (OstreeRepo *self, g_return_val_if_fail (OSTREE_OBJECT_TYPE_IS_META (objtype), FALSE); + /* Special caching for dirmeta objects, since they're commonly referenced many + * times. + */ + const gboolean is_dirmeta_cachable = + (objtype == OSTREE_OBJECT_TYPE_DIR_META && out_variant && !out_stream); + if (is_dirmeta_cachable) + { + GMutex *lock = &self->cache_lock; + g_mutex_lock (lock); + GVariant *cache_hit = NULL; + /* Look it up, if we have a cache */ + if (self->dirmeta_cache) + cache_hit = g_hash_table_lookup (self->dirmeta_cache, sha256); + if (cache_hit) + *out_variant = g_variant_ref (cache_hit); + g_mutex_unlock (lock); + if (cache_hit) + return TRUE; + } + _ostree_loose_path (loose_path_buf, sha256, objtype, self->mode); if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd, @@ -2547,6 +2455,16 @@ load_metadata_internal (OstreeRepo *self, data, TRUE); g_variant_ref_sink (ret_variant); } + + /* Now, let's put it in the cache */ + if (is_dirmeta_cachable) + { + GMutex *lock = &self->cache_lock; + g_mutex_lock (lock); + if (self->dirmeta_cache) + g_hash_table_replace (self->dirmeta_cache, g_strdup (sha256), g_variant_ref (ret_variant)); + g_mutex_unlock (lock); + } } else if (out_stream) { @@ -2584,27 +2502,19 @@ query_info_for_bare_content_object (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; struct stat stbuf; - int res; - g_autoptr(GFileInfo) ret_info = NULL; - do - res = fstatat (self->objects_dir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) + if (TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0) { if (errno == ENOENT) { *out_info = NULL; - ret = TRUE; - goto out; + return TRUE; } - glnx_set_error_from_errno (error); - goto out; + return glnx_throw_errno (error); } - ret_info = _ostree_header_gfile_info_new (stbuf.st_mode, stbuf.st_uid, stbuf.st_gid); + g_autoptr(GFileInfo) ret_info = _ostree_header_gfile_info_new (stbuf.st_mode, stbuf.st_uid, stbuf.st_gid); if (S_ISREG (stbuf.st_mode)) { @@ -2614,20 +2524,13 @@ query_info_for_bare_content_object (OstreeRepo *self, { if (!ot_readlinkat_gfile_info (self->objects_dir_fd, loose_path_buf, ret_info, cancellable, error)) - goto out; + return FALSE; } else - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Not a regular file or symlink: %s", loose_path_buf); - goto out; - } + return glnx_throw (error, "Not a regular file or symlink: %s", loose_path_buf); - ret = TRUE; - if (out_info) - *out_info = g_steal_pointer (&ret_info); - out: - return ret; + ot_transfer_out_value (out_info, &ret_info); + return TRUE; } static GVariant * @@ -2705,16 +2608,14 @@ ostree_repo_load_file (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; gboolean found = FALSE; - OstreeRepoMode repo_mode; g_autoptr(GInputStream) ret_input = NULL; g_autoptr(GFileInfo) ret_file_info = NULL; g_autoptr(GVariant) ret_xattrs = NULL; + + OstreeRepoMode repo_mode = ostree_repo_get_mode (self); + char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; - - repo_mode = ostree_repo_get_mode (self); - _ostree_loose_path (loose_path_buf, checksum, OSTREE_OBJECT_TYPE_FILE, repo_mode); if (repo_mode == OSTREE_REPO_MODE_ARCHIVE_Z2) @@ -2725,29 +2626,29 @@ ostree_repo_load_file (OstreeRepo *self, if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd, error)) - goto out; + return FALSE; if (fd < 0 && self->commit_stagedir_fd != -1) { if (!ot_openat_ignore_enoent (self->commit_stagedir_fd, loose_path_buf, &fd, error)) - goto out; + return FALSE; } if (fd != -1) { tmp_stream = g_unix_input_stream_new (fd, TRUE); fd = -1; /* Transfer ownership */ - + if (!glnx_stream_fstat ((GFileDescriptorBased*) tmp_stream, &stbuf, error)) - goto out; - + return FALSE; + if (!ostree_content_stream_parse (TRUE, tmp_stream, stbuf.st_size, TRUE, out_input ? &ret_input : NULL, &ret_file_info, &ret_xattrs, cancellable, error)) - goto out; + return FALSE; found = TRUE; } @@ -2757,7 +2658,7 @@ ostree_repo_load_file (OstreeRepo *self, if (!query_info_for_bare_content_object (self, loose_path_buf, &ret_file_info, cancellable, error)) - goto out; + return FALSE; if (ret_file_info) { @@ -2770,10 +2671,17 @@ ostree_repo_load_file (OstreeRepo *self, g_autoptr(GBytes) bytes = NULL; glnx_fd_close int fd = -1; - bytes = ot_lgetxattrat (self->objects_dir_fd, loose_path_buf, - "user.ostreemeta", error); + /* In bare-user, symlinks are stored as regular files, so we just + * always do an open, then query the user.ostreemeta xattr for + * more information. + */ + fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC); + if (fd < 0) + return glnx_throw_errno (error); + + bytes = glnx_fgetxattr_bytes (fd, "user.ostreemeta", error); if (bytes == NULL) - goto out; + return FALSE; metadata = g_variant_new_from_bytes (OSTREE_FILEMETA_GVARIANT_FORMAT, bytes, FALSE); @@ -2783,21 +2691,6 @@ ostree_repo_load_file (OstreeRepo *self, mode = g_file_info_get_attribute_uint32 (ret_file_info, "unix::mode"); - /* Optimize this so that we only open the file if we - * need to; symlinks contain their content, and we only - * open regular files if the caller has requested an - * input stream. - */ - if (S_ISLNK (mode) || out_input) - { - fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC); - if (fd < 0) - { - glnx_set_error_from_errno (error); - goto out; - } - } - if (S_ISREG (mode) && out_input) { g_assert (fd != -1); @@ -2818,7 +2711,7 @@ ostree_repo_load_file (OstreeRepo *self, if (!g_input_stream_read_all (target_input, targetbuf, sizeof (targetbuf), &target_size, cancellable, error)) - goto out; + return FALSE; g_file_info_set_symlink_target (ret_file_info, targetbuf); } @@ -2838,10 +2731,7 @@ ostree_repo_load_file (OstreeRepo *self, { fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC); if (fd < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); ret_input = g_unix_input_stream_new (fd, TRUE); fd = -1; /* Transfer ownership */ @@ -2865,10 +2755,7 @@ ostree_repo_load_file (OstreeRepo *self, fd = openat (self->objects_dir_fd, loose_path_buf, O_RDONLY | O_CLOEXEC); if (fd < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); if (out_xattrs) { @@ -2876,7 +2763,7 @@ ostree_repo_load_file (OstreeRepo *self, ret_xattrs = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("(ayay)"), NULL, 0)); else if (!glnx_fd_get_all_xattrs (fd, &ret_xattrs, cancellable, error)) - goto out; + return FALSE; } if (out_input) @@ -2893,7 +2780,7 @@ ostree_repo_load_file (OstreeRepo *self, else if (!glnx_dfd_name_get_all_xattrs (self->objects_dir_fd, loose_path_buf, &ret_xattrs, cancellable, error)) - goto out; + return FALSE; } } } @@ -2908,22 +2795,20 @@ ostree_repo_load_file (OstreeRepo *self, out_file_info ? &ret_file_info : NULL, out_xattrs ? &ret_xattrs : NULL, cancellable, error)) - goto out; + return FALSE; } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Couldn't find file object '%s'", checksum); - goto out; + return FALSE; } } - ret = TRUE; ot_transfer_out_value (out_input, &ret_input); ot_transfer_out_value (out_file_info, &ret_file_info); ot_transfer_out_value (out_xattrs, &ret_xattrs); - out: - return ret; + return TRUE; } /** @@ -2948,7 +2833,6 @@ ostree_repo_load_object_stream (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; guint64 size; g_autoptr(GInputStream) ret_input = NULL; @@ -2957,7 +2841,7 @@ ostree_repo_load_object_stream (OstreeRepo *self, if (!load_metadata_internal (self, objtype, checksum, TRUE, NULL, &ret_input, &size, cancellable, error)) - goto out; + return FALSE; } else { @@ -2967,19 +2851,17 @@ ostree_repo_load_object_stream (OstreeRepo *self, if (!ostree_repo_load_file (self, checksum, &input, &finfo, &xattrs, cancellable, error)) - goto out; + return FALSE; if (!ostree_raw_file_to_content_stream (input, finfo, xattrs, &ret_input, &size, cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; ot_transfer_out_value (out_input, &ret_input); *out_size = size; - out: - return ret; + return TRUE; } /* @@ -2997,41 +2879,34 @@ _ostree_repo_has_loose_object (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - struct stat stbuf; - int res = -1; char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; - _ostree_loose_path (loose_path_buf, checksum, objtype, self->mode); - if (self->commit_stagedir_fd != -1) + gboolean found = FALSE; + /* It's easier to share code if we make this an array */ + const int dfd_searches[] = { self->commit_stagedir_fd, self->objects_dir_fd }; + for (guint i = 0; i < G_N_ELEMENTS (dfd_searches); i++) { - do - res = fstatat (self->commit_stagedir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1 && errno != ENOENT) + int dfd = dfd_searches[i]; + if (dfd == -1) + continue; + struct stat stbuf; + if (TEMP_FAILURE_RETRY (fstatat (dfd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0) { - glnx_set_error_from_errno (error); - goto out; + if (errno == ENOENT) + ; /* Next dfd */ + else + return glnx_throw_errno (error); + } + else + { + found = TRUE; + break; } } - if (res < 0) - { - do - res = fstatat (self->objects_dir_fd, loose_path_buf, &stbuf, AT_SYMLINK_NOFOLLOW); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1 && errno != ENOENT) - { - glnx_set_error_from_errno (error); - goto out; - } - } - - ret = TRUE; - *out_is_stored = (res != -1); -out: - return ret; + *out_is_stored = found; + return TRUE; } /** @@ -3056,12 +2931,11 @@ ostree_repo_has_object (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; gboolean ret_have_object; if (!_ostree_repo_has_loose_object (self, checksum, objtype, &ret_have_object, cancellable, error)) - goto out; + return FALSE; /* In the future, here is where we would also look up in metadata pack files */ @@ -3069,14 +2943,12 @@ ostree_repo_has_object (OstreeRepo *self, { if (!ostree_repo_has_object (self->parent_repo, objtype, checksum, &ret_have_object, cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; if (out_have_object) *out_have_object = ret_have_object; - out: - return ret; + return TRUE; } /** @@ -3098,10 +2970,7 @@ ostree_repo_delete_object (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - int res; char loose_path[_OSTREE_LOOSE_PATH_MAX]; - _ostree_loose_path (loose_path, sha256, objtype, self->mode); if (objtype == OSTREE_OBJECT_TYPE_COMMIT) @@ -3110,27 +2979,15 @@ ostree_repo_delete_object (OstreeRepo *self, _ostree_loose_path (meta_loose, sha256, OSTREE_OBJECT_TYPE_COMMIT_META, self->mode); - do - res = unlinkat (self->objects_dir_fd, meta_loose, 0); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (res == -1) + if (TEMP_FAILURE_RETRY (unlinkat (self->objects_dir_fd, meta_loose, 0)) < 0) { if (G_UNLIKELY (errno != ENOENT)) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "unlinkat(%s)", meta_loose); } } - do - res = unlinkat (self->objects_dir_fd, loose_path, 0); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_prefix_error_from_errno (error, "Deleting object %s.%s", sha256, ostree_object_type_to_string (objtype)); - goto out; - } + 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 the repository is configured to use tombstone commits, create one when deleting a commit. */ if (objtype == OSTREE_OBJECT_TYPE_COMMIT) @@ -3139,7 +2996,7 @@ ostree_repo_delete_object (OstreeRepo *self, GKeyFile *readonly_config = ostree_repo_get_config (self); if (!ot_keyfile_get_boolean_with_default (readonly_config, "core", "tombstone-commits", FALSE, &tombstone_commits, error)) - goto out; + return FALSE; if (tombstone_commits) { @@ -3155,13 +3012,11 @@ ostree_repo_delete_object (OstreeRepo *self, variant, cancellable, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -3171,25 +3026,21 @@ copy_detached_metadata (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GVariant) detached_meta = NULL; - if (!ostree_repo_read_commit_detached_metadata (source, checksum, &detached_meta, cancellable, error)) - goto out; + return FALSE; if (detached_meta) { if (!ostree_repo_write_commit_detached_metadata (self, checksum, detached_meta, cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -3201,14 +3052,13 @@ import_one_object_copy (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; guint64 length; g_autoptr(GInputStream) object_stream = NULL; if (!ostree_repo_load_object_stream (source, objtype, checksum, &object_stream, &length, cancellable, error)) - goto out; + return FALSE; if (objtype == OSTREE_OBJECT_TYPE_FILE) { @@ -3217,7 +3067,7 @@ import_one_object_copy (OstreeRepo *self, if (!ostree_repo_write_content_trusted (self, checksum, object_stream, length, cancellable, error)) - goto out; + return FALSE; } else { @@ -3226,7 +3076,7 @@ import_one_object_copy (OstreeRepo *self, object_stream, length, &real_csum, cancellable, error)) - goto out; + return FALSE; } } else @@ -3234,7 +3084,7 @@ import_one_object_copy (OstreeRepo *self, if (objtype == OSTREE_OBJECT_TYPE_COMMIT) { if (!copy_detached_metadata (self, source, checksum, cancellable, error)) - goto out; + return FALSE; } if (trusted) @@ -3242,7 +3092,7 @@ import_one_object_copy (OstreeRepo *self, if (!ostree_repo_write_metadata_stream_trusted (self, objtype, checksum, object_stream, length, cancellable, error)) - goto out; + return FALSE; } else { @@ -3251,19 +3101,17 @@ import_one_object_copy (OstreeRepo *self, if (!ostree_repo_load_variant (source, objtype, checksum, &variant, error)) - goto out; + return FALSE; if (!ostree_repo_write_metadata (self, objtype, checksum, variant, &real_csum, cancellable, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -3275,44 +3123,36 @@ import_one_object_link (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; char loose_path_buf[_OSTREE_LOOSE_PATH_MAX]; - _ostree_loose_path (loose_path_buf, checksum, objtype, self->mode); if (!_ostree_repo_ensure_loose_objdir_at (self->objects_dir_fd, loose_path_buf, cancellable, error)) - goto out; + return FALSE; *out_was_supported = TRUE; if (linkat (source->objects_dir_fd, loose_path_buf, self->objects_dir_fd, loose_path_buf, 0) != 0) { if (errno == EEXIST) - { - ret = TRUE; - } + return TRUE; else if (errno == EMLINK || errno == EXDEV || errno == EPERM) { /* EMLINK, EXDEV and EPERM shouldn't be fatal; we just can't do the * optimization of hardlinking instead of copying. */ *out_was_supported = FALSE; - ret = TRUE; + return TRUE; } else - glnx_set_error_from_errno (error); - - goto out; + return glnx_throw_errno (error); } if (objtype == OSTREE_OBJECT_TYPE_COMMIT) { if (!copy_detached_metadata (self, source, checksum, cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -3335,7 +3175,7 @@ gboolean ostree_repo_import_object_from (OstreeRepo *self, OstreeRepo *source, OstreeObjectType objtype, - const char *checksum, + const char *checksum, GCancellable *cancellable, GError **error) { @@ -3370,7 +3210,6 @@ ostree_repo_import_object_from_with_trust (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; gboolean hardlink_was_supported = FALSE; if (trusted && /* Don't hardlink into untrusted remotes */ @@ -3379,7 +3218,7 @@ ostree_repo_import_object_from_with_trust (OstreeRepo *self, if (!import_one_object_link (self, source, checksum, objtype, &hardlink_was_supported, cancellable, error)) - goto out; + return FALSE; } if (!hardlink_was_supported) @@ -3388,19 +3227,17 @@ ostree_repo_import_object_from_with_trust (OstreeRepo *self, if (!ostree_repo_has_object (self, objtype, checksum, &has_object, cancellable, error)) - goto out; + return FALSE; if (!has_object) { if (!import_one_object_copy (self, source, checksum, objtype, trusted, cancellable, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; + return TRUE; } @@ -3425,15 +3262,10 @@ ostree_repo_query_object_storage_size (OstreeRepo *self, GError **error) { char loose_path[_OSTREE_LOOSE_PATH_MAX]; - int res; - struct stat stbuf; - _ostree_loose_path (loose_path, sha256, objtype, self->mode); - do - res = fstatat (self->objects_dir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) + struct stat stbuf; + if (TEMP_FAILURE_RETRY (fstatat (self->objects_dir_fd, loose_path, &stbuf, AT_SYMLINK_NOFOLLOW)) < 0) return glnx_throw_errno_prefix (error, "Querying object %s.%s", sha256, ostree_object_type_to_string (objtype)); *out_size = stbuf.st_size; @@ -3607,31 +3439,26 @@ ostree_repo_list_commit_objects_starting_with (OstreeRepo *self GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GHashTable) ret_commits = NULL; - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (self->inited, FALSE); - ret_commits = g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, - (GDestroyNotify) g_variant_unref, - (GDestroyNotify) g_variant_unref); + g_autoptr(GHashTable) ret_commits = + g_hash_table_new_full (ostree_hash_object_name, g_variant_equal, + (GDestroyNotify) g_variant_unref, + (GDestroyNotify) g_variant_unref); if (!list_loose_objects (self, ret_commits, start, cancellable, error)) - goto out; - + return FALSE; if (self->parent_repo) { if (!list_loose_objects (self->parent_repo, ret_commits, start, cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; ot_transfer_out_value (out_commits, &ret_commits); - out: - return ret; + return TRUE; } /** @@ -3803,7 +3630,6 @@ void ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress, gpointer user_data) { - GString *buf; g_autofree char *status = NULL; gboolean scanning; guint outstanding_fetches; @@ -3815,37 +3641,46 @@ ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress guint fetched_delta_part_fallbacks; guint total_delta_part_fallbacks; - buf = g_string_new (""); + g_autoptr(GString) buf = g_string_new (""); - status = ostree_async_progress_get_status (progress); - outstanding_fetches = ostree_async_progress_get_uint (progress, "outstanding-fetches"); - outstanding_metadata_fetches = ostree_async_progress_get_uint (progress, "outstanding-metadata-fetches"); - outstanding_writes = ostree_async_progress_get_uint (progress, "outstanding-writes"); - scanning = ostree_async_progress_get_uint (progress, "scanning") == 1; - n_scanned_metadata = ostree_async_progress_get_uint (progress, "scanned-metadata"); - fetched_delta_parts = ostree_async_progress_get_uint (progress, "fetched-delta-parts"); - total_delta_parts = ostree_async_progress_get_uint (progress, "total-delta-parts"); - fetched_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "fetched-delta-fallbacks"); - total_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "total-delta-fallbacks"); + ostree_async_progress_get (progress, + "outstanding-fetches", "u", &outstanding_fetches, + "outstanding-metadata-fetches", "u", &outstanding_metadata_fetches, + "outstanding-writes", "u", &outstanding_writes, + "scanning", "u", &scanning, + "scanned-metadata", "u", &n_scanned_metadata, + "fetched-delta-parts", "u", &fetched_delta_parts, + "total-delta-parts", "u", &total_delta_parts, + "fetched-delta-fallbacks", "u", &fetched_delta_part_fallbacks, + "total-delta-fallbacks", "u", &total_delta_part_fallbacks, + "status", "s", &status, + NULL); - if (status) + if (*status != '\0') { g_string_append (buf, status); } else if (outstanding_fetches) { - guint64 bytes_transferred = ostree_async_progress_get_uint64 (progress, "bytes-transferred"); - guint fetched = ostree_async_progress_get_uint (progress, "fetched"); - guint metadata_fetched = ostree_async_progress_get_uint (progress, "metadata-fetched"); - guint requested = ostree_async_progress_get_uint (progress, "requested"); - guint64 start_time = ostree_async_progress_get_uint64 (progress, "start-time"); - guint64 total_delta_part_size = ostree_async_progress_get_uint64 (progress, "total-delta-part-size"); + guint64 bytes_transferred, start_time, total_delta_part_size; + guint fetched, metadata_fetched, requested; guint64 current_time = g_get_monotonic_time (); - g_autofree char *formatted_bytes_transferred = - g_format_size_full (bytes_transferred, 0); + g_autofree char *formatted_bytes_transferred = NULL; g_autofree char *formatted_bytes_sec = NULL; guint64 bytes_sec; + /* Note: This is not atomic wrt the above getter call. */ + ostree_async_progress_get (progress, + "bytes-transferred", "t", &bytes_transferred, + "fetched", "u", &fetched, + "metadata-fetched", "u", &metadata_fetched, + "requested", "u", &requested, + "start-time", "t", &start_time, + "total-delta-part-size", "t", &total_delta_part_size, + NULL); + + formatted_bytes_transferred = g_format_size_full (bytes_transferred, 0); + /* Ignore the first second, or when we haven't transferred any * data, since those could cause divide by zero below. */ @@ -3915,8 +3750,6 @@ ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress } glnx_console_text (buf->str); - - g_string_free (buf, TRUE); } /** @@ -3936,29 +3769,25 @@ ostree_repo_append_gpg_signature (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GVariant) metadata = NULL; - g_autoptr(GVariant) new_metadata = NULL; - if (!ostree_repo_read_commit_detached_metadata (self, commit_checksum, &metadata, cancellable, error)) - goto out; + return FALSE; - new_metadata = _ostree_detached_metadata_append_gpg_sig (metadata, signature_bytes); + g_autoptr(GVariant) new_metadata = + _ostree_detached_metadata_append_gpg_sig (metadata, signature_bytes); if (!ostree_repo_write_commit_detached_metadata (self, commit_checksum, new_metadata, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -4078,77 +3907,64 @@ ostree_repo_sign_commit (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GBytes) commit_data = NULL; g_autoptr(GBytes) signature = NULL; - g_autoptr(GVariant) commit_variant = NULL; - g_autoptr(GVariant) old_metadata = NULL; - g_autoptr(GVariant) new_metadata = NULL; - glnx_unref_object OstreeGpgVerifyResult *result = NULL; - GError *local_error = NULL; + g_autoptr(GVariant) commit_variant = NULL; 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 (error, "Failed to read commit"); + g_autoptr(GVariant) old_metadata = NULL; if (!ostree_repo_read_commit_detached_metadata (self, commit_checksum, &old_metadata, cancellable, error)) - { - g_prefix_error (error, "Failed to read detached metadata: "); - goto out; - } + return glnx_prefix_error (error, "Failed to read detached metadata"); commit_data = g_variant_get_data_as_bytes (commit_variant); /* 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. */ - result = _ostree_repo_gpg_verify_with_metadata (self, - commit_data, - old_metadata, - NULL, NULL, NULL, - cancellable, - &local_error); - - /* "Not found" just means the commit is not yet signed. That's okay. */ - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + g_autoptr(GError) local_error = NULL; + glnx_unref_object OstreeGpgVerifyResult *result + =_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata, + NULL, NULL, NULL, + cancellable, &local_error); + if (!result) { - g_clear_error (&local_error); - } - else if (local_error != NULL) - { - g_propagate_error (error, local_error); - goto out; + /* "Not found" just means the commit is not yet signed. That's okay. */ + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + { + g_clear_error (&local_error); + } + else + return g_propagate_error (error, g_steal_pointer (&local_error)), FALSE; } else if (ostree_gpg_verify_result_lookup (result, key_id, NULL)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS, "Commit is already signed with GPG key %s", key_id); - goto out; + return FALSE; } if (!sign_data (self, commit_data, key_id, homedir, &signature, cancellable, error)) - goto out; + return FALSE; - new_metadata = _ostree_detached_metadata_append_gpg_sig (old_metadata, signature); + g_autoptr(GVariant) new_metadata = + _ostree_detached_metadata_append_gpg_sig (old_metadata, signature); if (!ostree_repo_write_commit_detached_metadata (self, commit_checksum, new_metadata, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; -out: - return ret; + return TRUE; } /** @@ -4172,8 +3988,9 @@ ostree_repo_sign_delta (OstreeRepo *self, const gchar *homedir, GCancellable *cancellable, GError **error) -{ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "ostree_repo_sign_delta is deprecated"); +{ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "ostree_repo_sign_delta is deprecated"); return FALSE; } @@ -4194,34 +4011,29 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GBytes) summary_data = NULL; - g_autoptr(GVariant) existing_signatures = NULL; - g_autoptr(GVariant) new_metadata = NULL; - g_autoptr(GVariant) normalized = NULL; - guint i; - - summary_data = ot_file_mapat_bytes (self->repo_dir_fd, "summary", error); + g_autoptr(GBytes) summary_data = ot_file_mapat_bytes (self->repo_dir_fd, "summary", error); if (!summary_data) - goto out; + return FALSE; + g_autoptr(GVariant) existing_signatures = NULL; if (!ot_util_variant_map_at (self->repo_dir_fd, "summary.sig", G_VARIANT_TYPE (OSTREE_SUMMARY_SIG_GVARIANT_STRING), OT_VARIANT_MAP_ALLOW_NOENT, &existing_signatures, error)) - goto out; + return FALSE; - for (i = 0; key_id[i]; i++) + g_autoptr(GVariant) new_metadata = NULL; + for (guint i = 0; key_id[i]; i++) { g_autoptr(GBytes) signature_data = NULL; if (!sign_data (self, summary_data, key_id[i], homedir, &signature_data, cancellable, error)) - goto out; + return FALSE; new_metadata = _ostree_detached_metadata_append_gpg_sig (existing_signatures, signature_data); } - normalized = g_variant_get_normal_form (new_metadata); + g_autoptr(GVariant) normalized = g_variant_get_normal_form (new_metadata); if (!_ostree_repo_file_replace_contents (self, self->repo_dir_fd, @@ -4229,11 +4041,9 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self, g_variant_get_data (normalized), g_variant_get_size (normalized), cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } /* Special remote for _ostree_repo_gpg_verify_with_metadata() */ @@ -4297,7 +4107,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, OstreeRemote *remote; g_autoptr(GFile) file = NULL; - remote = ost_repo_get_remote_inherited (self, remote_name, error); + remote = _ostree_repo_get_remote_inherited (self, remote_name, error); if (remote == NULL) return NULL; @@ -4316,7 +4126,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, if (gpgkeypath) _ostree_gpg_verifier_add_key_ascii_file (verifier, gpgkeypath); - ost_remote_unref (remote); + ostree_remote_unref (remote); } if (add_global_keyring_dir) @@ -4647,6 +4457,10 @@ ostree_repo_verify_summary (OstreeRepo *self, * An OSTree repository can contain a high level "summary" file that * describes the available branches and other metadata. * + * If the timetable for making commits and updating the summary file is fairly + * regular, setting the `ostree.summary.expires` key in @additional_metadata + * will aid clients in working out when to check for updates. + * * It is regenerated automatically after a commit if * `core/commit-update-summary` is set. */ @@ -4656,32 +4470,26 @@ ostree_repo_regenerate_summary (OstreeRepo *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GHashTable) refs = NULL; - g_autoptr(GVariantBuilder) refs_builder = NULL; - g_autoptr(GVariant) summary = NULL; - GList *ordered_keys = NULL; - GList *iter = NULL; - g_auto(GVariantDict) additional_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER; - if (!ostree_repo_list_refs (self, NULL, &refs, cancellable, error)) - goto out; + return FALSE; + g_auto(GVariantDict) additional_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER; g_variant_dict_init (&additional_metadata_builder, additional_metadata); - refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(s(taya{sv}))")); + g_autoptr(GVariantBuilder) refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(s(taya{sv}))")); - ordered_keys = g_hash_table_get_keys (refs); + g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs); ordered_keys = g_list_sort (ordered_keys, (GCompareFunc)strcmp); - for (iter = ordered_keys; iter; iter = iter->next) + for (GList *iter = ordered_keys; iter; iter = iter->next) { const char *ref = iter->data; const char *commit = g_hash_table_lookup (refs, ref); - g_autofree char *remotename = NULL; - g_autoptr(GVariant) commit_obj = NULL; + g_auto(GVariantDict) commit_metadata_builder = OT_VARIANT_BUILDER_INITIALIZER; g_assert (commit); + g_autofree char *remotename = NULL; if (!ostree_parse_refspec (ref, &remotename, NULL, NULL)) g_assert_not_reached (); @@ -4689,55 +4497,59 @@ ostree_repo_regenerate_summary (OstreeRepo *self, if (remotename != NULL) continue; + g_autoptr(GVariant) commit_obj = NULL; if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, commit, &commit_obj, error)) - goto out; + return FALSE; - g_variant_builder_add_value (refs_builder, + g_variant_dict_init (&commit_metadata_builder, NULL); + + /* Forward the commit’s timestamp if it’s valid. */ + guint64 commit_timestamp = ostree_commit_get_timestamp (commit_obj); + g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (commit_timestamp); + + if (dt != NULL) + g_variant_dict_insert_value (&commit_metadata_builder, OSTREE_COMMIT_TIMESTAMP, + g_variant_new_uint64 (GUINT64_TO_BE (commit_timestamp))); + + g_variant_builder_add_value (refs_builder, g_variant_new ("(s(t@ay@a{sv}))", ref, (guint64) g_variant_get_size (commit_obj), ostree_checksum_to_bytes_v (commit), - ot_gvariant_new_empty_string_dict ())); + g_variant_dict_end (&commit_metadata_builder))); } { - guint i; g_autoptr(GPtrArray) delta_names = NULL; g_auto(GVariantDict) deltas_builder = OT_VARIANT_BUILDER_INITIALIZER; if (!ostree_repo_list_static_delta_names (self, &delta_names, cancellable, error)) - goto out; + return FALSE; g_variant_dict_init (&deltas_builder, NULL); - for (i = 0; i < delta_names->len; i++) + for (guint i = 0; i < delta_names->len; i++) { g_autofree char *from = NULL; g_autofree char *to = NULL; - g_autofree guchar *csum = NULL; - g_autofree char *superblock = NULL; - glnx_fd_close int superblock_file_fd = -1; - g_autoptr(GInputStream) in_stream = NULL; - if (!_ostree_parse_delta_name (delta_names->pdata[i], &from, &to, error)) - goto out; + return FALSE; - superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to); - superblock_file_fd = openat (self->repo_dir_fd, superblock, O_RDONLY | O_CLOEXEC); + g_autofree char *superblock = _ostree_get_relative_static_delta_superblock_path ((from && from[0]) ? from : NULL, to); + glnx_fd_close int superblock_file_fd = openat (self->repo_dir_fd, superblock, O_RDONLY | O_CLOEXEC); if (superblock_file_fd == -1) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); - in_stream = g_unix_input_stream_new (superblock_file_fd, TRUE); + g_autoptr(GInputStream) in_stream = g_unix_input_stream_new (superblock_file_fd, FALSE); if (!in_stream) - goto out; + return FALSE; + superblock_file_fd = -1; /* Transfer ownership */ + g_autofree guchar *csum = NULL; if (!ot_gio_checksum_stream (in_stream, &csum, cancellable, error)) - goto out; + return FALSE; g_variant_dict_insert_value (&deltas_builder, delta_names->pdata[i], ot_gvariant_new_bytearray (csum, 32)); } @@ -4745,6 +4557,12 @@ ostree_repo_regenerate_summary (OstreeRepo *self, g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_STATIC_DELTAS, g_variant_dict_end (&deltas_builder)); } + { + g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_LAST_MODIFIED, + g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC))); + } + + g_autoptr(GVariant) summary = NULL; { g_autoptr(GVariantBuilder) summary_builder = g_variant_builder_new (OSTREE_SUMMARY_GVARIANT_FORMAT); @@ -4762,22 +4580,15 @@ ostree_repo_regenerate_summary (OstreeRepo *self, g_variant_get_size (summary), cancellable, error)) - goto out; + return FALSE; if (unlinkat (self->repo_dir_fd, "summary.sig", 0) < 0) { if (errno != ENOENT) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "unlinkat"); } - ret = TRUE; - out: - if (ordered_keys) - g_list_free (ordered_keys); - return ret; + return TRUE; } gboolean @@ -4939,3 +4750,32 @@ _ostree_repo_allocate_tmpdir (int tmpdir_dfd, out: return ret; } + +/* See ostree-repo-private.h for more information about this */ +void +_ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state, + OstreeRepo *repo) +{ + state->repo = g_object_ref (repo); + GMutex *lock = &repo->cache_lock; + g_mutex_lock (lock); + repo->dirmeta_cache_refcount++; + if (repo->dirmeta_cache == NULL) + repo->dirmeta_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); + g_mutex_unlock (lock); + +} + +/* See ostree-repo-private.h for more information about this */ +void +_ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state) +{ + OstreeRepo *repo = state->repo; + GMutex *lock = &repo->cache_lock; + g_mutex_lock (lock); + repo->dirmeta_cache_refcount--; + if (repo->dirmeta_cache_refcount == 0) + g_clear_pointer (&repo->dirmeta_cache, (GDestroyNotify) g_hash_table_unref); + g_mutex_unlock (lock); + g_object_unref (repo); +} diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index 1664d65d..86bed09c 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -767,14 +767,17 @@ typedef struct { gboolean enable_fsync; /* Deprecated */ gboolean process_whiteouts; gboolean no_copy_fallback; - gboolean unused_bools[7]; + gboolean force_copy; /* Since: 2017.6 */ + gboolean unused_bools[6]; const char *subpath; OstreeRepoDevInoCache *devino_to_csum_cache; int unused_ints[6]; - gpointer unused_ptrs[7]; + gpointer unused_ptrs[5]; + OstreeSePolicy *sepolicy; /* Since: 2017.6 */ + const char *sepolicy_prefix; } OstreeRepoCheckoutAtOptions; _OSTREE_PUBLIC diff --git a/src/libostree/ostree-sepolicy-private.h b/src/libostree/ostree-sepolicy-private.h index 55d49eaf..def8ab74 100644 --- a/src/libostree/ostree-sepolicy-private.h +++ b/src/libostree/ostree-sepolicy-private.h @@ -37,5 +37,6 @@ gboolean _ostree_sepolicy_preparefscreatecon (OstreeSepolicyFsCreatecon *con, guint32 mode, GError **error); +GVariant *_ostree_filter_selinux_xattr (GVariant *xattrs); G_END_DECLS diff --git a/src/libostree/ostree-sepolicy.c b/src/libostree/ostree-sepolicy.c index 6063022c..7387ea0f 100644 --- a/src/libostree/ostree-sepolicy.c +++ b/src/libostree/ostree-sepolicy.c @@ -47,8 +47,6 @@ struct OstreeSePolicy { int rootfs_dfd_owned; GFile *path; - gboolean runtime_enabled; - #ifdef HAVE_SELINUX GFile *selinux_policy_root; struct selabel_handle *selinux_hnd; @@ -198,24 +196,21 @@ get_policy_checksum (char **out_csum, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *binary_policy_path = selinux_binary_policy_path (); const char *binfile_prefix = glnx_basename (binary_policy_path); g_autofree char *bindir_path = g_path_get_dirname (binary_policy_path); - glnx_fd_close int bindir_dfd = -1; g_autofree char *best_policy = NULL; int best_version = 0; - g_auto(GLnxDirFdIterator) dfd_iter = { 0,}; - + glnx_fd_close int bindir_dfd = -1; if (!glnx_opendirat (AT_FDCWD, bindir_path, TRUE, &bindir_dfd, error)) - goto out; + return FALSE; + g_auto(GLnxDirFdIterator) dfd_iter = { 0,}; if (!glnx_dirfd_iterator_init_at (bindir_dfd, ".", FALSE, &dfd_iter, error)) - goto out; + return FALSE; while (TRUE) { @@ -223,8 +218,7 @@ get_policy_checksum (char **out_csum, if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) - goto out; - + return FALSE; if (dent == NULL) break; @@ -259,44 +253,54 @@ get_policy_checksum (char **out_csum, } if (!best_policy) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Could not find binary policy file"); - goto out; - } + return glnx_throw (error, "Could not find binary policy file"); *out_csum = ot_checksum_file_at (bindir_dfd, best_policy, G_CHECKSUM_SHA256, cancellable, error); if (*out_csum == NULL) - goto out; + return FALSE; - ret = TRUE; -out: - return ret; + return TRUE; } #endif + +/* Workaround for http://marc.info/?l=selinux&m=149323809332417&w=2 */ +#ifdef HAVE_SELINUX +static gboolean +cached_is_selinux_enabled (void) +{ + static gsize initialized; + static gboolean cached_enabled; + if (g_once_init_enter (&initialized)) + { + cached_enabled = is_selinux_enabled () == 1; + g_once_init_leave (&initialized, 1); + } + return cached_enabled; +} +#endif + static gboolean initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { #ifdef HAVE_SELINUX - gboolean ret = FALSE; OstreeSePolicy *self = OSTREE_SEPOLICY (initable); - g_autoptr(GFile) path = NULL; - g_autoptr(GFile) etc_selinux_dir = NULL; - g_autoptr(GFile) policy_config_path = NULL; - g_autoptr(GFile) policy_root = NULL; - g_autoptr(GFileInputStream) filein = NULL; - g_autoptr(GDataInputStream) datain = NULL; gboolean enabled = FALSE; g_autofree char *policytype = NULL; const char *selinux_prefix = "SELINUX="; const char *selinuxtype_prefix = "SELINUXTYPE="; + /* First thing here, call is_selinux_enabled() to prime the cache. See the + * link above for more information why. + */ + (void) cached_is_selinux_enabled (); + /* TODO - use this below */ + g_autoptr(GFile) path = NULL; if (self->rootfs_dfd != -1) path = ot_fdrel_to_gfile (self->rootfs_dfd, "."); else if (self->path) @@ -306,45 +310,44 @@ initable_init (GInitable *initable, /* TODO - use this below */ if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->path), TRUE, &self->rootfs_dfd_owned, error)) - goto out; + return FALSE; self->rootfs_dfd = self->rootfs_dfd_owned; #endif } else g_assert_not_reached (); - etc_selinux_dir = g_file_resolve_relative_path (path, "etc/selinux"); + g_autoptr(GFile) etc_selinux_dir = g_file_resolve_relative_path (path, "etc/selinux"); if (!g_file_query_exists (etc_selinux_dir, NULL)) { g_object_unref (etc_selinux_dir); etc_selinux_dir = g_file_resolve_relative_path (path, "usr/etc/selinux"); } - policy_config_path = g_file_get_child (etc_selinux_dir, "config"); + g_autoptr(GFile) policy_config_path = g_file_get_child (etc_selinux_dir, "config"); + g_autoptr(GFile) policy_root = NULL; if (g_file_query_exists (policy_config_path, NULL)) { - filein = g_file_read (policy_config_path, cancellable, error); - if (!filein) - goto out; + g_autoptr(GFileInputStream) filein = filein = g_file_read (policy_config_path, cancellable, error); - datain = g_data_input_stream_new ((GInputStream*)filein); + if (!filein) + return FALSE; + + g_autoptr(GDataInputStream) datain = g_data_input_stream_new ((GInputStream*)filein); while (TRUE) { gsize len; - GError *temp_error = NULL; + g_autoptr(GError) temp_error = NULL; g_autofree char *line = g_data_input_stream_read_line_utf8 (datain, &len, cancellable, &temp_error); - + if (temp_error) - { - g_propagate_error (error, temp_error); - goto out; - } + return g_propagate_error (error, g_steal_pointer (&temp_error)), FALSE; if (!line) break; - + if (g_str_has_prefix (line, selinuxtype_prefix)) { policytype = g_strstrip (g_strdup (line + strlen (selinuxtype_prefix))); @@ -362,57 +365,32 @@ initable_init (GInitable *initable, if (enabled) { - self->runtime_enabled = is_selinux_enabled () == 1; + const char *policy_rootpath = gs_file_get_path_cached (policy_root); g_setenv ("LIBSELINUX_DISABLE_PCRE_PRECOMPILED", "1", FALSE); - if (selinux_set_policy_root (gs_file_get_path_cached (policy_root)) != 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "selinux_set_policy_root(%s): %s", - gs_file_get_path_cached (etc_selinux_dir), - strerror (errno)); - goto out; - } + if (selinux_set_policy_root (policy_rootpath) != 0) + return glnx_throw_errno_prefix (error, "selinux_set_policy_root(%s)", policy_rootpath); self->selinux_hnd = selabel_open (SELABEL_CTX_FILE, NULL, 0); if (!self->selinux_hnd) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "With policy root '%s': selabel_open(SELABEL_CTX_FILE): %s", - gs_file_get_path_cached (etc_selinux_dir), - strerror (errno)); - goto out; - } + return glnx_throw_errno_prefix (error, "With policy root '%s': selabel_open(SELABEL_CTX_FILE)", + policy_rootpath); - { - char *con = NULL; - if (selabel_lookup_raw (self->selinux_hnd, &con, "/", 0755) != 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "With policy root '%s': Failed to look up context of /: %s", - gs_file_get_path_cached (etc_selinux_dir), - strerror (errno)); - goto out; - } - freecon (con); - } + char *con = NULL; + if (selabel_lookup_raw (self->selinux_hnd, &con, "/", 0755) != 0) + return glnx_throw_errno_prefix (error, "With policy root '%s': Failed to look up context of /", + policy_rootpath); + freecon (con); if (!get_policy_checksum (&self->selinux_policy_csum, cancellable, error)) - { - g_prefix_error (error, "While calculating SELinux checksum: "); - goto out; - } + return glnx_prefix_error (error, "While calculating SELinux checksum"); self->selinux_policy_name = g_steal_pointer (&policytype); self->selinux_policy_root = g_object_ref (etc_selinux_dir); } - ret = TRUE; - out: - return ret; -#else - return TRUE; #endif + return TRUE; } static void @@ -580,11 +558,7 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self, GError **error) { #ifdef HAVE_SELINUX - gboolean ret = FALSE; g_autoptr(GFileInfo) src_info = NULL; - g_autofree char *label = NULL; - gboolean do_relabel = TRUE; - if (info != NULL) src_info = g_object_ref (info); else @@ -593,9 +567,10 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, cancellable, error); if (!src_info) - goto out; + return FALSE; } + gboolean do_relabel = TRUE; if (flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING) { char *existing_con = NULL; @@ -607,42 +582,31 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self, } } + g_autofree char *label = NULL; if (do_relabel) { - if (!ostree_sepolicy_get_label (self, path, + if (!ostree_sepolicy_get_label (self, path, g_file_info_get_attribute_uint32 (src_info, "unix::mode"), &label, cancellable, error)) - goto out; + return FALSE; if (!label) { if (!(flags & OSTREE_SEPOLICY_RESTORECON_FLAGS_ALLOW_NOLABEL)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No label found for '%s'", path); - goto out; - } + return glnx_throw (error, "No label found for '%s'", path); } else { - int res = lsetfilecon (gs_file_get_path_cached (target), label); - if (res != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + if (lsetfilecon (gs_file_get_path_cached (target), label) < 0) + return glnx_throw_errno_prefix (error, "lsetfilecon"); } } - ret = TRUE; if (out_new_label) *out_new_label = g_steal_pointer (&label); - out: - return ret; -#else - return TRUE; #endif + return TRUE; } /** @@ -660,7 +624,6 @@ ostree_sepolicy_setfscreatecon (OstreeSePolicy *self, GError **error) { #ifdef HAVE_SELINUX - gboolean ret = FALSE; g_autofree char *label = NULL; /* setfscreatecon() will bomb out if the host has SELinux disabled, @@ -669,24 +632,17 @@ ostree_sepolicy_setfscreatecon (OstreeSePolicy *self, * request. To correctly handle the case of disabled host but * enabled target will require nontrivial work. */ - if (!self->runtime_enabled) + if (!cached_is_selinux_enabled ()) return TRUE; if (!ostree_sepolicy_get_label (self, path, mode, &label, NULL, error)) - goto out; + return FALSE; if (setfscreatecon_raw (label) != 0) - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno_prefix (error, "setfscreatecon"); - ret = TRUE; - out: - return ret; -#else - return TRUE; #endif + return TRUE; } /** @@ -730,3 +686,44 @@ _ostree_sepolicy_fscreatecon_clear (OstreeSepolicyFsCreatecon *con) return; ostree_sepolicy_fscreatecon_cleanup (NULL); } + +/* + * Given @xattrs, filter out `security.selinux`, and return + * a new GVariant without it. Supports @xattrs as %NULL to + * mean "no xattrs", and also returns %NULL if no xattrs + * would result (rather than a zero-length array). + */ +GVariant * +_ostree_filter_selinux_xattr (GVariant *xattrs) +{ + if (!xattrs) + return NULL; + + gboolean have_xattrs = FALSE; + GVariantBuilder builder; + guint n = g_variant_n_children (xattrs); + for (guint i = 0; i < n; i++) + { + const char *name = NULL; + g_autoptr(GVariant) value = NULL; + + g_variant_get_child (xattrs, i, "(^&ay@ay)", + &name, &value); + + if (strcmp (name, "security.selinux") == 0) + continue; + /* Initialize builder lazily */ + if (!have_xattrs) + { + have_xattrs = TRUE; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ayay)")); + } + g_variant_builder_add (&builder, "(@ay@ay)", + g_variant_new_bytestring (name), + value); + } + /* Canonicalize zero length to NULL for efficiency */ + if (!have_xattrs) + return NULL; + return g_variant_ref_sink (g_variant_builder_end (&builder)); +} diff --git a/src/libostree/ostree-sysroot-cleanup.c b/src/libostree/ostree-sysroot-cleanup.c index 022654c3..499f20eb 100644 --- a/src/libostree/ostree-sysroot-cleanup.c +++ b/src/libostree/ostree-sysroot-cleanup.c @@ -25,127 +25,87 @@ #include "ostree-sysroot-private.h" +/* @deploydir_dfd: Directory FD for ostree/deploy + * @osname: Target osname + * @inout_deployments: All deployments in this subdir will be appended to this array + */ gboolean -_ostree_sysroot_list_deployment_dirs_for_os (GFile *osdir, +_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd, + const char *osname, GPtrArray *inout_deployments, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *osname = glnx_basename (gs_file_get_path_cached (osdir)); - g_autoptr(GFileEnumerator) dir_enum = NULL; - g_autoptr(GFile) osdeploy_dir = NULL; - GError *temp_error = NULL; - - osdeploy_dir = g_file_get_child (osdir, "deploy"); - - dir_enum = g_file_enumerate_children (osdeploy_dir, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, &temp_error); - if (!dir_enum) - { - if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) - { - g_clear_error (&temp_error); - goto done; - } - else - { - g_propagate_error (error, temp_error); - goto out; - } - } + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + const char *osdeploy_path = glnx_strjoina (osname, "/deploy"); + if (!ot_dfd_iter_init_allow_noent (deploydir_dfd, osdeploy_path, &dfd_iter, &exists, error)) + return FALSE; + if (!exists) + return TRUE; while (TRUE) { - const char *name; - GFileInfo *file_info = NULL; - GFile *child = NULL; - glnx_unref_object OstreeDeployment *deployment = NULL; - g_autofree char *csum = NULL; - gint deployserial; + struct dirent *dent; - if (!g_file_enumerator_iterate (dir_enum, &file_info, &child, - cancellable, error)) - goto out; - if (file_info == NULL) + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) break; - name = g_file_info_get_name (file_info); - - if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) + if (dent->d_type != DT_DIR) continue; - if (!_ostree_sysroot_parse_deploy_path_name (name, &csum, &deployserial, error)) - goto out; - - deployment = ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1); - g_ptr_array_add (inout_deployments, g_object_ref (deployment)); + g_autofree char *csum = NULL; + gint deployserial; + if (!_ostree_sysroot_parse_deploy_path_name (dent->d_name, &csum, &deployserial, error)) + return FALSE; + + g_ptr_array_add (inout_deployments, ostree_deployment_new (-1, osname, csum, deployserial, NULL, -1)); } - done: - ret = TRUE; - out: - return ret; + return TRUE; } +/* Return in @out_deployments a new array of OstreeDeployment loaded from the + * filesystem state. + */ static gboolean list_all_deployment_directories (OstreeSysroot *self, GPtrArray **out_deployments, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GFileEnumerator) dir_enum = NULL; - g_autoptr(GFile) deploydir = NULL; - g_autoptr(GPtrArray) ret_deployments = NULL; - GError *temp_error = NULL; + g_autoptr(GPtrArray) ret_deployments = + g_ptr_array_new_with_free_func (g_object_unref); - deploydir = g_file_resolve_relative_path (self->path, "ostree/deploy"); - - ret_deployments = g_ptr_array_new_with_free_func (g_object_unref); - - dir_enum = g_file_enumerate_children (deploydir, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, &temp_error); - if (!dir_enum) - { - if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) - { - g_clear_error (&temp_error); - goto done; - } - else - { - g_propagate_error (error, temp_error); - goto out; - } - } + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + gboolean exists; + if (!ot_dfd_iter_init_allow_noent (self->sysroot_fd, "ostree/deploy", &dfd_iter, &exists, error)) + return FALSE; + if (!exists) + return TRUE; while (TRUE) { - GFileInfo *file_info = NULL; - GFile *child = NULL; + struct dirent *dent; - if (!g_file_enumerator_iterate (dir_enum, &file_info, &child, - NULL, error)) - goto out; - if (file_info == NULL) + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) break; - if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY) + if (dent->d_type != DT_DIR) continue; - - if (!_ostree_sysroot_list_deployment_dirs_for_os (child, ret_deployments, + + if (!_ostree_sysroot_list_deployment_dirs_for_os (dfd_iter.fd, dent->d_name, + ret_deployments, cancellable, error)) - goto out; + return FALSE; } - - done: - ret = TRUE; + ot_transfer_out_value (out_deployments, &ret_deployments); - out: - return ret; + return TRUE; } static gboolean @@ -154,7 +114,7 @@ parse_bootdir_name (const char *name, char **out_csum) { const char *lastdash; - + if (out_osname) *out_osname = NULL; if (out_csum) @@ -164,7 +124,7 @@ parse_bootdir_name (const char *name, if (!lastdash) return FALSE; - + if (!ostree_validate_checksum_string (lastdash + 1, NULL)) return FALSE; @@ -183,7 +143,6 @@ list_all_boot_directories (OstreeSysroot *self, GError **error) { gboolean ret = FALSE; - g_autoptr(GFileEnumerator) dir_enum = NULL; g_autoptr(GFile) boot_ostree = NULL; g_autoptr(GPtrArray) ret_bootdirs = NULL; GError *temp_error = NULL; @@ -192,9 +151,10 @@ list_all_boot_directories (OstreeSysroot *self, ret_bootdirs = g_ptr_array_new_with_free_func (g_object_unref); - dir_enum = g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - cancellable, &temp_error); + g_autoptr(GFileEnumerator) dir_enum = + g_file_enumerate_children (boot_ostree, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + cancellable, &temp_error); if (!dir_enum) { if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index ed8c8bca..257a058b 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -255,7 +255,7 @@ ensure_directory_from_template (int orig_etc_fd, g_assert (path != NULL); g_assert (*path != '/' && *path != '\0'); - if (!ot_gopendirat (modified_etc_fd, path, TRUE, &src_dfd, error)) + if (!glnx_opendirat (modified_etc_fd, path, TRUE, &src_dfd, error)) goto out; /* Create with mode 0700, we'll fchmod/fchown later */ @@ -293,7 +293,7 @@ ensure_directory_from_template (int orig_etc_fd, } } - if (!ot_gopendirat (new_etc_fd, path, TRUE, &target_dfd, error)) + if (!glnx_opendirat (new_etc_fd, path, TRUE, &target_dfd, error)) goto out; if (!dirfd_copy_attributes_and_xattrs (modified_etc_fd, path, src_dfd, target_dfd, @@ -767,6 +767,7 @@ selinux_relabel_var_if_needed (OstreeSysroot *sysroot, static gboolean merge_configuration (OstreeSysroot *sysroot, + OstreeRepo *repo, OstreeDeployment *previous_deployment, OstreeDeployment *deployment, int deployment_dfd, @@ -829,19 +830,15 @@ merge_configuration (OstreeSysroot *sysroot, usretc_exists = TRUE; etc_exists = FALSE; } - + if (usretc_exists) { - glnx_fd_close int deployment_usr_dfd = -1; - - if (!glnx_opendirat (deployment_dfd, "usr", TRUE, &deployment_usr_dfd, error)) - goto out; - - /* TODO - set out labels as we copy files */ - g_assert (!etc_exists); - if (!copy_dir_recurse (deployment_usr_dfd, deployment_dfd, "etc", - sysroot->debug_flags, cancellable, error)) - goto out; + /* We need copies of /etc from /usr/etc (so admins can use vi), and if + * SELinux is enabled, we need to relabel. + */ + OstreeRepoCheckoutAtOptions etc_co_opts = { .force_copy = TRUE, + .subpath = "/usr/etc", + .sepolicy_prefix = "/etc"}; /* Here, we initialize SELinux policy from the /usr/etc inside * the root - this is before we've finalized the configuration @@ -849,13 +846,15 @@ merge_configuration (OstreeSysroot *sysroot, sepolicy = ostree_sepolicy_new (deployment_path, cancellable, error); if (!sepolicy) goto out; - if (ostree_sepolicy_get_name (sepolicy) != NULL) - { - if (!selinux_relabel_dir (sysroot, sepolicy, deployment_etc_path, "etc", + etc_co_opts.sepolicy = sepolicy; + + /* Copy usr/etc → etc */ + if (!ostree_repo_checkout_at (repo, &etc_co_opts, + deployment_dfd, "etc", + ostree_deployment_get_csum (deployment), cancellable, error)) - goto out; - } + goto out; } if (source_etc_path) @@ -1307,7 +1306,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, contents = glnx_file_get_contents_utf8_at (deployment_dfd, "etc/os-release", NULL, cancellable, error); if (!contents) - return g_prefix_error (error, "Reading /etc/os-release: "), FALSE; + return glnx_prefix_error (error, "Reading /etc/os-release"); } } else @@ -1315,7 +1314,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, contents = glnx_file_get_contents_utf8_at (deployment_dfd, "usr/lib/os-release", NULL, cancellable, error); if (!contents) - return g_prefix_error (error, "Reading /usr/lib/os-release: "), FALSE; + return glnx_prefix_error (error, "Reading /usr/lib/os-release"); } g_autoptr(GHashTable) osrelease_values = parse_os_release (contents, "\n"); @@ -1380,6 +1379,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, val = ostree_bootconfig_parser_get (bootconfig, "options"); + /* Note this is parsed in ostree-impl-system-generator.c */ g_autofree char *ostree_kernel_arg = g_strdup_printf ("ostree=/ostree/boot.%d/%s/%s/%d", new_bootversion, osname, bootcsum, ostree_deployment_get_bootserial (deployment)); @@ -1899,19 +1899,20 @@ allocate_deployserial (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - guint i; int new_deployserial = 0; g_autoptr(GPtrArray) tmp_current_deployments = g_ptr_array_new_with_free_func (g_object_unref); - const char *osdir_name = glnx_strjoina ("ostree/deploy/", osname); - g_autoptr(GFile) osdir = g_file_resolve_relative_path (self->path, osdir_name); + glnx_fd_close int deploy_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, "ostree/deploy", TRUE, &deploy_dfd, error)) + return FALSE; - if (!_ostree_sysroot_list_deployment_dirs_for_os (osdir, tmp_current_deployments, + if (!_ostree_sysroot_list_deployment_dirs_for_os (deploy_dfd, osname, + tmp_current_deployments, cancellable, error)) return FALSE; - for (i = 0; i < tmp_current_deployments->len; i++) + for (guint i = 0; i < tmp_current_deployments->len; i++) { OstreeDeployment *deployment = tmp_current_deployments->pdata[i]; @@ -2017,7 +2018,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, ostree_deployment_set_bootconfig (new_deployment, bootconfig); glnx_unref_object OstreeSePolicy *sepolicy = NULL; - if (!merge_configuration (self, merge_deployment, new_deployment, + if (!merge_configuration (self, repo, merge_deployment, new_deployment, deployment_dfd, &sepolicy, cancellable, error)) diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 4bc7802b..26cfd363 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -87,7 +87,8 @@ _ostree_sysroot_parse_deploy_path_name (const char *name, GError **error); gboolean -_ostree_sysroot_list_deployment_dirs_for_os (GFile *osdir, +_ostree_sysroot_list_deployment_dirs_for_os (int deploydir_dfd, + const char *osname, GPtrArray *inout_deployments, GCancellable *cancellable, GError **error); diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c index 4e7c8bf3..9816b3d6 100644 --- a/src/libostree/ostree-sysroot-upgrader.c +++ b/src/libostree/ostree-sysroot-upgrader.c @@ -22,6 +22,7 @@ #include "otutil.h" +#include "ostree.h" #include "ostree-sysroot-upgrader.h" /** @@ -50,7 +51,7 @@ struct OstreeSysrootUpgrader { char *override_csum; char *new_revision; -}; +}; enum { PROP_0, @@ -70,7 +71,6 @@ parse_refspec (OstreeSysrootUpgrader *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autofree char *origin_refspec = NULL; g_autofree char *unconfigured_state = NULL; g_autofree char *csum = NULL; @@ -82,37 +82,28 @@ parse_refspec (OstreeSysrootUpgrader *self, */ unconfigured_state = g_key_file_get_string (self->origin, "origin", "unconfigured-state", NULL); if (unconfigured_state) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "origin unconfigured-state: %s", unconfigured_state); - goto out; - } + return glnx_throw (error, "origin unconfigured-state: %s", unconfigured_state); } origin_refspec = g_key_file_get_string (self->origin, "origin", "refspec", NULL); if (!origin_refspec) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No origin/refspec in current deployment origin; cannot upgrade via ostree"); - goto out; - } + return glnx_throw (error, "No origin/refspec in current deployment origin; cannot upgrade via ostree"); + g_clear_pointer (&self->origin_remote, g_free); g_clear_pointer (&self->origin_ref, g_free); if (!ostree_parse_refspec (origin_refspec, - &self->origin_remote, + &self->origin_remote, &self->origin_ref, error)) - goto out; + return FALSE; csum = g_key_file_get_string (self->origin, "origin", "override-commit", NULL); if (csum != NULL && !ostree_validate_checksum_string (csum, error)) - goto out; + return FALSE; g_clear_pointer (&self->override_csum, g_free); self->override_csum = g_steal_pointer (&csum); - ret = TRUE; - out: - return ret; + return TRUE; } static gboolean @@ -120,17 +111,12 @@ ostree_sysroot_upgrader_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; OstreeSysrootUpgrader *self = (OstreeSysrootUpgrader*)initable; OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (self->sysroot); if (booted_deployment == NULL && self->osname == NULL) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Not currently booted into an OSTree system and no OS specified"); - goto out; - } + return glnx_throw (error, "Not currently booted into an OSTree system and no OS specified"); if (self->osname == NULL) { @@ -138,37 +124,23 @@ ostree_sysroot_upgrader_initable_init (GInitable *initable, self->osname = g_strdup (ostree_deployment_get_osname (booted_deployment)); } else if (self->osname[0] == '\0') - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid empty osname"); - goto out; - } + return glnx_throw (error, "Invalid empty osname"); - self->merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname); + self->merge_deployment = ostree_sysroot_get_merge_deployment (self->sysroot, self->osname); if (self->merge_deployment == NULL) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No previous deployment for OS '%s'", self->osname); - goto out; - } + return glnx_throw (error, "No previous deployment for OS '%s'", self->osname); self->origin = ostree_deployment_get_origin (self->merge_deployment); if (!self->origin) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No origin known for deployment %s.%d", - ostree_deployment_get_csum (self->merge_deployment), - ostree_deployment_get_deployserial (self->merge_deployment)); - goto out; - } + return glnx_throw (error, "No origin known for deployment %s.%d", + ostree_deployment_get_csum (self->merge_deployment), + ostree_deployment_get_deployserial (self->merge_deployment)); g_key_file_ref (self->origin); if (!parse_refspec (self, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } static void @@ -401,19 +373,15 @@ ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_clear_pointer (&self->origin, g_key_file_unref); if (origin) { self->origin = g_key_file_ref (origin); if (!parse_refspec (self, cancellable, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -447,21 +415,19 @@ ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo, const char *to_rev, GError **error) { - gboolean ret = FALSE; g_autoptr(GVariant) old_commit = NULL; - g_autoptr(GVariant) new_commit = NULL; - if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, from_rev, &old_commit, error)) - goto out; - + return FALSE; + + g_autoptr(GVariant) new_commit = NULL; if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, to_rev, &new_commit, error)) - goto out; + return FALSE; if (ostree_commit_get_timestamp (old_commit) > ostree_commit_get_timestamp (new_commit)) { @@ -470,25 +436,23 @@ ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo, g_autofree char *old_ts_str = NULL; g_autofree char *new_ts_str = NULL; - g_assert (old_ts); - g_assert (new_ts); + if (old_ts == NULL || new_ts == NULL) + return glnx_throw (error, "Upgrade target revision '%s' timestamp (%" G_GINT64_FORMAT ") or current revision '%s' timestamp (%" G_GINT64_FORMAT ") is invalid", + to_rev, ostree_commit_get_timestamp (new_commit), + from_rev, ostree_commit_get_timestamp (old_commit)); + old_ts_str = g_date_time_format (old_ts, "%c"); new_ts_str = g_date_time_format (new_ts, "%c"); g_date_time_unref (old_ts); g_date_time_unref (new_ts); - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit", - to_rev, new_ts_str, from_rev, old_ts_str); - goto out; + return glnx_throw (error, "Upgrade target revision '%s' with timestamp '%s' is chronologically older than current revision '%s' with timestamp '%s'; use --allow-downgrade to permit", + to_rev, new_ts_str, from_rev, old_ts_str); } - ret = TRUE; - out: - return ret; + return TRUE; } - /** * ostree_sysroot_upgrader_pull: * @self: Upgrader @@ -544,8 +508,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; char *refs_to_fetch[] = { NULL, NULL }; const char *from_revision = NULL; g_autofree char *origin_refspec = NULL; @@ -556,7 +519,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, refs_to_fetch[0] = self->origin_ref; if (!ostree_sysroot_get_repo (self->sysroot, &repo, cancellable, error)) - goto out; + return FALSE; if (self->origin_remote) origin_refspec = g_strconcat (self->origin_remote, ":", self->origin_ref, NULL); @@ -572,7 +535,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, if (!ostree_repo_pull_one_dir (repo, self->origin_remote, dir_to_pull, refs_to_fetch, flags, progress, cancellable, error)) - goto out; + return FALSE; if (progress) ostree_async_progress_finish (progress); @@ -586,7 +549,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, self->override_csum, cancellable, error)) - goto out; + return FALSE; self->new_revision = g_strdup (self->override_csum); } @@ -594,7 +557,7 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, { if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE, &self->new_revision, error)) - goto out; + return FALSE; } @@ -613,13 +576,11 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, if (!ostree_sysroot_upgrader_check_timestamps (repo, from_revision, self->new_revision, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -636,9 +597,7 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - glnx_unref_object OstreeDeployment *new_deployment = NULL; - + g_autoptr(OstreeDeployment) new_deployment = NULL; if (!ostree_sysroot_deploy_tree (self->sysroot, self->osname, self->new_revision, self->origin, @@ -646,18 +605,16 @@ ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self, NULL, &new_deployment, cancellable, error)) - goto out; + return FALSE; if (!ostree_sysroot_simple_write_deployment (self->sysroot, self->osname, new_deployment, self->merge_deployment, 0, cancellable, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } GType diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index bdf7376b..e47214c5 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -284,47 +284,33 @@ ostree_sysroot_ensure_initialized (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - struct stat stbuf; - if (!ensure_sysroot_fd (self, error)) - goto out; + return FALSE; if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/repo", 0755, cancellable, error)) - goto out; + return FALSE; if (!glnx_shutil_mkdir_p_at (self->sysroot_fd, "ostree/deploy", 0755, cancellable, error)) - goto out; + return FALSE; + struct stat stbuf; if (fstatat (self->sysroot_fd, "ostree/repo/objects", &stbuf, 0) != 0) { if (errno != ENOENT) - { - glnx_set_prefix_error_from_errno (error, "stat %s", "ostree/repo/objects"); - goto out; - } + return glnx_throw_errno_prefix (error, "stat(ostree/repo/objects)"); else { g_autoptr(GFile) repo_dir = g_file_resolve_relative_path (self->path, "ostree/repo"); glnx_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir); if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE, cancellable, error)) - goto out; + return FALSE; } } - ret = TRUE; - out: - return ret; -} - -static void -match_info_cleanup (void *loc) -{ - GMatchInfo **match = (GMatchInfo**)loc; - if (*match) g_match_info_unref (*match); + return TRUE; } gboolean @@ -333,13 +319,9 @@ _ostree_sysroot_parse_deploy_path_name (const char *name, int *out_serial, GError **error) { - gboolean ret = FALSE; - __attribute__((cleanup(match_info_cleanup))) GMatchInfo *match = NULL; - g_autofree char *serial_str = NULL; static gsize regex_initialized; static GRegex *regex; - if (g_once_init_enter (®ex_initialized)) { regex = g_regex_new ("^([0-9a-f]+)\\.([0-9]+)$", 0, 0, NULL); @@ -347,20 +329,14 @@ _ostree_sysroot_parse_deploy_path_name (const char *name, g_once_init_leave (®ex_initialized, 1); } + g_autoptr(GMatchInfo) match = NULL; if (!g_regex_match (regex, name, 0, &match)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid deploy name '%s', expected CHECKSUM.TREESERIAL", name); - goto out; - } + return glnx_throw (error, "Invalid deploy name '%s', expected CHECKSUM.TREESERIAL", name); + g_autofree char *serial_str = g_match_info_fetch (match, 2); *out_csum = g_match_info_fetch (match, 1); - serial_str = g_match_info_fetch (match, 2); *out_serial = (int)g_ascii_strtoll (serial_str, NULL, 10); - - ret = TRUE; - out: - return ret; + return TRUE; } gboolean @@ -370,49 +346,36 @@ _ostree_sysroot_read_current_subbootversion (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - struct stat stbuf; - g_autofree char *ostree_bootdir_name = g_strdup_printf ("ostree/boot.%d", bootversion); - if (!ensure_sysroot_fd (self, error)) - goto out; + return FALSE; + g_autofree char *ostree_bootdir_name = g_strdup_printf ("ostree/boot.%d", bootversion); + struct stat stbuf; if (fstatat (self->sysroot_fd, ostree_bootdir_name, &stbuf, AT_SYMLINK_NOFOLLOW) != 0) { if (errno == ENOENT) *out_subbootversion = 0; else - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); } else { - g_autofree char *current_subbootdir_name = NULL; - - current_subbootdir_name = glnx_readlinkat_malloc (self->sysroot_fd, ostree_bootdir_name, - cancellable, error); + g_autofree char *current_subbootdir_name = + glnx_readlinkat_malloc (self->sysroot_fd, ostree_bootdir_name, + cancellable, error); if (!current_subbootdir_name) - goto out; - + return FALSE; + if (g_str_has_suffix (current_subbootdir_name, ".0")) *out_subbootversion = 0; else if (g_str_has_suffix (current_subbootdir_name, ".1")) *out_subbootversion = 1; else - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid target '%s' in %s", - current_subbootdir_name, - ostree_bootdir_name); - goto out; - } + return glnx_throw (error, "Invalid target '%s' in %s", + current_subbootdir_name, ostree_bootdir_name); } - ret = TRUE; - out: - return ret; + return TRUE; } static gint @@ -451,60 +414,46 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - int fd; /* Temporary owned by iterator */ - g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion); - g_autoptr(GPtrArray) ret_loader_configs = NULL; - g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; - if (!ensure_sysroot_fd (self, error)) - goto out; + return FALSE; - ret_loader_configs = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + g_autoptr(GPtrArray) ret_loader_configs = + g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); - fd = glnx_opendirat_with_errno (self->sysroot_fd, entries_path, TRUE); - if (fd == -1) + g_autofree char *entries_path = g_strdup_printf ("boot/loader.%d/entries", bootversion); + gboolean entries_exists; + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!ot_dfd_iter_init_allow_noent (self->sysroot_fd, entries_path, + &dfd_iter, &entries_exists, error)) + return FALSE; + if (!entries_exists) { - if (errno == ENOENT) - goto done; - else - { - glnx_set_error_from_errno (error); - goto out; - } + /* Note early return */ + *out_loader_configs = g_steal_pointer (&ret_loader_configs); + return TRUE; } - if (!glnx_dirfd_iterator_init_take_fd (fd, &dfd_iter, error)) - goto out; - while (TRUE) { struct dirent *dent; struct stat stbuf; if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error)) - goto out; - + return FALSE; if (dent == NULL) break; if (fstatat (dfd_iter.fd, dent->d_name, &stbuf, 0) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); if (g_str_has_prefix (dent->d_name, "ostree-") && g_str_has_suffix (dent->d_name, ".conf") && S_ISREG (stbuf.st_mode)) { glnx_unref_object OstreeBootconfigParser *config = ostree_bootconfig_parser_new (); - + if (!ostree_bootconfig_parser_parse_at (config, dfd_iter.fd, dent->d_name, cancellable, error)) - { - g_prefix_error (error, "Parsing %s: ", dent->d_name); - goto out; - } + return glnx_prefix_error (error, "Parsing %s", dent->d_name); g_ptr_array_add (ret_loader_configs, g_object_ref (config)); } @@ -512,13 +461,8 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, /* Callers expect us to give them a sorted array */ g_ptr_array_sort (ret_loader_configs, compare_loader_configs_for_sorting); - - done: - if (out_loader_configs) - *out_loader_configs = g_steal_pointer (&ret_loader_configs); - ret = TRUE; - out: - return ret; + ot_transfer_out_value(out_loader_configs, &ret_loader_configs); + return TRUE; } static gboolean @@ -527,49 +471,34 @@ read_current_bootversion (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; int ret_bootversion; struct stat stbuf; if (fstatat (self->sysroot_fd, "boot/loader", &stbuf, AT_SYMLINK_NOFOLLOW) != 0) { if (errno != ENOENT) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno (error); ret_bootversion = 0; } else { - g_autofree char *target = NULL; - if (!S_ISLNK (stbuf.st_mode)) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Not a symbolic link: boot/loader"); - goto out; - } + return glnx_throw (error, "Not a symbolic link: boot/loader"); - target = glnx_readlinkat_malloc (self->sysroot_fd, "boot/loader", cancellable, error); + g_autofree char *target = + glnx_readlinkat_malloc (self->sysroot_fd, "boot/loader", cancellable, error); if (!target) - goto out; + return FALSE; if (g_strcmp0 (target, "loader.0") == 0) ret_bootversion = 0; else if (g_strcmp0 (target, "loader.1") == 0) ret_bootversion = 1; else - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid target '%s' in boot/loader", target); - goto out; - } + return glnx_throw (error, "Invalid target '%s' in boot/loader", target); } - ret = TRUE; *out_bootversion = ret_bootversion; - out: - return ret; + return TRUE; } static gboolean @@ -580,42 +509,29 @@ parse_origin (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autoptr(GKeyFile) ret_origin = NULL; g_autofree char *origin_path = g_strconcat ("../", deployment_name, ".origin", NULL); - struct stat stbuf; - g_autofree char *origin_contents = NULL; + g_autoptr(GKeyFile) ret_origin = g_key_file_new (); - ret_origin = g_key_file_new (); - + struct stat stbuf; if (fstatat (deployment_dfd, origin_path, &stbuf, 0) != 0) { - if (errno == ENOENT) - ; - else - { - glnx_set_error_from_errno (error); - goto out; - } + if (errno != ENOENT) + return glnx_throw_errno (error); } else { - origin_contents = glnx_file_get_contents_utf8_at (deployment_dfd, origin_path, - NULL, cancellable, error); + g_autofree char *origin_contents = + glnx_file_get_contents_utf8_at (deployment_dfd, origin_path, + NULL, cancellable, error); if (!origin_contents) - goto out; + return FALSE; if (!g_key_file_load_from_data (ret_origin, origin_contents, -1, 0, error)) - goto out; + return glnx_prefix_error (error, "Parsing %s", origin_path); } - ret = TRUE; - if (out_origin) - *out_origin = g_steal_pointer (&ret_origin); - out: - if (error) - g_prefix_error (error, "Parsing %s: ", origin_path); - return ret; + ot_transfer_out_value(out_origin, &ret_origin); + return TRUE; } static gboolean @@ -626,14 +542,8 @@ parse_bootlink (const char *bootlink, int *out_treebootserial, GError **error) { - gboolean ret = FALSE; - __attribute__((cleanup(match_info_cleanup))) GMatchInfo *match = NULL; - g_autofree char *bootversion_str = NULL; - g_autofree char *treebootserial_str = NULL; - static gsize regex_initialized; static GRegex *regex; - if (g_once_init_enter (®ex_initialized)) { regex = g_regex_new ("^/ostree/boot.([01])/([^/]+)/([^/]+)/([0-9]+)$", 0, 0, NULL); @@ -641,23 +551,17 @@ parse_bootlink (const char *bootlink, g_once_init_leave (®ex_initialized, 1); } + g_autoptr(GMatchInfo) match = NULL; if (!g_regex_match (regex, bootlink, 0, &match)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Invalid ostree= argument '%s', expected ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL", bootlink); - goto out; - } - - bootversion_str = g_match_info_fetch (match, 1); + return glnx_throw (error, "Invalid ostree= argument '%s', expected ostree=/ostree/boot.BOOTVERSION/OSNAME/BOOTCSUM/TREESERIAL", bootlink); + + g_autofree char *bootversion_str = g_match_info_fetch (match, 1); + g_autofree char *treebootserial_str = g_match_info_fetch (match, 4); *out_entry_bootversion = (int)g_ascii_strtoll (bootversion_str, NULL, 10); *out_osname = g_match_info_fetch (match, 2); *out_bootcsum = g_match_info_fetch (match, 3); - treebootserial_str = g_match_info_fetch (match, 4); *out_treebootserial = (int)g_ascii_strtoll (treebootserial_str, NULL, 10); - - ret = TRUE; - out: - return ret; + return TRUE; } static char * @@ -677,60 +581,54 @@ parse_deployment (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *relative_boot_link; - glnx_unref_object OstreeDeployment *ret_deployment = NULL; + if (!ensure_sysroot_fd (self, error)) + return FALSE; + int entry_boot_version; - int treebootserial = -1; - int deployserial = -1; g_autofree char *osname = NULL; g_autofree char *bootcsum = NULL; - g_autofree char *treecsum = NULL; - glnx_fd_close int deployment_dfd = -1; - const char *deploy_basename; - g_autofree char *treebootserial_target = NULL; - g_autoptr(GKeyFile) origin = NULL; - g_autofree char *unlocked_development_path = NULL; - struct stat stbuf; - - if (!ensure_sysroot_fd (self, error)) - goto out; - + int treebootserial = -1; if (!parse_bootlink (boot_link, &entry_boot_version, &osname, &bootcsum, &treebootserial, error)) - goto out; + return FALSE; - relative_boot_link = boot_link; + const char *relative_boot_link = boot_link; if (*relative_boot_link == '/') relative_boot_link++; - treebootserial_target = glnx_readlinkat_malloc (self->sysroot_fd, relative_boot_link, - cancellable, error); + g_autofree char *treebootserial_target = + glnx_readlinkat_malloc (self->sysroot_fd, relative_boot_link, + cancellable, error); if (!treebootserial_target) - goto out; - - deploy_basename = glnx_basename (treebootserial_target); + return FALSE; + const char *deploy_basename = glnx_basename (treebootserial_target); + g_autofree char *treecsum = NULL; + int deployserial = -1; if (!_ostree_sysroot_parse_deploy_path_name (deploy_basename, &treecsum, &deployserial, error)) - goto out; + return FALSE; + glnx_fd_close int deployment_dfd = -1; if (!glnx_opendirat (self->sysroot_fd, relative_boot_link, TRUE, &deployment_dfd, error)) - goto out; + return FALSE; + g_autoptr(GKeyFile) origin = NULL; if (!parse_origin (self, deployment_dfd, deploy_basename, &origin, cancellable, error)) - goto out; + return FALSE; - ret_deployment = ostree_deployment_new (-1, osname, treecsum, deployserial, - bootcsum, treebootserial); + glnx_unref_object OstreeDeployment *ret_deployment + = ostree_deployment_new (-1, osname, treecsum, deployserial, + bootcsum, treebootserial); if (origin) ostree_deployment_set_origin (ret_deployment, origin); ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE; - unlocked_development_path = get_unlocked_development_path (ret_deployment); + g_autofree char *unlocked_development_path = get_unlocked_development_path (ret_deployment); + struct stat stbuf; if (lstat (unlocked_development_path, &stbuf) == 0) ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT; else @@ -747,11 +645,9 @@ parse_deployment (OstreeSysroot *self, g_debug ("Deployment %s.%d unlocked=%d", treecsum, deployserial, ret_deployment->unlocked); - ret = TRUE; if (out_deployment) *out_deployment = g_steal_pointer (&ret_deployment); - out: - return ret; + return TRUE; } static char * @@ -787,29 +683,19 @@ list_deployments_process_one_boot_entry (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_autofree char *ostree_arg = NULL; - glnx_unref_object OstreeDeployment *deployment = NULL; - - ostree_arg = get_ostree_kernel_arg_from_config (config); + g_autofree char *ostree_arg = get_ostree_kernel_arg_from_config (config); if (ostree_arg == NULL) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No ostree= kernel argument found"); - goto out; - } - + return glnx_throw (error, "No ostree= kernel argument found"); + + glnx_unref_object OstreeDeployment *deployment = NULL; if (!parse_deployment (self, ostree_arg, &deployment, cancellable, error)) - goto out; - + return FALSE; + ostree_deployment_set_bootconfig (deployment, config); g_ptr_array_add (inout_deployments, g_object_ref (deployment)); - - ret = TRUE; - out: - return ret; + return TRUE; } static gint @@ -847,29 +733,21 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - guint i; - int bootversion = 0; - int subbootversion = 0; - struct stat stbuf; - g_autoptr(GPtrArray) boot_loader_configs = NULL; - g_autoptr(GPtrArray) deployments = NULL; - if (!ensure_sysroot_fd (self, error)) - goto out; + return FALSE; + int bootversion = 0; if (!read_current_bootversion (self, &bootversion, cancellable, error)) - goto out; + return FALSE; + int subbootversion = 0; if (!_ostree_sysroot_read_current_subbootversion (self, bootversion, &subbootversion, cancellable, error)) - goto out; + return FALSE; + struct stat stbuf; if (fstatat (self->sysroot_fd, "ostree/deploy", &stbuf, 0) < 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "fstatat"); if (out_changed) { @@ -877,8 +755,8 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, self->loaded_ts.tv_nsec == stbuf.st_mtim.tv_nsec) { *out_changed = FALSE; - ret = TRUE; - goto out; + /* Note early return */ + return TRUE; } } @@ -887,23 +765,24 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, self->bootversion = -1; self->subbootversion = -1; + g_autoptr(GPtrArray) boot_loader_configs = NULL; if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs, cancellable, error)) - goto out; + return FALSE; - deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); + g_autoptr(GPtrArray) deployments = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref); - for (i = 0; i < boot_loader_configs->len; i++) + for (guint i = 0; i < boot_loader_configs->len; i++) { OstreeBootconfigParser *config = boot_loader_configs->pdata[i]; if (!list_deployments_process_one_boot_entry (self, config, deployments, cancellable, error)) - goto out; + return FALSE; } g_ptr_array_sort (deployments, compare_deployments_by_boot_loader_version_reversed); - for (i = 0; i < deployments->len; i++) + for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; ostree_deployment_set_index (deployment, i); @@ -911,7 +790,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, if (!find_booted_deployment (self, deployments, &self->booted_deployment, cancellable, error)) - goto out; + return FALSE; self->bootversion = bootversion; self->subbootversion = subbootversion; @@ -920,11 +799,9 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, self->loaded = TRUE; self->loaded_ts = stbuf.st_mtim; - ret = TRUE; if (out_changed) *out_changed = TRUE; - out: - return ret; + return TRUE; } int @@ -1039,18 +916,13 @@ ostree_sysroot_get_repo (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - /* ostree_repo_open() is idempotent. */ if (!ostree_repo_open (self->repo, cancellable, error)) - goto out; + return FALSE; if (out_repo != NULL) *out_repo = g_object_ref (self->repo); - - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -1066,37 +938,33 @@ _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; gboolean is_active; - glnx_unref_object OstreeBootloader *ret_loader = NULL; - - ret_loader = (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot); + glnx_unref_object OstreeBootloader *ret_loader = + (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot); if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error)) - goto out; + return FALSE; + if (!is_active) { g_object_unref (ret_loader); ret_loader = (OstreeBootloader*)_ostree_bootloader_grub2_new (sysroot); if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error)) - goto out; + return FALSE; } if (!is_active) { g_object_unref (ret_loader); ret_loader = (OstreeBootloader*)_ostree_bootloader_uboot_new (sysroot); if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error)) - goto out; + return FALSE; } if (!is_active) g_clear_object (&ret_loader); - ret = TRUE; - if (out_bootloader) - *out_bootloader = g_steal_pointer (&ret_loader); - out: - return ret; + ot_transfer_out_value(out_bootloader, &ret_loader); + return TRUE; } char * @@ -1128,21 +996,17 @@ parse_kernel_commandline (OstreeKernelArgs **out_args, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GFile) proc_cmdline = g_file_new_for_path ("/proc/cmdline"); g_autofree char *contents = NULL; gsize len; if (!g_file_load_contents (proc_cmdline, cancellable, &contents, &len, NULL, error)) - goto out; + return FALSE; g_strchomp (contents); - - ret = TRUE; *out_args = _ostree_kernel_args_from_string (contents); - out: - return ret; + return TRUE; } static gboolean @@ -1152,50 +1016,37 @@ find_booted_deployment (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; struct stat root_stbuf; struct stat self_stbuf; glnx_unref_object OstreeDeployment *ret_deployment = NULL; if (stat ("/", &root_stbuf) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "stat /"); if (!ensure_sysroot_fd (self, error)) - goto out; + return FALSE; if (fstat (self->sysroot_fd, &self_stbuf) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "fstat"); if (root_stbuf.st_dev == self_stbuf.st_dev && root_stbuf.st_ino == self_stbuf.st_ino) - { - guint i; - const char *bootlink_arg; + { __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kernel_args = NULL; - if (!parse_kernel_commandline (&kernel_args, cancellable, error)) - goto out; - - bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree"); + return FALSE; + + const char *bootlink_arg = _ostree_kernel_args_get_last_value (kernel_args, "ostree"); if (bootlink_arg) { - for (i = 0; i < deployments->len; i++) + for (guint i = 0; i < deployments->len; i++) { OstreeDeployment *deployment = deployments->pdata[i]; g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); struct stat stbuf; if (fstatat (self->sysroot_fd, deployment_path, &stbuf, 0) != 0) - { - glnx_set_error_from_errno (error); - goto out; - } + return glnx_throw_errno_prefix (error, "fstatat"); if (stbuf.st_dev == root_stbuf.st_dev && stbuf.st_ino == root_stbuf.st_ino) @@ -1206,11 +1057,7 @@ find_booted_deployment (OstreeSysroot *self, } if (ret_deployment == NULL) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Unexpected state: ostree= kernel argument found, but / is not a deployment root"); - goto out; - } + return glnx_throw (error, "Unexpected state: ostree= kernel argument found, but / is not a deployment root"); } else { @@ -1218,10 +1065,8 @@ find_booted_deployment (OstreeSysroot *self, } } - ret = TRUE; ot_transfer_out_value (out_deployment, &ret_deployment); - out: - return ret; + return TRUE; } /** @@ -1261,7 +1106,7 @@ ostree_sysroot_get_merge_deployment (OstreeSysroot *self, if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0) continue; - + return g_object_ref (deployment); } } @@ -1325,11 +1170,10 @@ ostree_sysroot_try_lock (OstreeSysroot *self, gboolean *out_acquired, GError **error) { - gboolean ret = FALSE; g_autoptr(GError) local_error = NULL; if (!ensure_sysroot_fd (self, error)) - goto out; + return FALSE; /* Note use of LOCK_NB */ if (!glnx_make_lock_file (self->sysroot_fd, OSTREE_SYSROOT_LOCKFILE, @@ -1342,7 +1186,7 @@ ostree_sysroot_try_lock (OstreeSysroot *self, else { g_propagate_error (error, g_steal_pointer (&local_error)); - goto out; + return FALSE; } } else @@ -1350,9 +1194,7 @@ ostree_sysroot_try_lock (OstreeSysroot *self, *out_acquired = TRUE; } - ret = TRUE; - out: - return ret; + return TRUE; } /** @@ -1383,7 +1225,7 @@ lock_in_thread (GTask *task, if (g_cancellable_set_error_if_cancelled (cancellable, &local_error)) ostree_sysroot_unlock (self); - + out: if (local_error) g_task_return_error (task, local_error); @@ -1444,77 +1286,49 @@ ostree_sysroot_init_osname (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - const char *deploydir = glnx_strjoina ("ostree/deploy/", osname); - glnx_fd_close int dfd = -1; - if (!ensure_sysroot_fd (self, error)) - goto out; + return FALSE; + const char *deploydir = glnx_strjoina ("ostree/deploy/", osname); if (mkdirat (self->sysroot_fd, deploydir, 0777) < 0) - { - glnx_set_prefix_error_from_errno (error, "Creating %s", deploydir); - goto out; - } + return glnx_throw_errno_prefix (error, "Creating %s", deploydir); + glnx_fd_close int dfd = -1; if (!glnx_opendirat (self->sysroot_fd, deploydir, TRUE, &dfd, error)) - goto out; + return FALSE; if (mkdirat (dfd, "var", 0777) < 0) - { - glnx_set_prefix_error_from_errno (error, "Creating %s", "var"); - goto out; - } + return glnx_throw_errno_prefix (error, "Creating %s", "var"); /* This is a bit of a legacy hack...but we have to keep it around * now. We're ensuring core subdirectories of /var exist. */ if (mkdirat (dfd, "var/tmp", 0777) < 0) - { - glnx_set_prefix_error_from_errno (error, "Creating %s", "var/tmp"); - goto out; - } + return glnx_throw_errno_prefix (error, "Creating %s", "var/tmp"); if (fchmodat (dfd, "var/tmp", 01777, 0) < 0) - { - glnx_set_prefix_error_from_errno (error, "Fchmod %s", "var/tmp"); - goto out; - } + return glnx_throw_errno_prefix (error, "fchmod %s", "var/tmp"); if (mkdirat (dfd, "var/lib", 0777) < 0) - { - glnx_set_prefix_error_from_errno (error, "Creating %s", "var/tmp"); - goto out; - } + return glnx_throw_errno_prefix (error, "Creating %s", "var/tmp"); /* This needs to be available and properly labeled early during the boot * process (before tmpfiles.d kicks in), so that journald can flush logs from * the first boot there. https://bugzilla.redhat.com/show_bug.cgi?id=1265295 * */ if (mkdirat (dfd, "var/log", 0755) < 0) - { - glnx_set_prefix_error_from_errno (error, "Creating %s", "var/log"); - goto out; - } + return glnx_throw_errno_prefix (error, "Creating %s", "var/log"); if (symlinkat ("../run", dfd, "var/run") < 0) - { - glnx_set_prefix_error_from_errno (error, "Symlinking %s", "var/run"); - goto out; - } + return glnx_throw_errno_prefix (error, "Symlinking %s", "var/run"); if (symlinkat ("../run/lock", dfd, "var/lock") < 0) - { - glnx_set_prefix_error_from_errno (error, "Symlinking %s", "var/lock"); - goto out; - } + return glnx_throw_errno_prefix (error, "Symlinking %s", "var/lock"); if (!_ostree_sysroot_bump_mtime (self, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } /** diff --git a/src/libostree/ostree-types.h b/src/libostree/ostree-types.h index f6aea0f0..61ac4283 100644 --- a/src/libostree/ostree-types.h +++ b/src/libostree/ostree-types.h @@ -38,4 +38,8 @@ typedef struct OstreeSysrootUpgrader OstreeSysrootUpgrader; typedef struct OstreeMutableTree OstreeMutableTree; typedef struct OstreeRepoFile OstreeRepoFile; +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +typedef struct OstreeRemote OstreeRemote; +#endif + G_END_DECLS diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h index d5546832..f9549150 100644 --- a/src/libostree/ostree-version.h +++ b/src/libostree/ostree-version.h @@ -40,14 +40,14 @@ * * ostree release version component (e.g. 2 if %OSTREE_VERSION is 2017.2) */ -#define OSTREE_RELEASE_VERSION (5) +#define OSTREE_RELEASE_VERSION (6) /** * OSTREE_VERSION * * ostree version. */ -#define OSTREE_VERSION (2017.5) +#define OSTREE_VERSION (2017.6) /** * OSTREE_VERSION_S: @@ -55,7 +55,7 @@ * ostree version, encoded as a string, useful for printing and * concatenation. */ -#define OSTREE_VERSION_S "2017.5" +#define OSTREE_VERSION_S "2017.6" #define OSTREE_ENCODE_VERSION(year,release) \ ((year) << 16 | (release)) diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h index eb4ed8d3..5d1ac1e1 100644 --- a/src/libostree/ostree.h +++ b/src/libostree/ostree.h @@ -24,6 +24,9 @@ #include #include #include +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +#include +#endif #include #include #include diff --git a/src/libotutil/ot-checksum-utils.c b/src/libotutil/ot-checksum-utils.c index 39417044..eb0185bd 100644 --- a/src/libotutil/ot-checksum-utils.c +++ b/src/libotutil/ot-checksum-utils.c @@ -47,7 +47,7 @@ ot_csum_from_gchecksum (GChecksum *checksum) { guchar *ret = g_malloc (32); gsize len = 32; - + g_checksum_get_digest (checksum, ret, &len); g_assert (len == 32); return ret; @@ -62,13 +62,11 @@ ot_gio_write_update_checksum (GOutputStream *out, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - if (out) { if (!g_output_stream_write_all (out, data, len, out_bytes_written, cancellable, error)) - goto out; + return FALSE; } else if (out_bytes_written) { @@ -77,10 +75,7 @@ ot_gio_write_update_checksum (GOutputStream *out, if (checksum) g_checksum_update (checksum, data, len); - - ret = TRUE; - out: - return ret; + return TRUE; } gboolean @@ -90,8 +85,6 @@ ot_gio_splice_update_checksum (GOutputStream *out, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - g_return_val_if_fail (out != NULL || checksum != NULL, FALSE); if (checksum != NULL) @@ -101,24 +94,25 @@ ot_gio_splice_update_checksum (GOutputStream *out, do { if (!g_input_stream_read_all (in, buf, sizeof(buf), &bytes_read, cancellable, error)) - goto out; + return FALSE; if (!ot_gio_write_update_checksum (out, buf, bytes_read, &bytes_written, checksum, cancellable, error)) - goto out; + return FALSE; } while (bytes_read > 0); } else if (out != NULL) { if (g_output_stream_splice (out, in, 0, cancellable, error) < 0) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } +/* Copy @in to @out, return in @out_csum the binary checksum for + * all data read. + */ gboolean ot_gio_splice_get_checksum (GOutputStream *out, GInputStream *in, @@ -126,22 +120,14 @@ ot_gio_splice_get_checksum (GOutputStream *out, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - GChecksum *checksum = NULL; - g_autofree guchar *ret_csum = NULL; - - checksum = g_checksum_new (G_CHECKSUM_SHA256); + g_autoptr(GChecksum) checksum = g_checksum_new (G_CHECKSUM_SHA256); if (!ot_gio_splice_update_checksum (out, in, checksum, cancellable, error)) - goto out; + return FALSE; - ret_csum = ot_csum_from_gchecksum (checksum); - - ret = TRUE; + g_autofree guchar *ret_csum = ot_csum_from_gchecksum (checksum); ot_transfer_out_value (out_csum, &ret_csum); - out: - g_clear_pointer (&checksum, (GDestroyNotify) g_checksum_free); - return ret; + return TRUE; } gboolean @@ -162,21 +148,13 @@ ot_checksum_file_at (int dfd, GCancellable *cancellable, GError **error) { - GChecksum *checksum = NULL; - char *ret = NULL; g_autoptr(GInputStream) in = NULL; - if (!ot_openat_read_stream (dfd, path, TRUE, &in, cancellable, error)) - goto out; - - checksum = g_checksum_new (checksum_type); + return FALSE; + g_autoptr(GChecksum) checksum = g_checksum_new (checksum_type); if (!ot_gio_splice_update_checksum (NULL, in, checksum, cancellable, error)) - goto out; - - ret = g_strdup (g_checksum_get_string (checksum)); - out: - g_clear_pointer (&checksum, (GDestroyNotify) g_checksum_free); - return ret; + return FALSE; + return g_strdup (g_checksum_get_string (checksum)); } diff --git a/src/libotutil/ot-fs-utils.c b/src/libotutil/ot-fs-utils.c index a0a72ca5..529077fb 100644 --- a/src/libotutil/ot-fs-utils.c +++ b/src/libotutil/ot-fs-utils.c @@ -35,98 +35,6 @@ ot_fdrel_to_gfile (int dfd, const char *path) return g_file_new_for_path (abspath); } -int -ot_opendirat (int dfd, const char *path, gboolean follow) -{ - int flags = O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY; - if (!follow) - flags |= O_NOFOLLOW; - return openat (dfd, path, flags); -} - -gboolean -ot_gopendirat (int dfd, - const char *path, - gboolean follow, - int *out_fd, - GError **error) -{ - int ret = ot_opendirat (dfd, path, follow); - if (ret == -1) - { - glnx_set_error_from_errno (error); - return FALSE; - } - *out_fd = ret; - return TRUE; -} - -GBytes * -ot_lgetxattrat (int dfd, - const char *path, - const char *attribute, - GError **error) -{ - /* A workaround for the lack of lgetxattrat(), thanks to Florian Weimer: - * https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html - */ - g_autofree char *full_path = g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path); - GBytes *bytes = NULL; - ssize_t bytes_read, real_size; - char *buf; - - do - bytes_read = lgetxattr (full_path, attribute, NULL, 0); - while (G_UNLIKELY (bytes_read < 0 && errno == EINTR)); - if (G_UNLIKELY (bytes_read < 0)) - { - glnx_set_error_from_errno (error); - goto out; - } - - buf = g_malloc (bytes_read); - do - real_size = lgetxattr (full_path, attribute, buf, bytes_read); - while (G_UNLIKELY (real_size < 0 && errno == EINTR)); - if (G_UNLIKELY (real_size < 0)) - { - glnx_set_error_from_errno (error); - g_free (buf); - goto out; - } - - bytes = g_bytes_new_take (buf, real_size); - out: - return bytes; -} - -gboolean -ot_lsetxattrat (int dfd, - const char *path, - const char *attribute, - const void *value, - gsize value_size, - int flags, - GError **error) -{ - /* A workaround for the lack of lsetxattrat(), thanks to Florian Weimer: - * https://mail.gnome.org/archives/ostree-list/2014-February/msg00017.html - */ - g_autofree char *full_path = g_strdup_printf ("/proc/self/fd/%d/%s", dfd, path); - int res; - - do - res = lsetxattr (full_path, "user.ostreemeta", value, value_size, flags); - while (G_UNLIKELY (res == -1 && errno == EINTR)); - if (G_UNLIKELY (res == -1)) - { - glnx_set_error_from_errno (error); - return FALSE; - } - - return TRUE; -} - gboolean ot_readlinkat_gfile_info (int dfd, const char *path, @@ -264,6 +172,31 @@ ot_openat_ignore_enoent (int dfd, return ret; } +/* Like glnx_dirfd_iterator_init_at(), but if %ENOENT, then set + * @out_exists to %FALSE, and return successfully. + */ +gboolean +ot_dfd_iter_init_allow_noent (int dfd, + const char *path, + GLnxDirFdIterator *dfd_iter, + gboolean *out_exists, + GError **error) +{ + glnx_fd_close int fd = glnx_opendirat_with_errno (dfd, path, TRUE); + if (fd < 0) + { + if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "opendirat"); + *out_exists = FALSE; + return TRUE; + } + if (!glnx_dirfd_iterator_init_take_fd (fd, dfd_iter, error)) + return FALSE; + fd = -1; + *out_exists = TRUE; + return TRUE; +} + GBytes * ot_file_mapat_bytes (int dfd, const char *path, diff --git a/src/libotutil/ot-fs-utils.h b/src/libotutil/ot-fs-utils.h index 13909c8e..14df8acb 100644 --- a/src/libotutil/ot-fs-utils.h +++ b/src/libotutil/ot-fs-utils.h @@ -21,31 +21,12 @@ #pragma once #include "ot-unix-utils.h" +#include "libglnx.h" G_BEGIN_DECLS GFile * ot_fdrel_to_gfile (int dfd, const char *path); -int ot_opendirat (int dfd, const char *path, gboolean follow); -gboolean ot_gopendirat (int dfd, - const char *path, - gboolean follow, - int *out_fd, - GError **error); - -GBytes * ot_lgetxattrat (int dfd, - const char *path, - const char *attribute, - GError **error); - -gboolean ot_lsetxattrat (int dfd, - const char *path, - const char *attribute, - const void *value, - gsize value_size, - int flags, - GError **error); - gboolean ot_readlinkat_gfile_info (int dfd, const char *path, GFileInfo *target_info, @@ -73,6 +54,12 @@ gboolean ot_openat_ignore_enoent (int dfd, int *out_fd, GError **error); +gboolean ot_dfd_iter_init_allow_noent (int dfd, + const char *path, + GLnxDirFdIterator *dfd_iter, + gboolean *out_exists, + GError **error); + GBytes *ot_file_mapat_bytes (int dfd, const char *path, GError **error); diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c index b71f4845..001daa0a 100644 --- a/src/libotutil/ot-gpg-utils.c +++ b/src/libotutil/ot-gpg-utils.c @@ -67,7 +67,6 @@ ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, - const char *tmp_dir, char **out_tmp_home_dir, GOutputStream **out_pubring_stream, GCancellable *cancellable, @@ -85,10 +84,7 @@ ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, * and hand the caller an open output stream to concatenate necessary * keyring files. */ - if (tmp_dir == NULL) - tmp_dir = g_get_tmp_dir (); - - tmp_home_dir = g_build_filename (tmp_dir, "ostree-gpg-XXXXXX", NULL); + tmp_home_dir = g_build_filename (g_get_tmp_dir (), "ostree-gpg-XXXXXX", NULL); if (mkdtemp (tmp_home_dir) == NULL) { diff --git a/src/libotutil/ot-gpg-utils.h b/src/libotutil/ot-gpg-utils.h index c2337f7b..184a8d64 100644 --- a/src/libotutil/ot-gpg-utils.h +++ b/src/libotutil/ot-gpg-utils.h @@ -34,7 +34,6 @@ GLNX_DEFINE_CLEANUP_FUNCTION0(gpgme_ctx_t, ot_cleanup_gpgme_ctx, gpgme_release) void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error); gboolean ot_gpgme_ctx_tmp_home_dir (gpgme_ctx_t gpgme_ctx, - const char *tmp_dir, char **out_tmp_home_dir, GOutputStream **out_pubring_stream, GCancellable *cancellable, diff --git a/src/ostree/ostree-trivial-httpd.c b/src/ostree/ostree-trivial-httpd.c index d6f0c4d4..176f5ec7 100644 --- a/src/ostree/ostree-trivial-httpd.c +++ b/src/ostree/ostree-trivial-httpd.c @@ -457,10 +457,10 @@ httpd_callback (SoupServer *server, SoupMessage *msg, static void on_dir_changed (GFileMonitor *mon, - GFile *file, - GFile *other, - GFileMonitorEvent event, - gpointer user_data) + GFile *file, + GFile *other, + GFileMonitorEvent event, + gpointer user_data) { OtTrivialHttpd *self = user_data; diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c index f27316a3..0694ba77 100644 --- a/src/ostree/ot-admin-builtin-instutil.c +++ b/src/ostree/ot-admin-builtin-instutil.c @@ -47,12 +47,9 @@ static GOptionContext * ostree_admin_instutil_option_context_new_with_commands (void) { OstreeAdminInstUtilCommand *command = admin_instutil_subcommands; - GOptionContext *context; - GString *summary; + GOptionContext *context = g_option_context_new ("COMMAND"); - context = g_option_context_new ("COMMAND"); - - summary = g_string_new ("Builtin \"admin instutil\" Commands:"); + g_autoptr(GString) summary = g_string_new ("Builtin \"admin instutil\" Commands:"); while (command->name != NULL) { @@ -62,8 +59,6 @@ ostree_admin_instutil_option_context_new_with_commands (void) g_option_context_set_summary (context, summary->str); - g_string_free (summary, TRUE); - return context; } diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c index 940e5df0..79621a1d 100644 --- a/src/ostree/ot-admin-builtin-status.c +++ b/src/ostree/ot-admin-builtin-status.c @@ -124,7 +124,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro OstreeDeploymentUnlockedState unlocked = ostree_deployment_get_unlocked (deployment); g_autofree char *version = version_of_commit (repo, ref); glnx_unref_object OstreeGpgVerifyResult *result = NULL; - GString *output_buffer; guint jj, n_signatures; GError *local_error = NULL; @@ -159,6 +158,7 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro if (deployment_get_gpg_verify (deployment, repo)) { + g_autoptr(GString) output_buffer = g_string_sized_new (256); /* Print any digital signatures on this commit. */ result = ostree_repo_verify_commit_ext (repo, ref, NULL, NULL, @@ -176,7 +176,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro goto out; } - output_buffer = g_string_sized_new (256); n_signatures = ostree_gpg_verify_result_count_all (result); for (jj = 0; jj < n_signatures; jj++) @@ -186,7 +185,6 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro } g_print ("%s", output_buffer->str); - g_string_free (output_buffer, TRUE); } } } diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c index cc86ee43..00252c80 100644 --- a/src/ostree/ot-admin-builtin-undeploy.c +++ b/src/ostree/ot-admin-builtin-undeploy.c @@ -35,7 +35,6 @@ static GOptionEntry options[] = { gboolean ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; glnx_unref_object OstreeSysroot *sysroot = NULL; const char *deploy_index_str; @@ -48,16 +47,16 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr if (!ostree_admin_option_context_parse (context, options, &argc, &argv, OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER, &sysroot, cancellable, error)) - goto out; + return FALSE; if (argc < 2) { ot_util_usage_error (context, "INDEX must be specified", error); - goto out; + return FALSE; } if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; + return FALSE; current_deployments = ostree_sysroot_get_deployments (sysroot); deploy_index_str = argv[1]; @@ -65,31 +64,26 @@ ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GEr target_deployment = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); if (!target_deployment) - goto out; + return FALSE; if (target_deployment == ostree_sysroot_get_booted_deployment (sysroot)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Cannot undeploy currently booted deployment %i", deploy_index); - goto out; + return FALSE; } - + g_ptr_array_remove_index (current_deployments, deploy_index); if (!ostree_sysroot_write_deployments (sysroot, current_deployments, cancellable, error)) - goto out; + return FALSE; g_print ("Deleted deployment %s.%d\n", ostree_deployment_get_csum (target_deployment), ostree_deployment_get_deployserial (target_deployment)); - - if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) - { - g_prefix_error (error, "Performing final cleanup: "); - goto out; - } - ret = TRUE; - out: - return ret; + if (!ostree_sysroot_cleanup (sysroot, cancellable, error)) + return glnx_prefix_error (error, "Performing final cleanup"); + + return TRUE; } diff --git a/src/ostree/ot-admin-functions.c b/src/ostree/ot-admin-functions.c index 7ba2207e..672d384a 100644 --- a/src/ostree/ot-admin-functions.c +++ b/src/ostree/ot-admin-functions.c @@ -33,20 +33,11 @@ ot_admin_require_booted_deployment_or_osname (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); - if (booted_deployment == NULL && osname == NULL) - { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Not currently booted into an OSTree system and no --os= argument given"); - goto out; - } - - ret = TRUE; - out: - return ret; + return glnx_throw (error, "Not currently booted into an OSTree system and no --os= argument given"); + return TRUE; } /** @@ -141,7 +132,7 @@ ot_admin_sysroot_lock (OstreeSysroot *sysroot, g_source_set_callback (timeout_src, (GSourceFunc)on_sysroot_lock_timeout, &state, NULL); g_source_attach (timeout_src, state.mainctx); g_source_unref (timeout_src); - + on_sysroot_lock_timeout (&state); ostree_sysroot_lock_async (sysroot, NULL, (GAsyncReadyCallback)on_sysroot_lock_acquired, &state); @@ -161,14 +152,11 @@ gboolean ot_admin_execve_reboot (OstreeSysroot *sysroot, GError **error) { g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/"); - + if (g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot)) { if (execlp ("systemctl", "systemctl", "reboot", NULL) < 0) - { - glnx_set_error_from_errno (error); - return FALSE; - } + return glnx_throw_errno (error); } return TRUE; diff --git a/src/ostree/ot-builtin-admin.c b/src/ostree/ot-builtin-admin.c index 0d8290a8..16aaec03 100644 --- a/src/ostree/ot-builtin-admin.c +++ b/src/ostree/ot-builtin-admin.c @@ -56,12 +56,9 @@ static GOptionContext * ostree_admin_option_context_new_with_commands (void) { OstreeAdminCommand *command = admin_subcommands; - GOptionContext *context; - GString *summary; + GOptionContext *context = g_option_context_new ("--print-current-dir|COMMAND"); - context = g_option_context_new ("--print-current-dir|COMMAND"); - - summary = g_string_new ("Builtin \"admin\" Commands:"); + g_autoptr(GString) summary = g_string_new ("Builtin \"admin\" Commands:"); while (command->name != NULL) { @@ -71,8 +68,6 @@ ostree_admin_option_context_new_with_commands (void) g_option_context_set_summary (context, summary->str); - g_string_free (summary, TRUE); - return context; } diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index 74e27cfb..8ffe5bb7 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -42,6 +42,7 @@ static gboolean opt_from_stdin; static char *opt_from_file; static gboolean opt_disable_fsync; static gboolean opt_require_hardlinks; +static gboolean opt_force_copy; static gboolean parse_fsync_cb (const char *option_name, @@ -62,7 +63,7 @@ parse_fsync_cb (const char *option_name, static GOptionEntry options[] = { { "user-mode", 'U', 0, G_OPTION_ARG_NONE, &opt_user_mode, "Do not change file ownership or initialize extended attributes", NULL }, { "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Do not update or use the internal repository uncompressed object cache", NULL }, - { "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, + { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, { "union", 0, 0, G_OPTION_ARG_NONE, &opt_union, "Keep existing directories, overwrite existing files", NULL }, { "union-add", 0, 0, G_OPTION_ARG_NONE, &opt_union_add, "Keep existing files/directories, only add new", NULL }, { "whiteouts", 0, 0, G_OPTION_ARG_NONE, &opt_whiteouts, "Process 'whiteout' (Docker style) entries", NULL }, @@ -71,6 +72,7 @@ static GOptionEntry options[] = { { "from-file", 0, 0, G_OPTION_ARG_STRING, &opt_from_file, "Process many checkouts from input file", "FILE" }, { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" }, { "require-hardlinks", 'H', 0, G_OPTION_ARG_NONE, &opt_require_hardlinks, "Do not fall back to full copies if hardlinking fails", NULL }, + { "force-copy", 'C', 0, G_OPTION_ARG_NONE, &opt_force_copy, "Never hardlink (but may reflink if available)", NULL }, { NULL } }; @@ -89,7 +91,7 @@ process_one_checkout (OstreeRepo *repo, * `ostree_repo_checkout_at` until such time as we have a more * convenient infrastructure for testing C APIs with data. */ - if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add) + if (opt_disable_cache || opt_whiteouts || opt_require_hardlinks || opt_union_add || opt_force_copy) { OstreeRepoCheckoutAtOptions options = { 0, }; @@ -102,6 +104,11 @@ process_one_checkout (OstreeRepo *repo, "Cannot specify both --union and --union-add"); goto out; } + if (opt_require_hardlinks && opt_force_copy) + { + glnx_throw (error, "Cannot specify both --require-hardlinks and --force-copy"); + goto out; + } else if (opt_union) options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES; else if (opt_union_add) @@ -111,6 +118,7 @@ process_one_checkout (OstreeRepo *repo, if (subpath) options.subpath = subpath; options.no_copy_fallback = opt_require_hardlinks; + options.force_copy = opt_force_copy; if (!ostree_repo_checkout_at (repo, &options, AT_FDCWD, destination, diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index e6738c89..4b0d8821 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -76,7 +76,7 @@ static GOptionEntry options[] = { { "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent ref, or \"none\"", "REF" }, { "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject", "SUBJECT" }, { "body", 'm', 0, G_OPTION_ARG_STRING, &opt_body, "Full description", "BODY" }, - { "body-file", 'F', 0, G_OPTION_ARG_STRING, &opt_body_file, "Commit message from FILE path", "FILE" }, + { "body-file", 'F', 0, G_OPTION_ARG_FILENAME, &opt_body_file, "Commit message from FILE path", "FILE" }, { "editor", 'e', 0, G_OPTION_ARG_NONE, &opt_editor, "Use an editor to write the commit message", NULL }, { "branch", 'b', 0, G_OPTION_ARG_STRING, &opt_branch, "Branch", "BRANCH" }, { "orphan", 0, 0, G_OPTION_ARG_NONE, &opt_orphan, "Create a commit without writing a ref", NULL }, @@ -94,7 +94,7 @@ static GOptionEntry options[] = { { "skip-list", 0, 0, G_OPTION_ARG_FILENAME, &opt_skiplist_file, "File containing list of files to skip", "PATH" }, { "table-output", 0, 0, G_OPTION_ARG_NONE, &opt_table_output, "Output more information in a KEY: VALUE format", NULL }, { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the commit with", "KEY-ID"}, - { "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, { "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes, "Generate size information along with commit metadata", NULL }, { "disable-fsync", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()", "POLICY" }, @@ -218,7 +218,7 @@ commit_editor (OstreeRepo *repo, g_autofree char *input = NULL; g_autofree char *output = NULL; gboolean ret = FALSE; - GString *bodybuf = NULL; + g_autoptr(GString) bodybuf = NULL; char **lines = NULL; int i; @@ -288,8 +288,6 @@ commit_editor (OstreeRepo *repo, out: g_strfreev (lines); - if (bodybuf) - g_string_free (bodybuf, TRUE); return ret; } diff --git a/src/ostree/ot-builtin-export.c b/src/ostree/ot-builtin-export.c index f3cdfbe0..2d40112a 100644 --- a/src/ostree/ot-builtin-export.c +++ b/src/ostree/ot-builtin-export.c @@ -39,9 +39,9 @@ static gboolean opt_no_xattrs; static GOptionEntry options[] = { { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Skip output of extended attributes", NULL }, - { "subpath", 0, 0, G_OPTION_ARG_STRING, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, - { "prefix", 0, 0, G_OPTION_ARG_STRING, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" }, - { "output", 'o', 0, G_OPTION_ARG_STRING, &opt_output_path, "Output to PATH ", "PATH" }, + { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, + { "prefix", 0, 0, G_OPTION_ARG_FILENAME, &opt_prefix, "Add PATH as prefix to archive pathnames", "PATH" }, + { "output", 'o', 0, G_OPTION_ARG_FILENAME, &opt_output_path, "Output to PATH ", "PATH" }, { NULL } }; diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c index 2f154cff..7519d6db 100644 --- a/src/ostree/ot-builtin-fsck.c +++ b/src/ostree/ot-builtin-fsck.c @@ -246,6 +246,7 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError ** gpointer key, value; gboolean found_corruption = FALSE; guint n_partial = 0; + g_autoptr(GHashTable) all_refs = NULL; g_autoptr(GHashTable) objects = NULL; g_autoptr(GHashTable) commits = NULL; g_autoptr(GPtrArray) tombstones = NULL; @@ -254,6 +255,27 @@ ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError ** if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; + if (!opt_quiet) + g_print ("Validating refs...\n"); + + /* Validate that the commit for each ref is available */ + if (!ostree_repo_list_refs (repo, NULL, &all_refs, + cancellable, error)) + return FALSE; + g_hash_table_iter_init (&hash_iter, all_refs); + while (g_hash_table_iter_next (&hash_iter, &key, &value)) + { + const char *refname = key; + const char *checksum = value; + g_autoptr(GVariant) commit = NULL; + if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, + checksum, &commit, error)) + { + g_prefix_error (error, "Loading commit for ref %s: ", refname); + goto out; + } + } + if (!opt_quiet) g_print ("Enumerating objects...\n"); diff --git a/src/ostree/ot-builtin-gpg-sign.c b/src/ostree/ot-builtin-gpg-sign.c index c19ec682..e14eba68 100644 --- a/src/ostree/ot-builtin-gpg-sign.c +++ b/src/ostree/ot-builtin-gpg-sign.c @@ -26,13 +26,14 @@ #include "ot-builtins.h" #include "ostree.h" #include "otutil.h" +#include "ostree-core-private.h" static gboolean opt_delete; static char *opt_gpg_homedir; static GOptionEntry options[] = { { "delete", 'd', 0, G_OPTION_ARG_NONE, &opt_delete, "Delete signatures having any of the GPG KEY-IDs" }, - { "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" }, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" }, { NULL } }; @@ -85,7 +86,7 @@ delete_signatures (OstreeRepo *repo, g_variant_dict_init (&metadata_dict, old_metadata); signature_data = g_variant_dict_lookup_value (&metadata_dict, - "ostree.gpgsigs", + _OSTREE_METADATA_GPGSIGS_NAME, G_VARIANT_TYPE ("aay")); /* Taking the approach of deleting whatever matches we find for the @@ -154,7 +155,7 @@ delete_signatures (OstreeRepo *repo, /* Update the metadata dictionary. */ if (g_queue_is_empty (&signatures)) { - g_variant_dict_remove (&metadata_dict, "ostree.gpgsigs"); + g_variant_dict_remove (&metadata_dict, _OSTREE_METADATA_GPGSIGS_NAME); } else { @@ -170,7 +171,7 @@ delete_signatures (OstreeRepo *repo, } g_variant_dict_insert_value (&metadata_dict, - "ostree.gpgsigs", + _OSTREE_METADATA_GPGSIGS_NAME, g_variant_builder_end (&signature_builder)); } diff --git a/src/ostree/ot-builtin-ls.c b/src/ostree/ot-builtin-ls.c index 3abeb5c4..3e0336f6 100644 --- a/src/ostree/ot-builtin-ls.c +++ b/src/ostree/ot-builtin-ls.c @@ -47,15 +47,13 @@ static void print_one_file_text (GFile *f, GFileInfo *file_info) { - GString *buf = NULL; + g_autoptr(GString) buf = g_string_new (""); char type_c; guint32 mode; guint32 type; if (!ostree_repo_file_ensure_resolved ((OstreeRepoFile*)f, NULL)) g_assert_not_reached (); - - buf = g_string_new (""); type_c = '?'; mode = g_file_info_get_attribute_uint32 (file_info, "unix::mode"); @@ -119,8 +117,6 @@ print_one_file_text (GFile *f, g_string_append_printf (buf, " -> %s", g_file_info_get_attribute_byte_string (file_info, "standard::symlink-target")); g_print ("%s\n", buf->str); - - g_string_free (buf, TRUE); } static void diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c index 4287afcd..d88c5ee8 100644 --- a/src/ostree/ot-builtin-pull.c +++ b/src/ostree/ot-builtin-pull.c @@ -43,12 +43,12 @@ static char* opt_url; static GOptionEntry options[] = { { "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL }, - { "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL }, + { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, { "disable-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_disable_static_deltas, "Do not use static deltas", NULL }, { "require-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_require_static_deltas, "Require static deltas", NULL }, { "mirror", 0, 0, G_OPTION_ARG_NONE, &opt_mirror, "Write refs suitable for a mirror", NULL }, - { "subpath", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL }, + { "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only pull the provided subpath(s)", NULL }, { "untrusted", 0, 0, G_OPTION_ARG_NONE, &opt_untrusted, "Do not trust (local) sources", NULL }, { "dry-run", 0, 0, G_OPTION_ARG_NONE, &opt_dry_run, "Only print information on what will be downloaded (requires static deltas)", NULL }, { "depth", 0, 0, G_OPTION_ARG_INT, &opt_depth, "Traverse DEPTH parents (-1=infinite) (default: 0)", "DEPTH" }, @@ -84,27 +84,29 @@ dry_run_console_progress_changed (OstreeAsyncProgress *progress, guint fetched_delta_parts, total_delta_parts; guint fetched_delta_part_fallbacks, total_delta_part_fallbacks; guint64 fetched_delta_part_size, total_delta_part_size, total_delta_part_usize; - GString *buf; g_assert (!printed_console_progress); printed_console_progress = TRUE; - /* Number of parts */ - fetched_delta_parts = ostree_async_progress_get_uint (progress, "fetched-delta-parts"); - total_delta_parts = ostree_async_progress_get_uint (progress, "total-delta-parts"); - fetched_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "fetched-delta-fallbacks"); - total_delta_part_fallbacks = ostree_async_progress_get_uint (progress, "total-delta-fallbacks"); + ostree_async_progress_get (progress, + /* Number of parts */ + "fetched-delta-parts", "u", &fetched_delta_parts, + "total-delta-parts", "u", &total_delta_parts, + "fetched-delta-fallbacks", "u", &fetched_delta_part_fallbacks, + "total-delta-fallbacks", "u", &total_delta_part_fallbacks, + /* Size variables */ + "fetched-delta-part-size", "t", &fetched_delta_part_size, + "total-delta-part-size", "t", &total_delta_part_size, + "total-delta-part-usize", "t", &total_delta_part_usize, + NULL); + /* Fold the count of deltaparts + fallbacks for simplicity; if changing this, * please change ostree_repo_pull_default_console_progress_changed() first. */ fetched_delta_parts += fetched_delta_part_fallbacks; total_delta_parts += total_delta_part_fallbacks; - /* Size variables */ - fetched_delta_part_size = ostree_async_progress_get_uint64 (progress, "fetched-delta-part-size"); - total_delta_part_size = ostree_async_progress_get_uint64 (progress, "total-delta-part-size"); - total_delta_part_usize = ostree_async_progress_get_uint64 (progress, "total-delta-part-usize"); - buf = g_string_new (""); + g_autoptr(GString) buf = g_string_new (""); { g_autofree char *formatted_fetched = g_format_size (fetched_delta_part_size); @@ -119,7 +121,6 @@ dry_run_console_progress_changed (OstreeAsyncProgress *progress, formatted_usize); } g_print ("%s\n", buf->str); - g_string_free (buf, TRUE); } gboolean diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c index f0667a42..dd999c01 100644 --- a/src/ostree/ot-builtin-remote.c +++ b/src/ostree/ot-builtin-remote.c @@ -51,12 +51,9 @@ static GOptionContext * remote_option_context_new_with_commands (void) { OstreeRemoteCommand *subcommand = remote_subcommands; - GOptionContext *context; - GString *summary; + GOptionContext *context = g_option_context_new ("COMMAND"); - context = g_option_context_new ("COMMAND"); - - summary = g_string_new ("Builtin \"remote\" Commands:"); + g_autoptr(GString) summary = g_string_new ("Builtin \"remote\" Commands:"); while (subcommand->name != NULL) { @@ -66,8 +63,6 @@ remote_option_context_new_with_commands (void) g_option_context_set_summary (context, summary->str); - g_string_free (summary, TRUE); - return context; } diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c index 3aaa2303..dcd9090c 100644 --- a/src/ostree/ot-builtin-show.c +++ b/src/ostree/ot-builtin-show.c @@ -42,7 +42,7 @@ static GOptionEntry options[] = { { "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" }, { "print-detached-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_detached_metadata_key, "Print string value of detached metadata key", "KEY" }, { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" }, - { "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, { "gpg-verify-remote", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_verify_remote, "Use REMOTE name for GPG configuration", "REMOTE"}, { NULL } }; diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c index 1019f06f..c98436af 100644 --- a/src/ostree/ot-builtin-static-delta.c +++ b/src/ostree/ot-builtin-static-delta.c @@ -72,7 +72,7 @@ static GOptionEntry generate_options[] = { { "min-fallback-size", 0, 0, G_OPTION_ARG_STRING, &opt_min_fallback_size, "Minimum uncompressed size in megabytes for individual HTTP request", NULL}, { "max-bsdiff-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_bsdiff_size, "Maximum size in megabytes to consider bsdiff compression for input files", NULL}, { "max-chunk-size", 0, 0, G_OPTION_ARG_STRING, &opt_max_chunk_size, "Maximum size of delta chunks in megabytes", NULL}, - { "filename", 0, 0, G_OPTION_ARG_STRING, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"}, + { "filename", 0, 0, G_OPTION_ARG_FILENAME, &opt_filename, "Write the delta content to PATH (a directory). If not specified, the OSTree repository is used", "PATH"}, { NULL } }; diff --git a/src/ostree/ot-builtin-summary.c b/src/ostree/ot-builtin-summary.c index 04ba84e8..9055d972 100644 --- a/src/ostree/ot-builtin-summary.c +++ b/src/ostree/ot-builtin-summary.c @@ -20,19 +20,23 @@ #include "config.h" +#include "ostree-repo-private.h" +#include "ot-dump.h" #include "ot-main.h" #include "ot-builtins.h" #include "ostree.h" #include "otutil.h" -static gboolean opt_update; +static gboolean opt_update, opt_view, opt_raw; static char **opt_key_ids; static char *opt_gpg_homedir; static GOptionEntry options[] = { { "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL }, + { "view", 'v', 0, G_OPTION_ARG_NONE, &opt_view, "View the local summary file", NULL }, + { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "View the raw bytes of the summary file", NULL }, { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "GPG Key ID to sign the summary with", "KEY-ID"}, - { "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, + { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"}, { NULL } }; @@ -42,6 +46,7 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; glnx_unref_object OstreeRepo *repo = NULL; + OstreeDumpFlags flags = OSTREE_DUMP_NONE; context = g_option_context_new ("Manage summary metadata"); @@ -66,6 +71,19 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError goto out; } } + else if (opt_view) + { + g_autoptr(GBytes) summary_data = NULL; + + if (opt_raw) + flags |= OSTREE_DUMP_RAW; + + summary_data = ot_file_mapat_bytes (repo->repo_dir_fd, "summary", error); + if (!summary_data) + goto out; + + ot_dump_summary_bytes (summary_data, flags); + } else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, diff --git a/src/ostree/ot-dump.c b/src/ostree/ot-dump.c index 4fc84cbd..b24003c7 100644 --- a/src/ostree/ot-dump.c +++ b/src/ostree/ot-dump.c @@ -26,6 +26,8 @@ #include +#include "ostree-repo-private.h" +#include "ostree-repo-static-delta-private.h" #include "ot-dump.h" #include "otutil.h" #include "ot-admin-functions.h" @@ -199,6 +201,18 @@ dump_summary_ref (const char *ref_name, } } +static gchar * +uint64_secs_to_iso8601 (guint64 secs) +{ + g_autoptr(GDateTime) dt = g_date_time_new_from_unix_utc (secs); + g_autoptr(GDateTime) local = (dt != NULL) ? g_date_time_to_local (dt) : NULL; + + if (local != NULL) + return g_date_time_format (local, "%FT%T%:::z"); + else + return g_strdup ("invalid"); +} + void ot_dump_summary_bytes (GBytes *summary_bytes, OstreeDumpFlags flags) @@ -251,11 +265,35 @@ ot_dump_summary_bytes (GBytes *summary_bytes, g_variant_iter_init (&iter, exts); - /* XXX Should we print something more human-friendly for - * known extension names like 'ostree.static-deltas'? */ while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) { - g_autofree char *string = g_variant_print (value, FALSE); - g_print ("%s: %s\n", key, string); + g_autofree gchar *value_str = NULL; + const gchar *pretty_key = NULL; + + if (g_strcmp0 (key, OSTREE_SUMMARY_STATIC_DELTAS) == 0) + { + pretty_key = "Static Deltas"; + value_str = g_variant_print (value, FALSE); + } + else if (g_strcmp0 (key, OSTREE_SUMMARY_LAST_MODIFIED) == 0) + { + pretty_key = "Last-Modified"; + value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value))); + } + else if (g_strcmp0 (key, OSTREE_SUMMARY_EXPIRES) == 0) + { + pretty_key = "Expires"; + value_str = uint64_secs_to_iso8601 (GUINT64_FROM_BE (g_variant_get_uint64 (value))); + } + else + { + value_str = g_variant_print (value, FALSE); + } + + /* Print out. */ + if (pretty_key != NULL) + g_print ("%s (%s): %s\n", pretty_key, key, value_str); + else + g_print ("%s: %s\n", key, value_str); } } diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index 7eb65602..9aca8287 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -45,26 +45,23 @@ static GOptionEntry global_entries[] = { }; static GOptionEntry repo_entry[] = { - { "repo", 0, 0, G_OPTION_ARG_STRING, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" }, + { "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" }, { NULL } }; static GOptionEntry global_admin_entries[] = { /* No description since it's hidden from --help output. */ { "print-current-dir", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_print_current_dir, NULL, NULL }, - { "sysroot", 0, 0, G_OPTION_ARG_STRING, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" }, + { "sysroot", 0, 0, G_OPTION_ARG_FILENAME, &opt_sysroot, "Create a new OSTree sysroot at PATH", "PATH" }, { NULL } }; static GOptionContext * ostree_option_context_new_with_commands (OstreeCommand *commands) { - GOptionContext *context; - GString *summary; + GOptionContext *context = g_option_context_new ("COMMAND"); - context = g_option_context_new ("COMMAND"); - - summary = g_string_new ("Builtin Commands:"); + g_autoptr(GString) summary = g_string_new ("Builtin Commands:"); while (commands->name != NULL) { @@ -74,8 +71,6 @@ ostree_option_context_new_with_commands (OstreeCommand *commands) g_option_context_set_summary (context, summary->str); - g_string_free (summary, TRUE); - return context; } @@ -223,7 +218,6 @@ ostree_option_context_parse (GOptionContext *context, GError **error) { glnx_unref_object OstreeRepo *repo = NULL; - gboolean success = FALSE; /* Entries are listed in --help output in the order added. We add the * main entries ourselves so that we can add the --repo entry first. */ @@ -278,7 +272,7 @@ ostree_option_context_parse (GOptionContext *context, { g_propagate_error (error, g_steal_pointer (&local_error)); } - goto out; + return FALSE; } } else if (opt_repo != NULL) @@ -289,17 +283,14 @@ ostree_option_context_parse (GOptionContext *context, if (!(flags & OSTREE_BUILTIN_FLAG_NO_CHECK)) { if (!ostree_repo_open (repo, cancellable, error)) - goto out; + return FALSE; } } if (out_repo) *out_repo = g_steal_pointer (&repo); - success = TRUE; - -out: - return success; + return TRUE; } gboolean @@ -312,22 +303,19 @@ ostree_admin_option_context_parse (GOptionContext *context, GCancellable *cancellable, GError **error) { - g_autoptr(GFile) sysroot_path = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; - gboolean success = FALSE; - /* Entries are listed in --help output in the order added. We add the * main entries ourselves so that we can add the --sysroot entry first. */ g_option_context_add_main_entries (context, global_admin_entries, NULL); if (!ostree_option_context_parse (context, main_entries, argc, argv, OSTREE_BUILTIN_FLAG_NO_REPO, NULL, cancellable, error)) - goto out; + return FALSE; + g_autoptr(GFile) sysroot_path = NULL; if (opt_sysroot != NULL) sysroot_path = g_file_new_for_path (opt_sysroot); - sysroot = ostree_sysroot_new (sysroot_path); + glnx_unref_object OstreeSysroot *sysroot = ostree_sysroot_new (sysroot_path); if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER) { @@ -338,7 +326,7 @@ ostree_admin_option_context_parse (GOptionContext *context, { g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED, "You must be root to perform this command"); - goto out; + return FALSE; } } @@ -350,15 +338,11 @@ ostree_admin_option_context_parse (GOptionContext *context, g_autofree char *deployment_path = NULL; if (!ostree_sysroot_load (sysroot, cancellable, error)) - goto out; + return FALSE; deployments = ostree_sysroot_get_deployments (sysroot); if (deployments->len == 0) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Unable to find a deployment in sysroot"); - goto out; - } + return glnx_throw (error, "Unable to find a deployment in sysroot"); first_deployment = deployments->pdata[0]; deployment_file = ostree_sysroot_get_deployment_directory (sysroot, first_deployment); deployment_path = g_file_get_path (deployment_file); @@ -379,46 +363,36 @@ ostree_admin_option_context_parse (GOptionContext *context, { /* Released when sysroot is finalized, or on process exit */ if (!ot_admin_sysroot_lock (sysroot, error)) - goto out; + return FALSE; } if (out_sysroot) *out_sysroot = g_steal_pointer (&sysroot); - success = TRUE; - -out: - return success; + return TRUE; } gboolean ostree_ensure_repo_writable (OstreeRepo *repo, GError **error) { - gboolean ret; - - ret = ostree_repo_is_writable (repo, error); - - g_prefix_error (error, "Cannot write to repository: "); - - return ret; + if (!ostree_repo_is_writable (repo, error)) + return glnx_prefix_error (error, "Cannot write to repository"); + return TRUE; } void ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result) { - GString *buffer; - guint n_sigs, ii; - - n_sigs = ostree_gpg_verify_result_count_all (result); + guint n_sigs = ostree_gpg_verify_result_count_all (result); /* XXX If we ever add internationalization, use ngettext() here. */ g_print ("GPG: Verification enabled, found %u signature%s:\n", n_sigs, n_sigs == 1 ? "" : "s"); - buffer = g_string_sized_new (256); + g_autoptr(GString) buffer = g_string_sized_new (256); - for (ii = 0; ii < n_sigs; ii++) + for (guint ii = 0; ii < n_sigs; ii++) { g_string_append_c (buffer, '\n'); ostree_gpg_verify_result_describe (result, ii, buffer, " ", @@ -426,13 +400,11 @@ ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result) } g_print ("%s", buffer->str); - g_string_free (buffer, TRUE); } gboolean ot_enable_tombstone_commits (OstreeRepo *repo, GError **error) { - gboolean ret = FALSE; gboolean tombstone_commits = FALSE; GKeyFile *config = ostree_repo_get_config (repo); @@ -442,10 +414,8 @@ ot_enable_tombstone_commits (OstreeRepo *repo, GError **error) { g_key_file_set_boolean (config, "core", "tombstone-commits", TRUE); if (!ostree_repo_write_config (repo, config, error)) - goto out; + return FALSE; } - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/ostree/ot-remote-builtin-refs.c b/src/ostree/ot-remote-builtin-refs.c index f5b3afe3..9e6ee144 100644 --- a/src/ostree/ot-remote-builtin-refs.c +++ b/src/ostree/ot-remote-builtin-refs.c @@ -28,7 +28,7 @@ static char* opt_cache_dir; static GOptionEntry option_entries[] = { - { "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL }, + { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { NULL } }; diff --git a/src/ostree/ot-remote-builtin-summary.c b/src/ostree/ot-remote-builtin-summary.c index b4d99254..5ddcf69b 100644 --- a/src/ostree/ot-remote-builtin-summary.c +++ b/src/ostree/ot-remote-builtin-summary.c @@ -31,7 +31,7 @@ static gboolean opt_raw; static char* opt_cache_dir; static GOptionEntry option_entries[] = { - { "cache-dir", 0, 0, G_OPTION_ARG_STRING, &opt_cache_dir, "Use custom cache dir", NULL }, + { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data", NULL }, { NULL } }; diff --git a/src/ostree/ot-remote-cookie-util.c b/src/ostree/ot-remote-cookie-util.c index a96038aa..e3ca9eac 100644 --- a/src/ostree/ot-remote-cookie-util.c +++ b/src/ostree/ot-remote-cookie-util.c @@ -298,14 +298,18 @@ ot_list_cookies_at (int dfd, const char *jar_path, GError **error) while (ot_parse_cookies_next (parser)) { g_autoptr(GDateTime) expires = g_date_time_new_from_unix_utc (parser->expiration); - g_autofree char *expires_str = g_date_time_format (expires, "%Y-%m-%d %H:%M:%S +0000"); + g_autofree char *expires_str = NULL; + + if (expires != NULL) + expires_str = g_date_time_format (expires, "%Y-%m-%d %H:%M:%S +0000"); g_print ("--\n"); g_print ("Domain: %s\n", parser->domain); g_print ("Path: %s\n", parser->path); g_print ("Name: %s\n", parser->name); g_print ("Secure: %s\n", parser->secure); - g_print ("Expires: %s\n", expires_str); + if (expires_str != NULL) + g_print ("Expires: %s\n", expires_str); g_print ("Value: %s\n", parser->value); } #else diff --git a/src/rofiles-fuse/main.c b/src/rofiles-fuse/main.c index 3f0832f5..12a9d886 100644 --- a/src/rofiles-fuse/main.c +++ b/src/rofiles-fuse/main.c @@ -56,12 +56,12 @@ callback_getattr (const char *path, struct stat *st_data) if (!*path) { if (fstat (basefd, st_data) == -1) - return -errno; + return -errno; } else { if (fstatat (basefd, path, st_data, AT_SYMLINK_NOFOLLOW) == -1) - return -errno; + return -errno; } return 0; } @@ -85,7 +85,7 @@ callback_readlink (const char *path, char *buf, size_t size) static int callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi) + off_t offset, struct fuse_file_info *fi) { DIR *dp; struct dirent *de; @@ -102,7 +102,7 @@ callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler, { dfd = openat (basefd, path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); if (dfd == -1) - return -errno; + return -errno; } /* Transfers ownership of fd */ @@ -117,7 +117,7 @@ callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler, st.st_ino = de->d_ino; st.st_mode = de->d_type << 12; if (filler (buf, de->d_name, &st, 0)) - break; + break; } (void) closedir (dp); @@ -170,7 +170,7 @@ callback_symlink (const char *from, const char *to) if (fstatat (basefd, to, &stbuf, AT_SYMLINK_NOFOLLOW) == -1) { fprintf (stderr, "Failed to find newly created symlink '%s': %s\n", - to, g_strerror (errno)); + to, g_strerror (errno)); exit (EXIT_FAILURE); } return 0; @@ -209,19 +209,19 @@ can_write (const char *path) if (fstatat (basefd, path, &stbuf, 0) == -1) { if (errno == ENOENT) - return 0; + return 0; else - return -errno; + return -errno; } if (stbuf_is_regfile_hardlinked (&stbuf)) return -EROFS; return 0; } -#define VERIFY_WRITE(path) do { \ - int r = can_write (path); \ - if (r != 0) \ - return r; \ +#define VERIFY_WRITE(path) do { \ + int r = can_write (path); \ + if (r != 0) \ + return r; \ } while (0) static int @@ -366,7 +366,7 @@ callback_read_buf (const char *path, struct fuse_bufvec **bufp, static int callback_read (const char *path, char *buf, size_t size, off_t offset, - struct fuse_file_info *finfo) + struct fuse_file_info *finfo) { int r; r = pread (finfo->fh, buf, size, offset); @@ -390,7 +390,7 @@ callback_write_buf (const char *path, struct fuse_bufvec *buf, off_t offset, static int callback_write (const char *path, const char *buf, size_t size, off_t offset, - struct fuse_file_info *finfo) + struct fuse_file_info *finfo) { int r; r = pwrite (finfo->fh, buf, size, offset); @@ -426,7 +426,7 @@ static int callback_access (const char *path, int mode) { path = ENSURE_RELPATH (path); - + /* Apparently at least GNU coreutils rm calls `faccessat(W_OK)` * before trying to do an unlink. So...we'll just lie about * writable access here. @@ -438,14 +438,14 @@ callback_access (const char *path, int mode) static int callback_setxattr (const char *path, const char *name, const char *value, - size_t size, int flags) + size_t size, int flags) { return -ENOTSUP; } static int callback_getxattr (const char *path, const char *name, char *value, - size_t size) + size_t size) { return -ENOTSUP; } @@ -503,8 +503,7 @@ struct fuse_operations callback_oper = { .removexattr = callback_removexattr }; -enum -{ +enum { KEY_HELP, KEY_VERSION, }; @@ -513,19 +512,19 @@ static void usage (const char *progname) { fprintf (stdout, - "usage: %s basepath mountpoint [options]\n" - "\n" - " Makes basepath visible at mountpoint such that files are read-only, directories are writable\n" - "\n" - "general options:\n" - " -o opt,[opt...] mount options\n" - " -h --help print help\n" - "\n", progname); + "usage: %s basepath mountpoint [options]\n" + "\n" + " Makes basepath visible at mountpoint such that files are read-only, directories are writable\n" + "\n" + "general options:\n" + " -o opt,[opt...] mount options\n" + " -h --help print help\n" + "\n", progname); } static int rofs_parse_opt (void *data, const char *arg, int key, - struct fuse_args *outargs) + struct fuse_args *outargs) { (void) data; @@ -533,19 +532,19 @@ rofs_parse_opt (void *data, const char *arg, int key, { case FUSE_OPT_KEY_NONOPT: if (basefd == -1) - { - basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); - if (basefd == -1) - { - perror ("openat"); - exit (EXIT_FAILURE); - } - return 0; - } + { + basefd = openat (AT_FDCWD, arg, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); + if (basefd == -1) + { + perror ("openat"); + exit (EXIT_FAILURE); + } + return 0; + } else - { - return 1; - } + { + return 1; + } case FUSE_OPT_KEY_OPT: return 1; case KEY_HELP: diff --git a/src/switchroot/ostree-mount-util.h b/src/switchroot/ostree-mount-util.h index b24aa44d..1e7253d2 100644 --- a/src/switchroot/ostree-mount-util.h +++ b/src/switchroot/ostree-mount-util.h @@ -25,6 +25,10 @@ #include #include #include +#include +#include +#include +#include static inline int path_is_on_readonly_fs (char *path) @@ -37,4 +41,66 @@ path_is_on_readonly_fs (char *path) return (stvfsbuf.f_flag & ST_RDONLY) != 0; } +static inline char * +read_proc_cmdline (void) +{ + FILE *f = fopen("/proc/cmdline", "r"); + char *cmdline = NULL; + size_t len; + + if (!f) + goto out; + + /* Note that /proc/cmdline will not end in a newline, so getline + * will fail unelss we provide a length. + */ + if (getline (&cmdline, &len, f) < 0) + goto out; + /* ... but the length will be the size of the malloc buffer, not + * strlen(). Fix that. + */ + len = strlen (cmdline); + + if (cmdline[len-1] == '\n') + cmdline[len-1] = '\0'; +out: + if (f) + fclose (f); + return cmdline; +} + +static inline char * +read_proc_cmdline_ostree (void) +{ + char *cmdline = NULL; + const char *iter; + char *ret = NULL; + + cmdline = read_proc_cmdline (); + if (!cmdline) + err (EXIT_FAILURE, "failed to read /proc/cmdline"); + + iter = cmdline; + while (iter != NULL) + { + const char *next = strchr (iter, ' '); + const char *next_nonspc = next; + while (next_nonspc && *next_nonspc == ' ') + next_nonspc += 1; + if (strncmp (iter, "ostree=", strlen ("ostree=")) == 0) + { + const char *start = iter + strlen ("ostree="); + if (next) + ret = strndup (start, next - start); + else + ret = strdup (start); + break; + } + iter = next_nonspc; + } + + free (cmdline); + return ret; +} + #endif /* __OSTREE_MOUNT_UTIL_H_ */ diff --git a/src/switchroot/ostree-prepare-root.c b/src/switchroot/ostree-prepare-root.c index ce48a91e..9b8c3381 100644 --- a/src/switchroot/ostree-prepare-root.c +++ b/src/switchroot/ostree-prepare-root.c @@ -1,13 +1,13 @@ /* -*- c-file-style: "gnu" -*- * Switch to new root directory and start init. - * + * * Copyright 2011,2012,2013 Colin Walters * - * Based on code from util-linux/sys-utils/switch_root.c, + * Based on code from util-linux/sys-utils/switch_root.c, * Copyright 2002-2009 Red Hat, Inc. All rights reserved. * Authors: - * Peter Jones - * Jeremy Katz + * Peter Jones + * Jeremy Katz * * Relicensed with permission to LGPLv2+. * @@ -46,68 +46,6 @@ #include "ostree-mount-util.h" -static char * -read_proc_cmdline (void) -{ - FILE *f = fopen("/proc/cmdline", "r"); - char *cmdline = NULL; - size_t len; - - if (!f) - goto out; - - /* Note that /proc/cmdline will not end in a newline, so getline - * will fail unelss we provide a length. - */ - if (getline (&cmdline, &len, f) < 0) - goto out; - /* ... but the length will be the size of the malloc buffer, not - * strlen(). Fix that. - */ - len = strlen (cmdline); - - if (cmdline[len-1] == '\n') - cmdline[len-1] = '\0'; -out: - if (f) - fclose (f); - return cmdline; -} - -static char * -parse_ostree_cmdline (void) -{ - char *cmdline = NULL; - const char *iter; - char *ret = NULL; - - cmdline = read_proc_cmdline (); - if (!cmdline) - err (EXIT_FAILURE, "failed to read /proc/cmdline"); - - iter = cmdline; - while (iter != NULL) - { - const char *next = strchr (iter, ' '); - const char *next_nonspc = next; - while (next_nonspc && *next_nonspc == ' ') - next_nonspc += 1; - if (strncmp (iter, "ostree=", strlen ("ostree=")) == 0) - { - const char *start = iter + strlen ("ostree="); - if (next) - ret = strndup (start, next - start); - else - ret = strdup (start); - break; - } - iter = next_nonspc; - } - - free (cmdline); - return ret; -} - /* This is an API for other projects to determine whether or not the * currently running system is ostree-controlled. */ @@ -115,8 +53,8 @@ static void touch_run_ostree (void) { int fd; - - fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY, 0640); + + fd = open ("/run/ostree-booted", O_CREAT | O_WRONLY | O_NOCTTY | O_CLOEXEC, 0640); /* We ignore failures here in case /run isn't mounted...not much we * can do about that, but we don't want to fail. */ @@ -132,7 +70,7 @@ resolve_deploy_path (const char * root_mountpoint) struct stat stbuf; char *ostree_target, *deploy_path; - ostree_target = parse_ostree_cmdline (); + ostree_target = read_proc_cmdline_ostree (); if (!ostree_target) errx (EXIT_FAILURE, "No OSTree target; expected ostree=/ostree/boot.N/..."); @@ -211,9 +149,12 @@ main(int argc, char *argv[]) if (chdir (deploy_path) < 0) err (EXIT_FAILURE, "failed to chdir to deploy_path"); + /* In the systemd case, this is handled by ostree-system-generator */ +#ifndef HAVE_SYSTEMD_AND_LIBMOUNT /* Link to the deployment's /var */ if (mount ("../../var", "var", NULL, MS_MGC_VAL|MS_BIND, NULL) < 0) err (EXIT_FAILURE, "failed to bind mount ../../var to var"); +#endif /* If /boot is on the same partition, use a bind mount to make it visible * at /boot inside the deployment. */ @@ -239,11 +180,11 @@ main(int argc, char *argv[]) * later boot and `systemd-remount-fs.service`. */ if (path_is_on_readonly_fs (".")) - { - if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) - err (EXIT_FAILURE, "failed to remount rootfs writable (for overlayfs)"); - } - + { + if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) + err (EXIT_FAILURE, "failed to remount rootfs writable (for overlayfs)"); + } + if (mount ("overlay", "usr", "overlay", 0, usr_ovl_options) < 0) err (EXIT_FAILURE, "failed to mount /usr overlayfs"); } diff --git a/src/switchroot/ostree-remount.c b/src/switchroot/ostree-remount.c index 589a3867..a6d14d08 100644 --- a/src/switchroot/ostree-remount.c +++ b/src/switchroot/ostree-remount.c @@ -38,28 +38,10 @@ #include "ostree-mount-util.h" -/* Having a writeable /var is necessary for full system functioning. - * If /var isn't writeable, we mount tmpfs over it. While this is - * somewhat outside of ostree's scope, having all /var twiddling - * in one place will make future maintenance easier. - */ -static void -maybe_mount_tmpfs_on_var (void) -{ - if (!path_is_on_readonly_fs ("/var")) - return; - - if (umount ("/var") < 0 && errno != EINVAL) - warn ("failed to unmount /var prior to mounting tmpfs, mounting over"); - - if (mount ("tmpfs", "/var", "tmpfs", 0, NULL) < 0) - err (EXIT_FAILURE, "failed to mount tmpfs on /var"); -} - int main(int argc, char *argv[]) { - const char *remounts[] = { "/sysroot", "/etc", "/home", "/root", "/tmp", "/var", NULL }; + const char *remounts[] = { "/sysroot", "/var", NULL }; struct stat stbuf; int i; @@ -69,8 +51,6 @@ main(int argc, char *argv[]) * to clear the readonly flag in that case. */ - maybe_mount_tmpfs_on_var (); - exit (EXIT_SUCCESS); } @@ -84,17 +64,25 @@ main(int argc, char *argv[]) */ if (S_ISLNK (stbuf.st_mode)) continue; + /* If not a mountpoint, skip it */ + struct statvfs stvfsbuf; + if (statvfs (target, &stvfsbuf) == -1) + continue; + /* If no read-only flag, skip it */ + if ((stvfsbuf.f_flag & ST_RDONLY) == 0) + continue; + /* It's a mounted, read-only fs; remount it */ if (mount (target, target, NULL, MS_REMOUNT | MS_SILENT, NULL) < 0) - { + { /* Also ignore ENINVAL - if the target isn't a mountpoint * already, then assume things are OK. */ if (errno != EINVAL) err (EXIT_FAILURE, "failed to remount %s", target); - } + } + else + printf ("Remounted: %s\n", target); } - maybe_mount_tmpfs_on_var (); - exit (EXIT_SUCCESS); } diff --git a/src/switchroot/ostree-system-generator.c b/src/switchroot/ostree-system-generator.c new file mode 100644 index 00000000..e7205b5a --- /dev/null +++ b/src/switchroot/ostree-system-generator.c @@ -0,0 +1,67 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * 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. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "ostree-cmdprivate.h" +#include "ostree-mount-util.h" + +static const char *arg_dest = "/tmp"; +static const char *arg_dest_late = "/tmp"; + +/* This program is a simple stub that calls the implementation that + * lives inside libostree. + */ +int +main(int argc, char *argv[]) +{ + /* Important: if this isn't an ostree-booted system, do nothing; people could + * have the package installed as a dependency for flatpak or whatever. + */ + { struct stat stbuf; + if (fstatat (AT_FDCWD, "/run/ostree-booted", &stbuf, 0) < 0) + exit (EXIT_SUCCESS); + } + + if (argc > 1 && argc != 4) + errx (EXIT_FAILURE, "This program takes three or no arguments"); + + if (argc > 1) + arg_dest = argv[1]; + if (argc > 3) + arg_dest_late = argv[3]; + + char *ostree_cmdline = read_proc_cmdline_ostree (); + if (!ostree_cmdline) + errx (EXIT_FAILURE, "Failed to find ostree= kernel argument"); + + { g_autoptr(GError) local_error = NULL; + if (!ostree_cmd__private__()->ostree_system_generator (ostree_cmdline, arg_dest, NULL, arg_dest_late, &local_error)) + errx (EXIT_FAILURE, "%s", local_error->message); + } + + exit (EXIT_SUCCESS); +} diff --git a/tests/basic-test.sh b/tests/basic-test.sh index f4b2b118..b209b839 100644 --- a/tests/basic-test.sh +++ b/tests/basic-test.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..65" +echo "1..66" $CMD_PREFIX ostree --version > version.yaml python -c 'import yaml; yaml.safe_load(open("version.yaml"))' @@ -28,7 +28,7 @@ echo "ok yaml version" CHECKOUT_U_ARG="" COMMIT_ARGS="" DIFF_ARGS="" -if grep bare-user-only repo/config; then +if grep -q bare-user-only repo/config; then # In bare-user-only repos we can only represent files with uid/gid 0, no # xattrs and canonical permissions, so we need to commit them as such, or # we end up with repos that don't pass fsck @@ -50,11 +50,14 @@ validate_checkout_basic() { $OSTREE checkout test2 checkout-test2 validate_checkout_basic checkout-test2 +if grep -q 'mode=bare$' repo/config; then + assert_not_streq $(stat -c '%h' checkout-test2/firstfile) 1 +fi echo "ok checkout" # Note this tests bare-user *and* bare-user-only rm checkout-test2 -rf -if grep bare-user repo/config; then +if grep -q bare-user repo/config; then $OSTREE checkout -U -H test2 checkout-test2 else $OSTREE checkout -H test2 checkout-test2 @@ -78,6 +81,14 @@ fi fi echo "ok checkout -H" +rm checkout-test2 -rf +$OSTREE checkout -C test2 checkout-test2 +for file in firstfile baz/cow baz/alink; do + assert_streq $(stat -c '%h' checkout-test2/$file) 1 +done + +echo "ok checkout -C" + $OSTREE rev-parse test2 $OSTREE rev-parse 'test2^' $OSTREE rev-parse 'test2^^' 2>/dev/null && fatal "rev-parse test2^^ unexpectedly succeeded!" @@ -330,6 +341,18 @@ cd ${test_tmpdir} $OSTREE checkout --subpath /yet/another test2 checkout-test2-subpath cd checkout-test2-subpath assert_file_has_content tree/green "leaf" +cd ${test_tmpdir} +rm checkout-test2-subpath -rf +$OSTREE ls -R test2 +# Test checking out a file +$OSTREE checkout --subpath /baz/saucer test2 checkout-test2-subpath +assert_file_has_content checkout-test2-subpath/saucer alien +# Test checking out a file without making a subdir +mkdir t +cd t +$OSTREE checkout --subpath /baz/saucer test2 . +assert_file_has_content saucer alien +rm t -rf echo "ok checkout subpath" cd ${test_tmpdir} diff --git a/tests/libostreetest.c b/tests/libostreetest.c index cda1649d..2fb83f51 100644 --- a/tests/libostreetest.c +++ b/tests/libostreetest.c @@ -99,7 +99,7 @@ ot_test_setup_sysroot (GCancellable *cancellable, { g_autoptr(GString) buf = g_string_new ("mutable-deployments"); if (statfs ("/", &stbuf) < 0) - return glnx_throw_errno (error), NULL; + return glnx_null_throw_errno (error); /* Keep this in sync with the overlayfs bits in libtest.sh */ #ifndef OVERLAYFS_SUPER_MAGIC #define OVERLAYFS_SUPER_MAGIC 0x794c7630 diff --git a/tests/libtest-core.sh b/tests/libtest-core.sh new file mode 100644 index 00000000..d1d3bbdf --- /dev/null +++ b/tests/libtest-core.sh @@ -0,0 +1,118 @@ +# Core source library for shell script tests +# +# 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. + +fatal() { + echo $@ 1>&2; exit 1 +} +# fatal() is shorter to type, but retain this alias +assert_not_reached () { + fatal "$@" +} + +# Some tests look for specific English strings. Use a UTF-8 version +# of the C (POSIX) locale if we have one, or fall back to POSIX +# (https://sourceware.org/glibc/wiki/Proposals/C.UTF-8) +if locale -a | grep C.UTF-8 >/dev/null; then + export LC_ALL=C.UTF-8 +else + export LC_ALL=C +fi + +# This should really be the default IMO +export G_DEBUG=fatal-warnings +assert_streq () { + test "$1" = "$2" || fatal "$1 != $2" +} + +assert_str_match () { + if ! echo "$1" | grep -E -q "$2"; then + fatal "$1 does not match regexp $2" + fi +} + +assert_not_streq () { + (! test "$1" = "$2") || fatal "$1 == $2" +} + +assert_has_file () { + test -f "$1" || fatal "Couldn't find '$1'" +} + +assert_has_dir () { + test -d "$1" || fatal "Couldn't find '$1'" +} + +assert_not_has_file () { + if test -f "$1"; then + sed -e 's/^/# /' < "$1" >&2 + fatal "File '$1' exists" + fi +} + +assert_not_file_has_content () { + if grep -q -e "$2" "$1"; then + sed -e 's/^/# /' < "$1" >&2 + fatal "File '$1' incorrectly matches regexp '$2'" + fi +} + +assert_not_has_dir () { + if test -d "$1"; then + fatal "Directory '$1' exists" + fi +} + +assert_file_has_content () { + if ! grep -q -e "$2" "$1"; then + sed -e 's/^/# /' < "$1" >&2 + fatal "File '$1' doesn't match regexp '$2'" + fi +} + +assert_file_has_content_literal () { + if ! grep -q -F -e "$2" "$1"; then + sed -e 's/^/# /' < "$1" >&2 + fatal "File '$1' doesn't match fixed string list '$2'" + fi +} + +assert_symlink_has_content () { + if ! test -L "$1"; then + echo 1>&2 "File '$1' is not a symbolic link" + exit 1 + fi + if ! readlink "$1" | grep -q -e "$2"; then + sed -e 's/^/# /' < "$1" >&2 + echo 1>&2 "Symbolic link '$1' doesn't match regexp '$2'" + exit 1 + fi +} + +assert_file_empty() { + if test -s "$1"; then + sed -e 's/^/# /' < "$1" >&2 + fatal "File '$1' is not empty" + fi +} + +# Use to skip all of these tests +skip() { + echo "1..0 # SKIP" "$@" + exit 0 +} diff --git a/tests/libtest.sh b/tests/libtest.sh index 58351f81..3ce718f9 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -17,6 +17,8 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. +dn=$(dirname $0) + if [ -n "${G_TEST_SRCDIR:-}" ]; then test_srcdir="${G_TEST_SRCDIR}/tests" else @@ -28,26 +30,10 @@ if [ -n "${G_TEST_BUILDDIR:-}" ]; then else test_builddir=$(dirname $0) fi - -fatal() { - echo $@ 1>&2; exit 1 -} -# fatal() is shorter to type, but retain this alias -assert_not_reached () { - fatal "$@" -} +. ${test_srcdir}/libtest-core.sh test_tmpdir=$(pwd) -# Some tests look for specific English strings. Use a UTF-8 version -# of the C (POSIX) locale if we have one, or fall back to POSIX -# (https://sourceware.org/glibc/wiki/Proposals/C.UTF-8) -if locale -a | grep C.UTF-8 >/dev/null; then - export LC_ALL=C.UTF-8 -else - export LC_ALL=C -fi - # Sanity check that we're in a tmpdir that has # just .testtmp (created by tap-driver for `make check`, # or nothing at all (as ginstest-runner does) @@ -62,8 +48,6 @@ if ! test -f .testtmp; then touch .testtmp fi -export G_DEBUG=fatal-warnings - # Also, unbreak `tar` inside `make check`...Automake will inject # TAR_OPTIONS: --owner=0 --group=0 --numeric-owner presumably so that # tarballs are predictable, except we don't want this in our tests. @@ -121,77 +105,17 @@ fi if test -n "${OSTREE_UNINSTALLED:-}"; then OSTREE_HTTPD=${OSTREE_UNINSTALLED}/ostree-trivial-httpd else - OSTREE_HTTPD="${CMD_PREFIX} ostree trivial-httpd" + # trivial-httpd is now in $libexecdir by default, which we don't + # know at this point. Fortunately, libtest.sh is also in + # $libexecdir, so make an educated guess. If it's not found, assume + # it's still runnable as "ostree trivial-httpd". + if [ -x "${test_srcdir}/../../libostree/ostree-trivial-httpd" ]; then + OSTREE_HTTPD="${CMD_PREFIX} ${test_srcdir}/../../libostree/ostree-trivial-httpd" + else + OSTREE_HTTPD="${CMD_PREFIX} ostree trivial-httpd" + fi fi -assert_streq () { - test "$1" = "$2" || fatal "$1 != $2" -} - -assert_str_match () { - if ! echo "$1" | grep -E -q "$2"; then - fatal "$1 does not match regexp $2" - fi -} - -assert_not_streq () { - (! test "$1" = "$2") || fatal "$1 == $2" -} - -assert_has_file () { - test -f "$1" || fatal "Couldn't find '$1'" -} - -assert_has_dir () { - test -d "$1" || fatal "Couldn't find '$1'" -} - -assert_not_has_file () { - if test -f "$1"; then - sed -e 's/^/# /' < "$1" >&2 - fatal "File '$1' exists" - fi -} - -assert_not_file_has_content () { - if grep -q -e "$2" "$1"; then - sed -e 's/^/# /' < "$1" >&2 - fatal "File '$1' incorrectly matches regexp '$2'" - fi -} - -assert_not_has_dir () { - if test -d "$1"; then - fatal "Directory '$1' exists" - fi -} - -assert_file_has_content () { - if ! grep -q -e "$2" "$1"; then - sed -e 's/^/# /' < "$1" >&2 - fatal "File '$1' doesn't match regexp '$2'" - fi -} - -assert_symlink_has_content () { - if ! test -L "$1"; then - echo 1>&2 "File '$1' is not a symbolic link" - exit 1 - fi - if ! readlink "$1" | grep -q -e "$2"; then - sed -e 's/^/# /' < "$1" >&2 - echo 1>&2 "Symbolic link '$1' doesn't match regexp '$2'" - exit 1 - fi -} - -assert_file_empty() { - if test -s "$1"; then - sed -e 's/^/# /' < "$1" >&2 - fatal "File '$1' is not empty" - fi -} - assert_files_hardlinked() { f1=$(stat -c %i $1) f2=$(stat -c %i $2) @@ -491,6 +415,9 @@ EOF mkdir sysroot export OSTREE_SYSROOT=sysroot ${CMD_PREFIX} ostree admin init-fs sysroot + if test -n "${OSTREE_NO_XATTRS:-}"; then + echo -e 'disable-xattrs=true\n' >> sysroot/ostree/repo/config + fi ${CMD_PREFIX} ostree admin os-init testos case $bootmode in @@ -541,11 +468,6 @@ os_repository_new_commit () cd ${test_tmpdir} } -skip() { - echo "1..0 # SKIP" "$@" - exit 0 -} - skip_without_user_xattrs () { touch test-xattrs setfattr -n user.testvalue -v somevalue test-xattrs || \ diff --git a/tests/pull-test.sh b/tests/pull-test.sh index f2486c31..f81d8023 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..15" +echo "1..16" # Try both syntaxes repo_init @@ -150,23 +150,33 @@ prev_rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main^) new_rev=$(ostree --repo=ostree-srv/gnomerepo rev-parse main) ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo summary -u +# Explicitly test delta fetches via ref name as well as commit hash +for delta_target in main ${new_rev}; do cd ${test_tmpdir} repo_init ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} -${CMD_PREFIX} ostree --repo=repo pull --dry-run --require-static-deltas origin main >dry-run-pull.txt +${CMD_PREFIX} ostree --repo=repo pull --dry-run --require-static-deltas origin ${delta_target} >dry-run-pull.txt # Compression can vary, so we support 400-699 assert_file_has_content dry-run-pull.txt 'Delta update: 0/1 parts, 0 bytes/[456][0-9][0-9] bytes, 455 bytes total uncompressed' rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main) assert_streq "${prev_rev}" "${rev}" ${CMD_PREFIX} ostree --repo=repo fsck +done +# Explicitly test delta fetches via ref name as well as commit hash +for delta_target in main ${new_rev}; do cd ${test_tmpdir} repo_init ${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} -${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main -rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main) -assert_streq "${new_rev}" "${rev}" +${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${delta_target} +if test ${delta_target} = main; then + rev=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main) + assert_streq "${new_rev}" "${rev}" +else + ${CMD_PREFIX} ostree --repo=repo rev-parse ${delta_target} +fi ${CMD_PREFIX} ostree --repo=repo fsck +done cd ${test_tmpdir} repo_init @@ -208,8 +218,23 @@ fi assert_file_has_content err.txt "deltas required, but none found" ${CMD_PREFIX} ostree --repo=repo fsck +# Now test with a partial commit +repo_init +${CMD_PREFIX} ostree --repo=repo pull --commit-metadata-only origin main@${prev_rev} +if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin main 2>err.txt; then + assert_not_reached "--require-static-deltas unexpectedly succeeded" +fi +assert_file_has_content err.txt "deltas required, but none found" echo "ok delta required but don't exist" +repo_init +${CMD_PREFIX} ostree --repo=repo pull origin main@${prev_rev} +if ${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${new_rev} 2>err.txt; then + assert_not_reached "--require-static-deltas unexpectedly succeeded" +fi +assert_file_has_content err.txt "deltas required, but none found" +echo "ok delta required for revision" + cd ${test_tmpdir} rm main-files -rf ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout main main-files diff --git a/tests/readdir-rand.c b/tests/readdir-rand.c index afef387c..10bf8677 100644 --- a/tests/readdir-rand.c +++ b/tests/readdir-rand.c @@ -83,7 +83,7 @@ readdir (DIR *dirp) struct dirent *(*real_readdir)(DIR *dirp) = dlsym (RTLD_NEXT, READDIR); struct dirent *ret; gboolean cache_another = TRUE; - + ensure_initialized (); /* The core idea here is that each time through the loop, we read a @@ -101,40 +101,40 @@ readdir (DIR *dirp) errno = 0; ret = real_readdir (dirp); if (ret == NULL && errno != 0) - goto out; + goto out; g_mutex_lock (&direntcache_lock); de = g_hash_table_lookup (direntcache, dirp); if (ret) - { - if (g_random_boolean ()) - { - struct dirent *copy; - if (!de) - { - de = dir_entries_new (); - g_hash_table_insert (direntcache, dirp, de); - } - copy = g_memdup (ret, sizeof (struct dirent)); - g_ptr_array_add (de->entries, copy); - } - else - { - cache_another = FALSE; - } - } + { + if (g_random_boolean ()) + { + struct dirent *copy; + if (!de) + { + de = dir_entries_new (); + g_hash_table_insert (direntcache, dirp, de); + } + copy = g_memdup (ret, sizeof (struct dirent)); + g_ptr_array_add (de->entries, copy); + } + else + { + cache_another = FALSE; + } + } else - { - if (de && de->offset < de->entries->len) - { - ret = de->entries->pdata[de->offset]; - de->offset++; - } - cache_another = FALSE; - } + { + if (de && de->offset < de->entries->len) + { + ret = de->entries->pdata[de->offset]; + de->offset++; + } + cache_another = FALSE; + } g_mutex_unlock (&direntcache_lock); } - + out: return ret; } @@ -145,7 +145,7 @@ closedir (DIR *dirp) int (*real_closedir)(DIR *dirp) = dlsym (RTLD_NEXT, "closedir"); ensure_initialized (); - + g_mutex_lock (&direntcache_lock); g_hash_table_remove (direntcache, dirp); g_mutex_unlock (&direntcache_lock); @@ -170,7 +170,7 @@ seekdir (DIR *dirp, long loc) ensure_initialized (); - /* For now, crash if seekdir is called when we have cached entries. + /* For now, crash if seekdir is called when we have cached entries. * If some app wants to use this and seekdir() we can implement it. */ assert_no_cached_entries (dirp); diff --git a/tests/test-basic-root.sh b/tests/test-basic-root.sh new file mode 100755 index 00000000..a2fa8809 --- /dev/null +++ b/tests/test-basic-root.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Copyright (C) 2011 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. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +id=$(id -u) + +if test ${id} != 0; then + skip "continued basic tests must be run as root (possibly in a container)" +fi + +setup_test_repository "bare" + +echo "1..1" + +nextid=$(($id + 1)) + +rm checkout-test2 -rf +$OSTREE checkout test2 checkout-test2 +$OSTREE commit ${COMMIT_ARGS} -b test2 --tree=ref=test2 --owner-uid=$nextid +$OSTREE ls test2 baz/cow > ls.txt +assert_file_has_content ls.txt '-00644 '${nextid}' '${id} +# As bare and running as root (e.g. Docker container), do some ownership tests +# https://github.com/ostreedev/ostree/pull/801 +# Both hardlinks and copies should respect ownership, but we don't have -C yet; +# add it when we do. +for opt in -H; do + rm test2-co -rf + $OSTREE checkout ${opt} test2 test2-co + assert_streq "$(stat -c '%u' test2-co/baz/cow)" ${nextid} + assert_streq "$(stat -c '%u' test2-co/baz/alink)" ${nextid} +done +rm test2-co -rf +# But user mode doesn't +$OSTREE checkout -U test2 test2-co +assert_streq "$(stat -c '%u' test2-co/baz/cow)" ${id} +assert_streq "$(stat -c '%u' test2-co/baz/alink)" ${id} +echo "ok ownership" diff --git a/tests/test-core.js b/tests/test-core.js index e9ace6e9..64d1b62d 100644 --- a/tests/test-core.js +++ b/tests/test-core.js @@ -52,4 +52,18 @@ let child = root.get_child('some-file'); let info = child.query_info("standard::name,standard::type,standard::size", 0, null); assertEquals(info.get_size(), 12); +// Write a ref and read it back +repo.prepare_transaction(null); +repo.transaction_set_refspec('someref', commit); +repo.commit_transaction(null, null); +let [,readCommit] = repo.resolve_rev('someref', false); +assertEquals(readCommit, commit); + +// Delete a ref +repo.prepare_transaction(null); +repo.transaction_set_refspec('someref', null); +repo.commit_transaction(null, null); +[,readCommit] = repo.resolve_rev('someref', true); +assertEquals(readCommit, null); + print("test-core complete"); diff --git a/tests/test-corruption.sh b/tests/test-corruption.sh index ef0e94ef..8e2aba56 100755 --- a/tests/test-corruption.sh +++ b/tests/test-corruption.sh @@ -19,10 +19,12 @@ set -euo pipefail -echo "1..2" +echo "1..3" . $(dirname $0)/libtest.sh +cd ${test_tmpdir} +rm repo files -rf setup_test_repository "bare" $OSTREE checkout test2 checkout-test2 cd checkout-test2 @@ -34,6 +36,8 @@ $OSTREE fsck -q echo "ok chmod" cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" rm checkout-test2 -rf $OSTREE checkout test2 checkout-test2 cd checkout-test2 @@ -41,3 +45,14 @@ chmod o+x firstfile $OSTREE fsck -q --delete && (echo 1>&2 "fsck unexpectedly succeeded"; exit 1) echo "ok chmod" + +cd ${test_tmpdir} +rm repo files -rf +setup_test_repository "bare" +find repo/ -name '*.commit' -delete +if $OSTREE fsck -q 2>err.txt; then + assert_not_reached "fsck unexpectedly succeeded" +fi +assert_file_has_content_literal err.txt "Loading commit for ref test2: No such metadata object" + +echo "ok missing commit" diff --git a/tests/test-delta.sh b/tests/test-delta.sh index 84320b80..8baee723 100755 --- a/tests/test-delta.sh +++ b/tests/test-delta.sh @@ -169,9 +169,9 @@ echo 'ok heuristic endian detection' ${CMD_PREFIX} ostree --repo=repo summary -u mkdir repo2 && ostree_repo_init repo2 --mode=bare-user -${CMD_PREFIX} ostree --repo=repo2 pull-local --require-static-deltas repo ${newrev} +${CMD_PREFIX} ostree --repo=repo2 pull-local --require-static-deltas repo ${origrev} ${CMD_PREFIX} ostree --repo=repo2 fsck -${CMD_PREFIX} ostree --repo=repo2 ls ${newrev} >/dev/null +${CMD_PREFIX} ostree --repo=repo2 ls ${origrev} >/dev/null echo 'ok pull delta' diff --git a/tests/test-gpg-verify-result.c b/tests/test-gpg-verify-result.c index d2c1ff66..62b05e33 100644 --- a/tests/test-gpg-verify-result.c +++ b/tests/test-gpg-verify-result.c @@ -28,11 +28,10 @@ #define assert_no_gpg_error(err, filename) \ G_STMT_START { \ if (err != GPG_ERR_NO_ERROR) { \ - GString *string = g_string_new ("assertion failed "); \ + g_autoptr(GString) string = g_string_new ("assertion failed "); \ g_string_append_printf (string, "%s: %s ", gpgme_strsource (err), gpgme_strerror (err)); \ g_string_append (string, filename ? filename : ""); \ g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, string->str); \ - g_string_free (string, TRUE); \ } \ } G_STMT_END diff --git a/tests/test-pull-many.sh b/tests/test-pull-many.sh deleted file mode 100755 index 73245a6b..00000000 --- a/tests/test-pull-many.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -# -# 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. - -set -euo pipefail - -. $(dirname $0)/libtest.sh - -setup_exampleos_repo - -echo '1..3' - -cd ${test_tmpdir} -set -x - -echo "$(date): Pulling content..." -rev=$(${CMD_PREFIX} ostree --repo=ostree-srv/exampleos/repo rev-parse ${REF}) -${CMD_PREFIX} ostree --repo=repo pull --disable-static-deltas origin ${REF} -${CMD_PREFIX} ostree --repo=repo fsck -assert_streq ${rev} $(${CMD_PREFIX} ostree --repo=repo rev-parse ${REF}) - -echo "ok without deltas" - -previous=$(${CMD_PREFIX} ostree --repo=repo rev-parse ${rev}^) -rm repo/refs/{heads,remotes}/* -rf -${CMD_PREFIX} ostree --repo=repo prune --refs-only -${CMD_PREFIX} ostree --repo=repo pull origin ${REF}@${previous} -${CMD_PREFIX} ostree --repo=repo pull --dry-run --require-static-deltas origin ${REF} > output.txt -assert_file_has_content output.txt 'Delta update: 0/1 parts, 0 bytes/1.[012] MB, 1.[345] MB total uncompressed' - -echo "ok delta dry-run" - -${CMD_PREFIX} ostree --repo=repo pull --require-static-deltas origin ${REF} -assert_streq $(${CMD_PREFIX} ostree --repo=repo rev-parse ${REF}) ${rev} -${CMD_PREFIX} ostree --repo=repo fsck - -echo "ok" diff --git a/tests/test-repo-checkout-subpath.sh b/tests/test-repo-checkout-subpath.sh deleted file mode 100755 index 2da5adc2..00000000 --- a/tests/test-repo-checkout-subpath.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2011,2013 Colin Walters -# Copyright (C) 2014 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - -set -euo pipefail - -. $(dirname $0)/libtest.sh - -setup_test_repository "bare" - -echo '1..1' - -repopath=${test_tmpdir}/ostree-srv/gnomerepo - -${CMD_PREFIX} ostree --repo=repo checkout -U --subpath=/ test2 checkedout - -${CMD_PREFIX} ostree --repo=repo checkout -U --subpath=/firstfile test2 checkedout2 - -echo "ok" diff --git a/tests/test-rollsum.c b/tests/test-rollsum.c index 37c8bab8..a6c1bebd 100644 --- a/tests/test-rollsum.c +++ b/tests/test-rollsum.c @@ -152,7 +152,7 @@ test_bupsplit_sum(void) sum1a = bupsplit_sum(buf, 0, BUP_SELFTEST_SIZE); sum1b = bupsplit_sum(buf, 1, BUP_SELFTEST_SIZE); sum2a = bupsplit_sum(buf, BUP_SELFTEST_SIZE - BUP_WINDOWSIZE*5/2, - BUP_SELFTEST_SIZE - BUP_WINDOWSIZE); + BUP_SELFTEST_SIZE - BUP_WINDOWSIZE); sum2b = bupsplit_sum(buf, 0, BUP_SELFTEST_SIZE - BUP_WINDOWSIZE); sum3a = bupsplit_sum(buf, 0, BUP_WINDOWSIZE+3); sum3b = bupsplit_sum(buf, 3, BUP_WINDOWSIZE+3); diff --git a/tests/test-summary-view.sh b/tests/test-summary-view.sh new file mode 100755 index 00000000..6dcfd088 --- /dev/null +++ b/tests/test-summary-view.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# +# Copyright © 2017 Endless Mobile, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. +# +# Authors: +# - Philip Withnall + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +echo "1..2" + +COMMIT_SIGN="--gpg-homedir=${TEST_GPG_KEYHOME} --gpg-sign=${TEST_GPG_KEYID_1}" +setup_fake_remote_repo1 "archive-z2" "${COMMIT_SIGN}" + +# Set up a second branch. +mkdir ${test_tmpdir}/ostree-srv/other-files +cd ${test_tmpdir}/ostree-srv/other-files +echo 'hello world some object' > hello-world +${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit ${COMMIT_SIGN} -b other -s "A commit" -m "Example commit body" + +# Generate the summary file. +${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 +${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 + +# Check the summary file exists in the checkout, and can be viewed. +assert_has_file repo/summary +${OSTREE} summary --view > summary.txt +assert_file_has_content_literal summary.txt "* main" +assert_file_has_content_literal summary.txt "* other" +assert_file_has_content_literal summary.txt "ostree.summary.last-modified" +assert_file_has_content_literal summary.txt "Static Deltas (ostree.static-deltas): {}" +echo "ok view summary" + +# Check the summary can be viewed raw too. +${OSTREE} summary --view --raw > raw-summary.txt +assert_file_has_content_literal raw-summary.txt "('main', (" +assert_file_has_content_literal raw-summary.txt "('other', (" +assert_file_has_content_literal raw-summary.txt "{'ostree.summary.last-modified': expected-symbols.txt -eu-readelf -a ${G_TEST_BUILDDIR}/.libs/libostree-1.so | grep 'FUNC.*GLOBAL.*DEFAULT.*@@LIBOSTREE_' | sed -e 's,^.* \(ostree_[A-Za-z0-9_]*\)@@LIBOSTREE_[0-9_.]*,\1,' |sort -u > found-symbols.txt +grep --no-filename ' ostree_[A-Za-z0-9_]*;' ${G_TEST_SRCDIR}/src/libostree/libostree.sym $experimental_sym | sed -e 's,^ *\([A-Za-z0-9_]*\);,\1,' | sort -u > expected-symbols.txt +eu-readelf -a ${G_TEST_BUILDDIR}/.libs/libostree-1.so | grep 'FUNC.*GLOBAL.*DEFAULT.*@@LIBOSTREE_' | sed -e 's,^.* \(ostree_[A-Za-z0-9_]*\)@@LIBOSTREE_[0-9A-Z_.]*,\1,' |sort -u > found-symbols.txt diff -u expected-symbols.txt found-symbols.txt echo "ok exports" @@ -31,7 +39,7 @@ echo "ok exports" grep -E -v '(ostree_cmd__private__)|(ostree_fetcher_config_flags_get_type)' found-symbols.txt > expected-documented.txt echo "Verifying all public symbols are documented:" -grep '^ostree_' ${G_TEST_SRCDIR}/apidoc/ostree-sections.txt |sort -u > found-documented.txt +grep '^ostree_' ${G_TEST_SRCDIR}/apidoc/ostree-sections.txt $experimental_sections |sort -u > found-documented.txt diff -u expected-documented.txt found-documented.txt echo 'ok documented symbols'