Imported Upstream version 2016.4

This commit is contained in:
Simon McVittie 2016-03-28 12:33:19 +01:00
commit 36b5deae48
148 changed files with 4778 additions and 745 deletions

View File

@ -137,8 +137,9 @@ libostree_1_la_SOURCES += \
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)
libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions -export-symbols-regex '^ostree_'
$(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_INTERNAL_GPGME_CFLAGS) $(OT_DEP_LZMA_CFLAGS) $(OT_DEP_ZLIB_CFLAGS) \
-fvisibility=hidden '-D_OSTREE_PUBLIC=__attribute__((visibility("default"))) extern'
libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions -Wl,--version-script=$(top_srcdir)/src/libostree/libostree.sym
libostree_1_la_LIBADD = libotutil.la libbupsplit.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)
if USE_LIBARCHIVE
@ -158,6 +159,11 @@ libostree_1_la_CFLAGS += $(OT_INTERNAL_SOUP_CFLAGS)
libostree_1_la_LIBADD += $(OT_INTERNAL_SOUP_LIBS)
endif
if USE_LIBMOUNT
libostree_1_la_CFLAGS += $(OT_DEP_LIBMOUNT_CFLAGS)
libostree_1_la_LIBADD += $(OT_DEP_LIBMOUNT_LIBS)
endif
if USE_SELINUX
libostree_1_la_CFLAGS += $(OT_DEP_SELINUX_CFLAGS)
libostree_1_la_LIBADD += $(OT_DEP_SELINUX_LIBS)

View File

@ -19,7 +19,17 @@
if ENABLE_MAN
man1_files = ostree.1 ostree-admin-cleanup.1 ostree-admin-config-diff.1 ostree-admin-deploy.1 ostree-admin-init-fs.1 ostree-admin-instutil.1 ostree-admin-os-init.1 ostree-admin-status.1 ostree-admin-set-origin.1 ostree-admin-switch.1 ostree-admin-undeploy.1 ostree-admin-upgrade.1 ostree-admin.1 ostree-cat.1 ostree-checkout.1 ostree-checksum.1 ostree-commit.1 ostree-export.1 ostree-gpg-sign.1 ostree-config.1 ostree-diff.1 ostree-fsck.1 ostree-init.1 ostree-log.1 ostree-ls.1 ostree-prune.1 ostree-pull-local.1 ostree-pull.1 ostree-refs.1 ostree-remote.1 ostree-reset.1 ostree-rev-parse.1 ostree-show.1 ostree-summary.1 ostree-static-delta.1 ostree-trivial-httpd.1
man1_files = ostree.1 ostree-admin-cleanup.1 \
ostree-admin-config-diff.1 ostree-admin-deploy.1 \
ostree-admin-init-fs.1 ostree-admin-instutil.1 ostree-admin-os-init.1 \
ostree-admin-status.1 ostree-admin-set-origin.1 ostree-admin-switch.1 \
ostree-admin-undeploy.1 ostree-admin-upgrade.1 ostree-admin-unlock.1 \
ostree-admin.1 ostree-cat.1 ostree-checkout.1 ostree-checksum.1 \
ostree-commit.1 ostree-export.1 ostree-gpg-sign.1 ostree-config.1 \
ostree-diff.1 ostree-fsck.1 ostree-init.1 ostree-log.1 ostree-ls.1 \
ostree-prune.1 ostree-pull-local.1 ostree-pull.1 ostree-refs.1 \
ostree-remote.1 ostree-reset.1 ostree-rev-parse.1 ostree-show.1 \
ostree-summary.1 ostree-static-delta.1 ostree-trivial-httpd.1
if BUILDOPT_FUSE
man1_files += rofiles-fuse.1

View File

@ -66,6 +66,7 @@ ostree_SOURCES += \
src/ostree/ot-admin-builtin-status.c \
src/ostree/ot-admin-builtin-switch.c \
src/ostree/ot-admin-builtin-upgrade.c \
src/ostree/ot-admin-builtin-unlock.c \
src/ostree/ot-admin-builtins.h \
src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c \
src/ostree/ot-admin-instutil-builtin-set-kargs.c \

View File

@ -17,67 +17,69 @@
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
include $(top_srcdir)/buildutil/glib-tap.mk
if BUILDOPT_INSTALL_TESTS
# We should probably consider flipping the default for DEBUG. Also,
# include the builddir in $PATH so we find our just-built ostree
# binary.
TESTS_ENVIRONMENT += OT_TESTS_DEBUG=1 \
PATH=$$(cd $(top_builddir) && pwd):$${PATH}
insttestdir=$(pkglibexecdir)/installed-tests
testfiles = test-basic \
test-pull-subpath \
test-archivez \
test-remote-add \
test-remote-gpg-import \
test-commit-sign \
test-export \
test-help \
test-libarchive \
test-pull-archive-z \
test-pull-commit-only \
test-pull-corruption \
test-pull-depth \
test-pull-mirror-summary \
test-pull-large-metadata \
test-pull-metalink \
test-pull-summary-sigs \
test-pull-resume \
test-local-pull-depth \
test-gpg-signed-commit \
test-admin-upgrade-unconfigured \
test-admin-deploy-syslinux \
test-admin-deploy-2 \
test-admin-deploy-karg \
test-admin-deploy-switch \
test-admin-deploy-etcmerge-cornercases \
test-admin-deploy-uboot \
test-admin-instutil-set-kargs \
test-admin-upgrade-not-backwards \
test-admin-pull-deploy-commit \
test-admin-locking \
test-admin-deploy-clean \
test-repo-checkout-subpath \
test-reset-nonlinear \
test-oldstyle-partial \
test-setuid \
test-delta \
test-xattrs \
test-auto-summary \
test-prune \
test_scripts = \
tests/test-basic.sh \
tests/test-pull-subpath.sh \
tests/test-archivez.sh \
tests/test-remote-add.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-pull-archive-z.sh \
tests/test-pull-commit-only.sh \
tests/test-pull-corruption.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-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 \
tests/test-admin-deploy-switch.sh \
tests/test-admin-deploy-etcmerge-cornercases.sh \
tests/test-admin-deploy-uboot.sh \
tests/test-admin-instutil-set-kargs.sh \
tests/test-admin-upgrade-not-backwards.sh \
tests/test-admin-pull-deploy-commit.sh \
tests/test-admin-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-setuid.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 \
$(NULL)
if BUILDOPT_FUSE
testfiles += test-rofiles-fuse
test_scripts += tests/test-rofiles-fuse.sh
endif
insttest_SCRIPTS = $(addprefix tests/,$(testfiles:=.sh))
# This one uses corrupt-repo-ref.js
if BUILDOPT_GJS
testfiles += test-corruption
test_scripts += tests/test-corruption.sh
endif
testmetadir = $(datadir)/installed-tests/$(PACKAGE)
testmeta_DATA = $(testfiles:=.test)
insttest_DATA = tests/archive-test.sh \
installed_test_data = tests/archive-test.sh \
tests/pull-test.sh \
tests/libtest.sh \
tests/admin-test.sh \
@ -89,69 +91,61 @@ insttest_DATA = tests/archive-test.sh \
tests/pre-endian-deltas-repo-little.tar.xz \
$(NULL)
insttest_SCRIPTS += \
tests/syslinux-entries-crosscheck.py \
$(NULL)
test_extra_scripts = tests/syslinux-entries-crosscheck.py
gpginsttestdir = $(pkglibexecdir)/installed-tests/gpghome
# We can't use nobase_ as we need to strip off the tests/, can't
# use plain installed_ as we do need the gpghome/ prefix.
if ENABLE_INSTALLED_TESTS
gpginsttestdir = $(installed_testdir)/gpghome
gpginsttest_DATA = tests/gpghome/secring.gpg \
tests/gpghome/pubring.gpg \
tests/gpghome/trustdb.gpg \
tests/gpghome/key1.asc \
tests/gpghome/key2.asc \
tests/gpghome/key3.asc
gpginsttest_trusteddir = $(pkglibexecdir)/installed-tests/gpghome/trusted
gpginsttest_trusteddir = $(installed_testdir)/gpghome/trusted
gpginsttest_trusted_DATA = tests/gpghome/trusted/pubring.gpg
install-gpg-data-hook:
ln -sf trusted/pubring.gpg $(DESTDIR)$(gpginsttestdir)/pubring.gpg
INSTALL_DATA_HOOKS += install-gpg-data-hook
%.test: tests/%.sh Makefile
$(AM_V_GEN) (echo '[Test]' > $@.tmp; \
echo 'Exec=$(pkglibexecdir)/installed-tests/$(notdir $<)' >> $@.tmp; \
echo 'Type=session' >> $@.tmp; \
echo 'Output=TAP' >> $@.tmp; \
mv $@.tmp $@)
%.test: tests/%.js Makefile
$(AM_V_GEN) (echo '[Test]' > $@.tmp; \
echo 'Exec=env TESTDATADIR=$(pkglibexecdir)/installed-tests $(pkglibexecdir)/installed-tests/$(notdir $<)' >> $@.tmp; \
echo 'Type=session' >> $@.tmp; \
mv $@.tmp $@)
gpgvinsttestdir = $(installed_testdir)/gpg-verify-data
gpgvinsttest_DATA = $(addprefix tests/gpg-verify-data/, \
gpg.conf lgpl2 lgpl2.sig pubring.gpg secring.gpg trustdb.gpg)
endif
if BUILDOPT_GJS
insttest_SCRIPTS += tests/test-core.js \
installed_test_scripts = tests/test-core.js \
tests/test-sizes.js \
tests/test-sysroot.js \
$(NULL)
testmeta_DATA += test-core.test test-sizes.test test-sysroot.test
endif
insttest_LTLIBRARIES = libreaddir-rand.la
test_ltlibraries = libreaddir-rand.la
libreaddir_rand_la_SOURCES = tests/readdir-rand.c
libreaddir_rand_la_CFLAGS = $(OT_INTERNAL_GIO_UNIX_CFLAGS)
libreaddir_rand_la_LIBADD = $(OT_INTERNAL_GIO_UNIX_LIBS)
libreaddir_rand_la_LDFLAGS = -avoid-version
endif
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
# "make check" do not depend from --enable-installed-tests
# An interactive tool
noinst_PROGRAMS += tests/test-rollsum-cli
TESTS = 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
if USE_LIBARCHIVE
TESTS += tests/test-libarchive-import
test_programs += tests/test-libarchive-import
endif
check_PROGRAMS = $(TESTS)
TESTS_ENVIRONMENT = \
G_TEST_SRCDIR=$(abs_srcdir)/tests \
G_TEST_BUILDDIR=$(abs_builddir)/tests
TESTS_CFLAGS = $(ostree_bin_shared_cflags) $(OT_INTERNAL_GIO_UNIX_CFLAGS) -I$(srcdir)/libglnx
TESTS_LDADD = $(ostree_bin_shared_ldadd) $(OT_INTERNAL_GIO_UNIX_LIBS)
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)
noinst_LTLIBRARIES += libostreetest.la
libostreetest_la_SOURCES = tests/libostreetest.c
libostreetest_la_CFLAGS = $(common_tests_cflags) -I $(srcdir)/tests
libostreetest_la_LIBADD = $(common_tests_ldadd)
TESTS_CFLAGS = $(common_tests_cflags)
TESTS_LDADD = $(common_tests_ldadd) libostreetest.la
tests_test_rollsum_cli_SOURCES = src/libostree/ostree-rollsum.c tests/test-rollsum-cli.c
tests_test_rollsum_cli_CFLAGS = $(TESTS_CFLAGS) $(OT_DEP_ZLIB_CFLAGS)
@ -164,6 +158,12 @@ tests_test_rollsum_LDADD = libbupsplit.la $(TESTS_LDADD) $(OT_DEP_ZLIB_LIBS)
tests_test_mutable_tree_CFLAGS = $(TESTS_CFLAGS)
tests_test_mutable_tree_LDADD = $(TESTS_LDADD)
tests_test_basic_c_CFLAGS = $(TESTS_CFLAGS)
tests_test_basic_c_LDADD = $(TESTS_LDADD)
tests_test_sysroot_c_CFLAGS = $(TESTS_CFLAGS)
tests_test_sysroot_c_LDADD = $(TESTS_LDADD)
tests_test_ot_unix_utils_CFLAGS = $(TESTS_CFLAGS)
tests_test_ot_unix_utils_LDADD = $(TESTS_LDADD)
@ -179,8 +179,8 @@ tests_test_checksum_CFLAGS = $(TESTS_CFLAGS) $(libglnx_cflags)
tests_test_checksum_LDADD = $(TESTS_LDADD)
tests_test_libarchive_import_SOURCES = tests/test-libarchive-import.c
tests_test_libarchive_import_CFLAGS = $(TESTS_CFLAGS) $(libglnx_cflags)
tests_test_libarchive_import_LDADD = $(TESTS_LDADD)
tests_test_libarchive_import_CFLAGS = $(TESTS_CFLAGS) $(libglnx_cflags) $(OT_DEP_LIBARCHIVE_CFLAGS)
tests_test_libarchive_import_LDADD = $(TESTS_LDADD) $(OT_DEP_LIBARCHIVE_LIBS)
tests_test_keyfile_utils_CFLAGS = $(TESTS_CFLAGS)
tests_test_keyfile_utils_LDADD = $(TESTS_LDADD)
@ -210,3 +210,15 @@ EXTRA_DIST += \
tests/gpg-verify-data/secring.gpg \
tests/gpg-verify-data/trustdb.gpg \
tests/gpg-verify-data/gpg.conf
# 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.
if ENABLE_INSTALLED_TESTS
install-test-data-file-path-hack:
if test -L $(DESTDIR)$(installed_testdir)/tests; then \
rm $(DESTDIR)$(installed_testdir)/tests; \
fi
ln -s . $(DESTDIR)$(installed_testdir)/tests
INSTALL_DATA_HOOKS += install-test-data-file-path-hack
endif

View File

@ -19,7 +19,7 @@ include Makefile-decls.am
shortened_sysconfdir = $$(echo "$(sysconfdir)" | sed -e 's|^$(prefix)||' -e 's|^/||')
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
ACLOCAL_AMFLAGS = -I buildutil ${ACLOCAL_FLAGS}
AM_CPPFLAGS += -DDATADIR='"$(datadir)"' -DLIBEXECDIR='"$(libexecdir)"' \
-DLOCALEDIR=\"$(datadir)/locale\" -DSYSCONFDIR=\"$(sysconfdir)\" \
-DSHORTENED_SYSCONFDIR=\"$(shortened_sysconfdir)\" \
@ -100,12 +100,3 @@ release-tarball-embedded:
$(embed_dependency) embedded-dependencies/libsoup; \
mv ostree-embeddeps-$${GITVERSION}.tar{.tmp,}; \
gzip -f ostree-embeddeps-$${GITVERSION}.tar
check-local:
@echo " *** NOTE ***"
@echo " *** NOTE ***"
@echo " \"make check\" only runs a subset of OSTree's tests."
@echo " The other tests use: use https://live.gnome.org/GnomeGoals/InstalledTests"
@echo " To run them, ostree must be configured with --enable-installed-tests and installed"
@echo " *** NOTE ***"
@echo " *** NOTE ***"

View File

@ -44,7 +44,7 @@ provide a minimal host for Docker formatted Linux containers.
Replicating a base immutable OS, then using Docker for applications
meshes together two different tools with different tradeoffs.
[xdg-app](https://github.com/alexlarsson/xdg-app) uses OSTree
[xdg-app](https://github.com/alexlarsson/xdg-app) uses OSTree
for desktop application containers.
[GNOME Continuous](https://wiki.gnome.org/Projects/GnomeContinuous) is
@ -83,7 +83,7 @@ More documentation
New! See the docs online at [Read The Docs (OSTree)](https://ostree.readthedocs.org/en/latest/ )
Some more information is available on the old wiki page:
https://wiki.gnome.org/Projects/OSTree
<https://wiki.gnome.org/Projects/OSTree>
Contributing
------------

View File

@ -260,6 +260,7 @@ ostree_repo_write_content_async
ostree_repo_write_content_finish
ostree_repo_resolve_rev
ostree_repo_list_refs
ostree_repo_list_refs_ext
ostree_repo_remote_list_refs
ostree_repo_load_variant
ostree_repo_load_commit
@ -380,6 +381,7 @@ ostree_sysroot_new
ostree_sysroot_new_default
ostree_sysroot_get_path
ostree_sysroot_load
ostree_sysroot_load_if_changed
ostree_sysroot_lock
ostree_sysroot_try_lock
ostree_sysroot_lock_async
@ -396,6 +398,7 @@ ostree_sysroot_get_deployment_origin_path
ostree_sysroot_cleanup
ostree_sysroot_prepare_cleanup
ostree_sysroot_get_repo
ostree_sysroot_init_osname
ostree_sysroot_deployment_set_kargs
ostree_sysroot_write_deployments
ostree_sysroot_deploy_tree

125
buildutil/glib-tap.mk Normal file
View File

@ -0,0 +1,125 @@
# GLIB - Library of useful C routines
TESTS_ENVIRONMENT= \
G_TEST_SRCDIR="$(abs_srcdir)" \
G_TEST_BUILDDIR="$(abs_builddir)" \
UNINSTALLEDTESTS=1 \
G_DEBUG=gc-friendly \
MALLOC_CHECK_=2 \
MALLOC_PERTURB_=$$(($${RANDOM:-256} % 256))
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/buildutil/tap-driver.sh
LOG_COMPILER = $(top_srcdir)/buildutil/tap-test
TESTS =
installed_test_LTLIBRARIES =
installed_test_PROGRAMS =
installed_test_SCRIPTS =
installed_test_DATA =
nobase_installed_test_DATA =
noinst_SCRIPTS =
noinst_DATA =
check_LTLIBRARIES =
check_PROGRAMS =
check_SCRIPTS =
check_DATA =
# We support a fairly large range of possible variables. It is expected that all types of files in a test suite
# will belong in exactly one of the following variables.
#
# First, we support the usual automake suffixes, but in lowercase, with the customary meaning:
#
# test_programs, test_scripts, test_data, test_ltlibraries
#
# The above are used to list files that are involved in both uninstalled and installed testing. The
# test_programs and test_scripts are taken to be actual testcases and will be run as part of the test suite.
# Note that _data is always used with the nobase_ automake variable name to ensure that installed test data is
# installed in the same way as it appears in the package layout.
#
# In order to mark a particular file as being only for one type of testing, use 'installed' or 'uninstalled',
# like so:
#
# installed_test_programs, uninstalled_test_programs
# installed_test_scripts, uninstalled_test_scripts
# installed_test_data, uninstalled_test_data
# installed_test_ltlibraries, uninstalled_test_ltlibraries
#
# Additionally, we support 'extra' infixes for programs and scripts. This is used for support programs/scripts
# that should not themselves be run as testcases (but exist to be used from other testcases):
#
# test_extra_programs, installed_test_extra_programs, uninstalled_test_extra_programs
# test_extra_scripts, installed_test_extra_scripts, uninstalled_test_extra_scripts
#
# Additionally, for _scripts and _data, we support the customary dist_ prefix so that the named script or data
# file automatically end up in the tarball.
#
# dist_test_scripts, dist_test_data, dist_test_extra_scripts
# dist_installed_test_scripts, dist_installed_test_data, dist_installed_test_extra_scripts
# dist_uninstalled_test_scripts, dist_uninstalled_test_data, dist_uninstalled_test_extra_scripts
#
# Note that no file is automatically disted unless it appears in one of the dist_ variables. This follows the
# standard automake convention of not disting programs scripts or data by default.
#
# test_programs, test_scripts, uninstalled_test_programs and uninstalled_test_scripts (as well as their disted
# variants) will be run as part of the in-tree 'make check'. These are all assumed to be runnable under
# gtester. That's a bit strange for scripts, but it's possible.
TESTS += $(test_programs) $(test_scripts) $(uninstalled_test_programs) $(uninstalled_test_scripts) \
$(dist_test_scripts) $(dist_uninstalled_test_scripts)
# Note: build even the installed-only targets during 'make check' to ensure that they still work.
# We need to do a bit of trickery here and manage disting via EXTRA_DIST instead of using dist_ prefixes to
# prevent automake from mistreating gmake functions like $(wildcard ...) and $(addprefix ...) as if they were
# filenames, including removing duplicate instances of the opening part before the space, eg. '$(addprefix'.
all_test_programs = $(test_programs) $(uninstalled_test_programs) $(installed_test_programs) \
$(test_extra_programs) $(uninstalled_test_extra_programs) $(installed_test_extra_programs)
all_test_scripts = $(test_scripts) $(uninstalled_test_scripts) $(installed_test_scripts) \
$(test_extra_scripts) $(uninstalled_test_extra_scripts) $(installed_test_extra_scripts)
all_dist_test_scripts = $(dist_test_scripts) $(dist_uninstalled_test_scripts) $(dist_installed_test_scripts) \
$(dist_test_extra_scripts) $(dist_uninstalled_test_extra_scripts) $(dist_installed_test_extra_scripts)
all_test_scripts += $(all_dist_test_scripts)
EXTRA_DIST += $(all_dist_test_scripts)
all_test_data = $(test_data) $(uninstalled_test_data) $(installed_test_data)
all_dist_test_data = $(dist_test_data) $(dist_uninstalled_test_data) $(dist_installed_test_data)
all_test_data += $(all_dist_test_data)
EXTRA_DIST += $(all_dist_test_data)
all_test_ltlibs = $(test_ltlibraries) $(uninstalled_test_ltlibraries) $(installed_test_ltlibraries)
if ENABLE_ALWAYS_BUILD_TESTS
noinst_LTLIBRARIES += $(all_test_ltlibs)
noinst_PROGRAMS += $(all_test_programs)
noinst_SCRIPTS += $(all_test_scripts)
noinst_DATA += $(all_test_data)
else
check_LTLIBRARIES += $(all_test_ltlibs)
check_PROGRAMS += $(all_test_programs)
check_SCRIPTS += $(all_test_scripts)
check_DATA += $(all_test_data)
endif
if ENABLE_INSTALLED_TESTS
installed_test_PROGRAMS += $(test_programs) $(installed_test_programs) \
$(test_extra_programs) $(installed_test_extra_programs)
installed_test_SCRIPTS += $(test_scripts) $(installed_test_scripts) \
$(test_extra_scripts) $(test_installed_extra_scripts)
installed_test_SCRIPTS += $(dist_test_scripts) $(dist_test_extra_scripts) \
$(dist_installed_test_scripts) $(dist_installed_test_extra_scripts)
installed_test_DATA += $(test_data) $(installed_test_data)
installed_test_DATA += $(dist_test_data) $(dist_installed_test_data)
installed_test_LTLIBRARIES += $(test_ltlibraries) $(installed_test_ltlibraries)
installed_testcases = $(test_programs) $(installed_test_programs) \
$(test_scripts) $(installed_test_scripts) \
$(dist_test_scripts) $(dist_installed_test_scripts)
installed_test_meta_DATA = $(installed_testcases:=.test)
%.test: %$(EXEEXT) Makefile
$(AM_V_GEN) (echo '[Test]' > $@.tmp; \
echo 'Type=session' >> $@.tmp; \
echo 'Exec=env G_TEST_SRCDIR=$(installed_testdir) G_TEST_BUILDDIR=$(installed_testdir) $(installed_testdir)/$(notdir $<)' >> $@.tmp; \
mv $@.tmp $@)
CLEANFILES += $(installed_test_meta_DATA)
endif

28
buildutil/glibtests.m4 Normal file
View File

@ -0,0 +1,28 @@
dnl GLIB_TESTS
dnl
AC_DEFUN([GLIB_TESTS],
[
AC_ARG_ENABLE(installed-tests,
AS_HELP_STRING([--enable-installed-tests],
[Enable installation of some test cases]),
[case ${enableval} in
yes) ENABLE_INSTALLED_TESTS="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")
AC_ARG_ENABLE(always-build-tests,
AS_HELP_STRING([--enable-always-build-tests],
[Enable always building tests during 'make all']),
[case ${enableval} in
yes) ENABLE_ALWAYS_BUILD_TESTS="1" ;;
no) ENABLE_ALWAYS_BUILD_TESTS="" ;;
*) AC_MSG_ERROR([bad value ${enableval} for --enable-always-build-tests]) ;;
esac])
AM_CONDITIONAL([ENABLE_ALWAYS_BUILD_TESTS], test "$ENABLE_ALWAYS_BUILD_TESTS" = "1")
if test "$ENABLE_INSTALLED_TESTS" == "1"; then
AC_SUBST(installed_test_metadir, [${datadir}/installed-tests/]AC_PACKAGE_NAME)
AC_SUBST(installed_testdir, [${libexecdir}/installed-tests/]AC_PACKAGE_NAME)
fi
])

652
buildutil/tap-driver.sh Executable file
View File

@ -0,0 +1,652 @@
#! /bin/sh
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
scriptversion=2011-12-27.17; # UTC
# Make unconditional expansion of undefined variables an error. This
# helps a lot in preventing typo-related bugs.
set -u
me=tap-driver.sh
fatal ()
{
echo "$me: fatal: $*" >&2
exit 1
}
usage_error ()
{
echo "$me: $*" >&2
print_usage >&2
exit 2
}
print_usage ()
{
cat <<END
Usage:
tap-driver.sh --test-name=NAME --log-file=PATH --trs-file=PATH
[--expect-failure={yes|no}] [--color-tests={yes|no}]
[--enable-hard-errors={yes|no}] [--ignore-exit]
[--diagnostic-string=STRING] [--merge|--no-merge]
[--comments|--no-comments] [--] TEST-COMMAND
The \`--test-name', \`--log-file' and \`--trs-file' options are mandatory.
END
}
# TODO: better error handling in option parsing (in particular, ensure
# TODO: $log_file, $trs_file and $test_name are defined).
test_name= # Used for reporting.
log_file= # Where to save the result and output of the test script.
trs_file= # Where to save the metadata of the test run.
expect_failure=0
color_tests=0
merge=0
ignore_exit=0
comments=0
diag_string='#'
while test $# -gt 0; do
case $1 in
--help) print_usage; exit $?;;
--version) echo "$me $scriptversion"; exit $?;;
--test-name) test_name=$2; shift;;
--log-file) log_file=$2; shift;;
--trs-file) trs_file=$2; shift;;
--color-tests) color_tests=$2; shift;;
--expect-failure) expect_failure=$2; shift;;
--enable-hard-errors) shift;; # No-op.
--merge) merge=1;;
--no-merge) merge=0;;
--ignore-exit) ignore_exit=1;;
--comments) comments=1;;
--no-comments) comments=0;;
--diagnostic-string) diag_string=$2; shift;;
--) shift; break;;
-*) usage_error "invalid option: '$1'";;
esac
shift
done
test $# -gt 0 || usage_error "missing test command"
case $expect_failure in
yes) expect_failure=1;;
*) expect_failure=0;;
esac
if test $color_tests = yes; then
init_colors='
color_map["red"]="" # Red.
color_map["grn"]="" # Green.
color_map["lgn"]="" # Light green.
color_map["blu"]="" # Blue.
color_map["mgn"]="" # Magenta.
color_map["std"]="" # No color.
color_for_result["ERROR"] = "mgn"
color_for_result["PASS"] = "grn"
color_for_result["XPASS"] = "red"
color_for_result["FAIL"] = "red"
color_for_result["XFAIL"] = "lgn"
color_for_result["SKIP"] = "blu"'
else
init_colors=''
fi
# :; is there to work around a bug in bash 3.2 (and earlier) which
# does not always set '$?' properly on redirection failure.
# See the Autoconf manual for more details.
:;{
(
# Ignore common signals (in this subshell only!), to avoid potential
# problems with Korn shells. Some Korn shells are known to propagate
# to themselves signals that have killed a child process they were
# waiting for; this is done at least for SIGINT (and usually only for
# it, in truth). Without the `trap' below, such a behaviour could
# cause a premature exit in the current subshell, e.g., in case the
# test command it runs gets terminated by a SIGINT. Thus, the awk
# script we are piping into would never seen the exit status it
# expects on its last input line (which is displayed below by the
# last `echo $?' statement), and would thus die reporting an internal
# error.
# For more information, see the Autoconf manual and the threads:
# <http://lists.gnu.org/archive/html/bug-autoconf/2011-09/msg00004.html>
# <http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/004121.html>
trap : 1 3 2 13 15
if test $merge -gt 0; then
exec 2>&1
else
exec 2>&3
fi
"$@"
echo $?
) | LC_ALL=C ${AM_TAP_AWK-awk} \
-v me="$me" \
-v test_script_name="$test_name" \
-v log_file="$log_file" \
-v trs_file="$trs_file" \
-v expect_failure="$expect_failure" \
-v merge="$merge" \
-v ignore_exit="$ignore_exit" \
-v comments="$comments" \
-v diag_string="$diag_string" \
'
# FIXME: the usages of "cat >&3" below could be optimized when using
# FIXME: GNU awk, and/on on systems that supports /dev/fd/.
# Implementation note: in what follows, `result_obj` will be an
# associative array that (partly) simulates a TAP result object
# from the `TAP::Parser` perl module.
## ----------- ##
## FUNCTIONS ##
## ----------- ##
function fatal(msg)
{
print me ": " msg | "cat >&2"
exit 1
}
function abort(where)
{
fatal("internal error " where)
}
# Convert a boolean to a "yes"/"no" string.
function yn(bool)
{
return bool ? "yes" : "no";
}
function add_test_result(result)
{
if (!test_results_index)
test_results_index = 0
test_results_list[test_results_index] = result
test_results_index += 1
test_results_seen[result] = 1;
}
# Whether the test script should be re-run by "make recheck".
function must_recheck()
{
for (k in test_results_seen)
if (k != "XFAIL" && k != "PASS" && k != "SKIP")
return 1
return 0
}
# Whether the content of the log file associated to this test should
# be copied into the "global" test-suite.log.
function copy_in_global_log()
{
for (k in test_results_seen)
if (k != "PASS")
return 1
return 0
}
# FIXME: this can certainly be improved ...
function get_global_test_result()
{
if ("ERROR" in test_results_seen)
return "ERROR"
if ("FAIL" in test_results_seen || "XPASS" in test_results_seen)
return "FAIL"
all_skipped = 1
for (k in test_results_seen)
if (k != "SKIP")
all_skipped = 0
if (all_skipped)
return "SKIP"
return "PASS";
}
function stringify_result_obj(result_obj)
{
if (result_obj["is_unplanned"] || result_obj["number"] != testno)
return "ERROR"
if (plan_seen == LATE_PLAN)
return "ERROR"
if (result_obj["directive"] == "TODO")
return result_obj["is_ok"] ? "XPASS" : "XFAIL"
if (result_obj["directive"] == "SKIP")
return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL;
if (length(result_obj["directive"]))
abort("in function stringify_result_obj()")
return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL
}
function decorate_result(result)
{
color_name = color_for_result[result]
if (color_name)
return color_map[color_name] "" result "" color_map["std"]
# If we are not using colorized output, or if we do not know how
# to colorize the given result, we should return it unchanged.
return result
}
function report(result, details)
{
if (result ~ /^(X?(PASS|FAIL)|SKIP|ERROR)/)
{
msg = ": " test_script_name
add_test_result(result)
}
else if (result == "#")
{
msg = " " test_script_name ":"
}
else
{
abort("in function report()")
}
if (length(details))
msg = msg " " details
# Output on console might be colorized.
print decorate_result(result) msg
# Log the result in the log file too, to help debugging (this is
# especially true when said result is a TAP error or "Bail out!").
print result msg | "cat >&3";
}
function testsuite_error(error_message)
{
report("ERROR", "- " error_message)
}
function handle_tap_result()
{
details = result_obj["number"];
if (length(result_obj["description"]))
details = details " " result_obj["description"]
if (plan_seen == LATE_PLAN)
{
details = details " # AFTER LATE PLAN";
}
else if (result_obj["is_unplanned"])
{
details = details " # UNPLANNED";
}
else if (result_obj["number"] != testno)
{
details = sprintf("%s # OUT-OF-ORDER (expecting %d)",
details, testno);
}
else if (result_obj["directive"])
{
details = details " # " result_obj["directive"];
if (length(result_obj["explanation"]))
details = details " " result_obj["explanation"]
}
report(stringify_result_obj(result_obj), details)
}
# `skip_reason` should be empty whenever planned > 0.
function handle_tap_plan(planned, skip_reason)
{
planned += 0 # Avoid getting confused if, say, `planned` is "00"
if (length(skip_reason) && planned > 0)
abort("in function handle_tap_plan()")
if (plan_seen)
{
# Error, only one plan per stream is acceptable.
testsuite_error("multiple test plans")
return;
}
planned_tests = planned
# The TAP plan can come before or after *all* the TAP results; we speak
# respectively of an "early" or a "late" plan. If we see the plan line
# after at least one TAP result has been seen, assume we have a late
# plan; in this case, any further test result seen after the plan will
# be flagged as an error.
plan_seen = (testno >= 1 ? LATE_PLAN : EARLY_PLAN)
# If testno > 0, we have an error ("too many tests run") that will be
# automatically dealt with later, so do not worry about it here. If
# $plan_seen is true, we have an error due to a repeated plan, and that
# has already been dealt with above. Otherwise, we have a valid "plan
# with SKIP" specification, and should report it as a particular kind
# of SKIP result.
if (planned == 0 && testno == 0)
{
if (length(skip_reason))
skip_reason = "- " skip_reason;
report("SKIP", skip_reason);
}
}
function extract_tap_comment(line)
{
if (index(line, diag_string) == 1)
{
# Strip leading `diag_string` from `line`.
line = substr(line, length(diag_string) + 1)
# And strip any leading and trailing whitespace left.
sub("^[ \t]*", "", line)
sub("[ \t]*$", "", line)
# Return what is left (if any).
return line;
}
return "";
}
# When this function is called, we know that line is a TAP result line,
# so that it matches the (perl) RE "^(not )?ok\b".
function setup_result_obj(line)
{
# Get the result, and remove it from the line.
result_obj["is_ok"] = (substr(line, 1, 2) == "ok" ? 1 : 0)
sub("^(not )?ok[ \t]*", "", line)
# If the result has an explicit number, get it and strip it; otherwise,
# automatically assing the next progresive number to it.
if (line ~ /^[0-9]+$/ || line ~ /^[0-9]+[^a-zA-Z0-9_]/)
{
match(line, "^[0-9]+")
# The final `+ 0` is to normalize numbers with leading zeros.
result_obj["number"] = substr(line, 1, RLENGTH) + 0
line = substr(line, RLENGTH + 1)
}
else
{
result_obj["number"] = testno
}
if (plan_seen == LATE_PLAN)
# No further test results are acceptable after a "late" TAP plan
# has been seen.
result_obj["is_unplanned"] = 1
else if (plan_seen && testno > planned_tests)
result_obj["is_unplanned"] = 1
else
result_obj["is_unplanned"] = 0
# Strip trailing and leading whitespace.
sub("^[ \t]*", "", line)
sub("[ \t]*$", "", line)
# This will have to be corrected if we have a "TODO"/"SKIP" directive.
result_obj["description"] = line
result_obj["directive"] = ""
result_obj["explanation"] = ""
if (index(line, "#") == 0)
return # No possible directive, nothing more to do.
# Directives are case-insensitive.
rx = "[ \t]*#[ \t]*([tT][oO][dD][oO]|[sS][kK][iI][pP])[ \t]*"
# See whether we have the directive, and if yes, where.
pos = match(line, rx "$")
if (!pos)
pos = match(line, rx "[^a-zA-Z0-9_]")
# If there was no TAP directive, we have nothing more to do.
if (!pos)
return
# Let`s now see if the TAP directive has been escaped. For example:
# escaped: ok \# SKIP
# not escaped: ok \\# SKIP
# escaped: ok \\\\\# SKIP
# not escaped: ok \ # SKIP
if (substr(line, pos, 1) == "#")
{
bslash_count = 0
for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--)
bslash_count += 1
if (bslash_count % 2)
return # Directive was escaped.
}
# Strip the directive and its explanation (if any) from the test
# description.
result_obj["description"] = substr(line, 1, pos - 1)
# Now remove the test description from the line, that has been dealt
# with already.
line = substr(line, pos)
# Strip the directive, and save its value (normalized to upper case).
sub("^[ \t]*#[ \t]*", "", line)
result_obj["directive"] = toupper(substr(line, 1, 4))
line = substr(line, 5)
# Now get the explanation for the directive (if any), with leading
# and trailing whitespace removed.
sub("^[ \t]*", "", line)
sub("[ \t]*$", "", line)
result_obj["explanation"] = line
}
function get_test_exit_message(status)
{
if (status == 0)
return ""
if (status !~ /^[1-9][0-9]*$/)
abort("getting exit status")
if (status < 127)
exit_details = ""
else if (status == 127)
exit_details = " (command not found?)"
else if (status >= 128 && status <= 255)
exit_details = sprintf(" (terminated by signal %d?)", status - 128)
else if (status > 256 && status <= 384)
# We used to report an "abnormal termination" here, but some Korn
# shells, when a child process die due to signal number n, can leave
# in $? an exit status of 256+n instead of the more standard 128+n.
# Apparently, both behaviours are allowed by POSIX (2008), so be
# prepared to handle them both. See also Austing Group report ID
# 0000051 <http://www.austingroupbugs.net/view.php?id=51>
exit_details = sprintf(" (terminated by signal %d?)", status - 256)
else
# Never seen in practice.
exit_details = " (abnormal termination)"
return sprintf("exited with status %d%s", status, exit_details)
}
function write_test_results()
{
print ":global-test-result: " get_global_test_result() > trs_file
print ":recheck: " yn(must_recheck()) > trs_file
print ":copy-in-global-log: " yn(copy_in_global_log()) > trs_file
for (i = 0; i < test_results_index; i += 1)
print ":test-result: " test_results_list[i] > trs_file
close(trs_file);
}
BEGIN {
## ------- ##
## SETUP ##
## ------- ##
'"$init_colors"'
# Properly initialized once the TAP plan is seen.
planned_tests = 0
COOKED_PASS = expect_failure ? "XPASS": "PASS";
COOKED_FAIL = expect_failure ? "XFAIL": "FAIL";
# Enumeration-like constants to remember which kind of plan (if any)
# has been seen. It is important that NO_PLAN evaluates "false" as
# a boolean.
NO_PLAN = 0
EARLY_PLAN = 1
LATE_PLAN = 2
testno = 0 # Number of test results seen so far.
bailed_out = 0 # Whether a "Bail out!" directive has been seen.
# Whether the TAP plan has been seen or not, and if yes, which kind
# it is ("early" is seen before any test result, "late" otherwise).
plan_seen = NO_PLAN
## --------- ##
## PARSING ##
## --------- ##
is_first_read = 1
while (1)
{
# Involutions required so that we are able to read the exit status
# from the last input line.
st = getline
if (st < 0) # I/O error.
fatal("I/O error while reading from input stream")
else if (st == 0) # End-of-input
{
if (is_first_read)
abort("in input loop: only one input line")
break
}
if (is_first_read)
{
is_first_read = 0
nextline = $0
continue
}
else
{
curline = nextline
nextline = $0
$0 = curline
}
# Copy any input line verbatim into the log file.
print | "cat >&3"
# Parsing of TAP input should stop after a "Bail out!" directive.
if (bailed_out)
continue
# TAP test result.
if ($0 ~ /^(not )?ok$/ || $0 ~ /^(not )?ok[^a-zA-Z0-9_]/)
{
testno += 1
setup_result_obj($0)
handle_tap_result()
}
# TAP plan (normal or "SKIP" without explanation).
else if ($0 ~ /^1\.\.[0-9]+[ \t]*$/)
{
# The next two lines will put the number of planned tests in $0.
sub("^1\\.\\.", "")
sub("[^0-9]*$", "")
handle_tap_plan($0, "")
continue
}
# TAP "SKIP" plan, with an explanation.
else if ($0 ~ /^1\.\.0+[ \t]*#/)
{
# The next lines will put the skip explanation in $0, stripping
# any leading and trailing whitespace. This is a little more
# tricky in truth, since we want to also strip a potential leading
# "SKIP" string from the message.
sub("^[^#]*#[ \t]*(SKIP[: \t][ \t]*)?", "")
sub("[ \t]*$", "");
handle_tap_plan(0, $0)
}
# "Bail out!" magic.
# Older versions of prove and TAP::Harness (e.g., 3.17) did not
# recognize a "Bail out!" directive when preceded by leading
# whitespace, but more modern versions (e.g., 3.23) do. So we
# emulate the latter, "more modern" behaviour.
else if ($0 ~ /^[ \t]*Bail out!/)
{
bailed_out = 1
# Get the bailout message (if any), with leading and trailing
# whitespace stripped. The message remains stored in `$0`.
sub("^[ \t]*Bail out![ \t]*", "");
sub("[ \t]*$", "");
# Format the error message for the
bailout_message = "Bail out!"
if (length($0))
bailout_message = bailout_message " " $0
testsuite_error(bailout_message)
}
# Maybe we have too look for dianogtic comments too.
else if (comments != 0)
{
comment = extract_tap_comment($0);
if (length(comment))
report("#", comment);
}
}
## -------- ##
## FINISH ##
## -------- ##
# A "Bail out!" directive should cause us to ignore any following TAP
# error, as well as a non-zero exit status from the TAP producer.
if (!bailed_out)
{
if (!plan_seen)
{
testsuite_error("missing test plan")
}
else if (planned_tests != testno)
{
bad_amount = testno > planned_tests ? "many" : "few"
testsuite_error(sprintf("too %s tests run (expected %d, got %d)",
bad_amount, planned_tests, testno))
}
if (!ignore_exit)
{
# Fetch exit status from the last line.
exit_message = get_test_exit_message(nextline)
if (exit_message)
testsuite_error(exit_message)
}
}
write_test_results()
exit 0
} # End of "BEGIN" block.
'
# TODO: document that we consume the file descriptor 3 :-(
} 3>"$log_file"
test $? -eq 0 || fatal "I/O or internal error"
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

23
buildutil/tap-test Executable file
View File

@ -0,0 +1,23 @@
#! /bin/bash
#
# Run a test in tap mode, ensuring we have a temporary directory. We
# always use /var/tmp becuase we might want to use user xattrs, which
# aren't available on tmpfs.
#
# The test binary is passed as $1
srcd=$(cd $(dirname $1) && pwd)
bn=$(basename $1)
tempdir=$(mktemp -d /var/tmp/tap-test.XXXXXX)
touch ${tempdir}/.testtmp
function cleanup () {
if test -n "${TEST_SKIP_CLEANUP:-}"; then
echo "Skipping cleanup of ${tempdir}"
else if test -f ${tempdir}/.test; then
rm "${tempdir}" -rf
fi
fi
}
trap cleanup EXIT
cd ${tempdir}
${srcd}/${bn} -k --tap

4
cfg.mk
View File

@ -1,4 +1,4 @@
export VC_LIST_EXCEPT_DEFAULT=^(lib/.*|m4/.*|md5/.*|build-aux/.*|src/gettext\.h|.*ChangeLog)$$
export VC_LIST_EXCEPT_DEFAULT=^(lib/.*|m4/.*|md5/.*|build-aux/.*|src/gettext\.h|.*ChangeLog|buildutil/.*)$$
local-checks-to-skip = \
sc_const_long_option \
@ -27,4 +27,4 @@ local-checks-to-skip = \
show-vc-list-except:
@$(VC_LIST_EXCEPT)
VC_LIST_ALWAYS_EXCLUDE_REGEX = ^ABOUT-NLS|maint.mk|*.gpg|*.sig$$
VC_LIST_ALWAYS_EXCLUDE_REGEX = ^ABOUT-NLS|maint.mk|*.gpg|*.sig|.xz$$

View File

@ -1,11 +1,11 @@
AC_PREREQ([2.63])
AC_INIT([ostree], [2016.3], [walters@verbum.org])
AC_INIT([ostree], [2016.4], [walters@verbum.org])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_MACRO_DIR([buildutil])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([1.13 -Wno-portability foreign no-define tar-ustar no-dist-gzip dist-xz
color-tests parallel-tests subdir-objects])
color-tests subdir-objects])
AM_MAINTAINER_MODE([enable])
AM_SILENT_RULES([yes])
AC_USE_SYSTEM_EXTENSIONS
@ -34,11 +34,7 @@ LT_INIT([disable-static])
OSTREE_FEATURES=""
AC_SUBST([OSTREE_FEATURES])
AC_ARG_ENABLE(installed_tests,
AS_HELP_STRING([--enable-installed-tests],
[Install test programs (default: no)]),,
[enable_installed_tests=no])
AM_CONDITIONAL(BUILDOPT_INSTALL_TESTS, test x$enable_installed_tests = xyes)
GLIB_TESTS
AC_CHECK_HEADER([sys/xattr.h],,[AC_MSG_ERROR([You must have sys/xattr.h from glibc])])
@ -196,6 +192,31 @@ AS_IF([ test x$with_selinux != xno ], [
if test x$with_selinux != xno; then OSTREE_FEATURES="$OSTREE_FEATURES +selinux"; fi
AM_CONDITIONAL(USE_SELINUX, test $with_selinux != no)
dnl This is what is in RHEL7.2 right now, picking it arbitrarily
LIBMOUNT_DEPENDENCY="mount >= 2.23.0"
AC_ARG_WITH(libmount,
AS_HELP_STRING([--without-libmount], [Do not use libmount]),
:, with_libmount=maybe)
AS_IF([ test x$with_libmount != xno ], [
AC_MSG_CHECKING([for $LIBMOUNT_DEPENDENCY])
PKG_CHECK_EXISTS($LIBMOUNT_DEPENDENCY, have_libmount=yes, have_libmount=no)
AC_MSG_RESULT([$have_libmount])
AS_IF([ test x$have_libmount = xno && test x$with_libmount != xmaybe ], [
AC_MSG_ERROR([libmount is enabled but could not be found])
])
AS_IF([ test x$have_libmount = xyes], [
AC_DEFINE([HAVE_LIBMOUNT], 1, [Define if we have libmount.pc])
PKG_CHECK_MODULES(OT_DEP_LIBMOUNT, $LIBMOUNT_DEPENDENCY)
with_libmount=yes
], [
with_libmount=no
])
], [ with_libmount=no ])
if test x$with_libmount != xno; then OSTREE_FEATURES="$OSTREE_FEATURES +libmount"; fi
AM_CONDITIONAL(USE_LIBMOUNT, test $with_libmount != no)
# Enabled by default because I think people should use it.
AC_ARG_ENABLE(rofiles-fuse,
[AS_HELP_STRING([--enable-rofiles-fuse],
@ -264,6 +285,7 @@ echo "
libsoup (retrieve remote HTTP repositories): $with_soup
libsoup TLS client certs: $have_libsoup_client_certs
SELinux: $with_selinux
libmount: $with_libmount
libarchive (parse tar files directly): $with_libarchive
static deltas: yes (always enabled now)
man pages (xsltproc): $enable_man

17
contrib/golang/COPYING Normal file
View File

@ -0,0 +1,17 @@
Portions of this code are derived from:
https://github.com/dradtke/gotk3
Copyright (c) 2013 Conformal Systems LLC.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

2
contrib/golang/README.md Normal file
View File

@ -0,0 +1,2 @@
This file contains demonstration FFI bindings for using `-lostree-1`
and `-larchive` from golang.

View File

@ -0,0 +1,201 @@
/*
* Copyright (c) 2013 Conformal Systems <info@conformal.com>
*
* This file originated from: http://opensource.conformal.com/
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package ostree
// #cgo pkg-config: glib-2.0 gobject-2.0
// #include <glib.h>
// #include <glib-object.h>
// #include <gio/gio.h>
// #include "glibobject.go.h"
// #include <stdlib.h>
import "C"
import (
"unsafe"
"runtime"
"fmt"
"errors"
)
func GBool(b bool) C.gboolean {
if b {
return C.gboolean(1)
}
return C.gboolean(0)
}
func GoBool(b C.gboolean) bool {
if b != 0 {
return true
}
return false
}
type GError struct {
ptr unsafe.Pointer
}
func NewGError() GError {
return GError{nil}
}
func (e *GError) Native() *C.GError {
if e == nil {
return nil
}
return (*C.GError)(e.ptr)
}
func ConvertGError(e *C.GError) error {
defer C.g_error_free(e)
return errors.New(C.GoString((*C.char)(C._g_error_get_message(e))))
}
type GType uint
func (t GType) Name() string {
return C.GoString((*C.char)(C.g_type_name(C.GType(t))))
}
type GVariant struct {
ptr unsafe.Pointer
}
func GVariantNew(p unsafe.Pointer) *GVariant {
o := &GVariant{p}
runtime.SetFinalizer(o, (*GVariant).Unref)
return o;
}
func GVariantNewSink(p unsafe.Pointer) *GVariant {
o := &GVariant{p}
runtime.SetFinalizer(o, (*GVariant).Unref)
o.RefSink()
return o;
}
func (v *GVariant) native() *C.GVariant {
return (*C.GVariant)(v.ptr);
}
func (v *GVariant) Ref() {
C.g_variant_ref(v.native())
}
func (v *GVariant) Unref() {
C.g_variant_unref(v.native())
}
func (v *GVariant) RefSink() {
C.g_variant_ref_sink(v.native())
}
func (v *GVariant) TypeString() string {
cs := (*C.char)(C.g_variant_get_type_string(v.native()))
return C.GoString(cs)
}
func (v *GVariant) GetChildValue(i int) *GVariant {
cchild := C.g_variant_get_child_value(v.native(), C.gsize(i))
return GVariantNew(unsafe.Pointer(cchild));
}
func (v *GVariant) LookupString(key string) (string, error) {
ckey := C.CString(key)
defer C.free(unsafe.Pointer(ckey))
// TODO: Find a way to have constant C strings in golang
cstr := C._g_variant_lookup_string(v.native(), ckey)
if cstr == nil {
return "", fmt.Errorf("No such key: %s", key)
}
return C.GoString(cstr), nil
}
/*
* GObject
*/
// IObject is an interface type implemented by Object and all types which embed
// an Object. It is meant to be used as a type for function arguments which
// require GObjects or any subclasses thereof.
type IObject interface {
toGObject() *C.GObject
ToObject() *GObject
}
// Object is a representation of GLib's GObject.
type GObject struct {
ptr unsafe.Pointer
}
func GObjectNew(p unsafe.Pointer) *GObject {
o := &GObject{p}
runtime.SetFinalizer(o, (*GObject).Unref)
return o;
}
func (v *GObject) Ptr() unsafe.Pointer {
return v.ptr
}
func (v *GObject) Native() *C.GObject {
if v == nil || v.ptr == nil {
return nil
}
return (*C.GObject)(v.ptr)
}
func (v *GObject) toGObject() *C.GObject {
if v == nil {
return nil
}
return v.Native()
}
func (v *GObject) Ref() {
C.g_object_ref(C.gpointer(v.ptr))
}
func (v *GObject) Unref() {
C.g_object_unref(C.gpointer(v.ptr))
}
func (v *GObject) RefSink() {
C.g_object_ref_sink(C.gpointer(v.ptr))
}
func (v *GObject) IsFloating() bool {
c := C.g_object_is_floating(C.gpointer(v.ptr))
return GoBool(c)
}
func (v *GObject) ForceFloating() {
C.g_object_force_floating((*C.GObject)(v.ptr))
}
// GIO types
type GCancellable struct {
*GObject
}
func (self *GCancellable) native() *C.GCancellable {
return (*C.GCancellable)(self.ptr)
}
// At the moment, no cancellable API, just pass nil

View File

@ -0,0 +1,17 @@
#include <glib.h>
static char *
_g_error_get_message (GError *error)
{
g_assert (error != NULL);
return error->message;
}
static const char *
_g_variant_lookup_string (GVariant *v, const char *key)
{
const char *r;
if (g_variant_lookup (v, key, "&s", &r))
return r;
return NULL;
}

94
contrib/golang/ostree.go Normal file
View File

@ -0,0 +1,94 @@
// +build linux
// Public API specification for libostree Go bindings
package ostree
import (
"unsafe"
)
// #cgo pkg-config: ostree-1
// #include <stdlib.h>
// #include <glib.h>
// #include <ostree.h>
// #include "ostree.go.h"
import "C"
type Repo struct {
*GObject
}
func RepoGetType() GType {
return GType(C.ostree_repo_get_type())
}
func (r *Repo) native() *C.OstreeRepo {
return (*C.OstreeRepo)(r.ptr)
}
func repoFromNative(p *C.OstreeRepo) *Repo {
if p == nil {
return nil
}
o := GObjectNew(unsafe.Pointer(p))
r := &Repo{o}
return r
}
func RepoNewOpen(path string) (*Repo, error) {
var cerr *C.GError = nil
cpath := C.CString(path)
pathc := C.g_file_new_for_path(cpath);
defer C.g_object_unref(C.gpointer(pathc))
crepo := C.ostree_repo_new(pathc)
repo := repoFromNative(crepo);
r := GoBool(C.ostree_repo_open(repo.native(), nil, &cerr))
if !r {
return nil, ConvertGError(cerr)
}
return repo, nil
}
func (r *Repo) GetParent() *Repo {
return repoFromNative(C.ostree_repo_get_parent(r.native()))
}
type ObjectType int
const (
OBJECT_TYPE_FILE ObjectType = C.OSTREE_OBJECT_TYPE_FILE
OBJECT_TYPE_DIR_TREE = C.OSTREE_OBJECT_TYPE_DIR_TREE
OBJECT_TYPE_DIR_META = C.OSTREE_OBJECT_TYPE_DIR_META
OBJECT_TYPE_COMMIT = C.OSTREE_OBJECT_TYPE_COMMIT
OBJECT_TYPE_TOMBSTONE_COMMIT = C.OSTREE_OBJECT_TYPE_TOMBSTONE_COMMIT
)
func (repo *Repo) LoadVariant(t ObjectType, checksum string) (*GVariant, error) {
var cerr *C.GError = nil
var cvariant *C.GVariant = nil
r := GoBool(C.ostree_repo_load_variant(repo.native(), C.OstreeObjectType(t), C.CString(checksum), &cvariant, &cerr))
if !r {
return nil, ConvertGError(cerr)
}
variant := GVariantNew(unsafe.Pointer(cvariant))
return variant, nil
}
func (repo *Repo) ResolveRev(ref string) (string, error) {
var cerr *C.GError = nil
var crev *C.char = nil
r := GoBool(C.ostree_repo_resolve_rev(repo.native(), C.CString(ref), GBool(true), &crev, &cerr))
if !r {
return "", ConvertGError(cerr)
}
defer C.free(unsafe.Pointer(crev))
return C.GoString(crev), nil
}
func (commit *GVariant) CommitGetMetadataKeyString(key string) (string, error) {
cmeta := GVariantNew(unsafe.Pointer(C.g_variant_get_child_value(commit.native(), 0)))
return cmeta.LookupString(key)
}

View File

@ -0,0 +1,21 @@
#include <ostree.h>
#include <string.h>
static void
_ostree_repo_checkout_options_init_docker_union (OstreeRepoCheckoutOptions *opts)
{
memset (opts, 0, sizeof (*opts));
opts->mode = OSTREE_REPO_CHECKOUT_MODE_USER;
opts->overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
opts->disable_fsync = 1;
opts->process_whiteouts = 1;
}
static const char *
_g_variant_lookup_string (GVariant *v, const char *key)
{
const char *r;
if (g_variant_lookup (v, key, "&s", &r))
return r;
return NULL;
}

View File

@ -0,0 +1,55 @@
// +build linux
// Public API specification for libostree Go bindings
package ostree
import (
"testing"
)
func TestTypeName(t *testing.T) {
name := RepoGetType().Name();
if name != "OstreeRepo" {
t.Errorf("%s != OstreeRepo");
}
}
func TestRepoNew(t *testing.T) {
r, err := RepoNewOpen("/ostree/repo")
if err != nil {
t.Errorf("%s", err);
return
}
parent := r.GetParent()
if parent != nil {
t.Errorf("Expected no parent")
return
}
}
func TestRepoGetMetadataVersion(t *testing.T) {
r, err := RepoNewOpen("/ostree/repo")
if err != nil {
t.Errorf("%s", err);
return
}
commit,err := r.ResolveRev("rhel-atomic-host/7/x86_64/standard")
if err != nil {
t.Errorf("%s", err)
return
}
commitv,err := r.LoadVariant(OBJECT_TYPE_COMMIT, commit)
if err != nil {
t.Errorf("%s", err)
return
}
ver, err := commitv.CommitGetMetadataKeyString("version")
if err != nil {
t.Errorf("%s", err)
return
}
if ver != "7.1.3" {
t.Errorf("expected 7.1.3")
}
}

View File

@ -3,17 +3,18 @@ Submitting patches
You can:
1. Send mail to ostree-list@gnome.org, with the patch attached
1. Submit a pull request against https://github.com/GNOME/ostree
1. Attach them to https://bugzilla.gnome.org/
1. Send mail to <ostree-list@gnome.org>, with the patch attached
1. Submit a pull request against <https://github.com/GNOME/ostree>
1. Attach them to <https://bugzilla.gnome.org/>
Please look at "git log" and match the commit log style.
Please look at `git log` and match the commit log style.
Running the test suite
----------------------
Currently, ostree uses https://wiki.gnome.org/GnomeGoals/InstalledTests
To run just ostree's tests:
Currently, OSTree uses <https://wiki.gnome.org/GnomeGoals/InstalledTests>
To run just OSTree's tests:
./configure ... --enable-installed-tests
gnome-desktop-testing-runner -p 0 ostree/
@ -47,16 +48,16 @@ This is an example of an "early exit":
myfunc (...)
{
gboolean ret = FALSE;
/* some code */
/* some more code */
if (condition)
return FALSE;
/* some more code */
ret = TRUE;
out:
return ret;
@ -85,14 +86,14 @@ functions, particularly inside loops. For example, rather than:
{
/* deeply nested code */
}
/* more nested code */
}
}
}
Instead do this:
static gboolean
helperfunc (..., GError **error)
{
@ -100,22 +101,21 @@ Instead do this:
{
/* deeply nested code */
}
/* more nested code */
return ret;
}
while (condition)
{
/* some code */
if (!condition)
continue;
for (i = 0; i < somevalue; i++)
{
if (!helperfunc (..., i, error))
goto out;
}
}

View File

@ -140,7 +140,7 @@ Now, because we are merely installing new packages and not
removing anything, we can make the major optimization of reusing
our existing filesystem tree, and merely
*layering* the composed filesystem tree of
these new packages on top. A command like this:
these new packages on top. A command like this:
```
ostree commit -b osname/releasename/description

View File

@ -15,7 +15,7 @@ exactly one ref, which is stored in the `.origin` file for the
deployment. The command `ostree admin upgrade`
implements this.
o begin a simple upgrade, OSTree fetches the contents of the ref from
To begin a simple upgrade, OSTree fetches the contents of the ref from
the remote server. Suppose we're tracking a ref named
`exampleos/buildmaster/x86_64-runtime`. OSTree fetches the URL
`http://$example.com/repo/refs/exampleos/buildmaster/x86_64-runtime`,
@ -56,11 +56,10 @@ checking it back out of the repo into a deployment.
Given a commit to deploy, OSTree first allocates a directory for
it. This is of the form `/boot/loader/entries/ostree-$osname-$checksum.$serial.conf`.
he $serial is normally 0, but if a
The `$serial` is normally 0, but if a
given commit is deployed more than once, it will be incremented.
his is supported because the previous deployment may have
configuration in `/etc`
hat we do not want to use or overwrite.
configuration in `/etc` that we do not want to use or overwrite.
Now that we have a deployment directory, a 3-way merge is
performed between the (by default) currently booted deployment's
@ -74,7 +73,7 @@ hardlink farm; the running system is untouched, and the bootloader
configuration is untouched. We want to add this deployment o the
"deployment list".
To support a more general case, OSTree supports atomic ransitioning
To support a more general case, OSTree supports atomic transitioning
between arbitrary sets of deployments, with the restriction that the
currently booted deployment must always be in the new set. In the
normal case, we have exactly one deployment, which is the booted one,
@ -101,7 +100,10 @@ deployment lists. This happens when doing an upgrade that does not
include the kernel; think of a simple translation update. OSTree
optimizes for this case because on some systems `/boot` may be on a
separate medium such as flash storage not optimized for significant
amounts of write traffic.
amounts of write traffic. Related to this, modern OSTree has support
for having `/boot` be a read-only mount by default - it will
automatically remount read-write just for the portion of time
necessary to update the bootloader configuration.
To implement this, OSTree also maintains the directory
`/ostree/boot.<replaceable>bootversion</replaceable>`, which is a set

View File

@ -0,0 +1,180 @@
# Writing a buildsystem and managing repositories
OSTree is not a package system. It does not directly support building
source code. Rather, it is a tool for transporting and managing
content, along with package-system independent aspects like bootloader
management for updates.
We'll assume here that we're planning to generate commits on a build
server, then have client systems replicate it. Doing client-side
assembly is also possible of course, but this discussion will focus
primarily on server-side concerns.
## Build vs buy
Therefore, you need to either pick an existing tool for writing
content into an OSTree repository, or to write your own. An example
tool is [rpm-ostree](https://github.com/projectatomic/rpm-ostree) - it
takes as input RPMs, and commits them (currently oriented for a server
side, but aiming to do client side too).
## Initializing
For this initial discussion, we're assuming you have a single
`archive-z2` repository:
```
mkdir repo
ostree --repo=repo init --mode=archive-z2
```
You can export this via a static webserver, and configure clients to
pull from it.
## Writing your own OSTree buildsystem
There exist many, many systems that basically follow this pattern:
```
$pkg --installroot=/path/to/tmpdir install foo bar baz
$imagesystem commit --root=/path/to/tmpdir
```
For various values of `$pkg` such as `yum`, `apt-get`, etc., and
values of `$imagesystem` could be simple tarballs, Amazon Machine
Images, ISOs, etc.
Now obviously in this document, we're going to talk about the
situation where `$imagesystem` is OSTree. The general idea with
OSTree is that wherever you might store a series of tarballs for
applications or OS images, OSTree is likely going to be better. For
example, it supports GPG signatures, binary deltas, writing bootloader
configuration, etc.
OSTree does not include a package/component build system simply
because there already exist plenty of good ones - rather, it is
intended to provide an infrastructure layer.
The above mentioned `rpm-ostree compose tree` chooses RPM as the value
of `$pkg` - so binaries are built as RPMs, then committed as a whole
into an OSTree commit.
But let's discuss building our own. If you're just experimenting,
it's quite easy to start with the command line. We'll assume for this
purpose that you have a build process that outputs a directory tree -
we'll call this tool `$pkginstallroot` (which could be `yum
--installroot` or `dbootstrap`, etc.).
Your initial prototype is going to look like:
```
$pkginstallroot /path/to/tmpdir
ostree --repo=repo commit -s 'build' -b exampleos/x86_64/standard --tree=dir=/path/to/tmpdir
```
Alternatively, if your build system can generate a tarball, you can
commit that tarball into OSTree. For example,
[OpenEmbedded](http://www.openembedded.org/) can output a tarball, and
one can commit it via:
```
ostree commit -s 'build' -b exampleos/x86_64/standard --tree=tar=myos.tar
```
## Constructing trees from unions
The above is a very simplistic model, and you will quickly notice that
it's slow. This is because OSTree has to re-checksum and recompress
the content each time it's committed. (Most of the CPU time is spent
in compression which gets thrown away if the content turns out to be
already stored).
A more advanced approach is to store components in OSTree itself, then
union them, and recommit them. At this point, we recommend taking a
look at the OSTree API, and choose a programming language supported by
[GObject Introspection](https://wiki.gnome.org/Projects/GObjectIntrospection)
to write your buildsystem scripts. Python may be a good choice, or
you could choose custom C code, etc.
For the purposes of this tutorial we will use shell script, but it's
strongly recommended to choose a real programming language for your
build system.
Let's say that your build system produces separate artifacts (whether
those are RPMs, zip files, or whatever). These artifacts should be
the result of `make install DESTDIR=` or similar. Basically
equivalent to RPMs/debs.
Further, in order to make things fast, we will need a separate
`bare-user` repository in order to perform checkouts quickly via
hardlinks. We'll then export content into the `archive-z2` repository
for use by client systems.
```
mkdir build-repo
ostree --repo=build-repo init --mode=bare-user
```
You can begin committing those as individual branches:
```
ostree --repo=build-repo commit -b exampleos/x86_64/bash --tree=tar=bash-4.2-bin.tar.gz
ostree --repo=build-repo commit -b exampleos/x86_64/systemd --tree=tar=systemd-224-bin.tar.gz
```
Set things up so that whenever a package changes, you redo the
`commit` with the new package version - conceptually, the branch
tracks the individual package versions over time, and defaults to
"latest". This isn't required - one could also include the version in
the branch name, and have metadata outside to determine "latest" (or
the desired version).
Now, to construct our final tree:
```
rm exampleos-build -rf
for package in bash systemd; do
ostree --repo=build-repo checkout -U --union exampleos/x86_64/${package} exampleos-build
done
# Set up a "rofiles-fuse" mount point; this ensures that any processes
# we run for post-processing of the tree don't corrupt the hardlinks.
mkdir -p mnt
rofiles-fuse exampleos-build mnt
# Now run global "triggers", generate cache files:
ldconfig -r mnt
(Insert other programs here)
fusermount -u mnt
ostree --repo=build-repo commit -b exampleos/x86_64/standard --link-checkout-speedup exampleos-build
```
There are a number of interesting things going on here. The major
architectural change is that we're using `--link-checkout-speedup`.
This is a way to tell OSTree that our checkout is made via hardlinks,
and to scan the repository in order to build up a reverse `(device,
inode) -> checksum` mapping.
In order for this mapping to be accurate, we needed the `rofiles-fuse`
to ensure that any changed files had new inodes (and hence a new
checksum).
## Migrating content between repositories
Now that we have content in our `build-repo` repository (in
`bare-user` mode), we need to move the `exampleos/x86_64/standard`
branch content into the repository just named `repo` (in `archive-z2`
mode) for export, which will involve zlib compression of new objects.
We likely want to generate static deltas after that as well.
Let's copy the content:
```
ostree --repo=repo pull-local build-repo exampleos/x86_64/standard
```
Clients can now incrementally download new objects - however, this
would also be a good time to generate a delta from the previous
commit.
```
ostree --repo=repo static-delta generate exampleos/x86_64/standard
```

View File

@ -13,7 +13,7 @@ OSTree is designed to boot directly into exactly one deployment
at a time; each deployment is intended to be a target for
`chroot()` or equivalent.
### "osname": Group of deployments that share /var</title>
### "osname": Group of deployments that share /var
Each deployment is grouped in exactly one "osname". From above, you
can see that an osname is physically represented in the

View File

@ -67,7 +67,7 @@ or an unprivileged container.
## Static deltas
OSTree itself was originally focused on a continous delivery model, where
OSTree itself was originally focused on a continuous delivery model, where
client systems are expected to update regularly. However, many OS vendors
would like to supply content that's updated e.g. once a month or less often.
@ -82,7 +82,7 @@ object. Static deltas also support `from NULL`, where the client can
more efficiently download a commit object from scratch.
Effectively, we're spending server-side storage (and one-time compute
cost), and gaining efficiency in client network bandwith.
cost), and gaining efficiency in client network bandwidth.
## Static delta repository layout
@ -99,7 +99,7 @@ management easier for filesystem tools
A delta is named `$(mbase64 $from)-$(mbase64 $to)`, for example
`GpTyZaVut2jXFPWnO4LJiKEdRTvOw_mFUCtIKW1NIX0-L8f+VVDkEBKNc1Ncd+mDUrSVR4EyybQGCkuKtkDnTwk`,
which in sha256 format is
which in SHA256 format is
`1a94f265a56eb768d714f5a73b82c988a11d453bcec3f985502b48296d4d217d-2fc7fe5550e410128d73535c77e98352b495478132c9b4060a4b8ab640e74f09`.
Finally, the actual content can be found in
@ -136,7 +136,7 @@ The superblock contains:
- delta generation timestamp
- the new commit object
- An array of recursive deltas to apply
- An array of per-part metadata, including total object sizes (compressed and uncompressed),
- An array of per-part metadata, including total object sizes (compressed and uncompressed),
- An array of fallback objects
Let's define a delta part, then return to discuss details:
@ -160,14 +160,14 @@ a per-file delta algorithm called
[bsdiff](https://github.com/mendsley/bsdiff) that most notably works
well on executable code.
The current delta compiler scans for files with maching basenamesin
The current delta compiler scans for files with matching basenames in
each commit that have a similar size, and attempts a bsdiff between
them. (It would make sense later to have a build system provide a
hint for this - for example, files within a same package).
A generated bsdiff is included in the payload blob, and applying it is
an instruction.
## Fallback objects
It's possible for there to be large-ish files which might be resistant

View File

@ -1,6 +1,6 @@
# OSTree Overview
## Introduction
## Introduction
OSTree an upgrade system for Linux-based operating systems that
performs atomic upgrades of complete filesystem trees. It is
@ -15,7 +15,7 @@ content-addressed object store, and layered on top of that is
bootloader configuration, management of
`/etc`, and other functions to perform an
upgrade beyond just replicating files.
You can use OSTree standalone in the pure replication model,
but another approach is to add a package manager on top,
thus creating a hybrid tree/package system.
@ -46,7 +46,7 @@ HTTP, and where the OS includes (if desired) an entirely
separate mechanism to install applications, stored in `/var` if they're system global, or
`/home` for per-user
application installation. An example application mechanism is
http://docker.io/
<http://docker.io/>
However, it is entirely possible to use OSTree underneath a
package system, where the contents of `/usr` are computed on the client.
@ -79,6 +79,13 @@ filesystem that supports hard links. Note: OSTree will
transparently take advantage of some BTRFS features if deployed
on it.
OSTree is orthogonal to virtualization mechanisms like AMIs and qcow2
images, though it's most useful though if you plan to update stateful
VMs in-place, rather than generating new images.
In practice, users of "bare metal" configurations will find the OSTree
model most useful.
## Atomic transitions between parallel-installable read-only filesystem trees
Another deeply fundamental difference between both package

View File

@ -0,0 +1,207 @@
# Related Projects
OSTree is in many ways very evolutionary. It builds on concepts and
ideas introduced from many different projects such as
[Systemd Stateless](http://0pointer.net/blog/projects/stateless.html),
[Systemd Bootloader Spec](https://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/),
[Chromium Autoupdate](http://dev.chromium.org/chromium-os/chromiumos-design-docs/filesystem-autoupdate),
the much older
[Fedora/Red Hat Stateless Project](https://fedoraproject.org/wiki/StatelessLinux),
[Linux VServer](http://linux-vserver.org/index.php?title=util-vserver:Vhashify&oldid=2285)
and many more.
As mentioned elsewhere, OSTree is strongly influenced by package
manager designs as well. This page is not intended to be an
exhaustive list of such projects, but we will try to keep it up to
date, and relatively agnostic.
Broadly speaking, projects in this area fall into two camps; either
a tool to snapshot systems on the client side (dpkg/rpm + BTRFS/LVM),
or a tool to compose on a server and replicate (ChromiumOS, Clear
Linux). OSTree is flexible enough to do both.
## Combining dpkg/rpm + (BTRFS/LVM)
In this approach, one uses a block/filesystem snapshot tool underneath
the system package manager.
The
[oVirt Node imgbased](https://gerrit.ovirt.org/gitweb?p=imgbased.git)
tool is an example of this approach, as are a few others below.
Regarding [BTRFS](https://btrfs.wiki.kernel.org/index.php/Main_Page)
in particular - the OSTree author believes that Linux storage is a
wide world, and while BTRFS is quite good, it is not everywhere now,
nor will it be in the near future. There are other recently developed
filesystems like [f2fs](https://en.wikipedia.org/wiki/F2FS), and Red
Hat Enterprise Linux still defaults to
[XFS](https://en.wikipedia.org/wiki/XFS).
Using a snapshot tool underneath a package manager does help
significantly. In the rest of this text, we will use "BTRFS" as a
mostly generic tool for filesystem snapshots.
The obvious thing to do is layer BTRFS under dpkg/rpm, and have a
separate subvolume for `/home` so rollbacks don't lose your data. See
e.g. [Fedora BTRFS Rollback Feature](http://fedoraproject.org/wiki/Features/SystemRollbackWithBtrfs).
More generally, if you want to use BTRFS to roll back changes made by
dpkg/rpm, you have to carefully set up the partition layout so that
the files laid out by dpkg/rpm are installed in a subvolume to
snapshot.
This problem in many ways is addressed by the changes OSTree forces,
such as putting all local state in `/var` (e.g. `/usr/local` ->
`/var/usrlocal`). Then one can BTRFS snapshot `/usr`. This gets pretty
far, except handling `/etc` is messy. This is something OSTree does
well.
In general, if one really tries to flesh out the BTRFS approach, a
nontrivial middle layer of code between dpkg/rpm and BTRFS (or deep
awareness of BTRFS in dpkg/rpm itself) will be required.
The OSTree author believes that having total freedom at the block
storage layer is better for general purpose operating systems. For
example, with OSTree, one is free to use BTRFS in any way you like -
you can use a subvolume for `/home`, or you can not.
Furthermore, in its most basic incarnation, the rpm/dpkg + BTRFS
doesn't solve the race conditions that happen when unpacking packages
into the live system, such as deleting the files underneath Firefox
while it's running. One could unpack packages into a separate root,
and switch to that, which gets closer to the OSTree architecture.
Note though OSTree does take advantage of BTRFS if installed on top of
it! In particular, it will use reflink for the copies of `/etc` if
available.
All of the above also applies if one replaces "BTRFS" with "LVM
snapshots" except for the reflinks.
Finally, see the next portion around ChromiumOS for why a hybrid but
integrated package/image system improves on this.
## ChromiumOS updater
Many people who look at OSTree are most interested in using
it as an updater for embedded or fixed-purpose systems, similar to use cases
from the [ChromiumOS updater](http://dev.chromium.org/chromium-os/chromiumos-design-docs/filesystem-autoupdate).
The ChromiumOS approach uses two partitions that are swapped via the
bootloader. It has a very network-efficient update protocol, using a
custom binary delta scheme between filesystem snapshots.
This model even allows for switching filesystem types in an update.
A major downside of this approach is that the OS size is doubled on
disk always. In contrast, OSTree uses plain Unix hardlinks, which
means it essentially only requires disk space proportional to the
changed files, plus some small fixed overhead.
This means with OSTree, one can easily have more than two trees
(deployments). Another example is that the system OSTree repository
could *also* be used for application containers.
Finally, the author of OSTree believes that what one really wants for
many cases is image replication *with* the ability to layer on some
additional components (e.g. packages) - a hybrid model. This is what
[rpm-ostree](https://github.com/projectatomic/rpm-ostree/) is aiming
to support.
## Ubuntu Image Based Updates
See <https://wiki.ubuntu.com/ImageBasedUpgrades>. Very architecturally
similar to ChromeOS, although more interesting is discussion for
supporting package installation on top, similar to
[rpm-ostree package layering](https://github.com/projectatomic/rpm-ostree/pull/107).
## Clear Linux Software update
The
[Clear Linux Software update](https://clearlinux.org/features/software-update)
system is not very well documented.
[This mailing list post](https://lists.clearlinux.org/pipermail/dev/2016-January/000159.html)
has some reverse-engineered design documentation.
Like OSTree static deltas, it also uses bsdiff for network efficiency.
More information will be filled in here over time. The OSTree author
believes that at the moment, the "CL updater" is not truly atomic in
the sense that because it applies updates live, there is a window
where the OS root may be inconsistent.
## OLPC update
OSTree is basically a generalization of olpc-update, except using
plain HTTP instead of rsync. OSTree has the notion of separate trees
that one can track independently or parallel install, while still
sharing storage via the hardlinked repository, whereas olpc-update
uses version numbers for a single OS.
OSTree has built-in plain old HTTP replication which can be served
from a static webserver, whereas olpc-update uses `rsync` (more server
load, but more efficient on the network side). The OSTree solution to
improving network bandwidth consumption is via static deltas.
See
[this comment](http://blog.verbum.org/2013/08/26/ostree-v2013-6-released/#comment-1169)
for a comparison.
## NixOS
See [NixOS](http://nixos.org/). It was a very influential project for
OSTree. NixOS and OSTree both support the idea of independent "roots"
that are bootable.
In NixOS, the entire system is based on checksums of package inputs
(build dependencies) - see [Nix store](http://nixos.org/nix/manual/#chap-package-management/). A both
positive and negative of the Nix model is that a change in the build
dependencies (e.g. being built with a newer gcc), requires a cascading
rebuild of everything.
In OSTree, the checksums are of object *content* (including extended
attributes). This means that any data that's identical is
transparently, automatically shared on disk. It's possible to ask the
Nix store to deduplicate, (via hard links and immutable bit), but this
is significantly less efficient than the OSTree approach. The Nix use
of the ext immutable bit is racy, since it has to be briefly removed
to make a hard link.
At the lowest level, OSTree is just "git for binaries" - it isn't tied
strongly to any particular build system. You can put whatever data you
want inside an OSTree repository, built however you like. So for
example, while one could make a build system that did the "purely
functional" approach of Nix, it also works to have a build system that
just rebuilds individual components (packages) as they change, without
forcing a rebuild of their dependencies.
The author of OSTree believes that while Nix has some good ideas,
forcing a rebuild of everything for a security update to e.g. glibc is
not practical at scale.
## Solaris IPS
See
[Solaris IPS](http://hub.opensolaris.org/bin/view/Project+pkg/). Broadly,
this is a similar design as to a combination of BTRFS+RPM/deb. There
is a bootloader management system which combines with the snapshots.
It's relatively well thought through - however, it is a client-side
system assembly. If one wants to image servers and replicate
reliably, that'd be a different system.
## Conary
See
[Conary Updates and Rollbacks](http://wiki.rpath.com/wiki/Conary:Updates_and_Rollbacks). If
rpm/dpkg are like CVS, Conary is closer to Subversion. It's not bad,
but e.g. its rollback model is rather ad-hoc and not atomic. It also
is a fully client side system and doesn't have an image-like
replication with deltas.
## bmap
See
[bmap](https://source.tizen.org/documentation/reference/bmaptool/introduction).
A tool for optimized copying of disk images. Intended for offline use,
so not directly comparable.

View File

@ -54,12 +54,12 @@ modes: `bare`, `bare-user`, and `archive-z2`. A bare repository is
one where content files are just stored as regular files; it's
designed to be the source of a "hardlink farm", where each operating
system checkout is merely links into it. If you want to store files
owned by e.g. root in this mode, you must run OSTree as root.
owned by e.g. root in this mode, you must run OSTree as root.
The `bare-user` is a later addition that is like `bare` in that files
are unpacked, but it can (and should generally) be created as
non-root. In this mode, extended metadata such as owner uid, gid, and
extended attributes are stored but not actually applied.
extended attributes are stored but not actually applied.
The `bare-user` mode is useful for build systems that run as non-root
but want to generate root-owned content, as well as non-root container
systems.
@ -74,9 +74,13 @@ command, it will operate on the system repository.
## Refs
Like git, OSTree uses "refs" to which are text files that point to
particular commits (i.e. filesystem trees). For example, the
gnome-ostree operating system creates trees named like
Like git, OSTree uses the terminology "references" (abbreviated
"refs") which are text files that name (refer to) to particular
commits. See the
[Git Documentation](https://git-scm.com/book/en/v2/Git-Internals-Git-References)
for information on how git uses them. Unlike git though, it doesn't
usually make sense to have a "master" branch. There is a convention
for references in OSTree that looks like this:
`exampleos/buildmaster/x86_64-runtime` and
`exampleos/buildmaster/x86_64-devel-debug`. These two refs point to
two different generated filesystem trees. In this example, the
@ -88,3 +92,30 @@ the parent of a given commit. For example,
`exampleos/buildmaster/x86_64-runtime^` refers to the previous build,
and `exampleos/buildmaster/x86_64-runtime^^` refers to the one before
that.
## The summary file
A later addition to OSTree is the concept of a "summary" file, created
via the `ostree summary -u` command. This was introduced for a few
reasons. A primary use case is to be a target a
(Metalink)[https://en.wikipedia.org/wiki/Metalink], which requires a
single file with a known checksum as a target.
The summary file primarily contains two mappings:
- A mapping of the refs and their checksums, equivalent to fetching
the ref file individually
- A list of all static deltas, along with their metadata checksums
This currently means that it grows linearly with both items. On the
other hand, using the summary file, a client can enumerate branches.
Further, the summary file is fetched over e.g. pinned TLS, this
creates a strong end-to-end verification of the commit or static delta.
The summary file can also be GPG signed (detached), and currently this
is the only way provide GPG signatures (transitively) on deltas.
If a repository administrator creates a summary file, they must
thereafter run `ostree summary -u` to update it whenever a commit is
made or a static delta is generated.

View File

@ -0,0 +1,88 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!--
Copyright 2016 Colin Walters <walters@verbum.org>
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.
-->
<refentry id="ostree">
<refentryinfo>
<title>ostree admin unlock</title>
<productname>OSTree</productname>
<authorgroup>
<author>
<contrib>Developer</contrib>
<firstname>Colin</firstname>
<surname>Walters</surname>
<email>walters@verbum.org</email>
</author>
</authorgroup>
</refentryinfo>
<refmeta>
<refentrytitle>ostree admin unlock</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>ostree-admin-unlock</refname>
<refpurpose>Prepare the current deployment for hotfix or development</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>ostree admin unlock</command> <arg choice="opt" rep="repeat">OPTIONS</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
Remove the read-only bind mount on <literal>/usr</literal>
and replace it with a writable overlay filesystem. This
default invocation of "unlock" is intended for
development/testing purposes. All changes in the overlay
are lost on reboot. However, this command also supports
"hotfixes", see below.
</para>
</refsect1>
<refsect1>
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--hotfix</option></term>
<listitem><para>If this option is provided, the
current deployment will be cloned as a rollback
target. This option is intended for things like
emergency security updates to userspace components
such as <literal>sshd</literal>. The semantics here
differ from the default "development" unlock mode
in that reboots will retain any changes (which is what
you likely want for security hotfixes).
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>

View File

@ -57,7 +57,7 @@ Boston, MA 02111-1307, USA.
<refsect1>
<title>Description</title>
<para>
Lists all refs available on the host. If pecified, PREFIX assigns the refspec prefix; default prefix is null, which lists all refs.
Lists all refs available on the host. If specified, PREFIX assigns the refspec prefix; default prefix is null, which lists all refs.
</para>
</refsect1>
@ -65,6 +65,16 @@ Boston, MA 02111-1307, USA.
<title>Options</title>
<variablelist>
<varlistentry>
<term><option>--list</option></term>
<listitem><para> For historical reasons, <literal>refs</literal>
without this option will strip the specified prefix
from the output. Normally, one wants to see the full
ref, so providing this option ensures the refs are
printed in full, rather than
truncated. </para></listitem>
</varlistentry>
<varlistentry>
<term><option>--delete</option></term>

View File

@ -59,4 +59,3 @@ set -x
validate_delta_options
validate_delta_options --inline
validate_delta_options --disable-bsdiff

View File

@ -1,4 +1,4 @@
site_name: My Docs
site_name: OSTree
pages:
- Home: 'index.md'
- Contributing: 'CONTRIBUTING.md'
@ -9,3 +9,5 @@ pages:
- Atomic Upgrades: 'manual/atomic-upgrades.md'
- Adapting Existing Systems: 'manual/adapting-existing.md'
- Formats: 'manual/formats.md'
- Build Systems and Repos: 'manual/buildsystem-and-repos.md'
- Related Projects: 'manual/related-projects.md'

335
src/libostree/libostree.sym Normal file
View File

@ -0,0 +1,335 @@
/***
Copyright (C) 2016 Colin Walters <walters@verbum.org>
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.
***/
/*
Retroactively make all of these symbols 2016.3, which is
the first release where we started using versioned symbols. See
also https://www.berrange.com/posts/2011/01/13/versioning-in-the-libvirt-library/
*/
LIBOSTREE_2016.3 {
global:
ostree_async_progress_finish;
ostree_async_progress_get_status;
ostree_async_progress_get_type;
ostree_async_progress_get_uint;
ostree_async_progress_get_uint64;
ostree_async_progress_new;
ostree_async_progress_new_and_connect;
ostree_async_progress_set_status;
ostree_async_progress_set_uint;
ostree_async_progress_set_uint64;
ostree_bootconfig_parser_clone;
ostree_bootconfig_parser_get;
ostree_bootconfig_parser_get_type;
ostree_bootconfig_parser_new;
ostree_bootconfig_parser_parse;
ostree_bootconfig_parser_parse_at;
ostree_bootconfig_parser_set;
ostree_bootconfig_parser_write;
ostree_bootconfig_parser_write_at;
ostree_chain_input_stream_get_type;
ostree_chain_input_stream_new;
ostree_checksum_b64_inplace_from_bytes;
ostree_checksum_b64_inplace_to_bytes;
ostree_checksum_bytes_peek;
ostree_checksum_bytes_peek_validate;
ostree_checksum_file;
ostree_checksum_file_async;
ostree_checksum_file_async_finish;
ostree_checksum_file_from_input;
ostree_checksum_from_bytes;
ostree_checksum_from_bytes_v;
ostree_checksum_inplace_from_bytes;
ostree_checksum_inplace_to_bytes;
ostree_checksum_input_stream_get_type;
ostree_checksum_input_stream_new;
ostree_checksum_to_bytes;
ostree_checksum_to_bytes_v;
ostree_cmd__private__;
ostree_cmp_checksum_bytes;
ostree_commit_get_parent;
ostree_commit_get_timestamp;
ostree_content_file_parse;
ostree_content_file_parse_at;
ostree_content_stream_parse;
ostree_create_directory_metadata;
ostree_deployment_clone;
ostree_deployment_equal;
ostree_deployment_get_bootconfig;
ostree_deployment_get_bootcsum;
ostree_deployment_get_bootserial;
ostree_deployment_get_csum;
ostree_deployment_get_deployserial;
ostree_deployment_get_index;
ostree_deployment_get_origin;
ostree_deployment_get_origin_relpath;
ostree_deployment_get_osname;
ostree_deployment_get_type;
ostree_deployment_hash;
ostree_deployment_new;
ostree_deployment_set_bootconfig;
ostree_deployment_set_bootserial;
ostree_deployment_set_index;
ostree_deployment_set_origin;
ostree_diff_dirs;
ostree_diff_item_get_type;
ostree_diff_item_ref;
ostree_diff_item_unref;
ostree_diff_print;
ostree_fetcher_config_flags_get_type;
ostree_gpg_verify_result_count_all;
ostree_gpg_verify_result_count_valid;
ostree_gpg_verify_result_describe;
ostree_gpg_verify_result_describe_variant;
ostree_gpg_verify_result_get;
ostree_gpg_verify_result_get_all;
ostree_gpg_verify_result_get_type;
ostree_gpg_verify_result_lookup;
ostree_hash_object_name;
ostree_metadata_variant_type;
ostree_mutable_tree_ensure_dir;
ostree_mutable_tree_ensure_parent_dirs;
ostree_mutable_tree_get_contents_checksum;
ostree_mutable_tree_get_files;
ostree_mutable_tree_get_metadata_checksum;
ostree_mutable_tree_get_subdirs;
ostree_mutable_tree_get_type;
ostree_mutable_tree_lookup;
ostree_mutable_tree_new;
ostree_mutable_tree_replace_file;
ostree_mutable_tree_set_contents_checksum;
ostree_mutable_tree_set_metadata_checksum;
ostree_mutable_tree_walk;
ostree_object_from_string;
ostree_object_name_deserialize;
ostree_object_name_serialize;
ostree_object_to_string;
ostree_object_type_from_string;
ostree_object_type_to_string;
ostree_parse_refspec;
ostree_raw_file_to_content_stream;
ostree_repo_abort_transaction;
ostree_repo_add_gpg_signature_summary;
ostree_repo_append_gpg_signature;
ostree_repo_checkout_gc;
ostree_repo_checkout_tree;
ostree_repo_checkout_tree_at;
ostree_repo_commit_modifier_get_type;
ostree_repo_commit_modifier_new;
ostree_repo_commit_modifier_ref;
ostree_repo_commit_modifier_set_devino_cache;
ostree_repo_commit_modifier_set_sepolicy;
ostree_repo_commit_modifier_set_xattr_callback;
ostree_repo_commit_modifier_unref;
ostree_repo_commit_transaction;
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;
ostree_repo_commit_traverse_iter_init_commit;
ostree_repo_commit_traverse_iter_init_dirtree;
ostree_repo_commit_traverse_iter_next;
ostree_repo_copy_config;
ostree_repo_create;
ostree_repo_delete_object;
ostree_repo_devino_cache_get_type;
ostree_repo_devino_cache_new;
ostree_repo_devino_cache_ref;
ostree_repo_devino_cache_unref;
ostree_repo_export_tree_to_archive;
ostree_repo_file_ensure_resolved;
ostree_repo_file_get_checksum;
ostree_repo_file_get_repo;
ostree_repo_file_get_root;
ostree_repo_file_get_type;
ostree_repo_file_get_xattrs;
ostree_repo_file_tree_find_child;
ostree_repo_file_tree_get_contents;
ostree_repo_file_tree_get_contents_checksum;
ostree_repo_file_tree_get_metadata;
ostree_repo_file_tree_get_metadata_checksum;
ostree_repo_file_tree_query_child;
ostree_repo_file_tree_set_metadata;
ostree_repo_get_config;
ostree_repo_get_disable_fsync;
ostree_repo_get_mode;
ostree_repo_get_parent;
ostree_repo_get_path;
ostree_repo_get_type;
ostree_repo_has_object;
ostree_repo_import_archive_to_mtree;
ostree_repo_import_object_from;
ostree_repo_is_system;
ostree_repo_is_writable;
ostree_repo_list_commit_objects_starting_with;
ostree_repo_list_objects;
ostree_repo_list_refs;
ostree_repo_list_static_delta_names;
ostree_repo_load_commit;
ostree_repo_load_file;
ostree_repo_load_object_stream;
ostree_repo_load_variant;
ostree_repo_load_variant_if_exists;
ostree_repo_mode_from_string;
ostree_repo_new;
ostree_repo_new_default;
ostree_repo_new_for_sysroot_path;
ostree_repo_open;
ostree_repo_prepare_transaction;
ostree_repo_prune;
ostree_repo_prune_static_deltas;
ostree_repo_pull;
ostree_repo_pull_default_console_progress_changed;
ostree_repo_pull_one_dir;
ostree_repo_pull_with_options;
ostree_repo_query_object_storage_size;
ostree_repo_read_commit;
ostree_repo_read_commit_detached_metadata;
ostree_repo_regenerate_summary;
ostree_repo_remote_add;
ostree_repo_remote_change;
ostree_repo_remote_delete;
ostree_repo_remote_fetch_summary;
ostree_repo_remote_get_gpg_verify;
ostree_repo_remote_get_gpg_verify_summary;
ostree_repo_remote_get_url;
ostree_repo_remote_gpg_import;
ostree_repo_remote_list;
ostree_repo_remote_list_refs;
ostree_repo_resolve_rev;
ostree_repo_scan_hardlinks;
ostree_repo_set_disable_fsync;
ostree_repo_set_ref_immediate;
ostree_repo_sign_commit;
ostree_repo_sign_delta;
ostree_repo_static_delta_execute_offline;
ostree_repo_static_delta_generate;
ostree_repo_transaction_set_ref;
ostree_repo_transaction_set_refspec;
ostree_repo_transaction_stats_get_type;
ostree_repo_traverse_commit;
ostree_repo_traverse_commit_union;
ostree_repo_traverse_new_reachable;
ostree_repo_verify_commit;
ostree_repo_verify_commit_ext;
ostree_repo_verify_summary;
ostree_repo_write_archive_to_mtree;
ostree_repo_write_commit;
ostree_repo_write_commit_detached_metadata;
ostree_repo_write_commit_with_time;
ostree_repo_write_config;
ostree_repo_write_content;
ostree_repo_write_content_async;
ostree_repo_write_content_finish;
ostree_repo_write_content_trusted;
ostree_repo_write_dfd_to_mtree;
ostree_repo_write_directory_to_mtree;
ostree_repo_write_metadata;
ostree_repo_write_metadata_async;
ostree_repo_write_metadata_finish;
ostree_repo_write_metadata_stream_trusted;
ostree_repo_write_metadata_trusted;
ostree_repo_write_mtree;
ostree_sepolicy_fscreatecon_cleanup;
ostree_sepolicy_get_label;
ostree_sepolicy_get_name;
ostree_sepolicy_get_path;
ostree_sepolicy_get_type;
ostree_sepolicy_new;
ostree_sepolicy_restorecon;
ostree_sepolicy_setfscreatecon;
ostree_sysroot_cleanup;
ostree_sysroot_deployment_set_kargs;
ostree_sysroot_deployment_set_mutable;
ostree_sysroot_deploy_tree;
ostree_sysroot_ensure_initialized;
ostree_sysroot_get_booted_deployment;
ostree_sysroot_get_bootversion;
ostree_sysroot_get_deployment_directory;
ostree_sysroot_get_deployment_dirpath;
ostree_sysroot_get_deployment_origin_path;
ostree_sysroot_get_deployments;
ostree_sysroot_get_fd;
ostree_sysroot_get_merge_deployment;
ostree_sysroot_get_path;
ostree_sysroot_get_repo;
ostree_sysroot_get_subbootversion;
ostree_sysroot_get_type;
ostree_sysroot_load;
ostree_sysroot_lock;
ostree_sysroot_lock_async;
ostree_sysroot_lock_finish;
ostree_sysroot_new;
ostree_sysroot_new_default;
ostree_sysroot_origin_new_from_refspec;
ostree_sysroot_prepare_cleanup;
ostree_sysroot_simple_write_deployment;
ostree_sysroot_try_lock;
ostree_sysroot_unload;
ostree_sysroot_unlock;
ostree_sysroot_upgrader_check_timestamps;
ostree_sysroot_upgrader_deploy;
ostree_sysroot_upgrader_dup_origin;
ostree_sysroot_upgrader_flags_get_type;
ostree_sysroot_upgrader_get_origin;
ostree_sysroot_upgrader_get_origin_description;
ostree_sysroot_upgrader_get_type;
ostree_sysroot_upgrader_new;
ostree_sysroot_upgrader_new_for_os;
ostree_sysroot_upgrader_new_for_os_with_flags;
ostree_sysroot_upgrader_pull;
ostree_sysroot_upgrader_pull_one_dir;
ostree_sysroot_upgrader_set_origin;
ostree_sysroot_write_deployments;
ostree_sysroot_write_origin_file;
ostree_validate_checksum_string;
ostree_validate_rev;
ostree_validate_structureof_checksum_string;
ostree_validate_structureof_commit;
ostree_validate_structureof_csum_v;
ostree_validate_structureof_dirmeta;
ostree_validate_structureof_dirtree;
ostree_validate_structureof_file_mode;
ostree_validate_structureof_objtype;
local:
*;
};
LIBOSTREE_2016.4 {
global:
ostree_repo_get_dfd;
ostree_repo_list_refs_ext;
ostree_sysroot_init_osname;
ostree_sysroot_load_if_changed;
ostree_sysroot_deployment_unlock;
ostree_deployment_get_unlocked;
ostree_deployment_unlocked_state_to_string;
} LIBOSTREE_2016.3;
/* NOTE NOTE NOTE
* Versions above here are released. Only add symbols below this line.
* NOTE NOTE NOTE
*/
/* UNCOMMENT WITH NEW SYMBOLS HERE:
LIBOSTREE_2016.5 {
global:
} LIBOSTREE_2016.4;
*/

View File

@ -41,29 +41,39 @@ struct OstreeAsyncProgressClass
void (*changed) (OstreeAsyncProgress *self, gpointer user_data);
};
_OSTREE_PUBLIC
GType ostree_async_progress_get_type (void) G_GNUC_CONST;
_OSTREE_PUBLIC
OstreeAsyncProgress *ostree_async_progress_new (void);
_OSTREE_PUBLIC
OstreeAsyncProgress *ostree_async_progress_new_and_connect (void (*changed) (OstreeAsyncProgress *self, gpointer user_data), gpointer user_data);
_OSTREE_PUBLIC
char *ostree_async_progress_get_status (OstreeAsyncProgress *self);
_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
void ostree_async_progress_set_status (OstreeAsyncProgress *self,
const char *status);
_OSTREE_PUBLIC
void ostree_async_progress_set_uint (OstreeAsyncProgress *self,
const char *key,
guint value);
_OSTREE_PUBLIC
void ostree_async_progress_set_uint64 (OstreeAsyncProgress *self,
const char *key,
guint64 value);
_OSTREE_PUBLIC
void ostree_async_progress_finish (OstreeAsyncProgress *self);
G_END_DECLS

View File

@ -30,38 +30,47 @@ G_BEGIN_DECLS
typedef struct _OstreeBootconfigParser OstreeBootconfigParser;
_OSTREE_PUBLIC
GType ostree_bootconfig_parser_get_type (void) G_GNUC_CONST;
_OSTREE_PUBLIC
OstreeBootconfigParser * ostree_bootconfig_parser_new (void);
_OSTREE_PUBLIC
OstreeBootconfigParser * ostree_bootconfig_parser_clone (OstreeBootconfigParser *self);
_OSTREE_PUBLIC
gboolean ostree_bootconfig_parser_parse (OstreeBootconfigParser *self,
GFile *path,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_bootconfig_parser_parse_at (OstreeBootconfigParser *self,
int dfd,
const char *path,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_bootconfig_parser_write (OstreeBootconfigParser *self,
GFile *output,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_bootconfig_parser_write_at (OstreeBootconfigParser *self,
int dfd,
const char *path,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_bootconfig_parser_set (OstreeBootconfigParser *self,
const char *key,
const char *value);
_OSTREE_PUBLIC
const char *ostree_bootconfig_parser_get (OstreeBootconfigParser *self,
const char *key);

View File

@ -293,9 +293,9 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
g_autoptr(GFile) efi_new_config_temp = NULL;
g_autoptr(GFile) efi_orig_config = NULL;
g_autoptr(GFile) new_config_path = NULL;
glnx_unref_object GSSubprocessContext *procctx = NULL;
glnx_unref_object GSSubprocess *proc = NULL;
g_auto(GStrv) child_env = g_get_environ ();
GSubprocessFlags subp_flags = 0;
glnx_unref_object GSubprocessLauncher *launcher = NULL;
glnx_unref_object GSubprocess *proc = NULL;
g_autofree char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion);
g_autoptr(GFile) config_path_efi_dir = NULL;
g_autofree char *grub2_mkconfig_chroot = NULL;
@ -337,41 +337,35 @@ _ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader,
bootversion);
}
procctx = gs_subprocess_context_newv ("grub2-mkconfig", "-o",
gs_file_get_path_cached (new_config_path),
NULL);
child_env = g_environ_setenv (child_env, "_OSTREE_GRUB2_BOOTVERSION", bootversion_str, TRUE);
if (!g_getenv ("OSTREE_DEBUG_GRUB2"))
subp_flags |= (G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_SILENCE);
launcher = g_subprocess_launcher_new (subp_flags);
g_subprocess_launcher_setenv (launcher, "_OSTREE_GRUB2_BOOTVERSION", bootversion_str, TRUE);
/* We have to pass our state to the child */
if (self->is_efi)
child_env = g_environ_setenv (child_env, "_OSTREE_GRUB2_IS_EFI", "1", TRUE);
gs_subprocess_context_set_environment (procctx, child_env);
gs_subprocess_context_set_stdout_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
if (g_getenv ("OSTREE_DEBUG_GRUB2"))
gs_subprocess_context_set_stderr_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT);
else
gs_subprocess_context_set_stderr_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
g_subprocess_launcher_setenv (launcher, "_OSTREE_GRUB2_IS_EFI", "1", TRUE);
/* We need to chroot() if we're not in /. This assumes our caller has
* set up the bind mounts outside.
*/
if (grub2_mkconfig_chroot != NULL)
{
gs_subprocess_context_set_child_setup (procctx, grub2_child_setup, grub2_mkconfig_chroot);
}
g_subprocess_launcher_set_child_setup (launcher, grub2_child_setup, grub2_mkconfig_chroot, NULL);
/* In the current Fedora grub2 package, this script doesn't even try
to be atomic; it just does:
cat ${grub_cfg}.new > ${grub_cfg}
rm -f ${grub_cfg}.new
cat ${grub_cfg}.new > ${grub_cfg}
rm -f ${grub_cfg}.new
Upstream is fixed though.
*/
proc = gs_subprocess_new (procctx, cancellable, error);
if (!proc)
goto out;
proc = g_subprocess_launcher_spawn (launcher, error,
"grub2-mkconfig", "-o",
gs_file_get_path_cached (new_config_path),
NULL);
if (!gs_subprocess_wait_sync_check (proc, cancellable, error))
if (!g_subprocess_wait_check (proc, cancellable, error))
goto out;
/* Now let's fdatasync() for the new file */

View File

@ -59,8 +59,10 @@ struct _OstreeChainInputStreamClass
void (*_g_reserved5) (void);
};
_OSTREE_PUBLIC
GType ostree_chain_input_stream_get_type (void) G_GNUC_CONST;
_OSTREE_PUBLIC
OstreeChainInputStream * ostree_chain_input_stream_new (GPtrArray *streams);
G_END_DECLS

View File

@ -57,8 +57,10 @@ struct _OstreeChecksumInputStreamClass
void (*_g_reserved5) (void);
};
_OSTREE_PUBLIC
GType ostree_checksum_input_stream_get_type (void) G_GNUC_CONST;
_OSTREE_PUBLIC
OstreeChecksumInputStream * ostree_checksum_input_stream_new (GInputStream *stream,
GChecksum *checksum);

View File

@ -29,7 +29,8 @@ typedef struct {
gboolean (* ostree_static_delta_dump) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error);
} OstreeCmdPrivateVTable;
const OstreeCmdPrivateVTable *
/* Note this not really "public", we just export the symbol, but not the header */
_OSTREE_PUBLIC const OstreeCmdPrivateVTable *
ostree_cmd__private__ (void);
G_END_DECLS

View File

@ -155,7 +155,8 @@ ostree_parse_refspec (const char *refspec,
ret = TRUE;
gs_transfer_out_value (out_remote, &remote);
if (out_remote)
*out_remote = g_steal_pointer (&remote);
if (out_ref != NULL)
*out_ref = g_match_info_fetch (match, 2);
out:
@ -766,7 +767,8 @@ ostree_checksum_file (GFile *f,
if (objtype == OSTREE_OBJECT_TYPE_FILE)
{
if (!gs_file_get_all_xattrs (f, &xattrs, cancellable, error))
if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f),
&xattrs, cancellable, error))
goto out;
}
@ -950,7 +952,8 @@ _ostree_make_temporary_symlink_at (int tmp_dirfd,
}
ret = TRUE;
gs_transfer_out_value (out_name, &tmpname);
if (out_name)
*out_name = g_steal_pointer (&tmpname);
out:
return ret;
}

View File

@ -23,6 +23,7 @@
#pragma once
#include <gio/gio.h>
#include <ostree-types.h>
G_BEGIN_DECLS
@ -164,63 +165,86 @@ typedef enum {
OSTREE_REPO_MODE_BARE_USER
} OstreeRepoMode;
const GVariantType *ostree_metadata_variant_type (OstreeObjectType objtype);
const _OSTREE_PUBLIC
GVariantType *ostree_metadata_variant_type (OstreeObjectType objtype);
_OSTREE_PUBLIC
gboolean ostree_validate_checksum_string (const char *sha256,
GError **error);
_OSTREE_PUBLIC
guchar *ostree_checksum_to_bytes (const char *checksum);
_OSTREE_PUBLIC
GVariant *ostree_checksum_to_bytes_v (const char *checksum);
_OSTREE_PUBLIC
void ostree_checksum_b64_inplace_to_bytes (const char *checksum,
guint8 *buf);
_OSTREE_PUBLIC
char * ostree_checksum_from_bytes (const guchar *csum);
_OSTREE_PUBLIC
char * ostree_checksum_from_bytes_v (GVariant *csum_v);
_OSTREE_PUBLIC
void ostree_checksum_inplace_from_bytes (const guchar *csum,
char *buf);
_OSTREE_PUBLIC
void ostree_checksum_b64_inplace_from_bytes (const guchar *csum,
char *buf);
_OSTREE_PUBLIC
void ostree_checksum_inplace_to_bytes (const char *checksum,
guchar *buf);
_OSTREE_PUBLIC
const guchar *ostree_checksum_bytes_peek (GVariant *bytes);
_OSTREE_PUBLIC
const guchar *ostree_checksum_bytes_peek_validate (GVariant *bytes, GError **error);
_OSTREE_PUBLIC
int ostree_cmp_checksum_bytes (const guchar *a, const guchar *b);
_OSTREE_PUBLIC
gboolean ostree_validate_rev (const char *rev, GError **error);
_OSTREE_PUBLIC
gboolean ostree_parse_refspec (const char *refspec,
char **out_remote,
char **out_ref,
GError **error);
_OSTREE_PUBLIC
void ostree_checksum_update_meta (GChecksum *checksum, GFileInfo *file_info, GVariant *xattrs);
_OSTREE_PUBLIC
const char * ostree_object_type_to_string (OstreeObjectType objtype);
_OSTREE_PUBLIC
OstreeObjectType ostree_object_type_from_string (const char *str);
_OSTREE_PUBLIC
guint ostree_hash_object_name (gconstpointer a);
_OSTREE_PUBLIC
GVariant *ostree_object_name_serialize (const char *checksum,
OstreeObjectType objtype);
_OSTREE_PUBLIC
void ostree_object_name_deserialize (GVariant *variant,
const char **out_checksum,
OstreeObjectType *out_objtype);
_OSTREE_PUBLIC
char * ostree_object_to_string (const char *checksum,
OstreeObjectType objtype);
_OSTREE_PUBLIC
void ostree_object_from_string (const char *str,
gchar **out_checksum,
OstreeObjectType *out_objtype);
gboolean
_OSTREE_PUBLIC gboolean
ostree_content_stream_parse (gboolean compressed,
GInputStream *input,
guint64 input_length,
@ -231,6 +255,7 @@ ostree_content_stream_parse (gboolean compressed,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_content_file_parse (gboolean compressed,
GFile *content_path,
gboolean trusted,
@ -240,6 +265,7 @@ gboolean ostree_content_file_parse (gboolean compressed,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_content_file_parse_at (gboolean compressed,
int parent_dfd,
const char *path,
@ -250,6 +276,7 @@ gboolean ostree_content_file_parse_at (gboolean compressed,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_raw_file_to_content_stream (GInputStream *input,
GFileInfo *file_info,
GVariant *xattrs,
@ -258,6 +285,7 @@ gboolean ostree_raw_file_to_content_stream (GInputStream *input,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_checksum_file_from_input (GFileInfo *file_info,
GVariant *xattrs,
GInputStream *in,
@ -266,12 +294,14 @@ gboolean ostree_checksum_file_from_input (GFileInfo *file_info,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_checksum_file (GFile *f,
OstreeObjectType objtype,
guchar **out_csum,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_checksum_file_async (GFile *f,
OstreeObjectType objtype,
int io_priority,
@ -279,38 +309,49 @@ void ostree_checksum_file_async (GFile *f,
GAsyncReadyCallback callback,
gpointer user_data);
_OSTREE_PUBLIC
gboolean ostree_checksum_file_async_finish (GFile *f,
GAsyncResult *result,
guchar **out_csum,
GError **error);
_OSTREE_PUBLIC
GVariant *ostree_create_directory_metadata (GFileInfo *dir_info,
GVariant *xattrs);
/* VALIDATION */
_OSTREE_PUBLIC
gboolean ostree_validate_structureof_objtype (guchar objtype,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_validate_structureof_csum_v (GVariant *checksum,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_validate_structureof_checksum_string (const char *checksum,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_validate_structureof_file_mode (guint32 mode,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_validate_structureof_commit (GVariant *commit,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_validate_structureof_dirtree (GVariant *dirtree,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_validate_structureof_dirmeta (GVariant *dirmeta,
GError **error);
_OSTREE_PUBLIC
gchar * ostree_commit_get_parent (GVariant *commit_variant);
_OSTREE_PUBLIC
guint64 ostree_commit_get_timestamp (GVariant *commit_variant);
G_END_DECLS

View File

@ -24,6 +24,21 @@
G_BEGIN_DECLS
struct _OstreeDeployment
{
GObject parent_instance;
int index; /* Global offset */
char *osname; /* osname */
char *csum; /* OSTree checksum of tree */
int deployserial; /* How many times this particular csum appears in deployment list */
char *bootcsum; /* Checksum of kernel+initramfs */
int bootserial; /* An integer assigned to this tree per its ${bootcsum} */
OstreeBootconfigParser *bootconfig; /* Bootloader configuration */
GKeyFile *origin; /* How to construct an upgraded version of this tree */
OstreeDeploymentUnlockedState unlocked; /* The unlocked state */
};
void _ostree_deployment_set_bootcsum (OstreeDeployment *self, const char *bootcsum);
G_END_DECLS

View File

@ -23,20 +23,6 @@
#include "ostree-deployment-private.h"
#include "libglnx.h"
struct _OstreeDeployment
{
GObject parent_instance;
int index; /* Global offset */
char *osname; /* osname */
char *csum; /* OSTree checksum of tree */
int deployserial; /* How many times this particular csum appears in deployment list */
char *bootcsum; /* Checksum of kernel+initramfs */
int bootserial; /* An integer assigned to this tree per its ${bootcsum} */
OstreeBootconfigParser *bootconfig; /* Bootloader configuration */
GKeyFile *origin; /* How to construct an upgraded version of this tree */
};
typedef GObjectClass OstreeDeploymentClass;
G_DEFINE_TYPE (OstreeDeployment, ostree_deployment, G_TYPE_OBJECT)
@ -258,6 +244,7 @@ ostree_deployment_new (int index,
self->deployserial = deployserial;
self->bootcsum = g_strdup (bootcsum);
self->bootserial = bootserial;
self->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_NONE;
return self;
}
@ -279,3 +266,24 @@ ostree_deployment_get_origin_relpath (OstreeDeployment *self)
ostree_deployment_get_csum (self),
ostree_deployment_get_deployserial (self));
}
const char *
ostree_deployment_unlocked_state_to_string (OstreeDeploymentUnlockedState state)
{
switch (state)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
return "none";
case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX:
return "hotfix";
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
return "development";
}
g_assert_not_reached ();
}
OstreeDeploymentUnlockedState
ostree_deployment_get_unlocked (OstreeDeployment *self)
{
return self->unlocked;
}

View File

@ -30,11 +30,15 @@ G_BEGIN_DECLS
typedef struct _OstreeDeployment OstreeDeployment;
_OSTREE_PUBLIC
GType ostree_deployment_get_type (void) G_GNUC_CONST;
_OSTREE_PUBLIC
guint ostree_deployment_hash (gconstpointer v);
_OSTREE_PUBLIC
gboolean ostree_deployment_equal (gconstpointer ap, gconstpointer bp);
_OSTREE_PUBLIC
OstreeDeployment * ostree_deployment_new (int index,
const char *osname,
const char *csum,
@ -42,22 +46,48 @@ OstreeDeployment * ostree_deployment_new (int index,
const char *bootcsum,
int bootserial);
_OSTREE_PUBLIC
int ostree_deployment_get_index (OstreeDeployment *self);
_OSTREE_PUBLIC
const char *ostree_deployment_get_osname (OstreeDeployment *self);
_OSTREE_PUBLIC
int ostree_deployment_get_deployserial (OstreeDeployment *self);
_OSTREE_PUBLIC
const char *ostree_deployment_get_csum (OstreeDeployment *self);
_OSTREE_PUBLIC
const char *ostree_deployment_get_bootcsum (OstreeDeployment *self);
_OSTREE_PUBLIC
int ostree_deployment_get_bootserial (OstreeDeployment *self);
_OSTREE_PUBLIC
OstreeBootconfigParser *ostree_deployment_get_bootconfig (OstreeDeployment *self);
_OSTREE_PUBLIC
GKeyFile *ostree_deployment_get_origin (OstreeDeployment *self);
_OSTREE_PUBLIC
void ostree_deployment_set_index (OstreeDeployment *self, int index);
_OSTREE_PUBLIC
void ostree_deployment_set_bootserial (OstreeDeployment *self, int index);
_OSTREE_PUBLIC
void ostree_deployment_set_bootconfig (OstreeDeployment *self, OstreeBootconfigParser *bootconfig);
_OSTREE_PUBLIC
void ostree_deployment_set_origin (OstreeDeployment *self, GKeyFile *origin);
_OSTREE_PUBLIC
OstreeDeployment *ostree_deployment_clone (OstreeDeployment *self);
_OSTREE_PUBLIC
char *ostree_deployment_get_origin_relpath (OstreeDeployment *self);
typedef enum {
OSTREE_DEPLOYMENT_UNLOCKED_NONE,
OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT,
OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX
} OstreeDeploymentUnlockedState;
_OSTREE_PUBLIC
const char *ostree_deployment_unlocked_state_to_string (OstreeDeploymentUnlockedState state);
_OSTREE_PUBLIC
OstreeDeploymentUnlockedState ostree_deployment_get_unlocked (OstreeDeployment *self);
G_END_DECLS

View File

@ -48,7 +48,8 @@ get_file_checksum (OstreeDiffFlags flags,
if (!(flags & OSTREE_DIFF_FLAGS_IGNORE_XATTRS))
{
if (!gs_file_get_all_xattrs (f, &xattrs, cancellable, error))
if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (f),
&xattrs, cancellable, error))
goto out;
}

View File

@ -47,11 +47,15 @@ struct _OstreeDiffItem
char *target_checksum;
};
_OSTREE_PUBLIC
OstreeDiffItem *ostree_diff_item_ref (OstreeDiffItem *diffitem);
_OSTREE_PUBLIC
void ostree_diff_item_unref (OstreeDiffItem *diffitem);
_OSTREE_PUBLIC
GType ostree_diff_item_get_type (void);
_OSTREE_PUBLIC
gboolean ostree_diff_dirs (OstreeDiffFlags flags,
GFile *a,
GFile *b,
@ -61,6 +65,7 @@ gboolean ostree_diff_dirs (OstreeDiffFlags flags,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_diff_print (GFile *a,
GFile *b,
GPtrArray *modified,

View File

@ -33,6 +33,7 @@ G_BEGIN_DECLS
/*** BEGIN enumeration-production ***/
#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ())
_OSTREE_PUBLIC
GType @enum_name@_get_type (void) G_GNUC_CONST;
/*** END enumeration-production ***/

View File

@ -406,7 +406,7 @@ session_thread_request_uri (ThreadClosure *thread_closure,
exists = FALSE;
else
{
gs_set_error_from_errno (&local_error, errno);
glnx_set_error_from_errno (&local_error);
g_task_return_error (task, local_error);
return;
}
@ -706,7 +706,7 @@ finish_stream (OstreeFetcherPendingURI *pending,
pending->out_tmpfile,
&stbuf, AT_SYMLINK_NOFOLLOW) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -922,7 +922,7 @@ on_request_sent (GObject *object,
pending->out_tmpfile, oflags, 0666);
if (fd == -1)
{
gs_set_error_from_errno (&local_error, errno);
glnx_set_error_from_errno (&local_error);
goto out;
}
pending->out_stream = g_unix_output_stream_new (fd, TRUE);

View File

@ -21,6 +21,7 @@
#pragma once
#include <gio/gio.h>
#include <ostree-types.h>
G_BEGIN_DECLS
@ -82,21 +83,27 @@ typedef enum {
OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL
} OstreeGpgSignatureAttr;
_OSTREE_PUBLIC
GType ostree_gpg_verify_result_get_type (void);
_OSTREE_PUBLIC
guint ostree_gpg_verify_result_count_all (OstreeGpgVerifyResult *result);
_OSTREE_PUBLIC
guint ostree_gpg_verify_result_count_valid (OstreeGpgVerifyResult *result);
_OSTREE_PUBLIC
gboolean ostree_gpg_verify_result_lookup (OstreeGpgVerifyResult *result,
const gchar *key_id,
guint *out_signature_index);
_OSTREE_PUBLIC
GVariant * ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result,
guint signature_index,
OstreeGpgSignatureAttr *attrs,
guint n_attrs);
_OSTREE_PUBLIC
GVariant * ostree_gpg_verify_result_get_all (OstreeGpgVerifyResult *result,
guint signature_index);
@ -113,12 +120,14 @@ typedef enum {
OSTREE_GPG_SIGNATURE_FORMAT_DEFAULT = 0
} OstreeGpgSignatureFormatFlags;
_OSTREE_PUBLIC
void ostree_gpg_verify_result_describe (OstreeGpgVerifyResult *result,
guint signature_index,
GString *output_buffer,
const gchar *line_prefix,
OstreeGpgSignatureFormatFlags flags);
_OSTREE_PUBLIC
void ostree_gpg_verify_result_describe_variant (GVariant *variant,
GString *output_buffer,
const gchar *line_prefix,

View File

@ -65,7 +65,7 @@ _ostree_kernel_args_new (void)
}
void
_ostree_kernel_args_free (OstreeKernelArgs *kargs)
_ostree_kernel_arg_autofree (OstreeKernelArgs *kargs)
{
if (!kargs)
return;
@ -77,7 +77,7 @@ _ostree_kernel_args_free (OstreeKernelArgs *kargs)
void
_ostree_kernel_args_cleanup (void *loc)
{
_ostree_kernel_args_free (*((OstreeKernelArgs**)loc));
_ostree_kernel_arg_autofree (*((OstreeKernelArgs**)loc));
}
void

View File

@ -45,50 +45,62 @@ struct OstreeMutableTreeClass
GObjectClass parent_class;
};
_OSTREE_PUBLIC
GType ostree_mutable_tree_get_type (void) G_GNUC_CONST;
_OSTREE_PUBLIC
OstreeMutableTree *ostree_mutable_tree_new (void);
_OSTREE_PUBLIC
void ostree_mutable_tree_set_metadata_checksum (OstreeMutableTree *self,
const char *checksum);
_OSTREE_PUBLIC
const char *ostree_mutable_tree_get_metadata_checksum (OstreeMutableTree *self);
_OSTREE_PUBLIC
void ostree_mutable_tree_set_contents_checksum (OstreeMutableTree *self,
const char *checksum);
_OSTREE_PUBLIC
const char *ostree_mutable_tree_get_contents_checksum (OstreeMutableTree *self);
_OSTREE_PUBLIC
gboolean ostree_mutable_tree_replace_file (OstreeMutableTree *self,
const char *name,
const char *checksum,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_mutable_tree_ensure_dir (OstreeMutableTree *self,
const char *name,
OstreeMutableTree **out_subdir,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_mutable_tree_lookup (OstreeMutableTree *self,
const char *name,
char **out_file_checksum,
OstreeMutableTree **out_subdir,
GError **error);
gboolean
_OSTREE_PUBLIC gboolean
ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree *self,
GPtrArray *split_path,
const char *metadata_checksum,
OstreeMutableTree **out_parent,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_mutable_tree_walk (OstreeMutableTree *self,
GPtrArray *split_path,
guint start,
OstreeMutableTree **out_subdir,
GError **error);
_OSTREE_PUBLIC
GHashTable * ostree_mutable_tree_get_subdirs (OstreeMutableTree *self);
_OSTREE_PUBLIC
GHashTable * ostree_mutable_tree_get_files (OstreeMutableTree *self);
G_END_DECLS

View File

@ -73,7 +73,7 @@ checkout_object_for_uncompressed_cache (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -91,7 +91,7 @@ checkout_object_for_uncompressed_cache (OstreeRepo *self,
{
if (errno != EEXIST)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
g_prefix_error (error, "Storing file '%s': ", temp_filename);
goto out;
}
@ -144,7 +144,7 @@ write_regular_file_content (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -153,13 +153,13 @@ write_regular_file_content (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
if (xattrs)
{
if (!gs_fd_set_all_xattrs (fd, xattrs, cancellable, error))
if (!glnx_fd_set_all_xattrs (fd, xattrs, cancellable, error))
goto out;
}
}
@ -168,7 +168,7 @@ write_regular_file_content (OstreeRepo *self,
{
if (fsync (fd) == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -203,7 +203,7 @@ checkout_file_from_input_at (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -214,13 +214,13 @@ checkout_file_from_input_at (OstreeRepo *self,
g_file_info_get_attribute_uint32 (file_info, "unix::gid"),
AT_SYMLINK_NOFOLLOW) == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
if (xattrs)
{
if (!gs_dfd_and_name_set_all_xattrs (destination_dfd, destination_name,
if (!glnx_dfd_name_set_all_xattrs (destination_dfd, destination_name,
xattrs, cancellable, error))
goto out;
}
@ -242,7 +242,7 @@ checkout_file_from_input_at (OstreeRepo *self,
while (G_UNLIKELY (fd == -1 && errno == EINTR));
if (fd == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
temp_out = g_unix_output_stream_new (fd, TRUE);
@ -288,7 +288,7 @@ checkout_file_unioning_from_input_at (OstreeRepo *repo,
if (xattrs)
{
if (!gs_dfd_and_name_set_all_xattrs (destination_dfd, temp_filename,
if (!glnx_dfd_name_set_all_xattrs (destination_dfd, temp_filename,
xattrs, cancellable, error))
goto out;
}
@ -318,7 +318,7 @@ checkout_file_unioning_from_input_at (OstreeRepo *repo,
if (G_UNLIKELY (renameat (destination_dfd, temp_filename,
destination_dfd, destination_name) == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -373,7 +373,7 @@ checkout_file_hardlink (OstreeRepo *self,
else
{
g_prefix_error (error, "Hardlinking %s to %s: ", loose_path, destination_name);
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -650,14 +650,13 @@ checkout_tree_at (OstreeRepo *self,
did_exist = TRUE;
else
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
if (!gs_file_open_dir_fd_at (destination_parent_fd, destination_name,
&destination_dfd,
cancellable, error))
if (!glnx_opendirat (destination_parent_fd, destination_name, TRUE,
&destination_dfd, error))
goto out;
/* Set the xattrs now, so any derived labeling works */
@ -668,7 +667,7 @@ checkout_tree_at (OstreeRepo *self,
if (xattrs)
{
if (!gs_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error))
if (!glnx_fd_set_all_xattrs (destination_dfd, xattrs, cancellable, error))
goto out;
}
}
@ -734,7 +733,7 @@ checkout_tree_at (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -748,7 +747,7 @@ checkout_tree_at (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -764,7 +763,7 @@ checkout_tree_at (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -773,7 +772,7 @@ checkout_tree_at (OstreeRepo *self,
{
if (fsync (destination_dfd) == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}

View File

@ -65,10 +65,9 @@ _ostree_repo_ensure_loose_objdir_at (int dfd,
loose_prefix[2] = '\0';
if (mkdirat (dfd, loose_prefix, 0777) == -1)
{
int errsv = errno;
if (G_UNLIKELY (errsv != EEXIST))
if (G_UNLIKELY (errno != EEXIST))
{
gs_set_error_from_errno (error, errsv);
glnx_set_error_from_errno (error);
return FALSE;
}
}
@ -118,7 +117,7 @@ write_file_metadata_to_xattr (int fd,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
g_prefix_error (error, "Unable to set xattr: ");
return FALSE;
}
@ -155,7 +154,7 @@ _ostree_repo_commit_loose_final (OstreeRepo *self,
{
if (errno != EEXIST)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
g_prefix_error (error, "Storing file '%s': ", temp_filename);
goto out;
}
@ -195,7 +194,7 @@ commit_loose_object_trusted (OstreeRepo *self,
self->target_owner_gid,
AT_SYMLINK_NOFOLLOW) == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -213,13 +212,13 @@ commit_loose_object_trusted (OstreeRepo *self,
uid, gid,
AT_SYMLINK_NOFOLLOW) == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
if (xattrs != NULL)
{
if (!gs_dfd_and_name_set_all_xattrs (self->tmp_dir_fd, temp_filename,
if (!glnx_dfd_name_set_all_xattrs (self->tmp_dir_fd, temp_filename,
xattrs, cancellable, error))
goto out;
}
@ -236,7 +235,7 @@ commit_loose_object_trusted (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -245,13 +244,13 @@ commit_loose_object_trusted (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
if (xattrs)
{
if (!gs_fd_set_all_xattrs (fd, xattrs, cancellable, error))
if (!glnx_fd_set_all_xattrs (fd, xattrs, cancellable, error))
goto out;
}
}
@ -272,7 +271,7 @@ commit_loose_object_trusted (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -294,7 +293,7 @@ commit_loose_object_trusted (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -306,7 +305,7 @@ commit_loose_object_trusted (OstreeRepo *self,
{
if (fsync (fd) == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -453,7 +452,9 @@ fallocate_stream (GFileDescriptorBased *stream,
int r = posix_fallocate (fd, 0, size);
if (r != 0)
{
gs_set_error_from_errno (error, r);
/* posix_fallocate is a weird deviation from errno standards */
errno = r;
glnx_set_error_from_errno (error);
goto out;
}
}
@ -511,7 +512,7 @@ _ostree_repo_commit_untrusted_content_bare (OstreeRepo *self,
fd = openat (self->tmp_dir_fd, state->temp_filename, O_RDONLY);
if (fd == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -597,7 +598,8 @@ _ostree_repo_open_trusted_content_bare (OstreeRepo *self,
out_state->temp_filename = temp_filename;
temp_filename = NULL;
out_state->fd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*)ret_stream);
gs_transfer_out_value (out_stream, &ret_stream);
if (out_stream)
*out_stream = g_steal_pointer (&ret_stream);
}
*out_have_object = have_obj;
out:
@ -843,7 +845,7 @@ write_object (OstreeRepo *self,
if (fstatat (self->tmp_dir_fd, temp_filename, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -1224,7 +1226,7 @@ rename_pending_loose_objects (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -1264,14 +1266,14 @@ rename_pending_loose_objects (OstreeRepo *self,
if (G_UNLIKELY (renameat (child_dfd_iter.fd, loose_objpath + 3,
self->objects_dir_fd, loose_objpath) < 0))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
}
if (!gs_shutil_rm_rf_at (self->tmp_dir_fd, self->commit_stagedir_name,
cancellable, error))
if (!glnx_shutil_rm_rf_at (self->tmp_dir_fd, self->commit_stagedir_name,
cancellable, error))
goto out;
ret = TRUE;
@ -1321,7 +1323,7 @@ cleanup_tmpdir (OstreeRepo *self,
delta = curtime_secs - mtime;
if (delta > 60*60*24)
{
if (!gs_shutil_rm_rf (path, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (path), cancellable, error))
goto out;
}
}
@ -1448,7 +1450,7 @@ ostree_repo_commit_transaction (OstreeRepo *self,
if (syncfs (self->tmp_dir_fd) < 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -2322,20 +2324,21 @@ get_modified_xattrs (OstreeRepo *self,
{
if (path)
{
if (!gs_file_get_all_xattrs (path, &ret_xattrs, cancellable, error))
if (!glnx_dfd_name_get_all_xattrs (AT_FDCWD, gs_file_get_path_cached (path),
&ret_xattrs, cancellable, error))
goto out;
}
else if (dfd_subpath == NULL)
{
g_assert (dfd != -1);
if (!gs_fd_get_all_xattrs (dfd, &ret_xattrs,
if (!glnx_fd_get_all_xattrs (dfd, &ret_xattrs,
cancellable, error))
goto out;
}
else
{
g_assert (dfd != -1);
if (!gs_dfd_and_name_get_all_xattrs (dfd, dfd_subpath, &ret_xattrs,
if (!glnx_dfd_name_get_all_xattrs (dfd, dfd_subpath, &ret_xattrs,
cancellable, error))
goto out;
}
@ -2371,7 +2374,8 @@ get_modified_xattrs (OstreeRepo *self,
}
ret = TRUE;
gs_transfer_out_value (out_xattrs, &ret_xattrs);
if (out_xattrs)
*out_xattrs = g_steal_pointer (&ret_xattrs);
out:
return ret;
}
@ -2686,7 +2690,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
if (fstat (src_dfd_iter->fd, &dir_stbuf) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -2742,7 +2746,7 @@ write_dfd_iter_to_mtree_internal (OstreeRepo *self,
if (fstatat (src_dfd_iter->fd, dent->d_name, &stbuf, AT_SYMLINK_NOFOLLOW) == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -2966,7 +2970,8 @@ ostree_repo_write_mtree (OstreeRepo *self,
}
ret = TRUE;
ot_transfer_out_value (out_file, &ret_file);
if (out_file)
*out_file = g_steal_pointer (&ret_file);
out:
return ret;
}

View File

@ -40,38 +40,52 @@ struct _OstreeRepoFileClass
GObjectClass parent_class;
};
_OSTREE_PUBLIC
GType ostree_repo_file_get_type (void) G_GNUC_CONST;
_OSTREE_PUBLIC
gboolean ostree_repo_file_ensure_resolved (OstreeRepoFile *self,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_file_get_xattrs (OstreeRepoFile *self,
GVariant **out_xattrs,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeRepo * ostree_repo_file_get_repo (OstreeRepoFile *self);
_OSTREE_PUBLIC
OstreeRepoFile * ostree_repo_file_get_root (OstreeRepoFile *self);
_OSTREE_PUBLIC
void ostree_repo_file_make_empty_tree (OstreeRepoFile *self);
_OSTREE_PUBLIC
void ostree_repo_file_tree_set_metadata (OstreeRepoFile *self,
const char *checksum,
GVariant *metadata);
_OSTREE_PUBLIC
const char *ostree_repo_file_tree_get_contents_checksum (OstreeRepoFile *self);
_OSTREE_PUBLIC
const char *ostree_repo_file_tree_get_metadata_checksum (OstreeRepoFile *self);
_OSTREE_PUBLIC
GVariant *ostree_repo_file_tree_get_contents (OstreeRepoFile *self);
_OSTREE_PUBLIC
GVariant *ostree_repo_file_tree_get_metadata (OstreeRepoFile *self);
_OSTREE_PUBLIC
const char * ostree_repo_file_get_checksum (OstreeRepoFile *self);
_OSTREE_PUBLIC
int ostree_repo_file_tree_find_child (OstreeRepoFile *self,
const char *name,
gboolean *is_dir,
GVariant **out_container);
_OSTREE_PUBLIC
gboolean ostree_repo_file_tree_query_child (OstreeRepoFile *self,
int n,
const char *attributes,

View File

@ -290,7 +290,6 @@ write_libarchive_entry_to_mtree (OstreeRepo *self,
out:
return ret;
}
#endif
static gboolean
create_empty_dir_with_uidgid (OstreeRepo *self,
@ -308,6 +307,7 @@ create_empty_dir_with_uidgid (OstreeRepo *self,
return _ostree_repo_write_directory_meta (self, tmp_dir_info, NULL, out_csum, cancellable, error);
}
#endif
/**
* ostree_repo_import_archive_to_mtree:
@ -331,6 +331,7 @@ ostree_repo_import_archive_to_mtree (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
#ifdef HAVE_LIBARCHIVE
gboolean ret = FALSE;
struct archive *a = archive;
struct archive_entry *entry;
@ -393,6 +394,11 @@ ostree_repo_import_archive_to_mtree (OstreeRepo *self,
ret = TRUE;
out:
return ret;
#else
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
"This version of ostree is not compiled with libarchive support");
return FALSE;
#endif
}
/**

View File

@ -33,6 +33,8 @@ G_BEGIN_DECLS
#define _OSTREE_OBJECT_SIZES_ENTRY_SIGNATURE "ay"
#define _OSTREE_SUMMARY_CACHE_PATH "tmp/cache/summaries"
/**
* OstreeRepo:
*
@ -316,5 +318,23 @@ _ostree_repo_read_bare_fd (OstreeRepo *self,
gboolean
_ostree_repo_update_mtime (OstreeRepo *self,
GError **error);
/* Load the summary from the cache if the provided .sig file is the same as the
cached version. */
gboolean
_ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
const char *remote,
GBytes *summary_sig,
GBytes **summary,
GCancellable *cancellable,
GError **error);
gboolean
_ostree_repo_cache_summary (OstreeRepo *self,
const char *remote,
GBytes *summary,
GBytes *summary_sig,
GCancellable *cancellable,
GError **error);
G_END_DECLS

View File

@ -112,6 +112,68 @@ maybe_prune_loose_object (OtPruneData *data,
return ret;
}
static gboolean
_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;
fd = glnx_opendirat_with_errno (self->repo_dir_fd, _OSTREE_SUMMARY_CACHE_PATH, 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;
while (TRUE)
{
size_t len;
gboolean has_sig_suffix = FALSE;
struct dirent *dent;
if (!glnx_dirfd_iterator_next_dent (&dfd_iter, &dent, cancellable, error))
goto out;
if (dent == NULL)
break;
len = strlen (dent->d_name);
if (len > 4 && g_strcmp0 (dent->d_name + len - 4, ".sig") == 0)
{
has_sig_suffix = TRUE;
dent->d_name[len - 4] = '\0';
}
if (!g_hash_table_contains (self->remotes, dent->d_name))
{
/* Restore the previous value to get the file name. */
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;
}
}
}
ret = TRUE;
out:
return ret;
}
/**
* ostree_repo_prune_static_deltas:
* @self: Repo
@ -174,7 +236,7 @@ ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
deltadir = _ostree_get_relative_static_delta_path (from, to, NULL);
if (!gs_shutil_rm_rf_at (self->repo_dir_fd, deltadir,
if (!glnx_shutil_rm_rf_at (self->repo_dir_fd, deltadir,
cancellable, error))
goto out;
}
@ -241,10 +303,28 @@ ostree_repo_prune (OstreeRepo *self,
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *checksum = value;
if (!ostree_repo_traverse_commit_union (self, checksum, depth, data.reachable,
cancellable, error))
OstreeRepoCommitState commitstate;
GError *local_error = NULL;
if (!ostree_repo_load_commit (self, checksum, NULL, &commitstate,
error))
goto out;
if (!ostree_repo_traverse_commit_union (self, checksum, depth, data.reachable,
cancellable, &local_error))
{
/* Don't fail traversing a partial commit */
if ((commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) > 0 &&
g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&local_error);
}
else
{
g_propagate_error (error, local_error);
goto out;
}
}
}
}
@ -260,15 +340,33 @@ ostree_repo_prune (OstreeRepo *self,
GVariant *serialized_key = key;
const char *checksum;
OstreeObjectType objtype;
OstreeRepoCommitState commitstate;
GError *local_error = NULL;
ostree_object_name_deserialize (serialized_key, &checksum, &objtype);
if (objtype != OSTREE_OBJECT_TYPE_COMMIT)
continue;
if (!ostree_repo_traverse_commit_union (self, checksum, depth, data.reachable,
cancellable, error))
if (!ostree_repo_load_commit (self, checksum, NULL, &commitstate,
error))
goto out;
if (!ostree_repo_traverse_commit_union (self, checksum, depth, data.reachable,
cancellable, &local_error))
{
/* Don't fail traversing a partial commit */
if ((commitstate & OSTREE_REPO_COMMIT_STATE_PARTIAL) > 0 &&
g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&local_error);
}
else
{
g_propagate_error (error, local_error);
goto out;
}
}
}
}
@ -295,6 +393,9 @@ ostree_repo_prune (OstreeRepo *self,
if (!ostree_repo_prune_static_deltas (self, NULL, cancellable, error))
goto out;
if (!_ostree_repo_prune_tmp (self, cancellable, error))
goto out;
ret = TRUE;
*out_objects_total = (data.n_reachable_meta + data.n_unreachable_meta +
data.n_reachable_content + data.n_unreachable_content);

View File

@ -28,6 +28,7 @@
#include "ostree-repo-static-delta-private.h"
#include "ostree-metalink.h"
#include "otutil.h"
#include "ot-fs-utils.h"
#include <gio/gunixinputstream.h>
@ -794,7 +795,7 @@ meta_fetch_on_complete (GObject *object,
OstreeObjectType objtype;
GError *local_error = NULL;
GError **error = &local_error;
gs_fd_close int fd = -1;
glnx_fd_close int fd = -1;
ostree_object_name_deserialize (fetch_data->object, &checksum, &objtype);
g_debug ("fetch of %s%s complete", ostree_object_to_string (checksum, objtype),
@ -840,7 +841,7 @@ meta_fetch_on_complete (GObject *object,
fd = openat (_ostree_fetcher_get_dfd (fetcher), temp_path, O_RDONLY | O_CLOEXEC);
if (fd == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -949,7 +950,7 @@ static_deltapart_fetch_on_complete (GObject *object,
g_autoptr(GVariant) part = NULL;
GError *local_error = NULL;
GError **error = &local_error;
gs_fd_close int fd = -1;
glnx_fd_close int fd = -1;
g_debug ("fetch static delta part %s complete", fetch_data->expected_checksum);
@ -1187,7 +1188,8 @@ scan_one_metadata_object_c (OtPullData *pull_data,
if (pull_data->remote_repo_local)
{
if (!ostree_repo_import_object_from (pull_data->repo, pull_data->remote_repo_local,
if (!is_stored &&
!ostree_repo_import_object_from (pull_data->repo, pull_data->remote_repo_local,
objtype, tmp_checksum,
cancellable, error))
goto out;
@ -1398,8 +1400,8 @@ request_static_delta_superblock_sync (OtPullData *pull_data,
if (delta_superblock_data)
{
{
gs_free gchar *delta = NULL;
gs_free guchar *ret_csum = NULL;
g_autofree gchar *delta = NULL;
g_autofree guchar *ret_csum = NULL;
guchar *summary_csum;
g_autoptr (GInputStream) summary_is = NULL;
@ -1436,7 +1438,8 @@ request_static_delta_superblock_sync (OtPullData *pull_data,
}
ret = TRUE;
gs_transfer_out_value (out_delta_superblock, &ret_delta_superblock);
if (out_delta_superblock)
*out_delta_superblock = g_steal_pointer (&ret_delta_superblock);
out:
return ret;
}
@ -1767,6 +1770,102 @@ ostree_repo_pull_one_dir (OstreeRepo *self,
progress, cancellable, error);
}
gboolean
_ostree_repo_load_cache_summary_if_same_sig (OstreeRepo *self,
const char *remote,
GBytes *summary_sig,
GBytes **summary,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_PATH, "/", remote, ".sig");
glnx_fd_close int prev_fd = -1;
g_autoptr(GBytes) old_sig_contents = NULL;
if (!ot_openat_ignore_enoent (self->repo_dir_fd, summary_cache_sig_file, &prev_fd, error))
goto out;
if (prev_fd < 0)
{
ret = TRUE;
goto out;
}
old_sig_contents = glnx_fd_readall_bytes (prev_fd, cancellable, error);
if (!old_sig_contents)
goto out;
if (g_bytes_compare (old_sig_contents, summary_sig) == 0)
{
const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_PATH, "/", remote);
glnx_fd_close int summary_fd = -1;
GBytes *summary_data;
summary_fd = openat (self->repo_dir_fd, summary_cache_file, O_CLOEXEC | O_RDONLY);
if (summary_fd < 0)
{
if (errno == ENOENT)
{
(void) unlinkat (self->repo_dir_fd, summary_cache_sig_file, 0);
ret = TRUE;
goto out;
}
glnx_set_error_from_errno (error);
goto out;
}
summary_data = glnx_fd_readall_bytes (summary_fd, cancellable, error);
if (!summary_data)
goto out;
*summary = summary_data;
}
ret = TRUE;
out:
return ret;
}
gboolean
_ostree_repo_cache_summary (OstreeRepo *self,
const char *remote,
GBytes *summary,
GBytes *summary_sig,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
const char *summary_cache_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_PATH, "/", remote);
const char *summary_cache_sig_file = glnx_strjoina (_OSTREE_SUMMARY_CACHE_PATH, "/", remote, ".sig");
if (!glnx_shutil_mkdir_p_at (self->repo_dir_fd, _OSTREE_SUMMARY_CACHE_PATH, 0775, cancellable, error))
goto out;
if (!glnx_file_replace_contents_at (self->repo_dir_fd,
summary_cache_file,
g_bytes_get_data (summary, NULL),
g_bytes_get_size (summary),
self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW,
cancellable, error))
goto out;
if (!glnx_file_replace_contents_at (self->repo_dir_fd,
summary_cache_sig_file,
g_bytes_get_data (summary_sig, NULL),
g_bytes_get_size (summary_sig),
self->disable_fsync ? GLNX_FILE_REPLACE_NODATASYNC : GLNX_FILE_REPLACE_DATASYNC_NEW,
cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
}
/* Documented in ostree-repo.c */
gboolean
ostree_repo_pull_with_options (OstreeRepo *self,
@ -1995,15 +2094,36 @@ ostree_repo_pull_with_options (OstreeRepo *self,
g_autoptr(GVariant) refs = NULL;
g_autoptr(GVariant) deltas = NULL;
g_autoptr(GVariant) additional_metadata = NULL;
if (!pull_data->summary)
gboolean summary_from_cache = FALSE;
if (!pull_data->summary_data_sig)
{
uri = suburi_new (pull_data->base_uri, "summary.sig", NULL);
if (!fetch_uri_contents_membuf_sync (pull_data, uri, FALSE, TRUE,
&bytes_sig, cancellable, error))
goto out;
soup_uri_free (uri);
}
if (bytes_sig && !_ostree_repo_load_cache_summary_if_same_sig (self,
remote_name_or_baseurl,
bytes_sig,
&bytes_summary,
cancellable,
error))
goto out;
if (bytes_summary)
summary_from_cache = TRUE;
if (!pull_data->summary && !bytes_summary)
{
uri = suburi_new (pull_data->base_uri, "summary", NULL);
if (!fetch_uri_contents_membuf_sync (pull_data, uri, FALSE, TRUE,
&bytes_summary, cancellable, error))
goto out;
soup_uri_free (uri);
}
}
if (!bytes_summary && pull_data->gpg_verify_summary)
{
@ -2019,15 +2139,6 @@ ostree_repo_pull_with_options (OstreeRepo *self,
goto out;
}
if (bytes_summary)
{
uri = suburi_new (pull_data->base_uri, "summary.sig", NULL);
if (!fetch_uri_contents_membuf_sync (pull_data, uri, FALSE, TRUE,
&bytes_sig, cancellable, error))
goto out;
soup_uri_free (uri);
}
if (!bytes_sig && pull_data->gpg_verify_summary)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@ -2044,6 +2155,18 @@ ostree_repo_pull_with_options (OstreeRepo *self,
pull_data->summary_data_sig = g_bytes_ref (bytes_sig);
}
if (!summary_from_cache && bytes_summary && bytes_sig)
{
if (!_ostree_repo_cache_summary (self,
remote_name_or_baseurl,
bytes_summary,
bytes_sig,
cancellable,
error))
goto out;
}
if (pull_data->gpg_verify_summary && bytes_summary && bytes_sig)
{
g_autoptr(GVariant) sig_variant = NULL;

View File

@ -22,6 +22,7 @@
#include "ostree-repo-private.h"
#include "otutil.h"
#include "ot-fs-utils.h"
static gboolean
add_ref_to_set (const char *remote,
@ -114,31 +115,6 @@ write_checksum_file_at (OstreeRepo *self,
return ret;
}
static gboolean
openat_ignore_enoent (int dfd,
const char *path,
int *out_fd,
GError **error)
{
gboolean ret = FALSE;
int target_fd = -1;
target_fd = openat (dfd, path, O_CLOEXEC | O_RDONLY);
if (target_fd < 0)
{
if (errno != ENOENT)
{
glnx_set_error_from_errno (error);
goto out;
}
}
ret = TRUE;
*out_fd = target_fd;
out:
return ret;
}
static gboolean
find_ref_in_remotes (OstreeRepo *self,
const char *rev,
@ -168,7 +144,7 @@ find_ref_in_remotes (OstreeRepo *self,
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error))
goto out;
if (!openat_ignore_enoent (remote_dfd, rev, &ret_fd, error))
if (!ot_openat_ignore_enoent (remote_dfd, rev, &ret_fd, error))
goto out;
if (ret_fd != -1)
@ -247,21 +223,21 @@ resolve_refspec (OstreeRepo *self,
{
const char *remote_ref = glnx_strjoina ("refs/remotes/", remote, "/", ref);
if (!openat_ignore_enoent (self->repo_dir_fd, remote_ref, &target_fd, error))
if (!ot_openat_ignore_enoent (self->repo_dir_fd, remote_ref, &target_fd, error))
goto out;
}
else
{
const char *local_ref = glnx_strjoina ("refs/heads/", ref);
if (!openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error))
if (!ot_openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error))
goto out;
if (target_fd == -1)
{
local_ref = glnx_strjoina ("refs/remotes/", ref);
if (!openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error))
if (!ot_openat_ignore_enoent (self->repo_dir_fd, local_ref, &target_fd, error))
goto out;
if (target_fd == -1)
@ -508,24 +484,13 @@ enumerate_refs_recurse (OstreeRepo *repo,
return ret;
}
/**
* ostree_repo_list_refs:
* @self: Repo
* @refspec_prefix: (allow-none): Only list refs which match this prefix
* @out_all_refs: (out) (element-type utf8 utf8): Mapping from ref to checksum
* @cancellable: Cancellable
* @error: Error
*
* If @refspec_prefix is %NULL, list all local and remote refspecs,
* with their current values in @out_all_refs. Otherwise, only list
* refspecs which have @refspec_prefix as a prefix.
*/
gboolean
ostree_repo_list_refs (OstreeRepo *self,
const char *refspec_prefix,
GHashTable **out_all_refs,
GCancellable *cancellable,
GError **error)
static gboolean
_ostree_repo_list_refs_internal (OstreeRepo *self,
gboolean cut_prefix,
const char *refspec_prefix,
GHashTable **out_all_refs,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
g_autoptr(GHashTable) ret_all_refs = NULL;
@ -568,12 +533,14 @@ ostree_repo_list_refs (OstreeRepo *self,
{
glnx_fd_close int base_fd = -1;
g_autoptr(GString) base_path = g_string_new ("");
if (!cut_prefix)
g_string_printf (base_path, "%s/", ref_prefix);
if (!glnx_opendirat (self->repo_dir_fd, path, TRUE, &base_fd, error))
if (!glnx_opendirat (self->repo_dir_fd, cut_prefix ? path : prefix_path, TRUE, &base_fd, error))
goto out;
if (!enumerate_refs_recurse (self, remote, base_fd, base_path,
base_fd, ".",
base_fd, cut_prefix ? "." : ref_prefix,
ret_all_refs, cancellable, error))
goto out;
}
@ -639,6 +606,54 @@ ostree_repo_list_refs (OstreeRepo *self,
return ret;
}
/**
* ostree_repo_list_refs:
* @self: Repo
* @refspec_prefix: (allow-none): Only list refs which match this prefix
* @out_all_refs: (out) (element-type utf8 utf8): Mapping from ref to checksum
* @cancellable: Cancellable
* @error: Error
*
* If @refspec_prefix is %NULL, list all local and remote refspecs,
* with their current values in @out_all_refs. Otherwise, only list
* refspecs which have @refspec_prefix as a prefix.
*/
gboolean
ostree_repo_list_refs (OstreeRepo *self,
const char *refspec_prefix,
GHashTable **out_all_refs,
GCancellable *cancellable,
GError **error)
{
return _ostree_repo_list_refs_internal (self, TRUE, refspec_prefix, out_all_refs, cancellable, error);
}
/**
* ostree_repo_list_refs_ext:
* @self: Repo
* @refspec_prefix: (allow-none): Only list refs which match this prefix
* @out_all_refs: (out) (element-type utf8 utf8): Mapping from ref to checksum
* @flags: Options controlling listing behavior
* @cancellable: Cancellable
* @error: Error
*
* If @refspec_prefix is %NULL, list all local and remote refspecs,
* with their current values in @out_all_refs. Otherwise, only list
* refspecs which have @refspec_prefix as a prefix. Differently from
* ostree_repo_list_refs(), the prefix will not be removed from the ref
* name.
*/
gboolean
ostree_repo_list_refs_ext (OstreeRepo *self,
const char *refspec_prefix,
GHashTable **out_all_refs,
OstreeRepoListRefsExtFlags flags,
GCancellable *cancellable,
GError **error)
{
return _ostree_repo_list_refs_internal (self, FALSE, refspec_prefix, out_all_refs, cancellable, error);
}
/**
* ostree_repo_remote_list_refs:
* @self: Repo

View File

@ -181,7 +181,8 @@ build_content_sizenames_filtered (OstreeRepo *repo,
g_ptr_array_sort (ret_sizenames, compare_sizenames);
ret = TRUE;
gs_transfer_out_value (out_sizenames, &ret_sizenames);
if (out_sizenames)
*out_sizenames = g_steal_pointer (&ret_sizenames);
out:
return ret;
}
@ -296,7 +297,8 @@ _ostree_delta_compute_similar_objects (OstreeRepo *repo,
}
ret = TRUE;
gs_transfer_out_value (out_modified_regfile_content, &ret_modified_regfile_content);
if (out_modified_regfile_content)
*out_modified_regfile_content = g_steal_pointer (&ret_modified_regfile_content);
out:
return ret;
}

View File

@ -456,7 +456,7 @@ get_unpacked_unlinked_content (OstreeRepo *repo,
{
gboolean ret = FALSE;
g_autofree char *tmpname = g_strdup ("tmpostree-deltaobj-XXXXXX");
gs_fd_close int fd = -1;
glnx_fd_close int fd = -1;
g_autoptr(GBytes) ret_content = NULL;
g_autoptr(GInputStream) istream = NULL;
g_autoptr(GFileInfo) ret_finfo = NULL;
@ -465,7 +465,7 @@ get_unpacked_unlinked_content (OstreeRepo *repo,
fd = g_mkstemp (tmpname);
if (fd == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
/* Doesn't need a name */
@ -488,7 +488,8 @@ get_unpacked_unlinked_content (OstreeRepo *repo,
}
ret = TRUE;
gs_transfer_out_value (out_content, &ret_content);
if (out_content)
*out_content = g_steal_pointer (&ret_content);
out:
return ret;
}
@ -532,7 +533,8 @@ try_content_bsdiff (OstreeRepo *repo,
ret_bsdiff->tmp_to = tmp_to; tmp_to = NULL;
ret = TRUE;
gs_transfer_out_value (out_bsdiff, &ret_bsdiff);
if (out_bsdiff)
*out_bsdiff = g_steal_pointer (&ret_bsdiff);
out:
return ret;
}
@ -597,7 +599,8 @@ try_content_rollsum (OstreeRepo *repo,
ret_rollsum->tmp_to = tmp_to; tmp_to = NULL;
ret = TRUE;
gs_transfer_out_value (out_rollsum, &ret_rollsum);
if (out_rollsum)
*out_rollsum = g_steal_pointer (&ret_rollsum);
out:
if (matches)
_ostree_rollsum_matches_free (matches);
@ -1199,7 +1202,8 @@ get_fallback_headers (OstreeRepo *self,
ret_headers = g_variant_ref_sink (g_variant_builder_end (fallback_builder));
ret = TRUE;
gs_transfer_out_value (out_headers, &ret_headers);
if (out_headers)
*out_headers = g_steal_pointer (&ret_headers);
out:
return ret;
}

View File

@ -754,7 +754,7 @@ dispatch_write (OstreeRepo *repo,
{
if (lseek (state->read_source_fd, content_offset, SEEK_SET) == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
while (content_size > 0)
@ -767,7 +767,7 @@ dispatch_write (OstreeRepo *repo,
while (G_UNLIKELY (bytes_read == -1 && errno == EINTR));
if (bytes_read == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
if (G_UNLIKELY (bytes_read == 0))

View File

@ -377,9 +377,8 @@ traverse_dirtree (OstreeRepo *repo,
ostree_cleanup_repo_commit_traverse_iter
OstreeRepoCommitTraverseIter iter = { 0, };
if (!ostree_repo_load_variant_if_exists (repo, OSTREE_OBJECT_TYPE_DIR_TREE,
checksum, &dirtree,
error))
if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_DIR_TREE, checksum,
&dirtree, error))
goto out;
if (!ostree_repo_commit_traverse_iter_init_dirtree (&iter, repo, dirtree,
@ -503,7 +502,8 @@ ostree_repo_traverse_commit (OstreeRepo *repo,
goto out;
ret = TRUE;
gs_transfer_out_value (out_reachable, &ret_reachable);
if (out_reachable)
*out_reachable = g_steal_pointer (&ret_reachable);
out:
return ret;
}

View File

@ -34,6 +34,7 @@
#include "ostree-repo-file-enumerator.h"
#include "ostree-gpg-verifier.h"
#include "ostree-repo-static-delta-private.h"
#include "ot-fs-utils.h"
#ifdef HAVE_LIBSOUP
#include "ostree-metalink.h"
@ -1749,9 +1750,7 @@ repo_remote_fetch_summary (OstreeRepo *self,
g_autoptr(GMainContext) mainctx = NULL;
gboolean ret = FALSE;
SoupURI *base_uri = NULL;
uint i;
const char *filenames[] = {"summary", "summary.sig"};
GBytes **outputs[] = {out_summary, out_signatures};
gboolean from_cache = FALSE;
mainctx = g_main_context_new ();
g_main_context_push_thread_default (mainctx);
@ -1781,19 +1780,63 @@ repo_remote_fetch_summary (OstreeRepo *self,
}
}
for (i = 0; i < G_N_ELEMENTS (filenames); i++)
if (!_ostree_preload_metadata_file (self,
fetcher,
base_uri,
"summary.sig",
metalink_url_string ? TRUE : FALSE,
out_signatures,
cancellable,
error))
goto out;
if (*out_signatures)
{
if (!_ostree_repo_load_cache_summary_if_same_sig (self,
name,
*out_signatures,
out_summary,
cancellable,
error))
goto out;
}
if (*out_summary)
from_cache = TRUE;
else
{
if (!_ostree_preload_metadata_file (self,
fetcher,
base_uri,
filenames[i],
"summary",
metalink_url_string ? TRUE : FALSE,
outputs[i],
out_summary,
cancellable,
error))
goto out;
}
if (!from_cache && *out_summary && *out_signatures)
{
g_autoptr(GError) temp_error = NULL;
if (!_ostree_repo_cache_summary (self,
name,
*out_summary,
*out_signatures,
cancellable,
&temp_error))
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED))
g_debug ("No permissions to save summary cache");
else
{
g_propagate_error (error, g_steal_pointer (&temp_error));
goto out;
}
}
}
ret = TRUE;
out:
@ -2072,7 +2115,8 @@ enumerate_directory_allow_noent (GFile *dirpath,
}
ret = TRUE;
gs_transfer_out_value (out_direnum, &ret_direnum);
if (out_direnum)
*out_direnum = g_steal_pointer (&ret_direnum);
out:
return ret;
}
@ -2227,14 +2271,15 @@ ostree_repo_open (OstreeRepo *self,
goto out;
g_strdelimit (self->boot_id, "\n", '\0');
if (!gs_file_open_dir_fd (self->repodir, &self->repo_dir_fd, cancellable, error))
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE,
&self->repo_dir_fd, error))
{
g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir));
goto out;
}
if (!gs_file_open_dir_fd_at (self->repo_dir_fd, "objects",
&self->objects_dir_fd, cancellable, error))
if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE,
&self->objects_dir_fd, error))
{
g_prefix_error (error, "Opening objects/ directory: ");
goto out;
@ -2244,12 +2289,12 @@ ostree_repo_open (OstreeRepo *self,
if (!self->writable)
{
/* This is returned through ostree_repo_is_writable(). */
gs_set_error_from_errno (&self->writable_error, errno);
glnx_set_error_from_errno (&self->writable_error);
}
if (fstat (self->objects_dir_fd, &stbuf) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -2343,16 +2388,16 @@ ostree_repo_open (OstreeRepo *self,
goto out;
}
if (!gs_file_open_dir_fd (self->tmp_dir, &self->tmp_dir_fd, cancellable, error))
if (!glnx_opendirat (self->repo_dir_fd, "tmp", TRUE, &self->tmp_dir_fd, error))
goto out;
if (self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2 && self->enable_uncompressed_cache)
{
if (!gs_file_ensure_directory (self->uncompressed_objects_dir, TRUE, cancellable, error))
goto out;
if (!gs_file_open_dir_fd (self->uncompressed_objects_dir,
&self->uncompressed_objects_dir_fd,
cancellable, error))
if (!glnx_opendirat (self->repo_dir_fd, "uncompressed-objects-cache", TRUE,
&self->uncompressed_objects_dir_fd,
error))
goto out;
}
@ -2423,6 +2468,24 @@ ostree_repo_get_path (OstreeRepo *self)
return self->repodir;
}
/**
* ostree_repo_get_dfd:
* @self: Repo
*
* In some cases it's useful for applications to access the repository
* directly; for example, writing content into `repo/tmp` ensures it's
* on the same filesystem. Another case is detecting the mtime on the
* repository (to see whether a ref was written).
*
* Returns: File descriptor for repository root - owned by @self
*/
int
ostree_repo_get_dfd (OstreeRepo *self)
{
g_return_val_if_fail (self->repo_dir_fd != -1, -1);
return self->repo_dir_fd;
}
OstreeRepoMode
ostree_repo_get_mode (OstreeRepo *self)
{
@ -2463,7 +2526,7 @@ list_loose_objects_at (OstreeRepo *self,
d = fdopendir (dfd);
if (!d)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -2557,7 +2620,7 @@ list_loose_objects (OstreeRepo *self,
continue;
else
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -2573,32 +2636,6 @@ list_loose_objects (OstreeRepo *self,
return ret;
}
static gboolean
openat_allow_noent (int dfd,
const char *path,
int *fd,
GCancellable *cancellable,
GError **error)
{
GError *temp_error = NULL;
if (!gs_file_openat_noatime (dfd, path, fd,
cancellable, &temp_error))
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
*fd = -1;
g_clear_error (&temp_error);
}
else
{
g_propagate_error (error, temp_error);
return FALSE;
}
}
return TRUE;
}
static gboolean
load_metadata_internal (OstreeRepo *self,
OstreeObjectType objtype,
@ -2620,14 +2657,14 @@ load_metadata_internal (OstreeRepo *self,
_ostree_loose_path (loose_path_buf, sha256, objtype, self->mode);
if (!openat_allow_noent (self->objects_dir_fd, loose_path_buf, &fd,
cancellable, error))
if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd,
error))
goto out;
if (fd < 0 && self->commit_stagedir_fd != -1)
{
if (!openat_allow_noent (self->commit_stagedir_fd, loose_path_buf, &fd,
cancellable, error))
if (!ot_openat_ignore_enoent (self->commit_stagedir_fd, loose_path_buf, &fd,
error))
goto out;
}
@ -2714,7 +2751,7 @@ query_info_for_bare_content_object (OstreeRepo *self,
ret = TRUE;
goto out;
}
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -2738,7 +2775,8 @@ query_info_for_bare_content_object (OstreeRepo *self,
}
ret = TRUE;
gs_transfer_out_value (out_info, &ret_info);
if (out_info)
*out_info = g_steal_pointer (&ret_info);
out:
return ret;
}
@ -2821,8 +2859,8 @@ ostree_repo_load_file (OstreeRepo *self,
struct stat stbuf;
g_autoptr(GInputStream) tmp_stream = NULL;
if (!openat_allow_noent (self->objects_dir_fd, loose_path_buf, &fd,
cancellable, error))
if (!ot_openat_ignore_enoent (self->objects_dir_fd, loose_path_buf, &fd,
error))
goto out;
if (fd != -1)
@ -2859,7 +2897,7 @@ ostree_repo_load_file (OstreeRepo *self,
guint32 mode;
g_autoptr(GVariant) metadata = NULL;
g_autoptr(GBytes) bytes = NULL;
gs_fd_close int fd = -1;
glnx_fd_close int fd = -1;
bytes = ot_lgetxattrat (self->objects_dir_fd, loose_path_buf,
"user.ostreemeta", error);
@ -2918,7 +2956,7 @@ ostree_repo_load_file (OstreeRepo *self,
if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_REGULAR
&& (out_input || out_xattrs))
{
gs_fd_close int fd = -1;
glnx_fd_close int fd = -1;
if (!gs_file_openat_noatime (self->objects_dir_fd, loose_path_buf, &fd,
cancellable, error))
@ -2926,7 +2964,7 @@ ostree_repo_load_file (OstreeRepo *self,
if (out_xattrs)
{
if (!gs_fd_get_all_xattrs (fd, &ret_xattrs,
if (!glnx_fd_get_all_xattrs (fd, &ret_xattrs,
cancellable, error))
goto out;
}
@ -2940,7 +2978,7 @@ ostree_repo_load_file (OstreeRepo *self,
else if (g_file_info_get_file_type (ret_file_info) == G_FILE_TYPE_SYMBOLIC_LINK
&& out_xattrs)
{
if (!gs_dfd_and_name_get_all_xattrs (self->objects_dir_fd, loose_path_buf,
if (!glnx_dfd_name_get_all_xattrs (self->objects_dir_fd, loose_path_buf,
&ret_xattrs,
cancellable, error))
goto out;
@ -3063,7 +3101,7 @@ _ostree_repo_has_loose_object (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1 && errno != ENOENT)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -3077,7 +3115,7 @@ _ostree_repo_has_loose_object (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (res == -1 && errno != ENOENT)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -3195,7 +3233,7 @@ ostree_repo_delete_object (OstreeRepo *self,
{
if (G_UNLIKELY (errno != ENOENT))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -3206,7 +3244,7 @@ ostree_repo_delete_object (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -3342,7 +3380,7 @@ import_one_object_link (OstreeRepo *self,
ret = TRUE;
}
else
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -3446,7 +3484,7 @@ ostree_repo_query_object_storage_size (OstreeRepo *self,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -4053,7 +4091,8 @@ sign_data (OstreeRepo *self,
ret_signature = g_mapped_file_get_bytes (signature_file);
ret = TRUE;
gs_transfer_out_value (out_signature, &ret_signature);
if (out_signature)
*out_signature = g_steal_pointer (&ret_signature);
out:
if (commit_buffer)
gpgme_data_release (commit_buffer);
@ -4601,11 +4640,11 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
g_variant_dict_init (&deltas_builder, NULL);
for (i = 0; i < delta_names->len; i++)
{
gs_free char *from = NULL;
gs_free char *to = NULL;
gs_free guchar *csum = NULL;
gs_free char *superblock = NULL;
gs_fd_close int superblock_file_fd = -1;
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;
_ostree_parse_delta_name (delta_names->pdata[i], &from, &to);
@ -4613,7 +4652,7 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
superblock_file_fd = openat (self->repo_dir_fd, superblock, O_RDONLY | O_CLOEXEC);
if (superblock_file_fd == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -4656,7 +4695,7 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
{
if (errno != ENOENT)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}

View File

@ -36,46 +36,65 @@ G_BEGIN_DECLS
#define OSTREE_IS_REPO(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_REPO))
_OSTREE_PUBLIC
gboolean ostree_repo_mode_from_string (const char *mode,
OstreeRepoMode *out_mode,
GError **error);
_OSTREE_PUBLIC
GType ostree_repo_get_type (void);
_OSTREE_PUBLIC
OstreeRepo* ostree_repo_new (GFile *path);
_OSTREE_PUBLIC
OstreeRepo* ostree_repo_new_for_sysroot_path (GFile *repo_path,
GFile *sysroot_path);
_OSTREE_PUBLIC
OstreeRepo* ostree_repo_new_default (void);
_OSTREE_PUBLIC
gboolean ostree_repo_open (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_repo_set_disable_fsync (OstreeRepo *self,
gboolean disable_fsync);
_OSTREE_PUBLIC
gboolean ostree_repo_get_disable_fsync (OstreeRepo *self);
_OSTREE_PUBLIC
gboolean ostree_repo_is_system (OstreeRepo *repo);
_OSTREE_PUBLIC
gboolean ostree_repo_is_writable (OstreeRepo *self,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_create (OstreeRepo *self,
OstreeRepoMode mode,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
GFile * ostree_repo_get_path (OstreeRepo *self);
_OSTREE_PUBLIC
int ostree_repo_get_dfd (OstreeRepo *self);
_OSTREE_PUBLIC
OstreeRepoMode ostree_repo_get_mode (OstreeRepo *self);
_OSTREE_PUBLIC
GKeyFile * ostree_repo_get_config (OstreeRepo *self);
_OSTREE_PUBLIC
GKeyFile * ostree_repo_copy_config (OstreeRepo *self);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_add (OstreeRepo *self,
const char *name,
const char *url,
@ -83,6 +102,7 @@ gboolean ostree_repo_remote_add (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_delete (OstreeRepo *self,
const char *name,
GCancellable *cancellable,
@ -95,6 +115,7 @@ typedef enum {
OSTREE_REPO_REMOTE_CHANGE_DELETE_IF_EXISTS
} OstreeRepoRemoteChange;
_OSTREE_PUBLIC
gboolean ostree_repo_remote_change (OstreeRepo *self,
GFile *sysroot,
OstreeRepoRemoteChange changeop,
@ -104,24 +125,29 @@ gboolean ostree_repo_remote_change (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
char ** ostree_repo_remote_list (OstreeRepo *self,
guint *out_n_remotes);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_get_url (OstreeRepo *self,
const char *name,
char **out_url,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_get_gpg_verify (OstreeRepo *self,
const char *name,
gboolean *out_gpg_verify,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_get_gpg_verify_summary (OstreeRepo *self,
const char *name,
gboolean *out_gpg_verify_summary,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_gpg_import (OstreeRepo *self,
const char *name,
GInputStream *source_stream,
@ -130,6 +156,7 @@ gboolean ostree_repo_remote_gpg_import (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_fetch_summary (OstreeRepo *self,
const char *name,
GBytes **out_summary,
@ -137,8 +164,10 @@ gboolean ostree_repo_remote_fetch_summary (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeRepo * ostree_repo_get_parent (OstreeRepo *self);
_OSTREE_PUBLIC
gboolean ostree_repo_write_config (OstreeRepo *self,
GKeyFile *new_config,
GError **error);
@ -174,35 +203,43 @@ struct _OstreeRepoTransactionStats {
guint64 padding4;
};
_OSTREE_PUBLIC
GType ostree_repo_transaction_stats_get_type (void);
_OSTREE_PUBLIC
gboolean ostree_repo_scan_hardlinks (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_prepare_transaction (OstreeRepo *self,
gboolean *out_transaction_resume,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_commit_transaction (OstreeRepo *self,
OstreeRepoTransactionStats *out_stats,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_abort_transaction (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_repo_transaction_set_refspec (OstreeRepo *self,
const char *refspec,
const char *checksum);
_OSTREE_PUBLIC
void ostree_repo_transaction_set_ref (OstreeRepo *self,
const char *remote,
const char *ref,
const char *checksum);
_OSTREE_PUBLIC
gboolean ostree_repo_set_ref_immediate (OstreeRepo *self,
const char *remote,
const char *ref,
@ -210,6 +247,7 @@ gboolean ostree_repo_set_ref_immediate (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_has_object (OstreeRepo *self,
OstreeObjectType objtype,
const char *checksum,
@ -217,6 +255,7 @@ gboolean ostree_repo_has_object (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_metadata (OstreeRepo *self,
OstreeObjectType objtype,
const char *expected_checksum,
@ -225,6 +264,7 @@ gboolean ostree_repo_write_metadata (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_repo_write_metadata_async (OstreeRepo *self,
OstreeObjectType objtype,
const char *expected_checksum,
@ -233,11 +273,13 @@ void ostree_repo_write_metadata_async (OstreeRepo *self,
GAsyncReadyCallback callback,
gpointer user_data);
_OSTREE_PUBLIC
gboolean ostree_repo_write_metadata_finish (OstreeRepo *self,
GAsyncResult *result,
guchar **out_csum,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_content (OstreeRepo *self,
const char *expected_checksum,
GInputStream *object_input,
@ -246,6 +288,7 @@ gboolean ostree_repo_write_content (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_metadata_trusted (OstreeRepo *self,
OstreeObjectType objtype,
const char *checksum,
@ -253,6 +296,7 @@ gboolean ostree_repo_write_metadata_trusted (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_metadata_stream_trusted (OstreeRepo *self,
OstreeObjectType objtype,
const char *checksum,
@ -261,6 +305,7 @@ gboolean ostree_repo_write_metadata_stream_trusted (OstreeRepo *self
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_content_trusted (OstreeRepo *self,
const char *checksum,
GInputStream *object_input,
@ -268,6 +313,7 @@ gboolean ostree_repo_write_content_trusted (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_repo_write_content_async (OstreeRepo *self,
const char *expected_checksum,
GInputStream *object,
@ -276,35 +322,57 @@ void ostree_repo_write_content_async (OstreeRepo *self,
GAsyncReadyCallback callback,
gpointer user_data);
_OSTREE_PUBLIC
gboolean ostree_repo_write_content_finish (OstreeRepo *self,
GAsyncResult *result,
guchar **out_csum,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_resolve_rev (OstreeRepo *self,
const char *refspec,
gboolean allow_noent,
char **out_rev,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_list_refs (OstreeRepo *self,
const char *refspec_prefix,
GHashTable **out_all_refs,
GCancellable *cancellable,
GError **error);
/**
* OstreeRepoListRefsExtFlags:
* @OSTREE_REPO_LIST_REFS_EXT_NONE: No flags.
*/
typedef enum {
OSTREE_REPO_LIST_REFS_EXT_NONE = 0,
} OstreeRepoListRefsExtFlags;
_OSTREE_PUBLIC
gboolean ostree_repo_list_refs_ext (OstreeRepo *self,
const char *refspec_prefix,
GHashTable **out_all_refs,
OstreeRepoListRefsExtFlags flags,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_remote_list_refs (OstreeRepo *self,
const char *remote_name,
GHashTable **out_all_refs,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_load_variant (OstreeRepo *self,
OstreeObjectType objtype,
const char *sha256,
GVariant **out_variant,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_load_variant_if_exists (OstreeRepo *self,
OstreeObjectType objtype,
const char *sha256,
@ -315,12 +383,14 @@ typedef enum {
OSTREE_REPO_COMMIT_STATE_PARTIAL = (1 << 0),
} OstreeRepoCommitState;
_OSTREE_PUBLIC
gboolean ostree_repo_load_commit (OstreeRepo *self,
const char *checksum,
GVariant **out_commit,
OstreeRepoCommitState *out_state,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_load_file (OstreeRepo *self,
const char *checksum,
GInputStream **out_input,
@ -329,6 +399,7 @@ gboolean ostree_repo_load_file (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_load_object_stream (OstreeRepo *self,
OstreeObjectType objtype,
const char *checksum,
@ -337,6 +408,7 @@ gboolean ostree_repo_load_object_stream (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_query_object_storage_size (OstreeRepo *self,
OstreeObjectType objtype,
const char *sha256,
@ -344,6 +416,7 @@ gboolean ostree_repo_query_object_storage_size (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_import_object_from (OstreeRepo *self,
OstreeRepo *source,
OstreeObjectType objtype,
@ -351,6 +424,7 @@ gboolean ostree_repo_import_object_from (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_delete_object (OstreeRepo *self,
OstreeObjectType objtype,
const char *sha256,
@ -400,11 +474,13 @@ typedef enum {
*/
typedef struct OstreeRepoCommitModifier OstreeRepoCommitModifier;
_OSTREE_PUBLIC
OstreeRepoCommitModifier *ostree_repo_commit_modifier_new (OstreeRepoCommitModifierFlags flags,
OstreeRepoCommitFilter commit_filter,
gpointer user_data,
GDestroyNotify destroy_notify);
_OSTREE_PUBLIC
GType ostree_repo_commit_modifier_get_type (void);
typedef GVariant *(*OstreeRepoCommitModifierXattrCallback) (OstreeRepo *repo,
@ -412,20 +488,26 @@ typedef GVariant *(*OstreeRepoCommitModifierXattrCallback) (OstreeRepo *repo
GFileInfo *file_info,
gpointer user_data);
_OSTREE_PUBLIC
void ostree_repo_commit_modifier_set_xattr_callback (OstreeRepoCommitModifier *modifier,
OstreeRepoCommitModifierXattrCallback callback,
GDestroyNotify destroy,
gpointer user_data);
_OSTREE_PUBLIC
void ostree_repo_commit_modifier_set_sepolicy (OstreeRepoCommitModifier *modifier,
OstreeSePolicy *sepolicy);
_OSTREE_PUBLIC
void ostree_repo_commit_modifier_set_devino_cache (OstreeRepoCommitModifier *modifier,
OstreeRepoDevInoCache *cache);
_OSTREE_PUBLIC
OstreeRepoCommitModifier *ostree_repo_commit_modifier_ref (OstreeRepoCommitModifier *modifier);
_OSTREE_PUBLIC
void ostree_repo_commit_modifier_unref (OstreeRepoCommitModifier *modifier);
_OSTREE_PUBLIC
gboolean ostree_repo_write_directory_to_mtree (OstreeRepo *self,
GFile *dir,
OstreeMutableTree *mtree,
@ -433,6 +515,7 @@ gboolean ostree_repo_write_directory_to_mtree (OstreeRepo *
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_dfd_to_mtree (OstreeRepo *self,
int dfd,
const char *path,
@ -442,6 +525,7 @@ gboolean ostree_repo_write_dfd_to_mtree (OstreeRepo *self,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_archive_to_mtree (OstreeRepo *self,
GFile *archive,
OstreeMutableTree *mtree,
@ -466,6 +550,7 @@ typedef struct {
gpointer unused_ptrs[8];
} OstreeRepoImportArchiveOptions;
_OSTREE_PUBLIC
gboolean ostree_repo_import_archive_to_mtree (OstreeRepo *self,
OstreeRepoImportArchiveOptions *opts,
void *archive, /* Really struct archive * */
@ -490,6 +575,7 @@ typedef struct {
gpointer unused_ptrs[8];
} OstreeRepoExportArchiveOptions;
_OSTREE_PUBLIC
gboolean ostree_repo_export_tree_to_archive (OstreeRepo *self,
OstreeRepoExportArchiveOptions *opts,
OstreeRepoFile *root,
@ -497,12 +583,14 @@ gboolean ostree_repo_export_tree_to_archive (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_mtree (OstreeRepo *self,
OstreeMutableTree *mtree,
GFile **out_file,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_commit (OstreeRepo *self,
const char *parent,
const char *subject,
@ -513,6 +601,7 @@ gboolean ostree_repo_write_commit (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_commit_with_time (OstreeRepo *self,
const char *parent,
const char *subject,
@ -524,12 +613,14 @@ gboolean ostree_repo_write_commit_with_time (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_read_commit_detached_metadata (OstreeRepo *self,
const char *checksum,
GVariant **out_metadata,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_write_commit_detached_metadata (OstreeRepo *self,
const char *checksum,
GVariant *metadata,
@ -556,7 +647,7 @@ typedef enum {
OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES = 1
} OstreeRepoCheckoutOverwriteMode;
gboolean
_OSTREE_PUBLIC gboolean
ostree_repo_checkout_tree (OstreeRepo *self,
OstreeRepoCheckoutMode mode,
OstreeRepoCheckoutOverwriteMode overwrite_mode,
@ -592,11 +683,16 @@ typedef struct {
gpointer unused_ptrs[7];
} OstreeRepoCheckoutOptions;
_OSTREE_PUBLIC
GType ostree_repo_devino_cache_get_type (void);
_OSTREE_PUBLIC
OstreeRepoDevInoCache *ostree_repo_devino_cache_new (void);
_OSTREE_PUBLIC
OstreeRepoDevInoCache * ostree_repo_devino_cache_ref (OstreeRepoDevInoCache *cache);
_OSTREE_PUBLIC
void ostree_repo_devino_cache_unref (OstreeRepoDevInoCache *cache);
_OSTREE_PUBLIC
gboolean ostree_repo_checkout_tree_at (OstreeRepo *self,
OstreeRepoCheckoutOptions *options,
int destination_dfd,
@ -605,10 +701,12 @@ gboolean ostree_repo_checkout_tree_at (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_checkout_gc (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_read_commit (OstreeRepo *self,
const char *ref,
GFile **out_root,
@ -636,18 +734,21 @@ typedef enum {
*/
#define OSTREE_REPO_LIST_OBJECTS_VARIANT_TYPE (G_VARIANT_TYPE ("(bas)")
_OSTREE_PUBLIC
gboolean ostree_repo_list_objects (OstreeRepo *self,
OstreeRepoListObjectsFlags flags,
GHashTable **out_objects,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_list_commit_objects_starting_with ( OstreeRepo *self,
const char *start,
GHashTable **out_commits,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_list_static_delta_names (OstreeRepo *self,
GPtrArray **out_deltas,
GCancellable *cancellable,
@ -665,6 +766,7 @@ typedef enum {
OSTREE_STATIC_DELTA_GENERATE_OPT_MAJOR
} OstreeStaticDeltaGenerateOpt;
_OSTREE_PUBLIC
gboolean ostree_repo_static_delta_generate (OstreeRepo *self,
OstreeStaticDeltaGenerateOpt opt,
const char *from,
@ -674,14 +776,17 @@ gboolean ostree_repo_static_delta_generate (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_static_delta_execute_offline (OstreeRepo *self,
GFile *dir_or_file,
gboolean skip_validation,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
GHashTable *ostree_repo_traverse_new_reachable (void);
_OSTREE_PUBLIC
gboolean ostree_repo_traverse_commit (OstreeRepo *repo,
const char *commit_checksum,
int maxdepth,
@ -689,6 +794,7 @@ gboolean ostree_repo_traverse_commit (OstreeRepo *repo,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_traverse_commit_union (OstreeRepo *repo,
const char *commit_checksum,
int maxdepth,
@ -708,14 +814,14 @@ typedef enum {
OSTREE_REPO_COMMIT_TRAVERSE_FLAG_NONE = (1 << 0)
} OstreeRepoCommitTraverseFlags;
gboolean
_OSTREE_PUBLIC gboolean
ostree_repo_commit_traverse_iter_init_commit (OstreeRepoCommitTraverseIter *iter,
OstreeRepo *repo,
GVariant *commit,
OstreeRepoCommitTraverseFlags flags,
GError **error);
gboolean
_OSTREE_PUBLIC gboolean
ostree_repo_commit_traverse_iter_init_dirtree (OstreeRepoCommitTraverseIter *iter,
OstreeRepo *repo,
GVariant *dirtree,
@ -729,22 +835,26 @@ typedef enum {
OSTREE_REPO_COMMIT_ITER_RESULT_DIR
} OstreeRepoCommitIterResult;
_OSTREE_PUBLIC
OstreeRepoCommitIterResult ostree_repo_commit_traverse_iter_next (OstreeRepoCommitTraverseIter *iter,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_repo_commit_traverse_iter_get_file (OstreeRepoCommitTraverseIter *iter,
char **out_name,
char **out_checksum);
_OSTREE_PUBLIC
void ostree_repo_commit_traverse_iter_get_dir (OstreeRepoCommitTraverseIter *iter,
char **out_name,
char **out_content_checksum,
char **out_meta_checksum);
void
_OSTREE_PUBLIC void
ostree_repo_commit_traverse_iter_clear (OstreeRepoCommitTraverseIter *iter);
_OSTREE_PUBLIC
void ostree_repo_commit_traverse_iter_cleanup (void *p);
#define ostree_cleanup_repo_commit_traverse_iter __attribute__ ((cleanup(ostree_repo_commit_traverse_iter_cleanup)))
@ -761,11 +871,12 @@ typedef enum {
OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY
} OstreeRepoPruneFlags;
gboolean
_OSTREE_PUBLIC gboolean
ostree_repo_prune_static_deltas (OstreeRepo *self, const char *commit,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_prune (OstreeRepo *self,
OstreeRepoPruneFlags flags,
gint depth,
@ -787,6 +898,7 @@ typedef enum {
OSTREE_REPO_PULL_FLAGS_COMMIT_ONLY = (1 << 1)
} OstreeRepoPullFlags;
_OSTREE_PUBLIC
gboolean ostree_repo_pull (OstreeRepo *self,
const char *remote_name,
char **refs_to_fetch,
@ -795,7 +907,7 @@ gboolean ostree_repo_pull (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
gboolean
_OSTREE_PUBLIC gboolean
ostree_repo_pull_one_dir (OstreeRepo *self,
const char *remote_name,
const char *dir_to_pull,
@ -805,6 +917,7 @@ ostree_repo_pull_one_dir (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_pull_with_options (OstreeRepo *self,
const char *remote_name,
GVariant *options,
@ -812,9 +925,11 @@ gboolean ostree_repo_pull_with_options (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress,
gpointer user_data);
_OSTREE_PUBLIC
gboolean ostree_repo_sign_commit (OstreeRepo *self,
const gchar *commit_checksum,
const gchar *key_id,
@ -822,6 +937,7 @@ gboolean ostree_repo_sign_commit (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_sign_delta (OstreeRepo *self,
const gchar *from_commit,
const gchar *to_commit,
@ -830,19 +946,21 @@ gboolean ostree_repo_sign_delta (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
gboolean
_OSTREE_PUBLIC gboolean
ostree_repo_add_gpg_signature_summary (OstreeRepo *self,
const gchar **key_id,
const gchar *homedir,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_append_gpg_signature (OstreeRepo *self,
const gchar *commit_checksum,
GBytes *signature_bytes,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_verify_commit (OstreeRepo *self,
const gchar *commit_checksum,
GFile *keyringdir,
@ -850,6 +968,7 @@ gboolean ostree_repo_verify_commit (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeGpgVerifyResult * ostree_repo_verify_commit_ext (OstreeRepo *self,
const gchar *commit_checksum,
GFile *keyringdir,
@ -857,6 +976,7 @@ OstreeGpgVerifyResult * ostree_repo_verify_commit_ext (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeGpgVerifyResult * ostree_repo_verify_summary (OstreeRepo *self,
const char *remote_name,
GBytes *summary,
@ -864,6 +984,7 @@ OstreeGpgVerifyResult * ostree_repo_verify_summary (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_repo_regenerate_summary (OstreeRepo *self,
GVariant *additional_metadata,
GCancellable *cancellable,

View File

@ -347,10 +347,9 @@ ostree_sepolicy_get_label (OstreeSePolicy *self,
res = selabel_lookup_raw (self->selinux_hnd, &con, relpath, unix_mode);
if (res != 0)
{
int errsv = errno;
if (errsv != ENOENT)
if (errno != ENOENT)
{
gs_set_error_from_errno (error, errsv);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -443,14 +442,15 @@ ostree_sepolicy_restorecon (OstreeSePolicy *self,
int res = lsetfilecon (gs_file_get_path_cached (target), label);
if (res != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
}
ret = TRUE;
gs_transfer_out_value (out_new_label, &label);
if (out_new_label)
*out_new_label = g_steal_pointer (&label);
out:
return ret;
#else
@ -490,7 +490,7 @@ ostree_sepolicy_setfscreatecon (OstreeSePolicy *self,
if (setfscreatecon_raw (label) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
return FALSE;
}

View File

@ -30,16 +30,21 @@ G_BEGIN_DECLS
#define OSTREE_IS_SEPOLICY(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SEPOLICY))
_OSTREE_PUBLIC
GType ostree_sepolicy_get_type (void);
_OSTREE_PUBLIC
OstreeSePolicy* ostree_sepolicy_new (GFile *path,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
GFile * ostree_sepolicy_get_path (OstreeSePolicy *self);
_OSTREE_PUBLIC
const char *ostree_sepolicy_get_name (OstreeSePolicy *self);
_OSTREE_PUBLIC
gboolean ostree_sepolicy_get_label (OstreeSePolicy *self,
const char *relpath,
guint32 unix_mode,
@ -53,6 +58,7 @@ typedef enum {
OSTREE_SEPOLICY_RESTORECON_FLAGS_KEEP_EXISTING = (1 << 1)
} OstreeSePolicyRestoreconFlags;
_OSTREE_PUBLIC
gboolean ostree_sepolicy_restorecon (OstreeSePolicy *self,
const char *path,
GFileInfo *info,
@ -62,11 +68,13 @@ gboolean ostree_sepolicy_restorecon (OstreeSePolicy *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sepolicy_setfscreatecon (OstreeSePolicy *self,
const char *path,
guint32 mode,
GError **error);
_OSTREE_PUBLIC
void ostree_sepolicy_fscreatecon_cleanup (void **unused);
#define ostree_cleanup_sepolicy_fscreatecon __attribute__ ((cleanup(ostree_sepolicy_fscreatecon_cleanup)))

View File

@ -255,28 +255,28 @@ cleanup_other_bootversions (OstreeSysroot *self,
cleanup_subbootversion = self->subbootversion == 0 ? 1 : 0;
cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d", cleanup_bootversion);
if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error))
goto out;
g_clear_object (&cleanup_boot_dir);
cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d", cleanup_bootversion);
if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error))
goto out;
g_clear_object (&cleanup_boot_dir);
cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.0", cleanup_bootversion);
if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error))
goto out;
g_clear_object (&cleanup_boot_dir);
cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.1", cleanup_bootversion);
if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error))
goto out;
g_clear_object (&cleanup_boot_dir);
cleanup_boot_dir = ot_gfile_resolve_path_printf (self->path, "ostree/boot.%d.%d", self->bootversion,
cleanup_subbootversion);
if (!gs_shutil_rm_rf (cleanup_boot_dir, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (cleanup_boot_dir), cancellable, error))
goto out;
g_clear_object (&cleanup_boot_dir);
@ -377,7 +377,7 @@ cleanup_old_deployments (OstreeSysroot *self,
if (g_hash_table_lookup (active_boot_checksums, bootcsum))
continue;
if (!gs_shutil_rm_rf (bootdir, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (bootdir), cancellable, error))
goto out;
}
@ -401,7 +401,7 @@ cleanup_ref_prefix (OstreeRepo *repo,
prefix = g_strdup_printf ("ostree/%d/%d", bootversion, subbootversion);
if (!ostree_repo_list_refs (repo, prefix, &refs, cancellable, error))
if (!ostree_repo_list_refs_ext (repo, prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, cancellable, error))
goto out;
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
@ -410,8 +410,7 @@ cleanup_ref_prefix (OstreeRepo *repo,
g_hash_table_iter_init (&hashiter, refs);
while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
{
const char *suffix = hashkey;
g_autofree char *ref = g_strconcat (prefix, "/", suffix, NULL);
const char *ref = hashkey;
ostree_repo_transaction_set_refspec (repo, ref, NULL);
}

View File

@ -22,6 +22,12 @@
#include <gio/gunixinputstream.h>
#include <gio/gunixoutputstream.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
#ifdef HAVE_LIBMOUNT
#include <libmount.h>
#endif
#include "ostree-sysroot-private.h"
#include "ostree-deployment-private.h"
@ -97,26 +103,26 @@ dirfd_copy_attributes_and_xattrs (int src_parent_dfd,
* right. This will allow other users access if they have ACLs, but
* oh well.
*/
if (!gs_dfd_and_name_get_all_xattrs (src_parent_dfd, src_name,
if (!glnx_dfd_name_get_all_xattrs (src_parent_dfd, src_name,
&xattrs, cancellable, error))
goto out;
if (!gs_fd_set_all_xattrs (dest_dfd, xattrs,
if (!glnx_fd_set_all_xattrs (dest_dfd, xattrs,
cancellable, error))
goto out;
if (fstat (src_dfd, &src_stbuf) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
if (fchown (dest_dfd, src_stbuf.st_uid, src_stbuf.st_gid) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
if (fchmod (dest_dfd, src_stbuf.st_mode) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -144,7 +150,7 @@ copy_dir_recurse (int src_parent_dfd,
/* Create with mode 0700, we'll fchmod/fchown later */
if (mkdirat (dest_parent_dfd, name, 0700) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -158,7 +164,7 @@ copy_dir_recurse (int src_parent_dfd,
srcd = fdopendir (src_dfd);
if (!srcd)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -174,7 +180,7 @@ copy_dir_recurse (int src_parent_dfd,
if (fstatat (src_dfd, name, &child_stbuf,
AT_SYMLINK_NOFOLLOW) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -256,7 +262,7 @@ ensure_directory_from_template (int orig_etc_fd,
}
else
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
g_prefix_error (error, "mkdirat: ");
goto out;
}
@ -306,7 +312,7 @@ copy_modified_config_file (int orig_etc_fd,
if (fstatat (modified_etc_fd, path, &modified_stbuf, AT_SYMLINK_NOFOLLOW) < 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
g_prefix_error (error, "Failed to read modified config file '%s': ", path);
goto out;
}
@ -324,7 +330,7 @@ copy_modified_config_file (int orig_etc_fd,
dest_parent_dfd = dup (new_etc_fd);
if (dest_parent_dfd == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -337,7 +343,7 @@ copy_modified_config_file (int orig_etc_fd,
;
else
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -363,7 +369,7 @@ copy_modified_config_file (int orig_etc_fd,
{
if (unlinkat (new_etc_fd, path, 0) < 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
}
@ -450,11 +456,14 @@ merge_etc_changes (GFile *orig_etc,
removed->len,
added->len);
if (!gs_file_open_dir_fd (orig_etc, &orig_etc_fd, cancellable, error))
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (orig_etc), TRUE,
&orig_etc_fd, error))
goto out;
if (!gs_file_open_dir_fd (modified_etc, &modified_etc_fd, cancellable, error))
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (modified_etc), TRUE,
&modified_etc_fd, error))
goto out;
if (!gs_file_open_dir_fd (new_etc, &new_etc_fd, cancellable, error))
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (new_etc), TRUE,
&new_etc_fd, error))
goto out;
for (i = 0; i < removed->len; i++)
@ -467,7 +476,7 @@ merge_etc_changes (GFile *orig_etc,
g_assert (path);
target_file = g_file_resolve_relative_path (new_etc, path);
if (!gs_shutil_rm_rf (target_file, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (target_file), cancellable, error))
goto out;
}
@ -873,7 +882,8 @@ merge_configuration (OstreeSysroot *sysroot,
}
ret = TRUE;
gs_transfer_out_value (out_sepolicy, &sepolicy);
if (out_sepolicy)
*out_sepolicy = g_steal_pointer (&sepolicy);
out:
return ret;
}
@ -941,8 +951,8 @@ get_kernel_from_tree (int deployment_dfd,
g_auto(GLnxDirFdIterator) dfditer = { 0, };
g_autofree char *ret_kernel_name = NULL;
g_autofree char *ret_initramfs_name = NULL;
gs_free char *kernel_checksum = NULL;
gs_free char *initramfs_checksum = NULL;
g_autofree char *kernel_checksum = NULL;
g_autofree char *initramfs_checksum = NULL;
ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE);
if (ret_boot_dfd == -1)
@ -1360,7 +1370,7 @@ install_deployment_kernel (OstreeSysroot *sysroot,
{
if (errno != ENOENT)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
else
@ -1645,6 +1655,47 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self,
return ret;
}
static gboolean
is_ro_mount (const char *path)
{
#ifdef HAVE_LIBMOUNT
/* Dragging in all of this crud is apparently necessary just to determine
* whether something is a mount point.
*
* Systemd has a totally different implementation in
* src/basic/mount-util.c.
*/
struct libmnt_table *tb = mnt_new_table_from_file ("/proc/self/mountinfo");
struct libmnt_fs *fs;
struct libmnt_cache *cache;
gboolean is_mount = FALSE;
struct statvfs stvfsbuf;
if (!tb)
return FALSE;
/* to canonicalize all necessary paths */
cache = mnt_new_cache ();
mnt_table_set_cache (tb, cache);
fs = mnt_table_find_target(tb, path, MNT_ITER_BACKWARD);
is_mount = fs && mnt_fs_get_target (fs);
mnt_free_cache (cache);
mnt_free_table (tb);
if (!is_mount)
return FALSE;
/* We *could* parse the options, but it seems more reliable to
* introspect the actual mount at runtime.
*/
if (statvfs (path, &stvfsbuf) == 0)
return (stvfsbuf.f_flag & ST_RDONLY) != 0;
#endif
return FALSE;
}
/**
* ostree_sysroot_write_deployments:
* @self: Sysroot
@ -1666,6 +1717,7 @@ ostree_sysroot_write_deployments (OstreeSysroot *self,
gboolean requires_new_bootversion = FALSE;
gboolean found_booted_deployment = FALSE;
gboolean bootloader_is_atomic = FALSE;
gboolean boot_was_ro_mount = FALSE;
g_assert (self->loaded);
@ -1753,12 +1805,26 @@ ostree_sysroot_write_deployments (OstreeSysroot *self,
glnx_unref_object OstreeRepo *repo = NULL;
gboolean show_osname = FALSE;
if (self->booted_deployment)
boot_was_ro_mount = is_ro_mount ("/boot");
g_debug ("boot is ro: %s", boot_was_ro_mount ? "yes" : "no");
if (boot_was_ro_mount)
{
if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
{
glnx_set_prefix_error_from_errno (error, "%s", "Remounting /boot read-write");
goto out;
}
}
if (!_ostree_sysroot_query_bootloader (self, &bootloader, cancellable, error))
goto out;
new_loader_entries_dir = ot_gfile_resolve_path_printf (self->path, "boot/loader.%d/entries",
new_bootversion);
if (!gs_shutil_rm_rf (new_loader_entries_dir, cancellable, error))
if (!glnx_shutil_rm_rf_at (AT_FDCWD, gs_file_get_path_cached (new_loader_entries_dir), cancellable, error))
goto out;
if (!ot_util_ensure_directory_and_fsync (new_loader_entries_dir, cancellable, error))
goto out;
@ -1855,6 +1921,9 @@ ostree_sysroot_write_deployments (OstreeSysroot *self,
requires_new_bootversion ? "yes" : "no",
new_deployments->len - self->deployments->len);
if (!_ostree_sysroot_bump_mtime (self, error))
goto out;
/* Now reload from disk */
if (!ostree_sysroot_load (self, cancellable, error))
{
@ -1875,6 +1944,18 @@ ostree_sysroot_write_deployments (OstreeSysroot *self,
ret = TRUE;
out:
if (boot_was_ro_mount)
{
if (mount ("/boot", "/boot", NULL, MS_REMOUNT | MS_RDONLY | MS_SILENT, NULL) < 0)
{
/* Only make this a warning because we don't want to
* completely bomb out if some other process happened to
* jump in and open a file there.
*/
int errsv = errno;
g_printerr ("warning: Failed to remount /boot read-only: %s\n", strerror (errsv));
}
}
return ret;
}

View File

@ -49,6 +49,7 @@ struct OstreeSysroot {
int bootversion;
int subbootversion;
OstreeDeployment *booted_deployment;
struct timespec loaded_ts;
/* Only access through ostree_sysroot_get_repo() */
OstreeRepo *repo;
@ -57,6 +58,9 @@ struct OstreeSysroot {
};
#define OSTREE_SYSROOT_LOCKFILE "ostree/lock"
/* We keep some transient state in /run */
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/"
#define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development"
gboolean
_ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
@ -98,6 +102,9 @@ gboolean _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error);
gboolean _ostree_sysroot_bump_mtime (OstreeSysroot *sysroot,
GError **error);
typedef enum {
OSTREE_SYSROOT_CLEANUP_BOOTVERSIONS = 1 << 0,
OSTREE_SYSROOT_CLEANUP_DEPLOYMENTS = 1 << 1,

View File

@ -42,32 +42,42 @@ typedef enum {
OSTREE_SYSROOT_UPGRADER_FLAGS_IGNORE_UNCONFIGURED = (1 << 1),
} OstreeSysrootUpgraderFlags;
_OSTREE_PUBLIC
GType ostree_sysroot_upgrader_get_type (void);
_OSTREE_PUBLIC
GType ostree_sysroot_upgrader_flags_get_type (void);
_OSTREE_PUBLIC
OstreeSysrootUpgrader *ostree_sysroot_upgrader_new (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeSysrootUpgrader *ostree_sysroot_upgrader_new_for_os (OstreeSysroot *sysroot,
const char *osname,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeSysrootUpgrader *ostree_sysroot_upgrader_new_for_os_with_flags (OstreeSysroot *sysroot,
const char *osname,
OstreeSysrootUpgraderFlags flags,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
GKeyFile *ostree_sysroot_upgrader_get_origin (OstreeSysrootUpgrader *self);
_OSTREE_PUBLIC
GKeyFile *ostree_sysroot_upgrader_dup_origin (OstreeSysrootUpgrader *self);
_OSTREE_PUBLIC
gboolean ostree_sysroot_upgrader_set_origin (OstreeSysrootUpgrader *self, GKeyFile *origin,
GCancellable *cancellable, GError **error);
_OSTREE_PUBLIC
char *ostree_sysroot_upgrader_get_origin_description (OstreeSysrootUpgrader *self);
_OSTREE_PUBLIC
gboolean ostree_sysroot_upgrader_check_timestamps (OstreeRepo *repo,
const char *from_rev,
const char *to_rev,
@ -78,6 +88,7 @@ typedef enum {
OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_ALLOW_OLDER = (1 << 0)
} OstreeSysrootUpgraderPullFlags;
_OSTREE_PUBLIC
gboolean ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self,
OstreeRepoPullFlags flags,
OstreeSysrootUpgraderPullFlags upgrader_flags,
@ -86,6 +97,7 @@ gboolean ostree_sysroot_upgrader_pull (OstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
const char *dir_to_pull,
OstreeRepoPullFlags flags,
@ -95,6 +107,7 @@ gboolean ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_upgrader_deploy (OstreeSysrootUpgrader *self,
GCancellable *cancellable,
GError **error);

View File

@ -24,6 +24,7 @@
#include "ostree-core-private.h"
#include "ostree-sysroot-private.h"
#include "ostree-deployment-private.h"
#include "ostree-bootloader-uboot.h"
#include "ostree-bootloader-syslinux.h"
#include "ostree-bootloader-grub2.h"
@ -229,6 +230,19 @@ ostree_sysroot_get_fd (OstreeSysroot *self)
return self->sysroot_fd;
}
gboolean
_ostree_sysroot_bump_mtime (OstreeSysroot *self,
GError **error)
{
/* Allow other systems to monitor for changes */
if (utimensat (self->sysroot_fd, "ostree/deploy", NULL, 0) < 0)
{
glnx_set_prefix_error_from_errno (error, "%s", "futimens");
return FALSE;
}
return TRUE;
}
/**
* ostree_sysroot_unload:
* @self: Sysroot
@ -485,7 +499,8 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self,
g_ptr_array_sort (ret_loader_configs, compare_loader_configs_for_sorting);
done:
gs_transfer_out_value (out_loader_configs, &ret_loader_configs);
if (out_loader_configs)
*out_loader_configs = g_steal_pointer (&ret_loader_configs);
ret = TRUE;
out:
return ret;
@ -580,7 +595,8 @@ parse_origin (OstreeSysroot *self,
}
ret = TRUE;
gs_transfer_out_value (out_origin, &ret_origin);
if (out_origin)
*out_origin = g_steal_pointer (&ret_origin);
out:
if (error)
g_prefix_error (error, "Parsing %s: ", origin_path);
@ -631,6 +647,16 @@ parse_bootlink (const char *bootlink,
return ret;
}
static char *
get_unlocked_development_path (OstreeDeployment *deployment)
{
return g_strdup_printf ("%s%s.%d/%s",
_OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR,
ostree_deployment_get_csum (deployment),
ostree_deployment_get_deployserial (deployment),
_OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT);
}
static gboolean
parse_deployment (OstreeSysroot *self,
const char *boot_link,
@ -652,6 +678,8 @@ parse_deployment (OstreeSysroot *self,
g_autofree char *treebootserial_target = NULL;
g_autofree char *deploy_dir = NULL;
GKeyFile *origin = NULL;
g_autofree char *unlocked_development_path = NULL;
struct stat stbuf;
if (!ensure_sysroot_fd (self, error))
goto out;
@ -689,8 +717,27 @@ parse_deployment (OstreeSysroot *self,
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);
if (lstat (unlocked_development_path, &stbuf) == 0)
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
else
{
g_autofree char *existing_unlocked_state =
g_key_file_get_string (origin, "origin", "unlocked", NULL);
if (g_strcmp0 (existing_unlocked_state, "hotfix") == 0)
{
ret_deployment->unlocked = OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX;
}
/* TODO: warn on unknown unlock types? */
}
g_debug ("Deployment %s.%d unlocked=%d", treecsum, deployserial, ret_deployment->unlocked);
ret = TRUE;
gs_transfer_out_value (out_deployment, &ret_deployment);
if (out_deployment)
*out_deployment = g_steal_pointer (&ret_deployment);
out:
if (origin)
g_key_file_unref (origin);
@ -780,19 +827,24 @@ gboolean
ostree_sysroot_load (OstreeSysroot *self,
GCancellable *cancellable,
GError **error)
{
return ostree_sysroot_load_if_changed (self, NULL, cancellable, error);
}
gboolean
ostree_sysroot_load_if_changed (OstreeSysroot *self,
gboolean *out_changed,
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;
g_clear_pointer (&self->deployments, g_ptr_array_unref);
g_clear_pointer (&self->booted_deployment, g_object_unref);
self->bootversion = -1;
self->subbootversion = -1;
if (!ensure_sysroot_fd (self, error))
goto out;
@ -803,6 +855,28 @@ ostree_sysroot_load (OstreeSysroot *self,
cancellable, error))
goto out;
if (fstatat (self->sysroot_fd, "ostree/deploy", &stbuf, 0) < 0)
{
glnx_set_error_from_errno (error);
goto out;
}
if (out_changed)
{
if (self->loaded_ts.tv_sec == stbuf.st_mtim.tv_sec &&
self->loaded_ts.tv_nsec == stbuf.st_mtim.tv_nsec)
{
*out_changed = FALSE;
ret = TRUE;
goto out;
}
}
g_clear_pointer (&self->deployments, g_ptr_array_unref);
g_clear_pointer (&self->booted_deployment, g_object_unref);
self->bootversion = -1;
self->subbootversion = -1;
if (!_ostree_sysroot_read_boot_loader_configs (self, bootversion, &boot_loader_configs,
cancellable, error))
goto out;
@ -834,8 +908,11 @@ ostree_sysroot_load (OstreeSysroot *self,
self->deployments = deployments;
deployments = NULL; /* Transfer ownership */
self->loaded = TRUE;
self->loaded_ts = stbuf.st_mtim;
ret = TRUE;
if (out_changed)
*out_changed = TRUE;
out:
return ret;
}
@ -1005,7 +1082,8 @@ _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
g_clear_object (&ret_loader);
ret = TRUE;
gs_transfer_out_value (out_bootloader, &ret_loader);
if (out_bootloader)
*out_bootloader = g_steal_pointer (&ret_loader);
out:
return ret;
}
@ -1337,6 +1415,86 @@ ostree_sysroot_lock_finish (OstreeSysroot *self,
return g_task_propagate_boolean ((GTask*)result, error);
}
/**
* ostree_sysroot_init_osname:
* @self: Sysroot
* @osname: Name group of operating system checkouts
* @cancellable: Cancellable
* @error: Error
*
* Initialize the directory structure for an "osname", which is a
* group of operating system deployments, with a shared `/var`. One
* is required for generating a deployment.
*/
gboolean
ostree_sysroot_init_osname (OstreeSysroot *self,
const char *osname,
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;
if (mkdirat (self->sysroot_fd, deploydir, 0777) < 0)
{
glnx_set_prefix_error_from_errno (error, "Creating %s", deploydir);
goto out;
}
if (!glnx_opendirat (self->sysroot_fd, deploydir, TRUE, &dfd, error))
goto out;
if (mkdirat (dfd, "var", 0777) < 0)
{
glnx_set_prefix_error_from_errno (error, "Creating %s", "var");
goto out;
}
/* 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;
}
if (fchmodat (dfd, "var/tmp", 01777, 0) < 0)
{
glnx_set_prefix_error_from_errno (error, "Fchmod %s", "var/tmp");
goto out;
}
if (mkdirat (dfd, "var/lib", 0777) < 0)
{
glnx_set_prefix_error_from_errno (error, "Creating %s", "var/tmp");
goto out;
}
if (symlinkat ("../run", dfd, "var/run") < 0)
{
glnx_set_prefix_error_from_errno (error, "Symlinking %s", "var/run");
goto out;
}
if (symlinkat ("../run/lock", dfd, "var/lock") < 0)
{
glnx_set_prefix_error_from_errno (error, "Symlinking %s", "var/lock");
goto out;
}
if (!_ostree_sysroot_bump_mtime (self, error))
goto out;
ret = TRUE;
out:
return ret;
}
/**
* ostree_sysroot_simple_write_deployment:
* @sysroot: Sysroot
@ -1354,6 +1512,10 @@ ostree_sysroot_lock_finish (OstreeSysroot *self,
*
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is
* specified, then all current deployments will be kept.
*
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is
* specified, then instead of prepending, the new deployment will be
* added right after the booted or merge deployment, instead of first.
*/
gboolean
ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
@ -1370,6 +1532,8 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
g_autoptr(GPtrArray) deployments = NULL;
g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref);
gboolean retain = (flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0;
const gboolean make_default = !((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0);
gboolean added_new = FALSE;
deployments = ostree_sysroot_get_deployments (sysroot);
booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
@ -1377,23 +1541,44 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
if (osname == NULL && booted_deployment)
osname = ostree_deployment_get_osname (booted_deployment);
g_ptr_array_add (new_deployments, g_object_ref (new_deployment));
if (make_default)
{
g_ptr_array_add (new_deployments, g_object_ref (new_deployment));
added_new = TRUE;
}
for (i = 0; i < deployments->len; i++)
{
OstreeDeployment *deployment = deployments->pdata[i];
const gboolean is_merge_or_booted =
ostree_deployment_equal (deployment, booted_deployment) ||
ostree_deployment_equal (deployment, merge_deployment);
/* Keep deployments with different osnames, as well as the
* booted and merge deployments
*/
if (retain ||
(osname != NULL &&
strcmp (ostree_deployment_get_osname (deployment), osname) != 0) ||
ostree_deployment_equal (deployment, booted_deployment) ||
ostree_deployment_equal (deployment, merge_deployment))
(osname != NULL && strcmp (ostree_deployment_get_osname (deployment), osname) != 0) ||
is_merge_or_booted)
{
g_ptr_array_add (new_deployments, g_object_ref (deployment));
}
if (!added_new)
{
g_ptr_array_add (new_deployments, g_object_ref (new_deployment));
added_new = TRUE;
}
}
/* In this non-default case , an improvement in the future would be
* to put the new deployment right after the current default in the
* order.
*/
if (!added_new)
{
g_ptr_array_add (new_deployments, g_object_ref (new_deployment));
added_new = TRUE;
}
if (!ostree_sysroot_write_deployments (sysroot, new_deployments, cancellable, error))
@ -1406,3 +1591,263 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
out:
return ret;
}
static gboolean
clone_deployment (OstreeSysroot *sysroot,
OstreeDeployment *target_deployment,
OstreeDeployment *merge_deployment,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
__attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL;
glnx_unref_object OstreeDeployment *new_deployment = NULL;
/* Ensure we have a clean slate */
if (!ostree_sysroot_prepare_cleanup (sysroot, cancellable, error))
{
g_prefix_error (error, "Performing initial cleanup: ");
goto out;
}
kargs = _ostree_kernel_args_new ();
{ OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment);
g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1);
_ostree_kernel_args_append_argv (kargs, previous_args);
}
{
g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs);
if (!ostree_sysroot_deploy_tree (sysroot,
ostree_deployment_get_osname (target_deployment),
ostree_deployment_get_csum (target_deployment),
ostree_deployment_get_origin (target_deployment),
merge_deployment,
kargs_strv,
&new_deployment,
cancellable, error))
goto out;
}
/* Hotfixes push the deployment as rollback target, so it shouldn't
* be the default.
*/
if (!ostree_sysroot_simple_write_deployment (sysroot, ostree_deployment_get_osname (target_deployment),
new_deployment, merge_deployment,
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT,
cancellable, error))
goto out;
ret = TRUE;
out:
return ret;
}
/**
* ostree_sysroot_deployment_unlock:
* @self: Sysroot
* @deployment: Deployment
* @unlocked_state: Transition to this unlocked state
* @cancellable: Cancellable
* @error: Error
*
* Configure the target deployment @deployment such that it
* is writable. There are multiple modes, essentially differing
* in whether or not any changes persist across reboot.
*
* The `OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX` state is persistent
* across reboots.
*/
gboolean
ostree_sysroot_deployment_unlock (OstreeSysroot *self,
OstreeDeployment *deployment,
OstreeDeploymentUnlockedState unlocked_state,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
OstreeDeploymentUnlockedState current_unlocked =
ostree_deployment_get_unlocked (deployment);
glnx_unref_object OstreeDeployment *deployment_clone =
ostree_deployment_clone (deployment);
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone);
const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
const char *ovl_options = NULL;
g_autofree char *deployment_path = NULL;
glnx_fd_close int deployment_dfd = -1;
pid_t mount_child;
/* This function cannot re-lock */
g_return_val_if_fail (unlocked_state != OSTREE_DEPLOYMENT_UNLOCKED_NONE, FALSE);
if (current_unlocked != OSTREE_DEPLOYMENT_UNLOCKED_NONE)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Deployment is already in unlocked state: %s",
ostree_deployment_unlocked_state_to_string (current_unlocked));
goto out;
}
merge_deployment = ostree_sysroot_get_merge_deployment (self, ostree_deployment_get_osname (deployment));
if (!merge_deployment)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No previous deployment to duplicate");
goto out;
}
/* For hotfixes, we push a rollback target */
if (unlocked_state == OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX)
{
if (!clone_deployment (self, deployment, merge_deployment, cancellable, error))
goto out;
}
/* Crack it open */
if (!ostree_sysroot_deployment_set_mutable (self, deployment, TRUE,
cancellable, error))
goto out;
deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment);
if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error))
goto out;
switch (unlocked_state)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
g_assert_not_reached ();
break;
case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX:
{
/* Create the overlayfs directories in the deployment root
* directly for hotfixes. The ostree-prepare-root.c helper
* is also set up to detect and mount these.
*/
if (!glnx_shutil_mkdir_p_at (deployment_dfd, ".usr-ovl-upper", 0755, cancellable, error))
goto out;
if (!glnx_shutil_mkdir_p_at (deployment_dfd, ".usr-ovl-work", 0755, cancellable, error))
goto out;
ovl_options = hotfix_ovl_options;
}
break;
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
{
/* We're just doing transient development/hacking? Okay,
* stick the overlayfs bits in /var/tmp.
*/
char *development_ovldir = strdupa ("/var/tmp/ostree-unlock-ovl.XXXXXX");
const char *development_ovl_upper;
const char *development_ovl_work;
if (!glnx_mkdtempat (AT_FDCWD, development_ovldir, 0700, error))
goto out;
development_ovl_upper = glnx_strjoina (development_ovldir, "/upper");
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, development_ovl_upper, 0755, cancellable, error))
goto out;
development_ovl_work = glnx_strjoina (development_ovldir, "/work");
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, development_ovl_work, 0755, cancellable, error))
goto out;
ovl_options = glnx_strjoina ("lowerdir=usr,upperdir=", development_ovl_upper,
",workdir=", development_ovl_work);
}
}
g_assert (ovl_options != NULL);
/* Here we run `mount()` in a fork()ed child because we need to use
* `chdir()` in order to have the mount path options to overlayfs not
* look ugly.
*
* We can't `chdir()` inside a shared library since there may be
* threads, etc.
*/
{
/* Make a copy of the fd that's *not* FD_CLOEXEC so that we pass
* it to the child.
*/
glnx_fd_close int child_deployment_dfd = dup (deployment_dfd);
if (child_deployment_dfd < 0)
{
glnx_set_error_from_errno (error);
goto out;
}
mount_child = fork ();
if (mount_child < 0)
{
glnx_set_prefix_error_from_errno (error, "%s", "fork");
goto out;
}
else if (mount_child == 0)
{
/* Child process. Do NOT use any GLib API here. */
if (fchdir (child_deployment_dfd) < 0)
exit (EXIT_FAILURE);
(void) close (child_deployment_dfd);
if (mount ("overlay", "/usr", "overlay", 0, ovl_options) < 0)
exit (EXIT_FAILURE);
exit (EXIT_SUCCESS);
}
else
{
/* Parent */
int estatus;
if (TEMP_FAILURE_RETRY (waitpid (mount_child, &estatus, 0)) < 0)
{
glnx_set_prefix_error_from_errno (error, "%s", "waitpid() on mount helper");
goto out;
}
if (!g_spawn_check_exit_status (estatus, error))
{
g_prefix_error (error, "overlayfs mount helper: ");
goto out;
}
}
}
/* Now, write out the flag saying what we did */
switch (unlocked_state)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
g_assert_not_reached ();
break;
case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX:
g_key_file_set_string (origin_clone, "origin", "unlocked",
ostree_deployment_unlocked_state_to_string (unlocked_state));
if (!ostree_sysroot_write_origin_file (self, deployment, origin_clone,
cancellable, error))
goto out;
break;
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
{
g_autofree char *devpath = get_unlocked_development_path (deployment);
g_autofree char *devpath_parent = dirname (g_strdup (devpath));
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error))
goto out;
if (!g_file_set_contents (devpath, "", 0, error))
goto out;
}
}
/* For hotfixes we already pushed a rollback which will bump the
* mtime, but we need to bump it again so that clients get the state
* change for this deployment. For development we need to do this
* regardless.
*/
if (!_ostree_sysroot_bump_mtime (self, error))
goto out;
ret = TRUE;
out:
return ret;
}

View File

@ -31,82 +31,121 @@ G_BEGIN_DECLS
#define OSTREE_IS_SYSROOT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_SYSROOT))
_OSTREE_PUBLIC
GType ostree_sysroot_get_type (void);
_OSTREE_PUBLIC
OstreeSysroot* ostree_sysroot_new (GFile *path);
_OSTREE_PUBLIC
OstreeSysroot* ostree_sysroot_new_default (void);
_OSTREE_PUBLIC
GFile *ostree_sysroot_get_path (OstreeSysroot *self);
_OSTREE_PUBLIC
int ostree_sysroot_get_fd (OstreeSysroot *self);
_OSTREE_PUBLIC
gboolean ostree_sysroot_load (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_load_if_changed (OstreeSysroot *self,
gboolean *out_changed,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
void ostree_sysroot_unload (OstreeSysroot *self);
_OSTREE_PUBLIC
gboolean ostree_sysroot_ensure_initialized (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
int ostree_sysroot_get_bootversion (OstreeSysroot *self);
_OSTREE_PUBLIC
int ostree_sysroot_get_subbootversion (OstreeSysroot *self);
_OSTREE_PUBLIC
GPtrArray *ostree_sysroot_get_deployments (OstreeSysroot *self);
_OSTREE_PUBLIC
OstreeDeployment *ostree_sysroot_get_booted_deployment (OstreeSysroot *self);
_OSTREE_PUBLIC
GFile *ostree_sysroot_get_deployment_directory (OstreeSysroot *self,
OstreeDeployment *deployment);
_OSTREE_PUBLIC
char *ostree_sysroot_get_deployment_dirpath (OstreeSysroot *self,
OstreeDeployment *deployment);
_OSTREE_PUBLIC
GFile * ostree_sysroot_get_deployment_origin_path (GFile *deployment_path);
_OSTREE_PUBLIC
gboolean ostree_sysroot_lock (OstreeSysroot *self, GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_try_lock (OstreeSysroot *self,
gboolean *out_acquired,
GError **error);
_OSTREE_PUBLIC
void ostree_sysroot_lock_async (OstreeSysroot *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
_OSTREE_PUBLIC
gboolean ostree_sysroot_lock_finish (OstreeSysroot *self,
GAsyncResult *result,
GError **error);
_OSTREE_PUBLIC
void ostree_sysroot_unlock (OstreeSysroot *self);
_OSTREE_PUBLIC
gboolean ostree_sysroot_init_osname (OstreeSysroot *self,
const char *osname,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_cleanup (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_prepare_cleanup (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_write_origin_file (OstreeSysroot *sysroot,
OstreeDeployment *deployment,
GKeyFile *new_origin,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_get_repo (OstreeSysroot *self,
OstreeRepo **out_repo,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_set_kargs (OstreeSysroot *self,
OstreeDeployment *deployment,
char **new_kargs,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_write_deployments (OstreeSysroot *self,
GPtrArray *new_deployments,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self,
const char *osname,
const char *revision,
@ -117,24 +156,36 @@ gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
OstreeDeployment *deployment,
gboolean is_mutable,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_unlock (OstreeSysroot *self,
OstreeDeployment *deployment,
OstreeDeploymentUnlockedState unlocked_state,
GCancellable *cancellable,
GError **error);
_OSTREE_PUBLIC
OstreeDeployment *ostree_sysroot_get_merge_deployment (OstreeSysroot *self,
const char *osname);
_OSTREE_PUBLIC
GKeyFile *ostree_sysroot_origin_new_from_refspec (OstreeSysroot *self,
const char *refspec);
typedef enum {
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NONE = 0,
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN = (1 << 0)
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN = (1 << 0),
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT = (1 << 1)
} OstreeSysrootSimpleWriteDeploymentFlags;
_OSTREE_PUBLIC
gboolean ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
const char *osname,
OstreeDeployment *new_deployment,

View File

@ -24,6 +24,10 @@
#include <gio/gio.h>
#ifndef _OSTREE_PUBLIC
#define _OSTREE_PUBLIC extern
#endif
G_BEGIN_DECLS
typedef struct OstreeRepo OstreeRepo;

View File

@ -45,7 +45,7 @@ ot_gopendirat (int dfd,
int ret = ot_opendirat (dfd, path, follow);
if (ret == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
return FALSE;
}
*out_fd = ret;
@ -71,7 +71,7 @@ ot_lgetxattrat (int dfd,
while (G_UNLIKELY (bytes_read < 0 && errno == EINTR));
if (G_UNLIKELY (bytes_read < 0))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -81,7 +81,7 @@ ot_lgetxattrat (int dfd,
while (G_UNLIKELY (real_size < 0 && errno == EINTR));
if (G_UNLIKELY (real_size < 0))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
g_free (buf);
goto out;
}
@ -111,7 +111,7 @@ ot_lsetxattrat (int dfd,
while (G_UNLIKELY (res == -1 && errno == EINTR));
if (G_UNLIKELY (res == -1))
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
return FALSE;
}
@ -134,7 +134,7 @@ ot_readlinkat_gfile_info (int dfd,
while (G_UNLIKELY (len == -1 && errno == EINTR));
if (len == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
targetbuf[len] = '\0';
@ -180,7 +180,7 @@ ot_openat_read_stream (int dfd,
while (G_UNLIKELY (fd == -1 && errno == EINTR));
if (fd == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -205,3 +205,28 @@ ot_ensure_unlinked_at (int dfd,
}
return TRUE;
}
gboolean
ot_openat_ignore_enoent (int dfd,
const char *path,
int *out_fd,
GError **error)
{
gboolean ret = FALSE;
int target_fd = -1;
target_fd = openat (dfd, path, O_CLOEXEC | O_RDONLY);
if (target_fd < 0)
{
if (errno != ENOENT)
{
glnx_set_error_from_errno (error);
goto out;
}
}
ret = TRUE;
*out_fd = target_fd;
out:
return ret;
}

View File

@ -61,4 +61,9 @@ gboolean ot_ensure_unlinked_at (int dfd,
const char *path,
GError **error);
gboolean ot_openat_ignore_enoent (int dfd,
const char *path,
int *out_fd,
GError **error);
G_END_DECLS

View File

@ -309,7 +309,9 @@ ot_file_replace_contents_at (int dfd,
int r = posix_fallocate (fd, 0, g_bytes_get_size (contents));
if (r != 0)
{
gs_set_error_from_errno (error, r);
/* posix_fallocate is a weird deviation from errno standards */
errno = r;
glnx_set_error_from_errno (error);
goto out;
}
}
@ -320,7 +322,7 @@ ot_file_replace_contents_at (int dfd,
if (datasync && fdatasync (fd) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -329,7 +331,7 @@ ot_file_replace_contents_at (int dfd,
if (renameat (dfd, tmpname, dfd, path) == -1)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -360,8 +362,8 @@ ot_gfile_replace_contents_fsync (GFile *path,
parent = g_file_get_parent (path);
if (!gs_file_open_dir_fd (parent, &parent_dfd,
cancellable, error))
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (parent), TRUE,
&parent_dfd, error))
goto out;
if (!ot_file_replace_contents_at (parent_dfd, target_basename,
@ -424,12 +426,13 @@ ot_util_fsync_directory (GFile *dir,
gboolean ret = FALSE;
int dfd = -1;
if (!gs_file_open_dir_fd (dir, &dfd, cancellable, error))
if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (dir), TRUE,
&dfd, error))
goto out;
if (fsync (dfd) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}

View File

@ -204,7 +204,7 @@ ot_util_variant_map_fd (int fd,
if (fstat (fd, &stbuf) != 0)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}
@ -212,7 +212,7 @@ ot_util_variant_map_fd (int fd,
map = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, start);
if (!map)
{
gs_set_error_from_errno (error, errno);
glnx_set_error_from_errno (error);
goto out;
}

View File

@ -113,8 +113,8 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro
merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname);
/* Here we perform cleanup of any leftover data from previous
* partial failures. This avoids having to call gs_shutil_rm_rf()
* at random points throughout the process.
* partial failures. This avoids having to call
* glnx_shutil_rm_rf_at() at random points throughout the process.
*
* TODO: Add /ostree/transaction file, and only do this cleanup if
* we find it.

View File

@ -40,8 +40,6 @@ ot_admin_builtin_os_init (int argc, char **argv, GCancellable *cancellable, GErr
glnx_unref_object OstreeSysroot *sysroot = NULL;
gboolean ret = FALSE;
const char *osname = NULL;
g_autoptr(GFile) deploy_dir = NULL;
g_autoptr(GFile) dir = NULL;
context = g_option_context_new ("OSNAME - Initialize empty state for given operating system");
@ -61,48 +59,10 @@ ot_admin_builtin_os_init (int argc, char **argv, GCancellable *cancellable, GErr
osname = argv[1];
deploy_dir = ot_gfile_get_child_build_path (ostree_sysroot_get_path (sysroot), "ostree", "deploy", osname, NULL);
/* Ensure core subdirectories of /var exist, since we need them for
* dracut generation, and the host will want them too.
*/
g_clear_object (&dir);
dir = ot_gfile_get_child_build_path (deploy_dir, "var", "tmp", NULL);
if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
goto out;
if (chmod (gs_file_get_path_cached (dir), 01777) < 0)
{
gs_set_error_from_errno (error, errno);
goto out;
}
g_clear_object (&dir);
dir = ot_gfile_get_child_build_path (deploy_dir, "var", "lib", NULL);
if (!gs_file_ensure_directory (dir, TRUE, cancellable, error))
if (!ostree_sysroot_init_osname (sysroot, osname, cancellable, error))
goto out;
g_clear_object (&dir);
dir = ot_gfile_get_child_build_path (deploy_dir, "var", "run", NULL);
if (!g_file_test (gs_file_get_path_cached (dir), G_FILE_TEST_IS_SYMLINK))
{
if (symlink ("../run", gs_file_get_path_cached (dir)) < 0)
{
gs_set_error_from_errno (error, errno);
goto out;
}
}
dir = ot_gfile_get_child_build_path (deploy_dir, "var", "lock", NULL);
if (!g_file_test (gs_file_get_path_cached (dir), G_FILE_TEST_IS_SYMLINK))
{
if (symlink ("../run/lock", gs_file_get_path_cached (dir)) < 0)
{
gs_set_error_from_errno (error, errno);
goto out;
}
}
g_print ("%s initialized as OSTree root\n", gs_file_get_path_cached (deploy_dir));
g_print ("ostree/deploy/%s initialized as OSTree root\n", osname);
ret = TRUE;
out:

View File

@ -89,6 +89,9 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
glnx_unref_object OstreeRepo *repo = NULL;
OstreeDeployment *booted_deployment = NULL;
g_autoptr(GPtrArray) deployments = NULL;
const int is_tty = isatty (1);
const char *red_bold_prefix = is_tty ? "\x1b[31m\x1b[1m" : "";
const char *red_bold_suffix = is_tty ? "\x1b[22m\x1b[0m" : "";
guint i;
context = g_option_context_new ("List deployments");
@ -118,12 +121,15 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
OstreeDeployment *deployment = deployments->pdata[i];
GKeyFile *origin;
const char *ref = ostree_deployment_get_csum (deployment);
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;
origin = ostree_deployment_get_origin (deployment);
g_print ("%c %s %s.%d\n",
deployment == booted_deployment ? '*' : ' ',
ostree_deployment_get_osname (deployment),
@ -131,7 +137,15 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro
ostree_deployment_get_deployserial (deployment));
if (version)
g_print (" Version: %s\n", version);
origin = ostree_deployment_get_origin (deployment);
switch (unlocked)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
break;
default:
g_print (" %sUnlocked: %s%s\n", red_bold_prefix,
ostree_deployment_unlocked_state_to_string (unlocked),
red_bold_suffix);
}
if (!origin)
g_print (" origin: none\n");
else

View File

@ -34,6 +34,7 @@ static gboolean opt_reboot;
static char *opt_osname;
static GOptionEntry options[] = {
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after switching trees", NULL },
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" },
{ NULL }
};
@ -162,16 +163,11 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
goto out;
{
g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/");
if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
{
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
cancellable, error,
"systemctl", "reboot", NULL);
}
}
if (opt_reboot)
{
if (!ot_admin_execve_reboot (sysroot, error))
goto out;
}
ret = TRUE;
out:

View File

@ -0,0 +1,104 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2016 Colin Walters <walters@verbum.org>
*
* 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 "ot-main.h"
#include "ot-admin-builtins.h"
#include "ot-admin-functions.h"
#include "ostree.h"
#include "otutil.h"
#include "../libostree/ostree-kernel-args.h"
#include <glib/gi18n.h>
#include <err.h>
static gboolean opt_hotfix;
static GOptionEntry options[] = {
{ "hotfix", 0, 0, G_OPTION_ARG_NONE, &opt_hotfix, "Keep the current deployment as default", NULL },
{ NULL }
};
gboolean
ot_admin_builtin_unlock (int argc, char **argv, GCancellable *cancellable, GError **error)
{
gboolean ret = FALSE;
GOptionContext *context;
glnx_unref_object OstreeSysroot *sysroot = NULL;
glnx_unref_object OstreeRepo *repo = NULL;
g_autoptr(GPtrArray) new_deployments = NULL;
glnx_unref_object OstreeDeployment *merge_deployment = NULL;
OstreeDeployment *booted_deployment = NULL;
OstreeDeploymentUnlockedState target_state;
context = g_option_context_new ("Make the current deployment mutable (as a hotfix or development)");
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
&sysroot, cancellable, error))
goto out;
if (argc > 1)
{
ot_util_usage_error (context, "This command takes no extra arguments", error);
goto out;
}
if (!ostree_sysroot_load (sysroot, cancellable, error))
goto out;
booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
if (!booted_deployment)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Not currently booted into an OSTree system");
goto out;
}
target_state = opt_hotfix ? OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX : OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT;
if (!ostree_sysroot_deployment_unlock (sysroot, booted_deployment,
target_state, cancellable, error))
goto out;
switch (target_state)
{
case OSTREE_DEPLOYMENT_UNLOCKED_NONE:
g_assert_not_reached ();
break;
case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX:
g_print ("Hotfix mode enabled. A writable overlayfs is now mounted on /usr\n"
"for this booted deployment. A non-hotfixed clone has been created\n"
"as the non-default rollback target.\n");
break;
case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT:
g_print ("Development mode enabled. A writable overlayfs is now mounted on /usr.\n"
"All changes there will be discarded on reboot.\n");
break;
}
ret = TRUE;
out:
if (context)
g_option_context_free (context);
return ret;
}

View File

@ -97,6 +97,9 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr
"override-commit", NULL);
}
/* Should we consider requiring --discard-hotfix here? */
origin_changed |= g_key_file_remove_key (origin, "origin", "unlocked", NULL);
if (origin_changed)
{
/* XXX GCancellable parameter is not used. */
@ -133,16 +136,13 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr
}
else
{
g_autoptr(GFile) real_sysroot = g_file_new_for_path ("/");
if (!ostree_sysroot_upgrader_deploy (upgrader, cancellable, error))
goto out;
if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
if (opt_reboot)
{
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
cancellable, error,
"systemctl", "reboot", NULL);
if (!ot_admin_execve_reboot (sysroot, error))
goto out;
}
}

View File

@ -34,6 +34,7 @@ gboolean ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancella
gboolean ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error);
gboolean ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GError **error);
gboolean ot_admin_builtin_cleanup (int argc, char **argv, GCancellable *cancellable, GError **error);
gboolean ot_admin_builtin_unlock (int argc, char **argv, GCancellable *cancellable, GError **error);
gboolean ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GError **error);
gboolean ot_admin_builtin_set_origin (int argc, char **argv, GCancellable *cancellable, GError **error);
gboolean ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError **error);

View File

@ -155,3 +155,20 @@ ot_admin_sysroot_lock (OstreeSysroot *sysroot,
g_main_context_unref (state.mainctx);
return ret;
}
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 (execl ("systemctl", "systemctl", "reboot", NULL) < 0)
{
glnx_set_error_from_errno (error);
return FALSE;
}
}
return TRUE;
}

View File

@ -45,5 +45,8 @@ gboolean
ot_admin_sysroot_lock (OstreeSysroot *sysroot,
GError **error);
gboolean
ot_admin_execve_reboot (OstreeSysroot *sysroot,
GError **error);
G_END_DECLS

View File

@ -47,6 +47,7 @@ static OstreeAdminCommand admin_subcommands[] = {
{ "status", ot_admin_builtin_status },
{ "switch", ot_admin_builtin_switch },
{ "undeploy", ot_admin_builtin_undeploy },
{ "unlock", ot_admin_builtin_unlock },
{ "upgrade", ot_admin_builtin_upgrade },
{ NULL, NULL }
};

View File

@ -27,41 +27,28 @@
#include "ostree.h"
static gboolean opt_delete;
static gboolean opt_list;
static GOptionEntry options[] = {
{ "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Delete refs which match PREFIX, rather than listing them", NULL },
{ "list", 0, 0, G_OPTION_ARG_NONE, &opt_list, "Do not remove the prefix from the refs", NULL },
{ NULL }
};
gboolean
ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError **error)
static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellable *cancellable, GError **error)
{
gboolean ret = FALSE;
GOptionContext *context;
glnx_unref_object OstreeRepo *repo = NULL;
const char *refspec_prefix = NULL;
g_autoptr(GHashTable) refs = NULL;
GHashTableIter hashiter;
gpointer hashkey, hashvalue;
gboolean ret = FALSE;
context = g_option_context_new ("[PREFIX] - List refs");
if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
goto out;
if (argc >= 2)
refspec_prefix = argv[1];
/* Require a prefix when deleting to help avoid accidents. */
if (opt_delete && refspec_prefix == NULL)
if (opt_delete || opt_list)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"PREFIX is required when deleting refs");
goto out;
if (!ostree_repo_list_refs_ext (repo, refspec_prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE,
cancellable, error))
goto out;
}
if (!ostree_repo_list_refs (repo, refspec_prefix, &refs,
cancellable, error))
else if (!ostree_repo_list_refs (repo, refspec_prefix, &refs, cancellable, error))
goto out;
if (!opt_delete)
@ -90,6 +77,41 @@ ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError **
goto out;
}
}
ret = TRUE;
out:
return ret;
}
gboolean
ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError **error)
{
gboolean ret = FALSE;
GOptionContext *context;
glnx_unref_object OstreeRepo *repo = NULL;
int i;
context = g_option_context_new ("[PREFIX] - List refs");
if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error))
goto out;
if (argc >= 2)
{
for (i = 1; i < argc; i++)
if (!do_ref (repo, argv[i], cancellable, error))
goto out;
}
else
{
/* Require a prefix when deleting to help avoid accidents. */
if (opt_delete)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"At least one PREFIX is required when deleting refs");
goto out;
}
ret = do_ref (repo, NULL, cancellable, error);
}
ret = TRUE;
out:

View File

@ -427,10 +427,9 @@ ostree_builtin_trivial_httpd (int argc, char **argv, GCancellable *cancellable,
*/
if (prctl (PR_SET_PDEATHSIG, SIGTERM) != 0)
{
int errsv = errno;
if (errsv != ENOSYS)
if (errno != ENOSYS)
{
gs_set_error_from_errno (error, errsv);
glnx_set_error_from_errno (error);
goto out;
}
}

View File

@ -62,8 +62,7 @@ ot_editor_prompt (OstreeRepo *repo,
GCancellable *cancellable,
GError **error)
{
glnx_unref_object GSSubprocessContext *ctx = NULL;
glnx_unref_object GSSubprocess *proc = NULL;
glnx_unref_object GSubprocess *proc = NULL;
g_autoptr(GFile) file = NULL;
g_autoptr(GFileIOStream) io = NULL;
GOutputStream *output;
@ -92,16 +91,11 @@ ot_editor_prompt (OstreeRepo *repo,
g_autofree char *quoted_file = g_shell_quote (gs_file_get_path_cached (file));
args = g_strconcat (editor, " ", quoted_file, NULL);
}
ctx = gs_subprocess_context_newv ("/bin/sh", "-c", args, NULL);
gs_subprocess_context_set_stdin_disposition (ctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT);
gs_subprocess_context_set_stdout_disposition (ctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT);
gs_subprocess_context_set_stderr_disposition (ctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT);
proc = gs_subprocess_new (ctx, cancellable, error);
if (proc == NULL)
goto out;
proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDIN_INHERIT, error,
"/bin/sh", "-c", args, NULL);
if (!gs_subprocess_wait_sync_check (proc, cancellable, error))
if (!g_subprocess_wait_check (proc, cancellable, error))
{
g_prefix_error (error, "There was a problem with the editor '%s'", editor);
goto out;

View File

@ -294,7 +294,8 @@ ostree_option_context_parse (GOptionContext *context,
}
}
gs_transfer_out_value (out_repo, &repo);
if (out_repo)
*out_repo = g_steal_pointer (&repo);
success = TRUE;
@ -375,7 +376,8 @@ ostree_admin_option_context_parse (GOptionContext *context,
goto out;
}
gs_transfer_out_value (out_sysroot, &sysroot);
if (out_sysroot)
*out_sysroot = g_steal_pointer (&sysroot);
success = TRUE;

View File

@ -24,10 +24,8 @@
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/xattr.h>
@ -227,7 +225,7 @@ callback_symlink (const char *from, const char *to)
{
fprintf (stderr, "Failed to find newly created symlink '%s': %s\n",
to, g_strerror (errno));
exit (1);
exit (EXIT_FAILURE);
}
return 0;
}
@ -263,7 +261,7 @@ can_write (const char *path)
else
return -errno;
}
if (devino_set_contains (stbuf.st_dev, stbuf.st_ino))
if (!devino_set_contains (stbuf.st_dev, stbuf.st_ino))
return -EROFS;
return 0;
}
@ -545,7 +543,7 @@ rofs_parse_opt (void *data, const char *arg, int key,
if (basefd == -1)
{
perror ("openat");
exit (1);
exit (EXIT_FAILURE);
}
return 0;
}
@ -557,10 +555,10 @@ rofs_parse_opt (void *data, const char *arg, int key,
return 1;
case KEY_HELP:
usage (outargs->argv[0]);
exit (0);
exit (EXIT_SUCCESS);
default:
fprintf (stderr, "see `%s -h' for usage\n", outargs->argv[0]);
exit (1);
exit (EXIT_FAILURE);
}
return 1;
}
@ -584,13 +582,13 @@ main (int argc, char *argv[])
{
fprintf (stderr, "Invalid arguments\n");
fprintf (stderr, "see `%s -h' for usage\n", argv[0]);
exit (1);
exit (EXIT_FAILURE);
}
if (basefd == -1)
{
fprintf (stderr, "Missing basepath\n");
fprintf (stderr, "see `%s -h' for usage\n", argv[0]);
exit (1);
exit (EXIT_FAILURE);
}
created_devino_hash = g_hash_table_new_full (devino_hash, devino_equal, g_free, NULL);

View File

@ -26,6 +26,10 @@
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sys/mount.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/statvfs.h>
#include "ostree-mount-util.h"
@ -48,3 +52,18 @@ perrorv (const char *format, ...)
return 0;
}
int
path_is_on_readonly_fs (char *path)
{
struct statvfs stvfsbuf;
if (statvfs (path, &stvfsbuf) == -1)
{
perrorv ("statvfs(%s): ", path);
exit (EXIT_FAILURE);
}
return (stvfsbuf.f_flag & ST_RDONLY) != 0;
}

View File

@ -22,3 +22,5 @@
#pragma once
int perrorv (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
int path_is_on_readonly_fs (char *path);

View File

@ -111,7 +111,6 @@ touch_run_ostree (void)
int
main(int argc, char *argv[])
{
const char *readonly_bind_mounts[] = { "/usr", NULL };
const char *root_mountpoint = NULL;
char *ostree_target = NULL;
char *deploy_path = NULL;
@ -119,7 +118,7 @@ main(int argc, char *argv[])
char destpath[PATH_MAX];
char newroot[PATH_MAX];
struct stat stbuf;
int i;
int orig_cwd_dfd;
if (argc < 2)
{
@ -211,21 +210,70 @@ main(int argc, char *argv[])
}
}
/* Set up any read-only bind mounts (notably /usr) */
for (i = 0; readonly_bind_mounts[i] != NULL; i++)
/* Here we do a dance to chdir to the newroot so that we can have
* the potential overlayfs mount points not look ugly. However...I
* think we could do this a lot earlier and make all of the mounts
* here just be relative.
*/
orig_cwd_dfd = openat (AT_FDCWD, ".", O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
if (orig_cwd_dfd < 0)
{
snprintf (destpath, sizeof(destpath), "%s%s", newroot, readonly_bind_mounts[i]);
if (mount (destpath, destpath, NULL, MS_BIND, NULL) < 0)
perrorv ("failed to open .");
exit (EXIT_FAILURE);
}
if (chdir (newroot) < 0)
{
perrorv ("failed to chdir to newroot");
exit (EXIT_FAILURE);
}
/* Do we have a persistent overlayfs for /usr? If so, mount it now. */
if (lstat (".usr-ovl-work", &stbuf) == 0)
{
const char usr_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work";
/* Except overlayfs barfs if we try to mount it on a read-only
* filesystem. For this use case I think admins are going to be
* okay if we remount the rootfs here, rather than waiting until
* later boot and `systemd-remount-fs.service`.
*/
if (path_is_on_readonly_fs ("."))
{
perrorv ("failed to bind mount (class:readonly) %s", destpath);
exit (EXIT_FAILURE);
if (mount (".", ".", NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
{
perrorv ("Failed to remount rootfs writable (for overlayfs)");
exit (EXIT_FAILURE);
}
}
if (mount (destpath, destpath, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0)
if (mount ("overlay", "usr", "overlay", 0, usr_ovl_options) < 0)
{
perrorv ("failed to bind mount (class:readonly) %s", destpath);
perrorv ("failed to mount /usr overlayfs");
exit (EXIT_FAILURE);
}
}
else
{
/* Otherwise, a read-only bind mount for /usr */
if (mount ("usr", "usr", NULL, MS_BIND, NULL) < 0)
{
perrorv ("failed to bind mount (class:readonly) /usr");
exit (EXIT_FAILURE);
}
if (mount ("usr", "usr", NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL) < 0)
{
perrorv ("failed to bind mount (class:readonly) /usr");
exit (EXIT_FAILURE);
}
}
if (fchdir (orig_cwd_dfd) < 0)
{
perrorv ("failed to chdir to orig root");
exit (EXIT_FAILURE);
}
(void) close (orig_cwd_dfd);
touch_run_ostree ();

View File

@ -37,20 +37,6 @@
#include "ostree-mount-util.h"
static int
path_is_on_readonly_fs (char *path)
{
struct statvfs stvfsbuf;
if (statvfs (path, &stvfsbuf) == -1)
{
perrorv ("statvfs(%s): ", path);
exit (EXIT_FAILURE);
}
return (stvfsbuf.f_flag & ST_RDONLY) != 0;
}
/* 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

View File

@ -1,4 +1,4 @@
#
#!/bin/sh
# Copyright (C) 2011,2014 Colin Walters <walters@verbum.org>
#
# This library is free software; you can redistribute it and/or
@ -18,7 +18,7 @@
set -euo pipefail
echo "1..10"
echo "1..16"
function validate_bootloader() {
(cd ${test_tmpdir};
@ -27,11 +27,14 @@ function validate_bootloader() {
fi)
}
orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy)
${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime
rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime)
export rev
# This initial deployment gets kicked off with some kernel arguments
${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime
new_mtime=$(stat -c '%.Y' sysroot/ostree/deploy)
assert_not_streq "${orig_mtime}" "${new_mtime}"
${CMD_PREFIX} ostree admin status | tee status.txt
validate_bootloader
@ -56,7 +59,10 @@ ${CMD_PREFIX} ostree admin status
echo "ok layout"
orig_mtime=$(stat -c '%.Y' sysroot/ostree/deploy)
${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime
new_mtime=$(stat -c '%.Y' sysroot/ostree/deploy)
assert_not_streq "${orig_mtime}" "${new_mtime}"
# Need a new bootversion, sine we now have two deployments
assert_has_dir sysroot/boot/loader.0
assert_not_has_dir sysroot/boot/loader.1

View File

@ -19,7 +19,7 @@
set -euo pipefail
echo "1..48"
echo "1..50"
$OSTREE checkout test2 checkout-test2
echo "ok checkout"
@ -41,14 +41,6 @@ echo "ok shortened checksum"
(cd repo && ${CMD_PREFIX} ostree rev-parse test2)
echo "ok repo-in-cwd"
$OSTREE refs > reflist
assert_file_has_content reflist '^test2$'
rm reflist
$OSTREE refs --delete 2>/dev/null && (echo 1>&2 "refs --delete (without prefix) unexpectedly succeeded!"; exit 1)
echo "ok refs"
cd checkout-test2
assert_has_file firstfile
assert_has_file baz/cow
@ -246,15 +238,6 @@ if test -s file-objects; then
fi
echo "ok prune in archive-z2 deleted everything"
cd ${test_tmpdir}
$OSTREE commit -b test3 -s "Another commit" --tree=ref=test2
${CMD_PREFIX} ostree --repo=repo refs > reflist
assert_file_has_content reflist '^test3$'
${CMD_PREFIX} ostree --repo=repo refs --delete test3
${CMD_PREFIX} ostree --repo=repo refs > reflist
assert_not_file_has_content reflist '^test3$'
echo "ok reflist --delete"
cd ${test_tmpdir}
rm -rf test2-checkout
$OSTREE checkout test2 test2-checkout
@ -442,6 +425,8 @@ if test "$(id -u)" != "0"; then
assert_has_file expected-fail
assert_file_has_content error-message "Permission denied"
echo "ok unwritable repo was caught"
else
echo "ok # SKIP not run when root"
fi
cd ${test_tmpdir}
@ -449,10 +434,12 @@ rm -rf test2-checkout
mkdir -p test2-checkout
cd test2-checkout
touch blah
stat --printf="%Z\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-orig.txt
stat --printf="%.Y\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-orig.txt
$OSTREE commit -b test2 -s "Should bump the mtime"
stat --printf="%Z\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-new.txt
stat --printf="%.Y\n" ${test_tmpdir}/repo > ${test_tmpdir}/timestamp-new.txt
cd ..
if ! cmp timestamp-{orig,new}.txt; then
if cmp timestamp-{orig,new}.txt; then
assert_not_reached "failed to update mtime on repo"
fi
echo "ok mtime updated"

Some files were not shown because too many files have changed in this diff Show More