diff --git a/Makefile-bash.am b/Makefile-bash.am new file mode 100644 index 00000000..e61829a2 --- /dev/null +++ b/Makefile-bash.am @@ -0,0 +1,21 @@ +# Makefile for bash/ +# +# Copyright (C) 2017 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +completionsdir = @BASH_COMPLETIONSDIR@ +dist_completions_DATA = bash/ostree diff --git a/Makefile-otutil.am b/Makefile-otutil.am index db632705..ff7533e9 100644 --- a/Makefile-otutil.am +++ b/Makefile-otutil.am @@ -36,8 +36,6 @@ libotutil_la_SOURCES = \ src/libotutil/ot-variant-utils.h \ src/libotutil/ot-gio-utils.c \ src/libotutil/ot-gio-utils.h \ - src/libotutil/ot-log-utils.c \ - src/libotutil/ot-log-utils.h \ src/libotutil/ot-gpg-utils.c \ src/libotutil/ot-gpg-utils.h \ src/libotutil/otutil.c \ diff --git a/Makefile.am b/Makefile.am index 0939d4b7..b542d3c1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -111,6 +111,7 @@ endif include Makefile-tests.am include Makefile-boot.am include Makefile-man.am +include Makefile-bash.am release-tag: cd $(srcdir) && git $(srcdir) tag -m "Release $(VERSION)" v$(VERSION) diff --git a/Makefile.in b/Makefile.in index 522179f4..73d58487 100644 --- a/Makefile.in +++ b/Makefile.in @@ -259,6 +259,25 @@ # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. +# Makefile for bash/ +# +# Copyright (C) 2017 Red Hat Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + @@ -528,7 +547,8 @@ am__aclocal_m4_deps = $(top_srcdir)/buildutil/attributes.m4 \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(am__dist_gpginsttest_DATA_DIST) \ + $(am__configure_deps) $(dist_completions_DATA) \ + $(am__dist_gpginsttest_DATA_DIST) \ $(am__dist_gpginsttest_trusted_DATA_DIST) \ $(am__dist_gpgvinsttest_DATA_DIST) \ $(am__libostreeinclude_HEADERS_DIST) $(am__DIST_COMMON) @@ -576,7 +596,7 @@ am__installdirs = "$(DESTDIR)$(installed_testdir)" \ "$(DESTDIR)$(mkinitcpioinstalldir)" \ "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" \ "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" \ - "$(DESTDIR)$(gpginsttestdir)" \ + "$(DESTDIR)$(completionsdir)" "$(DESTDIR)$(gpginsttestdir)" \ "$(DESTDIR)$(gpginsttest_trusteddir)" \ "$(DESTDIR)$(gpgvinsttestdir)" "$(DESTDIR)$(dracutconfdir)" \ "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" \ @@ -846,7 +866,6 @@ am_libotutil_la_OBJECTS = \ src/libotutil/libotutil_la-ot-unix-utils.lo \ src/libotutil/libotutil_la-ot-variant-utils.lo \ src/libotutil/libotutil_la-ot-gio-utils.lo \ - src/libotutil/libotutil_la-ot-log-utils.lo \ src/libotutil/libotutil_la-ot-gpg-utils.lo \ src/libotutil/libotutil_la-otutil.lo \ src/libotutil/libotutil_la-ot-tool-util.lo $(am__objects_1) @@ -1396,12 +1415,13 @@ am__dist_gpginsttest_trusted_DATA_DIST = \ tests/gpghome/trusted/pubring.gpg am__dist_gpgvinsttest_DATA_DIST = $(addprefix tests/gpg-verify-data/, \ gpg.conf lgpl2 lgpl2.sig pubring.gpg secring.gpg trustdb.gpg) -DATA = $(dist_gpginsttest_DATA) $(dist_gpginsttest_trusted_DATA) \ - $(dist_gpgvinsttest_DATA) $(dracutconf_DATA) $(gir_DATA) \ - $(gpgreadme_DATA) $(installed_test_DATA) \ - $(installed_test_meta_DATA) $(mkinitcpioconf_DATA) \ - $(nobase_installed_test_DATA) $(noinst_DATA) $(pkgconfig_DATA) \ - $(systemdsystemunit_DATA) $(typelib_DATA) +DATA = $(dist_completions_DATA) $(dist_gpginsttest_DATA) \ + $(dist_gpginsttest_trusted_DATA) $(dist_gpgvinsttest_DATA) \ + $(dracutconf_DATA) $(gir_DATA) $(gpgreadme_DATA) \ + $(installed_test_DATA) $(installed_test_meta_DATA) \ + $(mkinitcpioconf_DATA) $(nobase_installed_test_DATA) \ + $(noinst_DATA) $(pkgconfig_DATA) $(systemdsystemunit_DATA) \ + $(typelib_DATA) am__libostreeinclude_HEADERS_DIST = src/libostree/ostree.h \ src/libostree/ostree-async-progress.h \ src/libostree/ostree-autocleanups.h \ @@ -1679,8 +1699,8 @@ TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ $(TEST_LOG_FLAGS) DIST_SUBDIRS = . apidoc -am__DIST_COMMON = $(srcdir)/Makefile-boot.am \ - $(srcdir)/Makefile-decls.am \ +am__DIST_COMMON = $(srcdir)/Makefile-bash.am \ + $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-decls.am \ $(srcdir)/Makefile-libostree-defines.am \ $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-man.am \ $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-otutil.am \ @@ -1753,6 +1773,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BASH_COMPLETIONSDIR = @BASH_COMPLETIONSDIR@ BUILDOPT_FUSE_CFLAGS = @BUILDOPT_FUSE_CFLAGS@ BUILDOPT_FUSE_LIBS = @BUILDOPT_FUSE_LIBS@ CC = @CC@ @@ -2152,8 +2173,6 @@ libotutil_la_SOURCES = \ src/libotutil/ot-variant-utils.h \ src/libotutil/ot-gio-utils.c \ src/libotutil/ot-gio-utils.h \ - src/libotutil/ot-log-utils.c \ - src/libotutil/ot-log-utils.h \ src/libotutil/ot-gpg-utils.c \ src/libotutil/ot-gpg-utils.h \ src/libotutil/otutil.c \ @@ -2643,6 +2662,8 @@ tests_test_gpg_verify_result_LDADD = $(TESTS_LDADD) $(OT_INTERNAL_GPGME_LIBS) @ENABLE_MAN_TRUE@ --stringparam man.copyright.section.enabled 0 @ENABLE_MAN_TRUE@XSLTPROC_MAN = $(XSLTPROC) $(XSLTPROC_FLAGS) +completionsdir = @BASH_COMPLETIONSDIR@ +dist_completions_DATA = bash/ostree embed_dependency = tar -C $(srcdir) --append --exclude='.git/*' --transform="s,^embedded-dependencies/,ostree-embeddeps-$${GITVERSION}/embedded-dependencies/," --file=$${TARFILE_TMP} git_version_rpm = $$(cd $(srcdir) && git describe | sed -e 's,-,\.,g' -e 's,^v,,') all: $(BUILT_SOURCES) config.h @@ -2652,7 +2673,7 @@ all: $(BUILT_SOURCES) config.h .SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs am--refresh: Makefile @: -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile-decls.am $(top_srcdir)/buildutil/glib-tap.mk $(srcdir)/libglnx/Makefile-libglnx.am.inc $(srcdir)/bsdiff/Makefile-bsdiff.am.inc $(srcdir)/Makefile-otutil.am $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-libostree-defines.am $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-switchroot.am $(srcdir)/src/rofiles-fuse/Makefile-inc.am $(srcdir)/Makefile-tests.am $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-man.am $(am__configure_deps) +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile-decls.am $(top_srcdir)/buildutil/glib-tap.mk $(srcdir)/libglnx/Makefile-libglnx.am.inc $(srcdir)/bsdiff/Makefile-bsdiff.am.inc $(srcdir)/Makefile-otutil.am $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-libostree-defines.am $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-switchroot.am $(srcdir)/src/rofiles-fuse/Makefile-inc.am $(srcdir)/Makefile-tests.am $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-man.am $(srcdir)/Makefile-bash.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ @@ -2674,7 +2695,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; -$(srcdir)/Makefile-decls.am $(top_srcdir)/buildutil/glib-tap.mk $(srcdir)/libglnx/Makefile-libglnx.am.inc $(srcdir)/bsdiff/Makefile-bsdiff.am.inc $(srcdir)/Makefile-otutil.am $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-libostree-defines.am $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-switchroot.am $(srcdir)/src/rofiles-fuse/Makefile-inc.am $(srcdir)/Makefile-tests.am $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-man.am $(am__empty): +$(srcdir)/Makefile-decls.am $(top_srcdir)/buildutil/glib-tap.mk $(srcdir)/libglnx/Makefile-libglnx.am.inc $(srcdir)/bsdiff/Makefile-bsdiff.am.inc $(srcdir)/Makefile-otutil.am $(srcdir)/Makefile-libostree.am $(srcdir)/Makefile-libostree-defines.am $(srcdir)/Makefile-ostree.am $(srcdir)/Makefile-switchroot.am $(srcdir)/src/rofiles-fuse/Makefile-inc.am $(srcdir)/Makefile-tests.am $(srcdir)/Makefile-boot.am $(srcdir)/Makefile-man.am $(srcdir)/Makefile-bash.am $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck @@ -3113,9 +3134,6 @@ src/libotutil/libotutil_la-ot-variant-utils.lo: \ src/libotutil/libotutil_la-ot-gio-utils.lo: \ src/libotutil/$(am__dirstamp) \ src/libotutil/$(DEPDIR)/$(am__dirstamp) -src/libotutil/libotutil_la-ot-log-utils.lo: \ - src/libotutil/$(am__dirstamp) \ - src/libotutil/$(DEPDIR)/$(am__dirstamp) src/libotutil/libotutil_la-ot-gpg-utils.lo: \ src/libotutil/$(am__dirstamp) \ src/libotutil/$(DEPDIR)/$(am__dirstamp) @@ -4220,7 +4238,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-gio-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-keyfile-utils.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-log-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-opt-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-tool-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/libotutil/$(DEPDIR)/libotutil_la-ot-unix-utils.Plo@am__quote@ @@ -4910,13 +4927,6 @@ src/libotutil/libotutil_la-ot-gio-utils.lo: src/libotutil/ot-gio-utils.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-gio-utils.lo `test -f 'src/libotutil/ot-gio-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gio-utils.c -src/libotutil/libotutil_la-ot-log-utils.lo: src/libotutil/ot-log-utils.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-log-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-log-utils.Tpo -c -o src/libotutil/libotutil_la-ot-log-utils.lo `test -f 'src/libotutil/ot-log-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-log-utils.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-log-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-log-utils.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/libotutil/ot-log-utils.c' object='src/libotutil/libotutil_la-ot-log-utils.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -c -o src/libotutil/libotutil_la-ot-log-utils.lo `test -f 'src/libotutil/ot-log-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-log-utils.c - src/libotutil/libotutil_la-ot-gpg-utils.lo: src/libotutil/ot-gpg-utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libotutil_la_CFLAGS) $(CFLAGS) -MT src/libotutil/libotutil_la-ot-gpg-utils.lo -MD -MP -MF src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Tpo -c -o src/libotutil/libotutil_la-ot-gpg-utils.lo `test -f 'src/libotutil/ot-gpg-utils.c' || echo '$(srcdir)/'`src/libotutil/ot-gpg-utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Tpo src/libotutil/$(DEPDIR)/libotutil_la-ot-gpg-utils.Plo @@ -6370,6 +6380,27 @@ uninstall-man5: } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) +install-dist_completionsDATA: $(dist_completions_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_completions_DATA)'; test -n "$(completionsdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(completionsdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(completionsdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(completionsdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(completionsdir)" || exit $$?; \ + done + +uninstall-dist_completionsDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_completions_DATA)'; test -n "$(completionsdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(completionsdir)'; $(am__uninstall_files_from_dir) install-dist_gpginsttestDATA: $(dist_gpginsttest_DATA) @$(NORMAL_INSTALL) @list='$(dist_gpginsttest_DATA)'; test -n "$(gpginsttestdir)" || list=; \ @@ -7827,7 +7858,7 @@ install-binPROGRAMS: install-libLTLIBRARIES installdirs: installdirs-recursive installdirs-am: - for dir in "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(privlibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(systemdsystemgeneratordir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(mkinitcpioinstalldir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(gpginsttestdir)" "$(DESTDIR)$(gpginsttest_trusteddir)" "$(DESTDIR)$(gpgvinsttestdir)" "$(DESTDIR)$(dracutconfdir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(installed_test_metadir)" "$(DESTDIR)$(mkinitcpioconfdir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(typelibdir)" "$(DESTDIR)$(libostreeincludedir)"; do \ + for dir in "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(privlibdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(systemdsystemgeneratordir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(dracutmoddir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(mkinitcpioinstalldir)" "$(DESTDIR)$(ostree_bootdir)" "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(completionsdir)" "$(DESTDIR)$(gpginsttestdir)" "$(DESTDIR)$(gpginsttest_trusteddir)" "$(DESTDIR)$(gpgvinsttestdir)" "$(DESTDIR)$(dracutconfdir)" "$(DESTDIR)$(girdir)" "$(DESTDIR)$(gpgreadmedir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(installed_test_metadir)" "$(DESTDIR)$(mkinitcpioconfdir)" "$(DESTDIR)$(installed_testdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(typelibdir)" "$(DESTDIR)$(libostreeincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) @@ -7915,7 +7946,8 @@ info: info-recursive info-am: -install-data-am: install-dist_gpginsttestDATA \ +install-data-am: install-dist_completionsDATA \ + install-dist_gpginsttestDATA \ install-dist_gpginsttest_trustedDATA \ install-dist_gpgvinsttestDATA install-dracutconfDATA \ install-dracutmodSCRIPTS install-girDATA install-gpgreadmeDATA \ @@ -7981,7 +8013,7 @@ ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-binSCRIPTS \ - uninstall-dist_gpginsttestDATA \ + uninstall-dist_completionsDATA uninstall-dist_gpginsttestDATA \ uninstall-dist_gpginsttest_trustedDATA \ uninstall-dist_gpgvinsttestDATA uninstall-dracutconfDATA \ uninstall-dracutmodSCRIPTS uninstall-girDATA \ @@ -8023,7 +8055,7 @@ uninstall-man: uninstall-man1 uninstall-man5 distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binPROGRAMS install-binSCRIPTS \ install-data install-data-am install-data-hook \ - install-dist_gpginsttestDATA \ + install-dist_completionsDATA install-dist_gpginsttestDATA \ install-dist_gpginsttest_trustedDATA \ install-dist_gpgvinsttestDATA install-dracutconfDATA \ install-dracutmodSCRIPTS install-dvi install-dvi-am \ @@ -8048,7 +8080,7 @@ uninstall-man: uninstall-man1 uninstall-man5 mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ recheck tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS uninstall-binSCRIPTS \ - uninstall-dist_gpginsttestDATA \ + uninstall-dist_completionsDATA uninstall-dist_gpginsttestDATA \ uninstall-dist_gpginsttest_trustedDATA \ uninstall-dist_gpgvinsttestDATA uninstall-dracutconfDATA \ uninstall-dracutmodSCRIPTS uninstall-girDATA \ diff --git a/README.md b/README.md index c985cd14..743d49df 100644 --- a/README.md +++ b/README.md @@ -98,9 +98,6 @@ 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: - - Contributing ------------ diff --git a/apidoc/Makefile.in b/apidoc/Makefile.in index 26ac6b1e..022a0f97 100644 --- a/apidoc/Makefile.in +++ b/apidoc/Makefile.in @@ -189,6 +189,7 @@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ +BASH_COMPLETIONSDIR = @BASH_COMPLETIONSDIR@ BUILDOPT_FUSE_CFLAGS = @BUILDOPT_FUSE_CFLAGS@ BUILDOPT_FUSE_LIBS = @BUILDOPT_FUSE_LIBS@ CC = @CC@ diff --git a/apidoc/html/index.html b/apidoc/html/index.html index 7a1aefbf..cce508d9 100644 --- a/apidoc/html/index.html +++ b/apidoc/html/index.html @@ -14,7 +14,7 @@
-

for OSTree 2017.9

+

for OSTree 2017.10


diff --git a/apidoc/html/ostree-Content-addressed-object-store.html b/apidoc/html/ostree-Content-addressed-object-store.html index ba5d4e11..ee519691 100644 --- a/apidoc/html/ostree-Content-addressed-object-store.html +++ b/apidoc/html/ostree-Content-addressed-object-store.html @@ -52,6 +52,14 @@ OstreeRepo * +ostree_repo_open_at () + + + + +OstreeRepo * + + ostree_repo_new () @@ -113,6 +121,14 @@ +OstreeRepo * + + +ostree_repo_create_at () + + + + gboolean @@ -348,6 +364,14 @@ gboolean +ostree_repo_set_alias_ref_immediate () + + + + +gboolean + + ostree_repo_set_cache_dir () @@ -1158,6 +1182,47 @@ ostree_repo_mode_from_string (const +

ostree_repo_open_at ()

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

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

+
+

Parameters

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

dfd

Directory fd

 

path

Path

 
+
+
+

Returns

+

An accessor object for an OSTree repository located at dfd ++ path +.

+

[transfer full]

+
+ +
+

ostree_repo_new ()

OstreeRepo *
 ostree_repo_new (GFile *path);
@@ -1366,6 +1431,76 @@ If the repository is not writable, the error<

+

ostree_repo_create_at ()

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

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

+

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

+

The options + dict may contain:

+
  • collection-id: s: Set as collection ID in repo/config (Since 2017.9)

+
+

Parameters

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

dfd

Directory fd

 

path

Path

 

mode

The mode to store the repository in

 

options

a{sv}: See below for accepted keys

 

cancellable

Cancellable

 

error

Error

 
+
+
+

Returns

+

A new OSTree repository reference.

+

[transfer full]

+
+
+
+

ostree_repo_create ()

gboolean
 ostree_repo_create (OstreeRepo *self,
@@ -1379,6 +1514,10 @@ repository, and finish creating any necessary files in a partially
 created repository.  However, this function cannot change the mode
 of an existing repository, and will silently ignore an attempt to
 do so.

+

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

+

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

Parameters

@@ -1417,6 +1556,24 @@ do so.

ostree_repo_get_path ()

GFile *
 ostree_repo_get_path (OstreeRepo *self);
+

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

+
+

Parameters

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

self

Repo

 
+

Returns

Path to repo.

@@ -2662,6 +2819,60 @@ case where we're creating or overwriting an existing ref.


+

ostree_repo_set_alias_ref_immediate ()

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

Like ostree_repo_set_ref_immediate(), but creates an alias.

+
+

Parameters

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

self

An OstreeRepo

 

remote

A remote for the ref.

[allow-none]

ref

The ref to write

 

target

The ref target to point it to, or NULL to unset.

[allow-none]

cancellable

GCancellable

 

error

GError

 
+
+
+
+

ostree_repo_set_cache_dir ()

gboolean
 ostree_repo_set_cache_dir (OstreeRepo *self,
@@ -7182,13 +7393,22 @@ in bytes, counting only content objects.

- + +

OSTREE_REPO_LIST_REFS_EXT_NONE

No flags.

  - + + +

OSTREE_REPO_LIST_REFS_EXT_ALIASES

+ +

Only list aliases. Since: 2017.10

+ +  + +
diff --git a/apidoc/html/ostree-GPG-signature-verification-results.html b/apidoc/html/ostree-GPG-signature-verification-results.html index 08ae98d9..8eae5500 100644 --- a/apidoc/html/ostree-GPG-signature-verification-results.html +++ b/apidoc/html/ostree-GPG-signature-verification-results.html @@ -115,6 +115,10 @@ +enum +OstreeGpgError + + typedef OstreeGpgVerifyResult @@ -515,6 +519,46 @@ signature from trusted keyring, otherwise FALSE

Types and Values

+

enum OstreeGpgError

+

Errors returned by signature creation and verification operations in OSTree. +These may be returned by any API which creates or verifies signatures.

+
+

Members

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

OSTREE_GPG_ERROR_NO_SIGNATURE

+

A signature was expected, but not found.

+
 

OSTREE_GPG_ERROR_INVALID_SIGNATURE

+

A signature was malformed.

+
 

OSTREE_GPG_ERROR_MISSING_KEY

+

A signature was found, but was created with a key not in the configured keyrings.

+
 
+
+

Since: 2017.10

+
+
+

OstreeGpgVerifyResult

typedef struct OstreeGpgVerifyResult OstreeGpgVerifyResult;
 
diff --git a/apidoc/html/ostree.devhelp2 b/apidoc/html/ostree.devhelp2 index dc4f8980..65aac791 100644 --- a/apidoc/html/ostree.devhelp2 +++ b/apidoc/html/ostree.devhelp2 @@ -82,6 +82,7 @@ + @@ -90,6 +91,7 @@ + @@ -119,6 +121,7 @@ + @@ -320,6 +323,7 @@ + @@ -392,6 +396,7 @@ + @@ -436,6 +441,9 @@ + + + diff --git a/apidoc/html/reference.html b/apidoc/html/reference.html index 90023f66..ff9e9081 100644 --- a/apidoc/html/reference.html +++ b/apidoc/html/reference.html @@ -417,6 +417,10 @@ OSTREE_CHECK_VERSION, macro in ostree-version

G

+OstreeGpgError, enum in GPG signature verification results +
+
+
OstreeGpgSignatureAttr, enum in GPG signature verification results
@@ -762,6 +766,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
+ostree_repo_create_at, function in Content-addressed object store +
+
+
ostree_repo_delete_object, function in Content-addressed object store
@@ -962,6 +970,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
+ostree_repo_open_at, function in Content-addressed object store +
+
+
ostree_repo_prepare_transaction, function in Content-addressed object store
@@ -1070,6 +1082,10 @@ OSTREE_RELEASE_VERSION, macro in ostree-version
+ostree_repo_set_alias_ref_immediate, function in Content-addressed object store +
+
+
ostree_repo_set_cache_dir, function in Content-addressed object store
diff --git a/apidoc/ostree-experimental-sections.txt b/apidoc/ostree-experimental-sections.txt index a2c2c295..23412dda 100644 --- a/apidoc/ostree-experimental-sections.txt +++ b/apidoc/ostree-experimental-sections.txt @@ -82,6 +82,7 @@ ostree_repo_get_collection_id ostree_repo_set_collection_id ostree_validate_collection_id ostree_repo_list_collection_refs +ostree_repo_remote_list_collection_refs ostree_repo_set_collection_ref_immediate ostree_repo_transaction_set_collection_ref diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index 47f351d2..90bec167 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -194,6 +194,7 @@ ostree_diff_item_get_type
ostree-gpg-verify-result +OstreeGpgError OstreeGpgVerifyResult OstreeGpgSignatureAttr ostree_gpg_verify_result_count_all @@ -210,6 +211,8 @@ OSTREE_GPG_VERIFY_RESULT OSTREE_IS_GPG_VERIFY_RESULT OSTREE_TYPE_GPG_VERIFY_RESULT ostree_gpg_verify_result_get_type +OSTREE_GPG_ERROR +ostree_gpg_error_quark
ostree-lzma-compressor @@ -268,6 +271,7 @@ ostree_mutable_tree_get_type OstreeRepo OstreeRepoMode ostree_repo_mode_from_string +ostree_repo_open_at ostree_repo_new ostree_repo_new_for_sysroot_path ostree_repo_new_default @@ -276,6 +280,7 @@ ostree_repo_set_disable_fsync ostree_repo_get_disable_fsync ostree_repo_is_system ostree_repo_is_writable +ostree_repo_create_at ostree_repo_create ostree_repo_get_path ostree_repo_get_mode @@ -307,6 +312,7 @@ ostree_repo_abort_transaction ostree_repo_transaction_set_refspec ostree_repo_transaction_set_ref ostree_repo_set_ref_immediate +ostree_repo_set_alias_ref_immediate ostree_repo_set_cache_dir ostree_repo_sign_delta ostree_repo_has_object diff --git a/apidoc/version.xml b/apidoc/version.xml index 6a862a53..f473df1c 100644 --- a/apidoc/version.xml +++ b/apidoc/version.xml @@ -1 +1 @@ -2017.9 \ No newline at end of file +2017.10 \ No newline at end of file diff --git a/autogen.sh b/autogen.sh index 0f32089a..17f6abf4 100755 --- a/autogen.sh +++ b/autogen.sh @@ -28,7 +28,6 @@ else gtkdocize fi -cd $olddir if ! test -f libglnx/README.md || ! test -f bsdiff/README.md; then git submodule update --init fi @@ -41,4 +40,5 @@ ln -sf ../libglnx/libglnx.m4 buildutil/libglnx.m4 autoreconf --force --install --verbose +cd $olddir test -n "$NOCONFIGURE" || "$srcdir/configure" "$@" diff --git a/bash/ostree b/bash/ostree new file mode 100644 index 00000000..f4305f69 --- /dev/null +++ b/bash/ostree @@ -0,0 +1,2148 @@ +#!/bin/bash +# +# bash completion file for ostree commands +# +# This script provides completion of: +# - commands and their options +# - ostree commit checksums +# - ostree ref names +# +# To enable the completions either: +# - place this file in /etc/bash_completion.d +# or +# - copy this file to e.g. ~/.ostree-completion.sh and add the line +# below to your .bashrc after bash completion features are loaded +# . ~/.ostree-completion.sh +# +# Note for developers: +# Please arrange options sorted alphabetically by long name with the short +# options immediately following their corresponding long form. +# This order should be applied to lists, alternatives and code blocks. + +# TODO +# +# - Long form options with an equal sign (--foo=BAR) are not parsed. +# +# - Structured option arguments (e.g. --foo KEY=VALUE) are not parsed. +# +# - Static deltas could likely be completed. (e.g. ostree static-delta delete [TAB]) +# +# - The "--repo PATH" option needs to come after the subcommand or it +# won't be picked up for completion of subsequent options. +# i.e. ostree commit --repo PATH ... <-- works +# ostree --repo PATH commit ... <-- does not work +# (Possibly an easy fix.) + + +# Finds the position of the first non-flag word. +__ostree_pos_first_nonflag() { + local argument_flags=$1 + + local counter=$cpos + while [ $counter -le $cword ]; do + if [ -n "$argument_flags" ] && eval "case '${words[$counter]}' in $argument_flags) true ;; *) false ;; esac"; then + (( counter++ )) + else + case "${words[$counter]}" in + -*) + ;; + *) + break + ;; + esac + fi + (( counter++ )) + done + + echo $counter +} + +# Transforms a multiline list of strings into a single line string +# with the words separated by "|". +# This is used to prepare arguments to __ostree_pos_first_nonflag(). +__ostree_to_alternatives() { + local parts=( $1 ) + local IFS='|' + echo "${parts[*]}" +} + +# Transforms a multiline list of options into an extglob pattern +# suitable for use in case statements. +__ostree_to_extglob() { + local extglob=$( __ostree_to_alternatives "$1" ) + echo "@($extglob)" +} + +# Transform object path to a 64-char checksum. +__ostree_object_to_checksum() { + local str=( $1 ) + # Trim off extension (e.g. .commit) + str=${str%.*} + # Isolate checksum portion (nn/nnn...) + str=${str: -65} + # Drop the slash + echo "${str/\//}" +} + +__ostree_compreply_all_options() { + COMPREPLY+=( $( compgen -W "$all_options" -- "$cur" ) ) +} + +__ostree_compreply_all_files() { + COMPREPLY+=( $( compgen -f "$cur" ) ) +} + +__ostree_compreply_dirs_only() { + COMPREPLY+=( $( compgen -d "$cur" ) ) +} + +# Find commit objects under $repo_path. +__ostree_compreply_commits() { + local objectsdir="$repo_path/objects" + if test -d "$objectsdir"; then + local commits=() + for path in `find "$objectsdir" -name "*.commit"`; do + commits+=( $( __ostree_object_to_checksum "$path" ) ) + done + COMPREPLY+=( $( compgen -W "$commits" -- "$cur" ) ) + fi +} + +# Find oses under $sysroot_path +__ostree_compreply_oses() { + local deploydir="$sysroot_path/ostree/deploy" + if test -d "$deploydir"; then + local oses=() + for path in `find "$deploydir" -mindepth 1 -maxdepth 1 -type d`; do + oses+=( $( basename "$path" ) ) + done + COMPREPLY+=( $( compgen -W "$oses" -- "$cur" ) ) + fi +} + +# Find refs under $repo_path. +__ostree_compreply_refs() { + refs=$( ostree refs --repo $repo_path 2>/dev/null ) + COMPREPLY+=( $( compgen -W "$refs" -- "$cur" ) ) +} + +# Find remotes under $repo_path. +__ostree_compreply_remotes() { + remotes=$( ostree remote list --repo $repo_path 2> /dev/null ) + COMPREPLY+=( $( compgen -W "$remotes" -- "$cur" ) ) +} + +# Find commit objects and refs under $repo_path. +__ostree_compreply_revisions() { + __ostree_compreply_commits + __ostree_compreply_refs +} + +# Subcommand processing. +# Locates the first occurrence of any of the subcommands contained in the +# first argument. In case of a match, calls the corresponding completion +# function and returns 0. +# If no match is found, 1 is returned. The calling function can then +# continue processing its completion. +# +# TODO If the preceding command has options that accept arguments and an +# argument is equal to one of the subcommands, this is falsely detected +# as a match. +__ostree_subcommands() { + local subcommands="$1" + + local counter=$cpos + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + $( __ostree_to_extglob "$subcommands" ) ) + local subcommand=${words[$counter]} + cpos=$counter + (( cpos++ )) + local completions_func=_ostree_${command//-/_}_${subcommand//-/_} + declare -F $completions_func >/dev/null && $completions_func + return 0 + ;; + esac + (( counter++ )) + done + return 1 +} + +# This handles "ostree [TAB]" (without a subcommand). +_ostree_ostree() { + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$main_boolean_options" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$commands" -- "$cur" ) ) + ;; + esac + + return 0 +} + +_ostree_admin_cleanup() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_config_diff() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --os + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --os) + __ostree_compreply_oses + return 0 + ;; + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_deploy() { + local boolean_options=" + $main_boolean_options + --retain + --karg-proc-cmdline + " + + local options_with_args=" + --karg + --karg-append + --origin-file + --os + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --origin-file) + __ostree_compreply_all_files + return 0 + ;; + --os) + __ostree_compreply_oses + return 0 + ;; + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_init_fs() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_instutil() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + if [ $cword -eq $argpos ]; then + local instutil_commands=" + grub2-generate + selinux-ensure-labeled + set-kargs + " + COMPREPLY=( $( compgen -W "$instutil_commands" -- "$cur" ) ) + fi + ;; + esac + + return 0 +} + +_ostree_admin_os_init() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_set_origin() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --index + --set -s + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + ;; + esac + + return 0 +} + +_ostree_admin_status() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_switch() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --os + --reboot -r + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --os) + __ostree_compreply_oses + return 0 + ;; + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_refs + fi + esac + + return 0 +} + +_ostree_admin_undeploy() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_unlock() { + local boolean_options=" + $main_boolean_options + --hotfix + " + + local options_with_args=" + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin_upgrade() { + local boolean_options=" + $main_boolean_options + --allow-downgrade + --deploy-only + --pull-only + --reboot -r + " + + local options_with_args=" + --os + --override-commit + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --override-commit) + __ostree_compreply_commits + return 0 + ;; + --sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_admin() { + local subcommands=" + cleanup + config-diff + deploy + init-fs + instutil + os-init + set-origin + status + switch + undeploy + unlock + upgrade + " + + __ostree_subcommands "$subcommands" && return 0 + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$main_boolean_options" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac + + return 0 +} + +_ostree_cat() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_dirs_only + fi + ;; + esac + + return 0 +} + +_ostree_checkout() { + local boolean_options=" + $main_boolean_options + --allow-noent + --bareuseronly-dirs -M + --disable-cache + --force-copy -C + --from-stdin + --require-hardlinks -H + --union + --union-add + --user-mode -U + --whiteouts + " + + local options_with_args=" + --from-file + --fsync + --repo + --subpath + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --from-file) + __ostree_compreply_all_files + return 0 + ;; + --repo|--subpath) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_dirs_only + fi + esac + + return 0 +} + +_ostree_checksum() { + local boolean_options=" + $main_boolean_options + " + + case "$cur" in + -*) + local all_options="$boolean_options" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "") ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_all_files + fi + ;; + esac + + return 0 +} + +_ostree_commit() { + local boolean_options=" + $main_boolean_options + --canonical-permissions + --editor -e + --generate-sizes + --link-checkout-speedup + --no-xattrs + --orphan + --skip-if-unchanged + --table-output + --tar-autocreate-parents + " + + local options_with_args=" + --add-detached-metadata-string + --add-metadata-string + --bind-ref + --body -m + --body-file -F + --branch -b + --fsync + --gpg-homedir + --gpg-sign + --owner-gid + --owner-uid + --parent + --repo + --skip-list + --statoverride + --subject -s + --timestamp + --tree + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --body-file|--skip-list|--statoverride) + __ostree_compreply_all_files + return 0 + ;; + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + --bind-ref) + __ostree_compreply_refs + return 0 + ;; + --parent) + __ostree_compreply_commits + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_all_files + fi + esac + + return 0 +} + +_ostree_config() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_diff() { + local boolean_options=" + $main_boolean_options + --fs-diff + --no-xattrs + --stats + " + + local options_with_args=" + --owner-gid + --owner-uid + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_dirs_only + fi + esac + + return 0 +} + +_ostree_export() { + local boolean_options=" + $main_boolean_options + --no-xattrs + " + + local options_with_args=" + --output -o + --prefix + --repo + --subpath + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --prefix|--repo|--subpath) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + +_ostree_fsck() { + local boolean_options=" + $main_boolean_options + --add-tombstones + --delete + --quiet -q + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_gpg_sign() { + local boolean_options=" + $main_boolean_options + --delete -d + " + + local options_with_args=" + --gpg-homedir + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + +_ostree_init() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --mode + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --mode) + COMPREPLY=( $( compgen -W "bare archive-z2" -- "$cur" ) ) + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_log() { + local boolean_options=" + $main_boolean_options + --raw + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + fi + esac + + return 0 +} + +_ostree_ls() { + local boolean_options=" + $main_boolean_options + --checksum -C + --dironly -d + --nul-filenames-only + --recursive -R + --xattrs -X + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + return 0 + fi + + __ostree_compreply_all_files + esac + + return 0 +} + +_ostree_prune() { + local boolean_options=" + $main_boolean_options + --no-prune + --refs-only + --static-deltas-only + " + + local options_with_args=" + --delete-commit + --depth + --keep-younger-than + --repo + --retain-branch-depth + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --delete-commit) + __ostree_compreply_commits + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_pull_local() { + local boolean_options=" + $main_boolean_options + --bareuseronly-files + --disable-fsync + --gpg-verify + --gpg-verify-summary + --require-static-deltas + --untrusted + " + + local options_with_args=" + --depth + --remote + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --remote) + __ostree_compreply_remotes + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_dirs_only + return 0 + fi + + __ostree_revisions + esac + + return 0 +} + +_ostree_pull() { + local boolean_options=" + $main_boolean_options + --commit-metadata-only + --cache-dir + --disable-fsync + --disable-static-deltas + --require-static-deltas + --mirror + --untrusted + --bareuseronly-files + --dry-run + " + + local options_with_args=" + --depth + --http-header + --localcache-repo -L + --repo + --subpath + --update-frequency + --url + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --localcache-repo|-L|--repo|--subpath) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_refs() { + local boolean_options=" + $main_boolean_options + --alias -A + --delete + --list + " + + local options_with_args=" + --create + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_remote_add() { + local boolean_options=" + $main_boolean_options + --if-not-exists + --no-gpg-verify + " + + local options_with_args=" + --contenturl + --gpg-import + --repo + --set + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo|--sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + --gpg-import) + __ostree_compreply_all_files + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_remote_add_cookie() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_delete() { + local boolean_options=" + $main_boolean_options + --if-exists + " + + local options_with_args=" + --repo + --sysroot + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo|--sysroot) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_delete_cookie() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_gpg_import() { + local boolean_options=" + $main_boolean_options + --stdin + " + + local options_with_args=" + --keyfile -k + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --keyfile|-k) + __ostree_compreply_all_files + return 0 + ;; + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_list() { + local boolean_options=" + $main_boolean_options + --show-urls -u + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_remote_list_cookies() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_refs() { + local boolean_options=" + $main_boolean_options + --cache-dir + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_show_url() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote_summary() { + local boolean_options=" + $main_boolean_options + --cache-dir + --raw + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_remotes + fi + esac + + return 0 +} + +_ostree_remote() { + local subcommands=" + add + add-cookie + delete + delete-cookie + gpg-import + list + list-cookies + refs + show-url + summary + " + + __ostree_subcommands "$subcommands" && return 0 + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$main_boolean_options" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac + + return 0 +} + +_ostree_reset() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_refs + elif [ $cword -eq $(($argpos + 1)) ]; then + __ostree_compreply_commits + fi + esac + + return 0 +} + +_ostree_rev_parse() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_revisions + fi + esac + + return 0 +} + +_ostree_show() { + local boolean_options=" + $main_boolean_options + --print-related + --raw + " + + local options_with_args=" + --gpg-homedir + --gpg-verify-remote + --print-detached-metadata-key + --print-metadata-key + --print-variant-type + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + --gpg-verify-remote) + __ostree_compreply_remotes + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta_apply_offline() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + *) + local argpos=$( __ostree_pos_first_nonflag $( __ostree_to_alternatives "$options_with_args" ) ) + + if [ $cword -eq $argpos ]; then + __ostree_compreply_all_files + fi + esac + + return 0 +} + +_ostree_static_delta_delete() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta_generate() { + local boolean_options=" + $main_boolean_options + --disable-bsdiff + --empty + --in-not-exists -n + --inline + --max-bsdiff-size + --max-chunk-size + --min-fallback-size + --swap-endianness + " + + local options_with_args=" + --filename + --from + --repo + --set-endianness + --to + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --filename|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + --from|--to) + __ostree_compreply_revisions + return 0 + ;; + --set-endianness) + COMPREPLY=( $( compgen -W "l B" -- "$cur" ) ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta_list() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta_show() { + local boolean_options=" + $main_boolean_options + " + + local options_with_args=" + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree_static_delta() { + local subcommands=" + apply-offline + delete + generate + list + show + " + + __ostree_subcommands "$subcommands" && return 0 + + case "$cur" in + -*) + COMPREPLY=( $( compgen -W "$main_boolean_options" -- "$cur" ) ) + ;; + *) + COMPREPLY=( $( compgen -W "$subcommands" -- "$cur" ) ) + ;; + esac + + return 0 +} + +_ostree_summary() { + local boolean_options=" + $main_boolean_options + --raw + --update -u + --view -v + " + + local options_with_args=" + --add-metadata -m + --gpg-homedir + --gpg-sign + --repo + " + + local options_with_args_glob=$( __ostree_to_extglob "$options_with_args" ) + + case "$prev" in + --gpg-homedir|--repo) + __ostree_compreply_dirs_only + return 0 + ;; + $options_with_args_glob ) + return 0 + ;; + esac + + case "$cur" in + -*) + local all_options="$boolean_options $options_with_args" + __ostree_compreply_all_options + ;; + esac + + return 0 +} + +_ostree() { + local commands=" + admin + cat + checkout + checksum + commit + config + diff + export + fsck + gpg-sign + init + log + ls + prune + pull-local + pull + refs + remote + reset + rev-parse + show + static-delta + summary + " + + # These are always available. + local main_boolean_options=" + --help -h + --verbose -v + --version + " + + COMPREPLY=() + local cur prev words cword + + _get_comp_words_by_ref cur prev words cword + + local command='ostree' cpos=0 + local counter + + local repo_path='/sysroot/ostree/repo' + local sysroot_path='/sysroot' + + # These options can affect argument completion. + # FIXME Only recognizes the form --foo BAR, not --foo=BAR. + counter=1 + while [ $counter -lt $cword ]; do + if test "${words[$counter - 1]}" = "--repo"; then + repo_path=${words[$counter]} + elif test "${words[$counter - 1]}" = "--sysroot"; then + sysroot_path=${words[$counter]} + repo_path="$sysroot_path/ostree/repo" + fi + (( counter++ )) + done + + counter=1 + while [ $counter -lt $cword ]; do + case "${words[$counter]}" in + $main_options_with_args_glob ) + (( counter++ )) + ;; + -*) + ;; + *) + command="${words[$counter]}" + cpos=$counter + (( cpos++ )) + break + ;; + esac + (( counter++ )) + done + + local completions_func=_ostree_${command//-/_} + declare -F $completions_func >/dev/null && $completions_func + + return 0 +} + +complete -F _ostree ostree diff --git a/config.h.in b/config.h.in index 2e5f07d6..58ca1516 100644 --- a/config.h.in +++ b/config.h.in @@ -1,5 +1,8 @@ /* config.h.in. Generated from configure.ac by autoheader. */ +/* Define if we are building with -fsanitize=address */ +#undef BUILDOPT_ASAN + /* Define if we are enabling ostree trivial-httpd entrypoint */ #undef BUILDOPT_ENABLE_TRIVIAL_HTTPD_CMDLINE @@ -9,6 +12,9 @@ /* Define if systemd and libmount */ #undef BUILDOPT_LIBSYSTEMD_AND_LIBMOUNT +/* Define if we are building with -fsanitize=thread */ +#undef BUILDOPT_TSAN + /* Define if we should avoid using O_TMPFILE */ #undef DISABLE_OTMPFILE diff --git a/configure b/configure index d6150247..1313c436 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libostree 2017.9. +# Generated by GNU Autoconf 2.69 for libostree 2017.10. # # Report bugs to . # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='libostree' PACKAGE_TARNAME='libostree' -PACKAGE_VERSION='2017.9' -PACKAGE_STRING='libostree 2017.9' +PACKAGE_VERSION='2017.10' +PACKAGE_STRING='libostree 2017.10' PACKAGE_BUGREPORT='walters@verbum.org' PACKAGE_URL='' @@ -764,6 +764,7 @@ GOBJECT_QUERY GLIB_GENMARSHAL GLIB_LIBS GLIB_CFLAGS +BASH_COMPLETIONSDIR PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG @@ -804,6 +805,8 @@ build_vendor build_cpu build LIBTOOL +BUILDOPT_TSAN_FALSE +BUILDOPT_TSAN_TRUE BUILDOPT_ASAN_FALSE BUILDOPT_ASAN_TRUE WARN_CFLAGS @@ -963,6 +966,7 @@ LT_SYS_LIBRARY_PATH PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR +BASH_COMPLETIONSDIR OT_DEP_GIO_UNIX_CFLAGS OT_DEP_GIO_UNIX_LIBS OT_DEP_LZMA_CFLAGS @@ -1533,7 +1537,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libostree 2017.9 to adapt to many kinds of systems. +\`configure' configures libostree 2017.10 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1603,7 +1607,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libostree 2017.9:";; + short | recursive ) echo "Configuration of libostree 2017.10:";; esac cat <<\_ACEOF @@ -1712,6 +1716,9 @@ Some influential environment variables: directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path + BASH_COMPLETIONSDIR + value of completionsdir for bash-completion, overriding + pkg-config OT_DEP_GIO_UNIX_CFLAGS C compiler flags for OT_DEP_GIO_UNIX, overriding pkg-config OT_DEP_GIO_UNIX_LIBS @@ -1839,7 +1846,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libostree configure 2017.9 +libostree configure 2017.10 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2254,7 +2261,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libostree $as_me 2017.9, which was +It was created by libostree $as_me 2017.10, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -3122,7 +3129,7 @@ fi # Define the identity of the package. PACKAGE='libostree' - VERSION='2017.9' + VERSION='2017.10' # Some tools Automake needs. @@ -5856,9 +5863,9 @@ test -n "$YACC" || YACC="yacc" YEAR_VERSION=2017 -RELEASE_VERSION=9 +RELEASE_VERSION=10 -PACKAGE_VERSION=2017.9 +PACKAGE_VERSION=2017.10 if echo "$CFLAGS" | grep -q -E -e '-Werror($| )'; then : @@ -5937,6 +5944,35 @@ else BUILDOPT_ASAN_FALSE= fi +if test -z "$BUILDOPT_ASAN_TRUE"; then : + +$as_echo "#define BUILDOPT_ASAN 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fsanitize=thread in CFLAGS" >&5 +$as_echo_n "checking for -fsanitize=thread in CFLAGS... " >&6; } +if echo $CFLAGS | grep -q -e -fsanitize=thread; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + using_tsan=yes +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + if test x$using_tsan = xyes; then + BUILDOPT_TSAN_TRUE= + BUILDOPT_TSAN_FALSE='#' +else + BUILDOPT_TSAN_TRUE='#' + BUILDOPT_TSAN_FALSE= +fi + +if test -z "$BUILDOPT_TSAN_TRUE"; then : + +$as_echo "#define BUILDOPT_TSAN 1" >>confdefs.h + +fi # Initialize libtool @@ -13878,6 +13914,34 @@ $as_echo "no" >&6; } fi fi +# PKG_CHECK_VAR added to pkg-config 0.28 + + + +if test -n "$BASH_COMPLETIONSDIR"; then + pkg_cv_BASH_COMPLETIONSDIR="$BASH_COMPLETIONSDIR" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"bash-completion\""; } >&5 + ($PKG_CONFIG --exists --print-errors "bash-completion") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_BASH_COMPLETIONSDIR=`$PKG_CONFIG --variable="completionsdir" "bash-completion" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +BASH_COMPLETIONSDIR=$pkg_cv_BASH_COMPLETIONSDIR + +if test "x$BASH_COMPLETIONSDIR" = x""; then : + BASH_COMPLETIONSDIR="${datadir}/bash-completion/completions" +fi + + # Check whether --enable-glibtest was given. if test "${enable_glibtest+set}" = set; then : enableval=$enable_glibtest; @@ -17416,6 +17480,10 @@ if test -z "${BUILDOPT_ASAN_TRUE}" && test -z "${BUILDOPT_ASAN_FALSE}"; then as_fn_error $? "conditional \"BUILDOPT_ASAN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${BUILDOPT_TSAN_TRUE}" && test -z "${BUILDOPT_TSAN_FALSE}"; then + as_fn_error $? "conditional \"BUILDOPT_TSAN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${ENABLE_INSTALLED_TESTS_TRUE}" && test -z "${ENABLE_INSTALLED_TESTS_FALSE}"; then as_fn_error $? "conditional \"ENABLE_INSTALLED_TESTS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 @@ -17961,7 +18029,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libostree $as_me 2017.9, which was +This file was extended by libostree $as_me 2017.10, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -18027,7 +18095,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -libostree config.status 2017.9 +libostree config.status 2017.10 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 01e6b534..5c13e742 100644 --- a/configure.ac +++ b/configure.ac @@ -4,7 +4,7 @@ dnl update libostree-released.sym from libostree-devel.sym, and update the check dnl in test-symbols.sh, and also set is_release_build=yes below. Then make dnl another post-release commit to bump the version, and set is_release_build=no. m4_define([year_version], [2017]) -m4_define([release_version], [9]) +m4_define([release_version], [10]) m4_define([package_version], [year_version.release_version]) AC_INIT([libostree], [package_version], [walters@verbum.org]) is_release_build=yes @@ -58,6 +58,19 @@ else AC_MSG_RESULT([no]) fi AM_CONDITIONAL(BUILDOPT_ASAN, [test x$using_asan = xyes]) +AM_COND_IF([BUILDOPT_ASAN], + [AC_DEFINE([BUILDOPT_ASAN], 1, [Define if we are building with -fsanitize=address])]) + +AC_MSG_CHECKING([for -fsanitize=thread in CFLAGS]) +if echo $CFLAGS | grep -q -e -fsanitize=thread; then + AC_MSG_RESULT([yes]) + using_tsan=yes +else + AC_MSG_RESULT([no]) +fi +AM_CONDITIONAL(BUILDOPT_TSAN, [test x$using_tsan = xyes]) +AM_COND_IF([BUILDOPT_TSAN], + [AC_DEFINE([BUILDOPT_TSAN], 1, [Define if we are building with -fsanitize=thread])]) # Initialize libtool LT_PREREQ([2.2.4]) @@ -75,6 +88,17 @@ AS_IF([test "$YACC" != "bison -y"], [AC_MSG_ERROR([bison not found but required] PKG_PROG_PKG_CONFIG +# PKG_CHECK_VAR added to pkg-config 0.28 +m4_define_default( + [PKG_CHECK_VAR], + [AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config]) + AS_IF([test -z "$$1"], [$1=`$PKG_CONFIG --variable="$3" "$2"`]) + AS_IF([test -n "$$1"], [$4], [$5])]) + +PKG_CHECK_VAR(BASH_COMPLETIONSDIR, [bash-completion], [completionsdir], , + BASH_COMPLETIONSDIR="${datadir}/bash-completion/completions") +AC_SUBST(BASH_COMPLETIONSDIR) + AM_PATH_GLIB_2_0(,,AC_MSG_ERROR([GLib not found])) dnl When bumping the gio-unix-2.0 dependency (or glib-2.0 in general), diff --git a/libglnx/glnx-console.c b/libglnx/glnx-console.c index 416d2768..c6d93311 100644 --- a/libglnx/glnx-console.c +++ b/libglnx/glnx-console.c @@ -187,11 +187,12 @@ text_percent_internal (const char *text, const guint n_spaces = sizeof (spaces) - 1; const guint ncolumns = glnx_console_columns (); const guint bar_min = 10; - const guint input_textlen = text ? strlen (text) : 0; if (text && !*text) text = NULL; + const guint input_textlen = text ? strlen (text) : 0; + if (percentage == current_percent && g_strcmp0 (text, current_text) == 0) return; @@ -221,7 +222,8 @@ text_percent_internal (const char *text, if (percentage == -1) { - fwrite (text, 1, input_textlen, stdout); + if (text != NULL) + fwrite (text, 1, input_textlen, stdout); /* Overwrite remaining space, if any */ if (ncolumns > input_textlen) @@ -273,7 +275,7 @@ void glnx_console_progress_text_percent (const char *text, guint percentage) { - g_return_if_fail (percentage >= 0 && percentage <= 100); + g_return_if_fail (percentage <= 100); text_percent_internal (text, percentage); } diff --git a/libglnx/glnx-dirfd.c b/libglnx/glnx-dirfd.c index 667a18dd..29a3ff7c 100644 --- a/libglnx/glnx-dirfd.c +++ b/libglnx/glnx-dirfd.c @@ -83,7 +83,7 @@ typedef struct GLnxRealDirfdIterator GLnxRealDirfdIterator; /** * glnx_dirfd_iterator_init_at: * @dfd: File descriptor, may be AT_FDCWD or -1 - * @path: Path, may be relative to @df + * @path: Path, may be relative to @dfd * @follow: If %TRUE and the last component of @path is a symlink, follow it * @out_dfd_iter: (out caller-allocates): A directory iterator, will be initialized * @error: Error diff --git a/libglnx/glnx-fdio.c b/libglnx/glnx-fdio.c index 756248d6..dc8459d9 100644 --- a/libglnx/glnx-fdio.c +++ b/libglnx/glnx-fdio.c @@ -31,9 +31,6 @@ #include #include #include -/* See linux.git/fs/btrfs/ioctl.h */ -#define BTRFS_IOCTL_MAGIC 0x94 -#define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int) #include #include @@ -43,6 +40,11 @@ #include #include +/* The standardized version of BTRFS_IOC_CLONE */ +#ifndef FICLONE +#define FICLONE _IOW(0x94, 9, int) +#endif + /* Returns the number of chars needed to format variables of the * specified type as a decimal string. Adds in extra space for a * negative '-' prefix (hence works correctly on signed @@ -654,13 +656,6 @@ copy_symlink_at (int src_dfd, * conveniently fit in with the rest of libglnx. */ -static int btrfs_reflink(int infd, int outfd) { - g_return_val_if_fail(infd >= 0, -1); - g_return_val_if_fail(outfd >= 0, -1); - - return ioctl (outfd, BTRFS_IOC_CLONE, infd); -} - /* Like write(), but loop until @nbytes are written, or an error * occurs. * @@ -703,8 +698,10 @@ glnx_loop_write(int fd, const void *buf, size_t nbytes) return 0; } -/* Read from @fdf until EOF, writing to @fdt. If @try_reflink is %TRUE, - * attempt to use any "reflink" functionality; see e.g. https://lwn.net/Articles/331808/ +/* Read from @fdf until EOF, writing to @fdt. If max_bytes is -1, a full-file + * clone will be attempted. Otherwise Linux copy_file_range(), sendfile() + * syscall will be attempted. If none of those work, this function will do a + * plain read()/write() loop. * * The file descriptor @fdf must refer to a regular file. * @@ -712,58 +709,123 @@ glnx_loop_write(int fd, const void *buf, size_t nbytes) * On error, this function returns `-1` and @errno will be set. */ int -glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink) +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes) { - bool try_sendfile = true; - int r; + /* Last updates from systemd as of commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca */ + static int have_cfr = -1; /* -1 means unknown */ + bool try_cfr = have_cfr != 0; + static int have_sendfile = -1; /* -1 means unknown */ + bool try_sendfile = have_sendfile != 0; g_return_val_if_fail (fdf >= 0, -1); g_return_val_if_fail (fdt >= 0, -1); g_return_val_if_fail (max_bytes >= -1, -1); - /* Try btrfs reflinks first. */ - if (try_reflink && max_bytes == (off_t) -1) + /* If we've requested to copy the whole range, try a full-file clone first. + */ + if (max_bytes == (off_t) -1) { - r = btrfs_reflink(fdf, fdt); - if (r >= 0) + if (ioctl (fdt, FICLONE, fdf) == 0) return 0; /* Fall through */ + struct stat stbuf; + + /* Gather the size so we can provide the whole thing at once to + * copy_file_range() or sendfile(). + */ + if (fstat (fdf, &stbuf) < 0) + return -1; + max_bytes = stbuf.st_size; } while (TRUE) { - size_t m = COPY_BUFFER_SIZE; ssize_t n; - if (max_bytes != (off_t) -1) + /* First, try copy_file_range(). Note this is an inlined version of + * try_copy_file_range() from systemd upstream, which works better since + * we use POSIX errno style. + */ + if (try_cfr) { - if ((off_t) m > max_bytes) - m = (size_t) max_bytes; - } - - /* First try sendfile(), unless we already tried */ - if (try_sendfile) - { - n = sendfile (fdt, fdf, NULL, m); + n = copy_file_range (fdf, NULL, fdt, NULL, max_bytes, 0u); if (n < 0) { - if (errno != EINVAL && errno != ENOSYS) + if (errno == ENOSYS) + { + /* No cfr in kernel, mark as permanently unavailable + * and fall through to sendfile(). + */ + have_cfr = 0; + try_cfr = false; + } + else if (errno == EXDEV) + /* We won't try cfr again for this run, but let's be + * conservative and not mark it as available/unavailable until + * we know for sure. + */ + try_cfr = false; + else return -1; - - try_sendfile = false; - /* use fallback below */ } - else if (n == 0) /* EOF */ - break; - else if (n > 0) - /* Succcess! */ - goto next; + else + { + /* cfr worked, mark it as available */ + if (have_cfr == -1) + have_cfr = 1; + + if (n == 0) /* EOF */ + break; + else + /* Success! */ + goto next; + } + } + + /* Next try sendfile(); this version is also changed from systemd upstream + * to match the same logic we have for copy_file_range(). + */ + if (try_sendfile) + { + n = sendfile (fdt, fdf, NULL, max_bytes); + if (n < 0) + { + if (G_IN_SET (errno, EINVAL, ENOSYS)) + { + /* No sendfile(), or it doesn't work on regular files. + * Mark it as permanently unavailable, and fall through + * to plain read()/write(). + */ + have_sendfile = 0; + try_sendfile = false; + } + else + return -1; + } + else + { + /* sendfile() worked, mark it as available */ + if (have_sendfile == -1) + have_sendfile = 1; + + if (n == 0) /* EOF */ + break; + else if (n > 0) + /* Succcess! */ + goto next; + } } /* As a fallback just copy bits by hand */ - { char buf[m]; + { size_t m = COPY_BUFFER_SIZE; + if (max_bytes != (off_t) -1) + { + if ((off_t) m > max_bytes) + m = (size_t) max_bytes; + } + char buf[m]; - n = read (fdf, buf, m); + n = TEMP_FAILURE_RETRY (read (fdf, buf, m)); if (n < 0) return -1; if (n == 0) /* EOF */ @@ -776,7 +838,7 @@ glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink next: if (max_bytes != (off_t) -1) { - g_assert(max_bytes >= n); + g_assert_cmpint (max_bytes, >=, n); max_bytes -= n; if (max_bytes == 0) break; @@ -867,7 +929,7 @@ glnx_file_copy_at (int src_dfd, goto out; } - r = glnx_regfile_copy_bytes (src_fd, dest_fd, (off_t) -1, TRUE); + r = glnx_regfile_copy_bytes (src_fd, dest_fd, (off_t) -1); if (r < 0) { glnx_set_error_from_errno (error); diff --git a/libglnx/glnx-fdio.h b/libglnx/glnx-fdio.h index 6b873e94..4ee24afa 100644 --- a/libglnx/glnx-fdio.h +++ b/libglnx/glnx-fdio.h @@ -170,7 +170,7 @@ int glnx_loop_write (int fd, const void *buf, size_t nbytes); int -glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes, gboolean try_reflink); +glnx_regfile_copy_bytes (int fdf, int fdt, off_t max_bytes); typedef enum { GLNX_FILE_COPY_OVERWRITE = (1 << 0), diff --git a/libglnx/glnx-local-alloc.h b/libglnx/glnx-local-alloc.h index 8c1914cf..46dd9d25 100644 --- a/libglnx/glnx-local-alloc.h +++ b/libglnx/glnx-local-alloc.h @@ -25,30 +25,6 @@ G_BEGIN_DECLS -#define GLNX_DEFINE_CLEANUP_FUNCTION(Type, name, func) \ - static inline void name (void *v) \ - { \ - func (*(Type*)v); \ - } - -#define GLNX_DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ - static inline void name (void *v) \ - { \ - if (*(Type*)v) \ - func (*(Type*)v); \ - } - -/** - * glnx_free: - * - * Call g_free() on a variable location when it goes out of scope. - */ -#define glnx_free __attribute__ ((cleanup(glnx_local_free))) -#ifdef GLNX_GSYSTEM_COMPAT -#define gs_free __attribute__ ((cleanup(glnx_local_free))) -#endif -GLNX_DEFINE_CLEANUP_FUNCTION(void*, glnx_local_free, g_free) - /** * glnx_unref_object: * @@ -57,141 +33,14 @@ GLNX_DEFINE_CLEANUP_FUNCTION(void*, glnx_local_free, g_free) * %NULL. */ #define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) -#ifdef GLNX_GSYSTEM_COMPAT -#define gs_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) -#endif -GLNX_DEFINE_CLEANUP_FUNCTION0(GObject*, glnx_local_obj_unref, g_object_unref) - -/** - * glnx_unref_variant: - * - * Call g_variant_unref() on a variable location when it goes out of - * scope. Note that unlike g_variant_unref(), the variable may be - * %NULL. - */ -#define glnx_unref_variant __attribute__ ((cleanup(glnx_local_variant_unref))) -#ifdef GLNX_GSYSTEM_COMPAT -#define gs_unref_variant __attribute__ ((cleanup(glnx_local_variant_unref))) -#endif -GLNX_DEFINE_CLEANUP_FUNCTION0(GVariant*, glnx_local_variant_unref, g_variant_unref) - -/** - * glnx_free_variant_iter: - * - * Call g_variant_iter_free() on a variable location when it goes out of - * scope. - */ -#define glnx_free_variant_iter __attribute__ ((cleanup(glnx_local_variant_iter_free))) -GLNX_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, glnx_local_variant_iter_free, g_variant_iter_free) - -/** - * glnx_free_variant_builder: - * - * Call g_variant_builder_unref() on a variable location when it goes out of - * scope. - */ -#define glnx_unref_variant_builder __attribute__ ((cleanup(glnx_local_variant_builder_unref))) -GLNX_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, glnx_local_variant_builder_unref, g_variant_builder_unref) - -/** - * glnx_unref_array: - * - * Call g_array_unref() on a variable location when it goes out of - * scope. Note that unlike g_array_unref(), the variable may be - * %NULL. - - */ -#define glnx_unref_array __attribute__ ((cleanup(glnx_local_array_unref))) -GLNX_DEFINE_CLEANUP_FUNCTION0(GArray*, glnx_local_array_unref, g_array_unref) - -/** - * glnx_unref_ptrarray: - * - * Call g_ptr_array_unref() on a variable location when it goes out of - * scope. Note that unlike g_ptr_array_unref(), the variable may be - * %NULL. - - */ -#define glnx_unref_ptrarray __attribute__ ((cleanup(glnx_local_ptrarray_unref))) -#ifdef GLNX_GSYSTEM_COMPAT -#define gs_unref_ptrarray __attribute__ ((cleanup(glnx_local_ptrarray_unref))) -#endif -GLNX_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, glnx_local_ptrarray_unref, g_ptr_array_unref) - -/** - * glnx_unref_hashtable: - * - * Call g_hash_table_unref() on a variable location when it goes out - * of scope. Note that unlike g_hash_table_unref(), the variable may - * be %NULL. - */ -#define glnx_unref_hashtable __attribute__ ((cleanup(glnx_local_hashtable_unref))) -#ifdef GLNX_GSYSTEM_COMPAT -#define gs_unref_hashtable __attribute__ ((cleanup(glnx_local_hashtable_unref))) -#endif -GLNX_DEFINE_CLEANUP_FUNCTION0(GHashTable*, glnx_local_hashtable_unref, g_hash_table_unref) - -/** - * glnx_free_list: - * - * Call g_list_free() on a variable location when it goes out - * of scope. - */ -#define glnx_free_list __attribute__ ((cleanup(glnx_local_free_list))) -GLNX_DEFINE_CLEANUP_FUNCTION(GList*, glnx_local_free_list, g_list_free) - -/** - * glnx_free_slist: - * - * Call g_slist_free() on a variable location when it goes out - * of scope. - */ -#define glnx_free_slist __attribute__ ((cleanup(glnx_local_free_slist))) -GLNX_DEFINE_CLEANUP_FUNCTION(GSList*, glnx_local_free_slist, g_slist_free) - -/** - * glnx_free_checksum: - * - * Call g_checksum_free() on a variable location when it goes out - * of scope. Note that unlike g_checksum_free(), the variable may - * be %NULL. - */ -#define glnx_free_checksum __attribute__ ((cleanup(glnx_local_checksum_free))) -GLNX_DEFINE_CLEANUP_FUNCTION0(GChecksum*, glnx_local_checksum_free, g_checksum_free) - -/** - * glnx_unref_bytes: - * - * Call g_bytes_unref() on a variable location when it goes out - * of scope. Note that unlike g_bytes_unref(), the variable may - * be %NULL. - */ -#define glnx_unref_bytes __attribute__ ((cleanup(glnx_local_bytes_unref))) -GLNX_DEFINE_CLEANUP_FUNCTION0(GBytes*, glnx_local_bytes_unref, g_bytes_unref) - -/** - * glnx_strfreev: - * - * Call g_strfreev() on a variable location when it goes out of scope. - */ -#define glnx_strfreev __attribute__ ((cleanup(glnx_local_strfreev))) -GLNX_DEFINE_CLEANUP_FUNCTION(char**, glnx_local_strfreev, g_strfreev) - -/** - * glnx_free_error: - * - * Call g_error_free() on a variable location when it goes out of scope. - */ -#define glnx_free_error __attribute__ ((cleanup(glnx_local_free_error))) -GLNX_DEFINE_CLEANUP_FUNCTION0(GError*, glnx_local_free_error, g_error_free) - -/** - * glnx_unref_keyfile: - * - * Call g_key_file_unref() on a variable location when it goes out of scope. - */ -#define glnx_unref_keyfile __attribute__ ((cleanup(glnx_local_keyfile_unref))) -GLNX_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, glnx_local_keyfile_unref, g_key_file_unref) +static inline void +glnx_local_obj_unref (void *v) +{ + GObject *o = *(GObject **)v; + if (o) + g_object_unref (o); +} +#define glnx_unref_object __attribute__ ((cleanup(glnx_local_obj_unref))) static inline void glnx_cleanup_close_fdp (int *fdp) @@ -204,7 +53,8 @@ glnx_cleanup_close_fdp (int *fdp) if (fd >= 0) { errsv = errno; - (void) close (fd); + if (close (fd) < 0) + g_assert (errno != EBADF); errno = errsv; } } diff --git a/libglnx/glnx-missing-syscall.h b/libglnx/glnx-missing-syscall.h index 2c583c6d..c4957e0c 100644 --- a/libglnx/glnx-missing-syscall.h +++ b/libglnx/glnx-missing-syscall.h @@ -52,3 +52,44 @@ static inline int renameat2(int oldfd, const char *oldname, int newfd, const cha # endif } #endif + +/* Copied from systemd git: + commit 6bda23dd6aaba50cf8e3e6024248cf736cc443ca + Author: Yu Watanabe + AuthorDate: Thu Jul 27 20:22:54 2017 +0900 + Commit: Zbigniew Jędrzejewski-Szmek + CommitDate: Thu Jul 27 07:22:54 2017 -0400 +*/ +#if !HAVE_DECL_COPY_FILE_RANGE +# ifndef __NR_copy_file_range +# if defined(__x86_64__) +# define __NR_copy_file_range 326 +# elif defined(__i386__) +# define __NR_copy_file_range 377 +# elif defined __s390__ +# define __NR_copy_file_range 375 +# elif defined __arm__ +# define __NR_copy_file_range 391 +# elif defined __aarch64__ +# define __NR_copy_file_range 285 +# elif defined __powerpc__ +# define __NR_copy_file_range 379 +# elif defined __arc__ +# define __NR_copy_file_range 285 +# else +# warning "__NR_copy_file_range not defined for your architecture" +# endif +# endif + +static inline ssize_t copy_file_range(int fd_in, loff_t *off_in, + int fd_out, loff_t *off_out, + size_t len, + unsigned int flags) { +# ifdef __NR_copy_file_range + return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags); +# else + errno = ENOSYS; + return -1; +# endif +} +#endif diff --git a/libglnx/glnx-xattrs.c b/libglnx/glnx-xattrs.c index 3ade89c1..79a14cd3 100644 --- a/libglnx/glnx-xattrs.c +++ b/libglnx/glnx-xattrs.c @@ -145,8 +145,8 @@ get_xattrs_impl (const char *path, { gboolean ret = FALSE; ssize_t bytes_read, real_size; - glnx_free char *xattr_names = NULL; - glnx_free char *xattr_names_canonical = NULL; + g_autofree char *xattr_names = NULL; + g_autofree char *xattr_names_canonical = NULL; GVariantBuilder builder; gboolean builder_initialized = FALSE; g_autoptr(GVariant) ret_xattrs = NULL; diff --git a/man/ostree-pull.xml b/man/ostree-pull.xml index 394a29c2..59a6dbc8 100644 --- a/man/ostree-pull.xml +++ b/man/ostree-pull.xml @@ -78,7 +78,7 @@ Boston, MA 02111-1307, USA. Like git's clone --reference. Reuse the provided - OSTree repo as a local object cache of objects when doing HTTP fetches. + OSTree repo as a local object cache when doing HTTP fetches. May be specified multiple times. @@ -132,12 +132,15 @@ Boston, MA 02111-1307, USA. This command can retrieve just a specific commit, or go all the way to performing a full mirror of the remote repository. If no BRANCH is specified, - all branches are retrieved. + all configured branches are retrieved. - A special syntax in the @ character allows - specifying a specific commit to retrieve from a branch. This + A special syntax in the @ character allows + specifying a specific commit to retrieve from a branch. The + use cases for this are somewhat similar to pulling a specific + git tag; one could e.g. script a system upgrade to a known-good + version, rather than the latest from the content provider. diff --git a/man/ostree-refs.xml b/man/ostree-refs.xml index 726a94ac..26a3203d 100644 --- a/man/ostree-refs.xml +++ b/man/ostree-refs.xml @@ -51,13 +51,17 @@ Boston, MA 02111-1307, USA. ostree refs OPTIONS PREFIX + + ostree refs EXISTING --create=NEWREF + Description - Lists all refs available on the host. If specified, 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. This command can also be used to create or delete refs. @@ -75,6 +79,16 @@ Boston, MA 02111-1307, USA. printed in full, rather than truncated. + + + =NEWREF + + + Create a ref pointing to the commit EXISTING. NEWREF must not already exist, and EXISTING + must be an existing commit. More than one ref can point to the same commit. + + + @@ -85,7 +99,15 @@ Boston, MA 02111-1307, USA. - + , + + + If used with , create an alias. Otherwise just list aliases. + + + + + , Enable interactions with refs using the combination of their @@ -99,8 +121,7 @@ Boston, MA 02111-1307, USA. is created. (This is an abuse of the refspec syntax.) When deleting refs, all refs whose collection ID equals - the value of the argument are - deleted. + PREFIX are deleted. diff --git a/man/ostree-remote.xml b/man/ostree-remote.xml index 2bb8aa71..bf41a10c 100644 --- a/man/ostree-remote.xml +++ b/man/ostree-remote.xml @@ -96,6 +96,13 @@ Boston, MA 02111-1307, USA. Changes remote repository configurations. The NAME refers to the name of the remote. + + The BRANCH arguments to the + add subcommand specifies the configured branches + for the remote. See the branches section in + ostree.repo-config5 + for more information. + The gpg-import subcommand can associate GPG keys to a specific remote repository for use when pulling signed commits from that repository (if GPG verification is enabled). diff --git a/man/ostree-static-delta.xml b/man/ostree-static-delta.xml index ed2e1f48..3b16aaff 100644 --- a/man/ostree-static-delta.xml +++ b/man/ostree-static-delta.xml @@ -90,6 +90,8 @@ Boston, MA 02111-1307, USA. Create delta to revision REV. (This option is required.) + The delta is from the parent of REV, unless specified otherwise by + or . diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml index 60458dfa..cf0bf7c0 100644 --- a/man/ostree.repo-config.xml +++ b/man/ostree.repo-config.xml @@ -114,6 +114,14 @@ Boston, MA 02111-1307, USA. + + + min-free-space-percent + Integer percentage value (0-99) that specifies a minimum + percentage of total space (in blocks) in the underlying filesystem to + keep free. The default value is 3. + + @@ -139,6 +147,13 @@ Boston, MA 02111-1307, USA. metadata: summary, static delta "superblocks". + + branches + A list of strings. Represents the default configured + branches to fetch from the remote when no specific branches are + requested during a pull operation. + + proxy A string value, if given should be a URL for a @@ -191,13 +206,6 @@ Boston, MA 02111-1307, USA. If set, pulls from this remote will fail with the configured text. This is intended for OS vendors which have a subscription process to access content. - - min-free-space-percent - Integer percentage value (0-99) that specifies a minimum - percentage of total space (in blocks) in the underlying filesystem to - keep free. The default value is 3. - - diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym index c93e388a..01f182f6 100644 --- a/src/libostree/libostree-devel.sym +++ b/src/libostree/libostree-devel.sym @@ -18,8 +18,6 @@ ***/ /* Add new symbols here. Release commits should copy this section into -released.sym. */ -LIBOSTREE_2017.10 { -}; /* Stub section for the stable release *after* this development one; don't * edit this other than to update the last number. This is just a copy/paste diff --git a/src/libostree/libostree-experimental.sym b/src/libostree/libostree-experimental.sym index 32ba0929..f60d4e01 100644 --- a/src/libostree/libostree-experimental.sym +++ b/src/libostree/libostree-experimental.sym @@ -70,6 +70,7 @@ global: ostree_repo_list_collection_refs; ostree_repo_pull_from_remotes_async; ostree_repo_pull_from_remotes_finish; + ostree_repo_remote_list_collection_refs; ostree_repo_resolve_keyring_for_collection; ostree_repo_set_collection_id; ostree_repo_set_collection_ref_immediate; diff --git a/src/libostree/libostree-released.sym b/src/libostree/libostree-released.sym index 0a138966..fe98858d 100644 --- a/src/libostree/libostree-released.sym +++ b/src/libostree/libostree-released.sym @@ -416,6 +416,17 @@ global: LIBOSTREE_2017.9 { }; +LIBOSTREE_2017.10 { + ostree_gpg_error_quark; + ostree_repo_set_alias_ref_immediate; + ostree_repo_open_at; + ostree_repo_create_at; +/* Inherit from .8 since .9 is empty and is also broken + * in that it doesn't have a parent currently; + * + */ +} LIBOSTREE_2017.8; + /* NOTE: Only add more content here in release commits! See the * comments at the top of this file. */ diff --git a/src/libostree/ostree-bootloader-grub2.c b/src/libostree/ostree-bootloader-grub2.c index 86970d36..ff83f151 100644 --- a/src/libostree/ostree-bootloader-grub2.c +++ b/src/libostree/ostree-bootloader-grub2.c @@ -38,9 +38,19 @@ * among others. */ #if defined(__i386__) || defined(__x86_64__) -#define GRUB2_USES_16 1 +#define GRUB2_SUFFIX "16" #else -#define GRUB2_USES_16 0 +#define GRUB2_SUFFIX "" +#endif +/* https://github.com/projectatomic/rpm-ostree-toolbox/issues/102#issuecomment-316483554 + * https://github.com/rhboot/grubby/blob/34b1436ccbd56eab8024314cab48f2fc880eef08/grubby.c#L63 + * + * This is true at least on Fedora/Red Hat Enterprise Linux for aarch64. + */ +#if defined(__aarch64__) +#define GRUB2_EFI_SUFFIX "" +#else +#define GRUB2_EFI_SUFFIX "efi" #endif struct _OstreeBootloaderGrub2 @@ -214,16 +224,12 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot "No \"linux\" key in bootloader config"); goto out; } + g_string_append (output, "linux"); if (is_efi) - g_string_append (output, "linuxefi "); + g_string_append (output, GRUB2_EFI_SUFFIX); else - { -#if GRUB2_USES_16 - g_string_append (output, "linux16 "); -#else - g_string_append (output, "linux "); -#endif - } + g_string_append (output, GRUB2_SUFFIX); + g_string_append_c (output, ' '); g_string_append (output, kernel); options = ostree_bootconfig_parser_get (config, "options"); @@ -237,16 +243,12 @@ _ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot initrd = ostree_bootconfig_parser_get (config, "initrd"); if (initrd) { + g_string_append (output, "initrd"); if (is_efi) - g_string_append (output, "initrdefi "); + g_string_append (output, GRUB2_EFI_SUFFIX); else - { -#if GRUB2_USES_16 - g_string_append (output, "initrd16 "); -#else - g_string_append (output, "initrd "); -#endif - } + g_string_append (output, GRUB2_SUFFIX); + g_string_append_c (output, ' '); g_string_append (output, initrd); g_string_append_c (output, '\n'); } diff --git a/src/libostree/ostree-bootloader.h b/src/libostree/ostree-bootloader.h index eb044300..de46422d 100644 --- a/src/libostree/ostree-bootloader.h +++ b/src/libostree/ostree-bootloader.h @@ -21,6 +21,7 @@ #pragma once #include +#include "otutil.h" G_BEGIN_DECLS @@ -48,6 +49,7 @@ struct _OstreeBootloaderInterface GError **error); gboolean (* is_atomic) (OstreeBootloader *self); }; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeBootloader, g_object_unref) GType _ostree_bootloader_get_type (void) G_GNUC_CONST; diff --git a/src/libostree/ostree-deployment.c b/src/libostree/ostree-deployment.c index 8bdc9b57..78afe18c 100644 --- a/src/libostree/ostree-deployment.c +++ b/src/libostree/ostree-deployment.c @@ -20,8 +20,9 @@ #include "config.h" +#include "otutil.h" +#include "ostree.h" #include "ostree-deployment-private.h" -#include "libglnx.h" typedef GObjectClass OstreeDeploymentClass; @@ -138,7 +139,7 @@ _ostree_deployment_set_bootcsum (OstreeDeployment *self, OstreeDeployment * ostree_deployment_clone (OstreeDeployment *self) { - glnx_unref_object OstreeBootconfigParser *new_bootconfig = NULL; + g_autoptr(OstreeBootconfigParser) new_bootconfig = NULL; OstreeDeployment *ret = ostree_deployment_new (self->index, self->osname, self->csum, self->deployserial, self->bootcsum, self->bootserial); @@ -159,7 +160,7 @@ ostree_deployment_clone (OstreeDeployment *self) new_origin = g_key_file_new (); success = g_key_file_load_from_data (new_origin, data, len, 0, NULL); g_assert (success); - + ostree_deployment_set_origin (ret, new_origin); } return ret; @@ -186,8 +187,8 @@ ostree_deployment_equal (gconstpointer ap, gconstpointer bp) { OstreeDeployment *a = (OstreeDeployment*)ap; OstreeDeployment *b = (OstreeDeployment*)bp; - - if (a == NULL && b == NULL) + + if (a == b) return TRUE; else if (a != NULL && b != NULL) return g_str_equal (ostree_deployment_get_osname (a), @@ -195,7 +196,7 @@ ostree_deployment_equal (gconstpointer ap, gconstpointer bp) g_str_equal (ostree_deployment_get_csum (a), ostree_deployment_get_csum (b)) && ostree_deployment_get_deployserial (a) == ostree_deployment_get_deployserial (b); - else + else return FALSE; } @@ -235,7 +236,7 @@ ostree_deployment_new (int index, int bootserial) { OstreeDeployment *self; - + /* index may be -1 */ g_return_val_if_fail (osname != NULL, NULL); g_return_val_if_fail (csum != NULL, NULL); diff --git a/src/libostree/ostree-fetcher-curl.c b/src/libostree/ostree-fetcher-curl.c index ae8bea73..57118f9c 100644 --- a/src/libostree/ostree-fetcher-curl.c +++ b/src/libostree/ostree-fetcher-curl.c @@ -425,11 +425,9 @@ static gboolean timer_cb (gpointer data) { OstreeFetcher *fetcher = data; - CURLMcode rc; GSource *orig_src = fetcher->timer_event; - rc = curl_multi_socket_action (fetcher->multi, CURL_SOCKET_TIMEOUT, 0, &fetcher->curl_running); - g_assert (rc == CURLM_OK); + (void)curl_multi_socket_action (fetcher->multi, CURL_SOCKET_TIMEOUT, 0, &fetcher->curl_running); check_multi_info (fetcher); if (fetcher->timer_event == orig_src) fetcher->timer_event = NULL; @@ -460,15 +458,12 @@ static gboolean event_cb (int fd, GIOCondition condition, gpointer data) { OstreeFetcher *fetcher = data; - CURLMcode rc; int action = (condition & G_IO_IN ? CURL_CSELECT_IN : 0) | (condition & G_IO_OUT ? CURL_CSELECT_OUT : 0); - rc = curl_multi_socket_action (fetcher->multi, fd, action, &fetcher->curl_running); - g_assert (rc == CURLM_OK); - + (void)curl_multi_socket_action (fetcher->multi, fd, action, &fetcher->curl_running); check_multi_info (fetcher); if (fetcher->curl_running > 0) { diff --git a/src/libostree/ostree-fetcher-soup.c b/src/libostree/ostree-fetcher-soup.c index f73554a2..e8185591 100644 --- a/src/libostree/ostree-fetcher-soup.c +++ b/src/libostree/ostree-fetcher-soup.c @@ -350,7 +350,7 @@ session_thread_set_tls_interaction_cb (ThreadClosure *thread_closure, const char *cert_and_key_path = data; /* str\0str\0 in one malloc buf */ const char *cert_path = cert_and_key_path; const char *key_path = cert_and_key_path + strlen (cert_and_key_path) + 1; - glnx_unref_object OstreeTlsCertInteraction *interaction = NULL; + g_autoptr(OstreeTlsCertInteraction) interaction = NULL; /* The GTlsInteraction instance must be created in the * session thread so it uses the correct GMainContext. */ diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c index 77594d9b..99756e2b 100644 --- a/src/libostree/ostree-gpg-verifier.c +++ b/src/libostree/ostree-gpg-verifier.c @@ -40,6 +40,7 @@ struct OstreeGpgVerifier { GObject parent; GList *keyrings; + GPtrArray *keyring_data; GPtrArray *key_ascii_files; }; @@ -53,6 +54,7 @@ ostree_gpg_verifier_finalize (GObject *object) g_list_free_full (self->keyrings, g_object_unref); if (self->key_ascii_files) g_ptr_array_unref (self->key_ascii_files); + g_clear_pointer (&self->keyring_data, (GDestroyNotify)g_ptr_array_unref); G_OBJECT_CLASS (_ostree_gpg_verifier_parent_class)->finalize (object); } @@ -71,6 +73,7 @@ _ostree_gpg_verifier_class_init (OstreeGpgVerifierClass *klass) static void _ostree_gpg_verifier_init (OstreeGpgVerifier *self) { + self->keyring_data = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref); } static void @@ -95,8 +98,8 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, { GLNX_AUTO_PREFIX_ERROR("GPG", error); gpgme_error_t gpg_error = 0; - ot_auto_gpgme_data gpgme_data_t data_buffer = NULL; - ot_auto_gpgme_data gpgme_data_t signature_buffer = NULL; + g_auto(gpgme_data_t) data_buffer = NULL; + g_auto(gpgme_data_t) signature_buffer = NULL; g_autofree char *tmp_dir = NULL; g_autoptr(GOutputStream) target_stream = NULL; OstreeGpgVerifyResult *result = NULL; @@ -151,6 +154,17 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, goto out; } + for (guint i = 0; i < self->keyring_data->len; i++) + { + GBytes *keyringd = self->keyring_data->pdata[i]; + gsize len; + gsize bytes_written; + const guint8 *buf = g_bytes_get_data (keyringd, &len); + if (!g_output_stream_write_all (target_stream, buf, len, &bytes_written, + cancellable, error)) + goto out; + } + if (!g_output_stream_close (target_stream, cancellable, error)) goto out; @@ -165,7 +179,7 @@ _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self, { const char *path = self->key_ascii_files->pdata[i]; glnx_fd_close int fd = -1; - ot_auto_gpgme_data gpgme_data_t kdata = NULL; + g_auto(gpgme_data_t) kdata = NULL; if (!glnx_openat_rdonly (AT_FDCWD, path, TRUE, &fd, error)) goto out; @@ -253,15 +267,28 @@ out: return result; } +/* Given @path which should contain a GPG keyring file, add it + * to the list of trusted keys. + */ void -_ostree_gpg_verifier_add_keyring (OstreeGpgVerifier *self, - GFile *path) +_ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self, + GFile *path) { g_return_if_fail (G_IS_FILE (path)); self->keyrings = g_list_append (self->keyrings, g_object_ref (path)); } +/* Given @keyring which should be the contents of a GPG keyring file, add it to + * the list of trusted keys. + */ +void +_ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self, + GBytes *keyring) +{ + g_ptr_array_add (self->keyring_data, g_bytes_ref (keyring)); +} + void _ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self, const char *path) @@ -276,32 +303,39 @@ _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self, GFile *path, GCancellable *cancellable, GError **error) + { - gboolean ret = FALSE; - g_autoptr(GFileEnumerator) enumerator = NULL; - - enumerator = g_file_enumerate_children (path, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NONE, - cancellable, error); - if (!enumerator) - goto out; + return _ostree_gpg_verifier_add_keyring_dir_at (self, AT_FDCWD, + gs_file_get_path_cached (path), + cancellable, error); +} + +gboolean +_ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error) + +{ + g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + if (!glnx_dirfd_iterator_init_at (dfd, path, FALSE, + &dfd_iter, error)) + return FALSE; while (TRUE) { - GFileInfo *file_info; - GFile *path; - const char *name; + struct dirent *dent; - if (!g_file_enumerator_iterate (enumerator, &file_info, &path, - cancellable, error)) - goto out; - if (file_info == NULL) + if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error)) + return FALSE; + if (dent == NULL) break; - if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_REGULAR) + if (dent->d_type != DT_REG) continue; - name = g_file_info_get_name (file_info); + const char *name = dent->d_name; /* Files with a .gpg suffix are typically keyrings except * for trustdb.gpg, which is the GPG trust database. */ @@ -315,12 +349,18 @@ _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self, if (g_str_equal (name, "secring.gpg")) continue; - self->keyrings = g_list_append (self->keyrings, g_object_ref (path)); + glnx_fd_close int fd = -1; + if (!glnx_openat_rdonly (dfd_iter.fd, dent->d_name, TRUE, &fd, error)) + return FALSE; + + g_autoptr(GBytes) data = glnx_fd_readall_bytes (fd, cancellable, error); + if (!data) + return FALSE; + + g_ptr_array_add (self->keyring_data, g_steal_pointer (&data)); } - ret = TRUE; - out: - return ret; + return TRUE; } gboolean diff --git a/src/libostree/ostree-gpg-verifier.h b/src/libostree/ostree-gpg-verifier.h index 4156d1bd..7d5a7594 100644 --- a/src/libostree/ostree-gpg-verifier.h +++ b/src/libostree/ostree-gpg-verifier.h @@ -55,12 +55,20 @@ gboolean _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier *self, GCancellable *cancellable, GError **error); +gboolean _ostree_gpg_verifier_add_keyring_dir_at (OstreeGpgVerifier *self, + int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + gboolean _ostree_gpg_verifier_add_global_keyring_dir (OstreeGpgVerifier *self, GCancellable *cancellable, GError **error); -void _ostree_gpg_verifier_add_keyring (OstreeGpgVerifier *self, - GFile *path); +void _ostree_gpg_verifier_add_keyring_data (OstreeGpgVerifier *self, + GBytes *data); +void _ostree_gpg_verifier_add_keyring_file (OstreeGpgVerifier *self, + GFile *path); void _ostree_gpg_verifier_add_key_ascii_file (OstreeGpgVerifier *self, const char *path); diff --git a/src/libostree/ostree-gpg-verify-result.c b/src/libostree/ostree-gpg-verify-result.c index 0277ce1e..f6689e63 100644 --- a/src/libostree/ostree-gpg-verify-result.c +++ b/src/libostree/ostree-gpg-verify-result.c @@ -237,34 +237,49 @@ ostree_gpg_verify_result_lookup (OstreeGpgVerifyResult *result, const gchar *key_id, guint *out_signature_index) { - g_autofree char *key_id_upper = NULL; + g_auto(gpgme_key_t) lookup_key = NULL; gpgme_signature_t signature; guint signature_index; - gboolean ret = FALSE; g_return_val_if_fail (OSTREE_IS_GPG_VERIFY_RESULT (result), FALSE); g_return_val_if_fail (key_id != NULL, FALSE); - /* signature->fpr is always upper-case. */ - key_id_upper = g_ascii_strup (key_id, -1); + /* fetch requested key_id from keyring to canonicalise ID */ + (void) gpgme_get_key (result->context, key_id, &lookup_key, 0); + + if (lookup_key == NULL) + { + g_debug ("Could not find key ID %s to lookup signature.", key_id); + return FALSE; + } for (signature = result->details->signatures, signature_index = 0; signature != NULL; signature = signature->next, signature_index++) { - if (signature->fpr == NULL) - continue; + g_auto(gpgme_key_t) signature_key = NULL; - if (g_str_has_suffix (signature->fpr, key_id_upper)) + (void) gpgme_get_key (result->context, signature->fpr, &signature_key, 0); + + if (signature_key == NULL) + { + g_debug ("Could not find key when looking up signature from %s.", signature->fpr); + continue; + } + + /* the first subkey in the list is the primary key */ + if (!g_strcmp0 (lookup_key->subkeys->fpr, + signature_key->subkeys->fpr)) { if (out_signature_index != NULL) *out_signature_index = signature_index; - ret = TRUE; - break; + /* Note early return */ + return TRUE; } + } - return ret; + return FALSE; } /** @@ -291,7 +306,7 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, guint n_attrs) { GVariantBuilder builder; - gpgme_key_t key = NULL; + g_auto(gpgme_key_t) key = NULL; gpgme_signature_t signature; guint ii; @@ -313,7 +328,8 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, * (OSTREE_GPG_SIGNATURE_ATTR_KEY_MISSING). */ for (ii = 0; ii < n_attrs; ii++) { - if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME || + if (attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT || + attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_NAME || attrs[ii] == OSTREE_GPG_SIGNATURE_ATTR_USER_EMAIL) { (void) gpgme_get_key (result->context, signature->fpr, &key, 0); @@ -357,7 +373,11 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, break; case OSTREE_GPG_SIGNATURE_ATTR_FINGERPRINT: - child = g_variant_new_string (signature->fpr); + if (key != NULL && key->subkeys != NULL) + v_string = key->subkeys->fpr; + else + v_string = signature->fpr; + child = g_variant_new_string (v_string); break; case OSTREE_GPG_SIGNATURE_ATTR_TIMESTAMP: @@ -407,9 +427,6 @@ ostree_gpg_verify_result_get (OstreeGpgVerifyResult *result, g_variant_builder_add_value (&builder, child); } - if (key != NULL) - gpgme_key_unref (key); - return g_variant_builder_end (&builder); } @@ -665,9 +682,12 @@ ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result, if (ostree_gpg_verify_result_count_valid (result) == 0) { - return glnx_throw (error, "%s", - "GPG signatures found, but none are in trusted keyring"); + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_MISSING_KEY, + "GPG signatures found, but none are in trusted keyring"); + return FALSE; } return TRUE; } + +G_DEFINE_QUARK (OstreeGpgError, ostree_gpg_error) diff --git a/src/libostree/ostree-gpg-verify-result.h b/src/libostree/ostree-gpg-verify-result.h index f9512538..f5fadd59 100644 --- a/src/libostree/ostree-gpg-verify-result.h +++ b/src/libostree/ostree-gpg-verify-result.h @@ -137,4 +137,25 @@ _OSTREE_PUBLIC gboolean ostree_gpg_verify_result_require_valid_signature (OstreeGpgVerifyResult *result, GError **error); +/** + * OstreeGpgError: + * @OSTREE_GPG_ERROR_NO_SIGNATURE: A signature was expected, but not found. + * @OSTREE_GPG_ERROR_INVALID_SIGNATURE: A signature was malformed. + * @OSTREE_GPG_ERROR_MISSING_KEY: A signature was found, but was created with a key not in the configured keyrings. + * + * Errors returned by signature creation and verification operations in OSTree. + * These may be returned by any API which creates or verifies signatures. + * + * Since: 2017.10 + */ +typedef enum { + OSTREE_GPG_ERROR_NO_SIGNATURE = 0, + OSTREE_GPG_ERROR_INVALID_SIGNATURE, + OSTREE_GPG_ERROR_MISSING_KEY, +} OstreeGpgError; + +_OSTREE_PUBLIC +GQuark ostree_gpg_error_quark (void); +#define OSTREE_GPG_ERROR (ostree_gpg_error_quark ()) + G_END_DECLS diff --git a/src/libostree/ostree-impl-system-generator.c b/src/libostree/ostree-impl-system-generator.c index d64c8a27..ed2bb97c 100644 --- a/src/libostree/ostree-impl-system-generator.c +++ b/src/libostree/ostree-impl-system-generator.c @@ -36,7 +36,7 @@ #ifdef HAVE_LIBMOUNT typedef FILE OtLibMountFile; -G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtLibMountFile, endmntent); +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtLibMountFile, endmntent) /* Taken from systemd path-util.c */ static bool diff --git a/src/libostree/ostree-libarchive-private.h b/src/libostree/ostree-libarchive-private.h index 865a4b8d..870ddf82 100644 --- a/src/libostree/ostree-libarchive-private.h +++ b/src/libostree/ostree-libarchive-private.h @@ -22,8 +22,10 @@ #pragma once +#include "config.h" + #include -#include "libglnx.h" +#include "otutil.h" #ifdef HAVE_LIBARCHIVE #include #include @@ -32,14 +34,10 @@ G_BEGIN_DECLS #ifdef HAVE_LIBARCHIVE -GLNX_DEFINE_CLEANUP_FUNCTION (void *, flatpak_local_free_write_archive, archive_write_free) -#define ot_cleanup_write_archive __attribute__((cleanup (flatpak_local_free_write_archive))) - -GLNX_DEFINE_CLEANUP_FUNCTION (void *, flatpak_local_free_read_archive, archive_read_free) -#define ot_cleanup_read_archive __attribute__((cleanup (flatpak_local_free_read_archive))) -#else -#define ot_cleanup_write_archive -#define ot_cleanup_read_archive +typedef struct archive OtAutoArchiveWrite; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveWrite, archive_write_free) +typedef struct archive OtAutoArchiveRead; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OtAutoArchiveRead, archive_read_free) #endif G_END_DECLS diff --git a/src/libostree/ostree-metalink.h b/src/libostree/ostree-metalink.h index 55ed92e8..60a24204 100644 --- a/src/libostree/ostree-metalink.h +++ b/src/libostree/ostree-metalink.h @@ -40,6 +40,7 @@ struct OstreeMetalinkClass { GObjectClass parent_class; }; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeMetalink, g_object_unref) GType _ostree_metalink_get_type (void) G_GNUC_CONST; diff --git a/src/libostree/ostree-mutable-tree.c b/src/libostree/ostree-mutable-tree.c index c263fbe4..5e933acc 100644 --- a/src/libostree/ostree-mutable-tree.c +++ b/src/libostree/ostree-mutable-tree.c @@ -22,9 +22,8 @@ #include "config.h" -#include "ostree-mutable-tree.h" #include "otutil.h" -#include "ostree-core.h" +#include "ostree.h" /** * SECTION:ostree-mutable-tree @@ -183,7 +182,7 @@ ostree_mutable_tree_ensure_dir (OstreeMutableTree *self, GError **error) { gboolean ret = FALSE; - glnx_unref_object OstreeMutableTree *ret_dir = NULL; + g_autoptr(OstreeMutableTree) ret_dir = NULL; g_return_val_if_fail (name != NULL, FALSE); @@ -219,7 +218,7 @@ ostree_mutable_tree_lookup (OstreeMutableTree *self, GError **error) { gboolean ret = FALSE; - glnx_unref_object OstreeMutableTree *ret_subdir = NULL; + g_autoptr(OstreeMutableTree) ret_subdir = NULL; g_autofree char *ret_file_checksum = NULL; ret_subdir = ot_gobject_refz (g_hash_table_lookup (self->subdirs, name)); @@ -261,7 +260,7 @@ ostree_mutable_tree_ensure_parent_dirs (OstreeMutableTree *self, gboolean ret = FALSE; int i; OstreeMutableTree *subdir = self; /* nofree */ - glnx_unref_object OstreeMutableTree *ret_parent = NULL; + g_autoptr(OstreeMutableTree) ret_parent = NULL; g_assert (metadata_checksum != NULL); diff --git a/src/libostree/ostree-repo-checkout.c b/src/libostree/ostree-repo-checkout.c index 15d0394b..3deaa297 100644 --- a/src/libostree/ostree-repo-checkout.c +++ b/src/libostree/ostree-repo-checkout.c @@ -46,7 +46,7 @@ checkout_state_clear (CheckoutState *state) if (state->selabel_path_buf) g_string_free (state->selabel_path_buf, TRUE); } -G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(CheckoutState, checkout_state_clear); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(CheckoutState, checkout_state_clear) static gboolean checkout_object_for_uncompressed_cache (OstreeRepo *self, @@ -122,7 +122,7 @@ write_regular_file_content (OstreeRepo *self, int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input); guint64 len = g_file_info_get_size (file_info); - if (glnx_regfile_copy_bytes (infd, outfd, (off_t)len, TRUE) < 0) + if (glnx_regfile_copy_bytes (infd, outfd, (off_t)len) < 0) return glnx_throw_errno_prefix (error, "regfile copy"); } else diff --git a/src/libostree/ostree-repo-commit.c b/src/libostree/ostree-repo-commit.c index 1d3d6840..1c6e5e8d 100644 --- a/src/libostree/ostree-repo-commit.c +++ b/src/libostree/ostree-repo-commit.c @@ -27,16 +27,16 @@ #include #include #include -#include "otutil.h" +#include +#include +#include "otutil.h" +#include "ostree.h" #include "ostree-core-private.h" #include "ostree-repo-private.h" #include "ostree-repo-file-enumerator.h" #include "ostree-checksum-input-stream.h" -#include "ostree-mutable-tree.h" #include "ostree-varint.h" -#include -#include gboolean _ostree_repo_ensure_loose_objdir_at (int dfd, @@ -467,7 +467,7 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self, if (G_IS_FILE_DESCRIPTOR_BASED (input)) { int infd = g_file_descriptor_based_get_fd ((GFileDescriptorBased*) input); - if (glnx_regfile_copy_bytes (infd, tmpf.fd, (off_t)length, TRUE) < 0) + if (glnx_regfile_copy_bytes (infd, tmpf.fd, (off_t)length) < 0) return glnx_throw_errno_prefix (error, "regfile copy"); } else @@ -485,10 +485,8 @@ create_regular_tmpfile_linkable_with_content (OstreeRepo *self, g_input_stream_read (input, buf, MIN (remaining, sizeof (buf)), cancellable, error); if (bytes_read < 0) return FALSE; - else if (G_UNLIKELY (bytes_read == 0 && remaining > 0)) - return glnx_throw (error, "Unexpected EOF with %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " bytes remaining", remaining, length); else if (bytes_read == 0) - break; + return glnx_throw (error, "Unexpected EOF with %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " bytes remaining", remaining, length); if (glnx_loop_write (tmpf.fd, buf, bytes_read) < 0) return glnx_throw_errno_prefix (error, "write"); remaining -= bytes_read; @@ -1448,7 +1446,31 @@ ostree_repo_set_ref_immediate (OstreeRepo *self, GError **error) { const OstreeCollectionRef _ref = { NULL, (gchar *) ref }; - return _ostree_repo_write_ref (self, remote, &_ref, checksum, + return _ostree_repo_write_ref (self, remote, &_ref, checksum, NULL, + cancellable, error); +} + +/** + * ostree_repo_set_alias_ref_immediate: + * @self: An #OstreeRepo + * @remote: (allow-none): A remote for the ref + * @ref: The ref to write + * @target: (allow-none): The ref target to point it to, or %NULL to unset + * @cancellable: GCancellable + * @error: GError + * + * Like ostree_repo_set_ref_immediate(), but creates an alias. + */ +gboolean +ostree_repo_set_alias_ref_immediate (OstreeRepo *self, + const char *remote, + const char *ref, + const char *target, + GCancellable *cancellable, + GError **error) +{ + const OstreeCollectionRef _ref = { NULL, (gchar *) ref }; + return _ostree_repo_write_ref (self, remote, &_ref, NULL, target, cancellable, error); } @@ -1480,7 +1502,7 @@ ostree_repo_set_collection_ref_immediate (OstreeRepo *self, g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - return _ostree_repo_write_ref (self, NULL, ref, checksum, + return _ostree_repo_write_ref (self, NULL, ref, checksum, NULL, cancellable, error); } @@ -2528,7 +2550,7 @@ write_directory_content_to_mtree_internal (OstreeRepo *self, { g_autoptr(GFile) child = NULL; g_autoptr(GFileInfo) modified_info = NULL; - glnx_unref_object OstreeMutableTree *child_mtree = NULL; + g_autoptr(OstreeMutableTree) child_mtree = NULL; g_autofree char *child_relpath = NULL; const char *name; GFileType file_type; diff --git a/src/libostree/ostree-repo-finder-avahi.c b/src/libostree/ostree-repo-finder-avahi.c index 433914b4..5ded9636 100644 --- a/src/libostree/ostree-repo-finder-avahi.c +++ b/src/libostree/ostree-repo-finder-avahi.c @@ -556,7 +556,8 @@ get_refs_and_checksums_from_summary (GBytes *summary_bytes, } /* Download the summary file from @remote, and return the bytes of the file in - * @out_summary_bytes. */ + * @out_summary_bytes. This will return %TRUE and set @out_summary_bytes to %NULL + * if the summary file does not exist. */ static gboolean fetch_summary_from_remote (OstreeRepo *repo, OstreeRemote *remote, @@ -648,6 +649,13 @@ get_checksums (OstreeRepoFinderAvahi *finder, error)) return FALSE; + if (summary_bytes == NULL) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No summary file found on server"); + return FALSE; + } + return get_refs_and_checksums_from_summary (summary_bytes, supported_ref_to_checksum, error); } @@ -816,9 +824,10 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService g_clear_pointer (&remote->keyring, g_free); remote->keyring = g_strdup (repo->keyring); + /* gpg-verify-summary is false since we use the unsigned summary file support. */ g_key_file_set_string (remote->options, remote->group, "url", repo->uri); g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE); - g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", TRUE); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE); get_checksums (finder, parent_repo, remote, supported_ref_to_checksum, &error); if (error != NULL) @@ -830,7 +839,7 @@ ostree_avahi_service_build_repo_finder_result (OstreeAvahiService g_ptr_array_add (results, ostree_repo_finder_result_new (remote, OSTREE_REPO_FINDER (finder), priority, supported_ref_to_checksum, - (summary_timestamp != NULL) ? GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp)) : 0)); + GUINT64_FROM_BE (g_variant_get_uint64 (summary_timestamp)))); } } diff --git a/src/libostree/ostree-repo-finder-config.c b/src/libostree/ostree-repo-finder-config.c index 79a63536..ada8479e 100644 --- a/src/libostree/ostree-repo-finder-config.c +++ b/src/libostree/ostree-repo-finder-config.c @@ -111,9 +111,10 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find for (i = 0; i < n_remotes; i++) { g_autoptr(GError) local_error = NULL; - g_autoptr(GHashTable) remote_refs = NULL; /* (element-type utf8 utf8) */ + g_autoptr(GHashTable) remote_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ const gchar *checksum; g_autofree gchar *remote_collection_id = NULL; + gboolean resolved_a_ref = FALSE; remote_name = remotes[i]; @@ -127,8 +128,9 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find continue; } - if (!ostree_repo_remote_list_refs (parent_repo, remote_name, &remote_refs, - cancellable, &local_error)) + if (!ostree_repo_remote_list_collection_refs (parent_repo, remote_name, + &remote_refs, cancellable, + &local_error)) { g_debug ("Ignoring remote ‘%s’ due to error loading its refs: %s", remote_name, local_error->message); @@ -139,13 +141,14 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find for (j = 0; refs[j] != NULL; j++) { if (g_strcmp0 (refs[j]->collection_id, remote_collection_id) == 0 && - g_hash_table_lookup_extended (remote_refs, refs[j]->ref_name, NULL, (gpointer *) &checksum)) + g_hash_table_lookup_extended (remote_refs, refs[j], NULL, (gpointer *) &checksum)) { /* The requested ref is listed in the refs for this remote. Add * the remote to the results, and the ref to its * @supported_ref_to_checksum. */ g_debug ("Resolved ref (%s, %s) to remote ‘%s’.", refs[j]->collection_id, refs[j]->ref_name, remote_name); + resolved_a_ref = TRUE; supported_ref_to_checksum = g_hash_table_lookup (repo_name_to_refs, remote_name); @@ -161,6 +164,9 @@ ostree_repo_finder_config_resolve_async (OstreeRepoFinder *find (gpointer) refs[j], g_strdup (checksum)); } } + + if (!resolved_a_ref) + g_debug ("Ignoring remote ‘%s’ due to it not advertising any of the requested refs.", remote_name); } /* Aggregate the results. */ diff --git a/src/libostree/ostree-repo-finder-mount.c b/src/libostree/ostree-repo-finder-mount.c index ffe31e99..7f257f68 100644 --- a/src/libostree/ostree-repo-finder-mount.c +++ b/src/libostree/ostree-repo-finder-mount.c @@ -31,6 +31,7 @@ #include "ostree-autocleanups.h" #include "ostree-remote-private.h" +#include "ostree-repo-private.h" #include "ostree-repo-finder.h" #include "ostree-repo-finder-mount.h" @@ -257,19 +258,16 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde { struct stat stbuf; g_autofree gchar *collection_and_ref = NULL; - g_autofree gchar *repo_dir_path = NULL; g_autofree gchar *resolved_repo_uri = NULL; g_autofree gchar *keyring = NULL; g_autoptr(UriAndKeyring) resolved_repo = NULL; collection_and_ref = g_build_filename (refs[i]->collection_id, refs[i]->ref_name, NULL); - repo_dir_path = g_build_filename (mount_root_path, ".ostree", "repos", - collection_and_ref, NULL); if (!glnx_fstatat (repos_dfd, collection_and_ref, &stbuf, AT_NO_AUTOMOUNT, &local_error)) { g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as querying info of ‘%s’ failed: %s", - refs[i]->collection_id, refs[i]->ref_name, mount_name, repo_dir_path, local_error->message); + refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, local_error->message); g_clear_error (&local_error); continue; } @@ -277,7 +275,7 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde if ((stbuf.st_mode & S_IFMT) != S_IFDIR) { g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as ‘%s’ is of type %u, not a directory.", - refs[i]->collection_id, refs[i]->ref_name, mount_name, repo_dir_path, (stbuf.st_mode & S_IFMT)); + refs[i]->collection_id, refs[i]->ref_name, mount_name, collection_and_ref, (stbuf.st_mode & S_IFMT)); g_clear_error (&local_error); continue; } @@ -294,27 +292,19 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde } /* Exclude repositories which resolve to @parent_repo. */ - g_autofree char *canonical_repo_dir_path = realpath (repo_dir_path, NULL); - g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (parent_repo)); - g_autofree char *canonical_parent_repo_path = realpath (parent_repo_path, NULL); - - if (g_strcmp0 (canonical_repo_dir_path, canonical_parent_repo_path) == 0) + if (stbuf.st_dev == parent_repo->device && + stbuf.st_ino == parent_repo->inode) { - g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository was the one we are resolving for: %s", - refs[i]->collection_id, refs[i]->ref_name, mount_name, canonical_parent_repo_path); + g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as it is the same as the one we are resolving", + refs[i]->collection_id, refs[i]->ref_name, mount_name); g_clear_error (&local_error); continue; } - /* Grab the given ref and a checksum for it from the repo. - * FIXME: Ideally, there would be some ostree_repo_open_at() which we - * could use to keep the openat() chain going. See - * https://github.com/ostreedev/ostree/pull/820. */ - g_autoptr(OstreeRepo) repo = NULL; - g_autoptr(GFile) repo_dir_file = g_file_new_for_path (repo_dir_path); - repo = ostree_repo_new (repo_dir_file); - - if (!ostree_repo_open (repo, cancellable, &local_error)) + /* Grab the given ref and a checksum for it from the repo, if it appears to be a valid repo */ + g_autoptr(OstreeRepo) repo = ostree_repo_open_at (repos_dfd, collection_and_ref, + cancellable, &local_error); + if (!repo) { g_debug ("Ignoring ref (%s, %s) on mount ‘%s’ as its repository could not be opened: %s", refs[i]->collection_id, refs[i]->ref_name, mount_name, local_error->message); @@ -358,6 +348,11 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde * $mount_root/.ostree/repos/$refs[i]->collection_id/$refs[i]->ref_name. * Add it to the results, keyed by the canonicalised repository URI * to deduplicate the results. */ + + g_autofree char *repo_abspath = g_build_filename (mount_root_path, ".ostree/repos", + collection_and_ref, NULL); + /* FIXME - why are we using realpath here? */ + g_autofree char *canonical_repo_dir_path = realpath (repo_abspath, NULL); resolved_repo_uri = g_strconcat ("file://", canonical_repo_dir_path, NULL); g_debug ("Resolved ref (%s, %s) on mount ‘%s’ to repo URI ‘%s’ with keyring ‘%s’.", refs[i]->collection_id, refs[i]->ref_name, mount_name, resolved_repo_uri, keyring); @@ -392,9 +387,10 @@ ostree_repo_finder_mount_resolve_async (OstreeRepoFinder *finde g_clear_pointer (&remote->keyring, g_free); remote->keyring = g_strdup (repo->keyring); + /* gpg-verify-summary is false since we use the unsigned summary file support. */ g_key_file_set_string (remote->options, remote->group, "url", repo->uri); g_key_file_set_boolean (remote->options, remote->group, "gpg-verify", TRUE); - g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", TRUE); + g_key_file_set_boolean (remote->options, remote->group, "gpg-verify-summary", FALSE); /* Set the timestamp in the #OstreeRepoFinderResult to 0 because * the code in ostree_repo_pull_from_remotes_async() will be able to diff --git a/src/libostree/ostree-repo-finder.c b/src/libostree/ostree-repo-finder.c index 7893978d..1ddb2c62 100644 --- a/src/libostree/ostree-repo-finder.c +++ b/src/libostree/ostree-repo-finder.c @@ -550,7 +550,9 @@ ostree_repo_finder_result_free (OstreeRepoFinderResult *result) { g_return_if_fail (result != NULL); - g_hash_table_unref (result->ref_to_checksum); + /* This may be NULL iff the result is freed half-way through find_remotes_cb() + * in ostree-repo-pull.c, and at no other time. */ + g_clear_pointer (&result->ref_to_checksum, g_hash_table_unref); g_object_unref (result->finder); ostree_remote_unref (result->remote); g_free (result); diff --git a/src/libostree/ostree-repo-libarchive.c b/src/libostree/ostree-repo-libarchive.c index 2e1696b5..1839a088 100644 --- a/src/libostree/ostree-repo-libarchive.c +++ b/src/libostree/ostree-repo-libarchive.c @@ -22,10 +22,10 @@ #include "config.h" +#include "otutil.h" +#include "ostree.h" #include "ostree-core-private.h" #include "ostree-repo-private.h" -#include "ostree-repo-file.h" -#include "ostree-mutable-tree.h" #ifdef HAVE_LIBARCHIVE #include @@ -185,7 +185,7 @@ mtree_ensure_dir_with_meta (OstreeRepo *repo, GCancellable *cancellable, GError **error) { - glnx_unref_object OstreeMutableTree *dir = NULL; + g_autoptr(OstreeMutableTree) dir = NULL; g_autofree guchar *csum_raw = NULL; g_autofree char *csum = NULL; @@ -374,7 +374,7 @@ aic_create_parent_dirs (OstreeRepoArchiveImportContext *ctx, GError **error) { g_autofree char *fullpath = NULL; - glnx_unref_object OstreeMutableTree *dir = NULL; + g_autoptr(OstreeMutableTree) dir = NULL; /* start with the root itself */ if (!aic_ensure_parent_dir (ctx, ctx->root, "/", &dir, cancellable, error)) @@ -643,7 +643,7 @@ aic_import_entry (OstreeRepoArchiveImportContext *ctx, GError **error) { g_autoptr(GFileInfo) fi = NULL; - glnx_unref_object OstreeMutableTree *parent = NULL; + g_autoptr(OstreeMutableTree) parent = NULL; g_autofree char *path = aic_get_final_entry_pathname (ctx, error); if (path == NULL) @@ -669,7 +669,7 @@ aic_import_from_hardlink (OstreeRepoArchiveImportContext *ctx, const char *name = glnx_basename (target); const char *name_dh = glnx_basename (dh->path); g_autoptr(GPtrArray) components = NULL; - glnx_unref_object OstreeMutableTree *parent = NULL; + g_autoptr(OstreeMutableTree) parent = NULL; if (!ostree_mutable_tree_lookup (dh->parent, name_dh, &csum, NULL, error)) return FALSE; @@ -696,8 +696,8 @@ aic_lookup_file_csum (OstreeRepoArchiveImportContext *ctx, { g_autofree char *csum = NULL; const char *name = glnx_basename (target); - glnx_unref_object OstreeMutableTree *parent = NULL; - glnx_unref_object OstreeMutableTree *subdir = NULL; + g_autoptr(OstreeMutableTree) parent = NULL; + g_autoptr(OstreeMutableTree) subdir = NULL; g_autoptr(GPtrArray) components = NULL; if (!ot_util_path_split_validate (target, &components, error)) @@ -900,7 +900,7 @@ ostree_repo_write_archive_to_mtree (OstreeRepo *self, { #ifdef HAVE_LIBARCHIVE gboolean ret = FALSE; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; #ifdef HAVE_ARCHIVE_READ_SUPPORT_FILTER_ALL diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index 5dd0dea7..e38e48bc 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -21,10 +21,10 @@ #pragma once #include +#include "otutil.h" #include "ostree-ref.h" #include "ostree-repo.h" #include "ostree-remote-private.h" -#include "otutil.h" G_BEGIN_DECLS @@ -96,7 +96,11 @@ struct OstreeRepo { char *commit_stagedir_name; GLnxLockFile commit_stagedir_lock; - GFile *repodir; + /* A cached fd-relative version, distinct from the case where we may have a + * user-provided absolute path. + */ + GFile *repodir_fdrel; + GFile *repodir; /* May be %NULL if we were opened via ostree_repo_open_at() */ int repo_dir_fd; int tmp_dir_fd; int cache_dir_fd; @@ -132,10 +136,13 @@ struct OstreeRepo { GHashTable *updated_uncompressed_dirs; GHashTable *object_sizes; - uid_t owner_uid; - uid_t target_owner_uid; + /* Cache the repo's device/inode to use for comparisons elsewhere */ + dev_t device; + ino_t inode; + uid_t owner_uid; /* Cache of repo's owner uid */ + uid_t target_owner_uid; /* Ensure files are chowned to this uid/gid */ gid_t target_owner_gid; - guint min_free_space_percent; + guint min_free_space_percent; /* See the min-free-space-percent config option */ guint test_error_flags; /* OstreeRepoTestErrorFlags */ @@ -173,7 +180,7 @@ _ostree_repo_memory_cache_ref_init (OstreeRepoMemoryCacheRef *state, void _ostree_repo_memory_cache_ref_destroy (OstreeRepoMemoryCacheRef *state); -G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OstreeRepoMemoryCacheRef, _ostree_repo_memory_cache_ref_destroy) #define OSTREE_REPO_TMPDIR_STAGING "staging-" #define OSTREE_REPO_TMPDIR_FETCHER "fetcher-" @@ -265,6 +272,7 @@ _ostree_repo_write_ref (OstreeRepo *self, const char *remote, const OstreeCollectionRef *ref, const char *rev, + const char *alias, GCancellable *cancellable, GError **error); diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 8ba69580..e21342fe 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -50,10 +50,21 @@ #include #include +#ifdef HAVE_LIBSYSTEMD +#include +#endif + +#define OSTREE_MESSAGE_FETCH_COMPLETE_ID SD_ID128_MAKE(75,ba,3d,eb,0a,f0,41,a9,a4,62,72,ff,85,d9,e7,3e) #define OSTREE_REPO_PULL_CONTENT_PRIORITY (OSTREE_FETCHER_DEFAULT_PRIORITY) #define OSTREE_REPO_PULL_METADATA_PRIORITY (OSTREE_REPO_PULL_CONTENT_PRIORITY - 100) +typedef enum { + OSTREE_FETCHER_SECURITY_STATE_CA_PINNED, + OSTREE_FETCHER_SECURITY_STATE_TLS, + OSTREE_FETCHER_SECURITY_STATE_INSECURE, +} OstreeFetcherSecurityState; + typedef struct { OstreeRepo *repo; int tmpdir_dfd; @@ -61,6 +72,8 @@ typedef struct { char *remote_name; OstreeRepoMode remote_mode; OstreeFetcher *fetcher; + OstreeFetcherSecurityState fetcher_security_state; + GPtrArray *meta_mirrorlist; /* List of base URIs for fetching metadata */ GPtrArray *content_mirrorlist; /* List of base URIs for fetching content */ OstreeRepo *remote_repo_local; @@ -1405,12 +1418,12 @@ gpg_verify_unwritten_commit (OtPullData *pull_data, { if (pull_data->gpg_verify) { - glnx_unref_object OstreeGpgVerifyResult *result = NULL; + g_autoptr(OstreeGpgVerifyResult) result = NULL; g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit); if (!detached_metadata) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, "Commit %s: no detached metadata found for GPG verification", checksum); return FALSE; @@ -1611,7 +1624,7 @@ scan_commit_object (OtPullData *pull_data, if (pull_data->gpg_verify) { - glnx_unref_object OstreeGpgVerifyResult *result = NULL; + g_autoptr(OstreeGpgVerifyResult) result = NULL; result = ostree_repo_verify_commit_for_remote (pull_data->repo, checksum, @@ -1777,6 +1790,7 @@ scan_one_metadata_object_c (OtPullData *pull_data, { if (objtype == OSTREE_OBJECT_TYPE_COMMIT) { + /* mark as partial to ensure we scan the commit below */ if (!write_commitpartial_for (pull_data, tmp_checksum, error)) return FALSE; } @@ -1806,6 +1820,12 @@ scan_one_metadata_object_c (OtPullData *pull_data, return FALSE; if (!localcache_repo_has_obj) continue; + if (objtype == OSTREE_OBJECT_TYPE_COMMIT) + { + /* mark as partial to ensure we scan the commit below */ + if (!write_commitpartial_for (pull_data, tmp_checksum, error)) + return FALSE; + } if (!ostree_repo_import_object_from_with_trust (pull_data->repo, refd_repo, objtype, tmp_checksum, !pull_data->is_untrusted, @@ -2450,7 +2470,7 @@ on_superblock_fetched (GObject *src, */ if (pull_data->gpg_verify_summary && !summary_csum) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, "GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)"); goto out; } @@ -2612,11 +2632,13 @@ static OstreeFetcher * _ostree_repo_remote_new_fetcher (OstreeRepo *self, const char *remote_name, gboolean gzip, + OstreeFetcherSecurityState *out_state, GError **error) { OstreeFetcher *fetcher = NULL; OstreeFetcherConfigFlags fetcher_flags = 0; gboolean tls_permissive = FALSE; + OstreeFetcherSecurityState ret_state = OSTREE_FETCHER_SECURITY_STATE_TLS; gboolean success = FALSE; g_return_val_if_fail (OSTREE_IS_REPO (self), NULL); @@ -2628,7 +2650,10 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self, goto out; if (tls_permissive) - fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE; + { + fetcher_flags |= OSTREE_FETCHER_FLAGS_TLS_PERMISSIVE; + ret_state = OSTREE_FETCHER_SECURITY_STATE_INSECURE; + } if (gzip) fetcher_flags |= OSTREE_FETCHER_FLAGS_TRANSFER_GZIP; @@ -2673,6 +2698,10 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self, if (tls_ca_path != NULL) { _ostree_fetcher_set_tls_database (fetcher, tls_ca_path); + + /* Don't change if it's already _INSECURE */ + if (ret_state == OSTREE_FETCHER_SECURITY_STATE_TLS) + ret_state = OSTREE_FETCHER_SECURITY_STATE_CA_PINNED; } } @@ -2706,6 +2735,8 @@ _ostree_repo_remote_new_fetcher (OstreeRepo *self, out: if (!success) g_clear_object (&fetcher); + if (out_state) + *out_state = ret_state; return fetcher; } @@ -2724,7 +2755,7 @@ _ostree_preload_metadata_file (OstreeRepo *self, if (is_metalink) { - glnx_unref_object OstreeMetalink *metalink = NULL; + g_autoptr(OstreeMetalink) metalink = NULL; GError *local_error = NULL; /* the metalink uri is buried in the mirrorlist as the first (and only) @@ -2874,7 +2905,7 @@ repo_remote_fetch_summary (OstreeRepo *self, GCancellable *cancellable, GError **error) { - glnx_unref_object OstreeFetcher *fetcher = NULL; + g_autoptr(OstreeFetcher) fetcher = NULL; g_autoptr(GMainContext) mainctx = NULL; gboolean ret = FALSE; gboolean from_cache = FALSE; @@ -2891,7 +2922,7 @@ repo_remote_fetch_summary (OstreeRepo *self, mainctx = g_main_context_new (); g_main_context_push_thread_default (mainctx); - fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, error); + fetcher = _ostree_repo_remote_new_fetcher (self, name, TRUE, NULL, error); if (fetcher == NULL) goto out; @@ -3001,10 +3032,13 @@ repo_remote_fetch_summary (OstreeRepo *self, * any options specific to this pull (such as extra headers). */ static gboolean -reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, GError **error) +reinitialize_fetcher (OtPullData *pull_data, const char *remote_name, + GError **error) { g_clear_object (&pull_data->fetcher); - pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, FALSE, error); + pull_data->fetcher = _ostree_repo_remote_new_fetcher (pull_data->repo, remote_name, FALSE, + &pull_data->fetcher_security_state, + error); if (pull_data->fetcher == NULL) return FALSE; @@ -3186,7 +3220,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_autoptr(GHashTable) requested_refs_to_fetch = NULL; /* (element-type OstreeCollectionRef utf8) */ g_autoptr(GHashTable) commits_to_fetch = NULL; g_autofree char *remote_mode_str = NULL; - glnx_unref_object OstreeMetalink *metalink = NULL; + g_autoptr(OstreeMetalink) metalink = NULL; OtPullData pull_data_real = { 0, }; OtPullData *pull_data = &pull_data_real; GKeyFile *remote_config = NULL; @@ -3210,6 +3244,10 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_autoptr(GHashTable) updated_requested_refs_to_fetch = NULL; /* (element-type OstreeCollectionRef utf8) */ int i; g_autofree char **opt_localcache_repos = NULL; + /* If refs or collection-refs has exactly one value, this will point to that + * value, otherwise NULL. Used for logging. + */ + const char *the_ref_to_fetch = NULL; if (options) { @@ -3239,6 +3277,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, (void) g_variant_lookup (options, "localcache-repos", "^a&s", &opt_localcache_repos); } + g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE); g_return_val_if_fail (pull_data->maxdepth >= -1, FALSE); g_return_val_if_fail (!opt_collection_refs_set || (refs_to_fetch == NULL && override_commit_ids == NULL), FALSE); @@ -3621,21 +3660,21 @@ ostree_repo_pull_with_options (OstreeRepo *self, if (!bytes_summary && pull_data->gpg_verify_summary) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "GPG verification enabled, but no summary found (use gpg-verify-summary=false in remote config to disable)"); goto out; } if (!bytes_summary && pull_data->require_static_deltas) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Fetch configured to require static deltas, but no summary found"); goto out; } if (!bytes_sig && pull_data->gpg_verify_summary) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, "GPG verification enabled, but no summary.sig found (use gpg-verify-summary=false in remote config to disable)"); goto out; } @@ -3892,6 +3931,15 @@ ostree_repo_pull_with_options (OstreeRepo *self, g_hash_table_unref (requested_refs_to_fetch); requested_refs_to_fetch = g_steal_pointer (&updated_requested_refs_to_fetch); + if (g_hash_table_size (requested_refs_to_fetch) == 1) + { + GLNX_HASH_TABLE_FOREACH (requested_refs_to_fetch, + const OstreeCollectionRef *, ref) + { + the_ref_to_fetch = ref->ref_name; + break; + } + } /* Create the state directory here - it's new with the commitpartial code, * and may not exist in older repositories. @@ -4060,6 +4108,69 @@ ostree_repo_pull_with_options (OstreeRepo *self, ostree_async_progress_set_status (pull_data->progress, buf->str); } +#ifdef HAVE_LIBSYSTEMD + if (bytes_transferred > 0 && pull_data->remote_name) + { + g_autoptr(GString) msg = g_string_new (""); + if (the_ref_to_fetch) + g_string_append_printf (msg, "libostree pull from '%s' for %s complete", + pull_data->remote_name, the_ref_to_fetch); + else + g_string_append_printf (msg, "libostree pull from '%s' for %u refs complete", + pull_data->remote_name, g_hash_table_size (requested_refs_to_fetch)); + + const char *gpg_verify_state; + if (pull_data->gpg_verify_summary) + { + if (pull_data->gpg_verify) + gpg_verify_state = "summary+commit"; + else + gpg_verify_state = "summary-only"; + } + else + gpg_verify_state = (pull_data->gpg_verify ? "commit" : "disabled"); + g_string_append_printf (msg, "\nsecurity: GPG: %s ", gpg_verify_state); + OstreeFetcherURI *first_uri = pull_data->meta_mirrorlist->pdata[0]; + g_autofree char *first_scheme = _ostree_fetcher_uri_get_scheme (first_uri); + if (g_str_has_prefix (first_scheme, "http")) + { + g_string_append (msg, "http: "); + switch (pull_data->fetcher_security_state) + { + case OSTREE_FETCHER_SECURITY_STATE_CA_PINNED: + g_string_append (msg, "CA-pinned"); + break; + case OSTREE_FETCHER_SECURITY_STATE_TLS: + g_string_append (msg, "TLS"); + break; + case OSTREE_FETCHER_SECURITY_STATE_INSECURE: + g_string_append (msg, "insecure"); + break; + } + } + g_string_append (msg, "\n"); + + if (pull_data->n_fetched_deltaparts > 0) + g_string_append_printf (msg, "delta: parts: %u loose: %u", + pull_data->n_fetched_deltaparts, + pull_data->n_fetched_metadata + pull_data->n_fetched_content); + else + g_string_append_printf (msg, "non-delta: meta: %u content: %u", + pull_data->n_fetched_metadata, pull_data->n_fetched_content); + const guint n_seconds = (guint) ((end_time - pull_data->start_time) / G_USEC_PER_SEC); + g_autofree char *formatted_xferred = g_format_size (bytes_transferred); + g_string_append_printf (msg, "\ntransfer: secs: %u size: %s", n_seconds, formatted_xferred); + + sd_journal_send ("MESSAGE=%s", msg->str, + "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_MESSAGE_FETCH_COMPLETE_ID), + "OSTREE_REMOTE=%s", pull_data->remote_name, + "OSTREE_GPG=%s", gpg_verify_state, + "OSTREE_SECONDS=%u", n_seconds, + "OSTREE_XFER_SIZE=%s", formatted_xferred, + NULL); + } +#endif + /* iterate over commits fetched and delete any commitpartial files */ if (pull_data->dirs == NULL && !pull_data->is_commit_only) { @@ -4730,6 +4841,14 @@ find_remotes_cb (GObject *obj, g_clear_error (&error); continue; } + else if (summary_bytes == NULL) + { + g_debug ("%s: Failed to download summary for result ‘%s’. Ignoring. %s", + G_STRFUNC, result->remote->name, + "No summary file exists on server"); + g_clear_pointer (&g_ptr_array_index (results, i), (GDestroyNotify) ostree_repo_finder_result_free); + continue; + } /* Check the metadata in the summary file, especially whether it contains * all the @refs we are interested in. */ @@ -4836,7 +4955,7 @@ find_remotes_cb (GObject *obj, goto error; fetcher = _ostree_repo_remote_new_fetcher (self, result->remote->name, - TRUE, &error); + TRUE, NULL, &error); if (fetcher == NULL) goto error; @@ -4857,7 +4976,7 @@ find_remotes_cb (GObject *obj, &error)) goto error; - glnx_unref_object OstreeGpgVerifyResult *verify_result = NULL; + g_autoptr(OstreeGpgVerifyResult) verify_result = NULL; verify_result = ostree_repo_verify_commit_for_remote (self, commit_metadata->checksum, @@ -4974,7 +5093,7 @@ find_remotes_cb (GObject *obj, { OstreeRepoFinderResult *result = g_ptr_array_index (results, i); g_autoptr(GHashTable) validated_ref_to_checksum = NULL; /* (element-type utf8 utf8) */ - gsize j; + gsize j, n_latest_refs; /* Previous error processing this result? */ if (result == NULL) @@ -4986,6 +5105,7 @@ find_remotes_cb (GObject *obj, ostree_collection_ref_equal, (GDestroyNotify) ostree_collection_ref_free, g_free); + n_latest_refs = 0; for (j = 0; refs[j] != NULL; j++) { @@ -4993,11 +5113,13 @@ find_remotes_cb (GObject *obj, if (pointer_table_get (refs_and_remotes_table, j, i) != latest_commit_for_ref) latest_commit_for_ref = NULL; + if (latest_commit_for_ref != NULL) + n_latest_refs++; g_hash_table_insert (validated_ref_to_checksum, ostree_collection_ref_dup (refs[j]), g_strdup (latest_commit_for_ref)); } - if (g_hash_table_size (validated_ref_to_checksum) == 0) + if (n_latest_refs == 0) { g_debug ("%s: Omitting remote ‘%s’ from results as none of its refs are new enough.", G_STRFUNC, result->remote->name); @@ -5229,7 +5351,7 @@ ostree_repo_pull_from_remotes_async (OstreeRepo *self, g_variant_dict_insert (&local_options_dict, "flags", "i", OSTREE_REPO_PULL_FLAGS_UNTRUSTED | flags); g_variant_dict_insert_value (&local_options_dict, "collection-refs", g_variant_builder_end (&refs_to_pull_builder)); g_variant_dict_insert (&local_options_dict, "gpg-verify", "b", TRUE); - g_variant_dict_insert (&local_options_dict, "gpg-verify-summary", "b", TRUE); + g_variant_dict_insert (&local_options_dict, "gpg-verify-summary", "b", FALSE); g_variant_dict_insert (&local_options_dict, "inherit-transaction", "b", TRUE); copy_option (&options_dict, &local_options_dict, "depth", G_VARIANT_TYPE ("i")); copy_option (&options_dict, &local_options_dict, "disable-static-deltas", G_VARIANT_TYPE ("b")); @@ -5497,7 +5619,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, if (gpg_verify_summary && signatures == NULL) { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + g_set_error (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, "GPG verification enabled, but no summary signatures found (use gpg-verify-summary=false in remote config to disable)"); goto out; } @@ -5505,7 +5627,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, /* Verify any summary signatures. */ if (gpg_verify_summary && summary != NULL && signatures != NULL) { - glnx_unref_object OstreeGpgVerifyResult *result = NULL; + g_autoptr(OstreeGpgVerifyResult) result = NULL; result = ostree_repo_verify_summary (self, name, @@ -5540,7 +5662,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, GError **error) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "This version of ostree was built without libsoup, and cannot fetch over HTTP"); + "This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP"); return FALSE; } @@ -5554,7 +5676,7 @@ ostree_repo_remote_fetch_summary_with_options (OstreeRepo *self, GError **error) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "This version of ostree was built without libsoup, and cannot fetch over HTTP"); + "This version of ostree was built without libsoup or libcurl, and cannot fetch over HTTP"); return FALSE; } diff --git a/src/libostree/ostree-repo-refs.c b/src/libostree/ostree-repo-refs.c index 491f22bd..6c113fb6 100644 --- a/src/libostree/ostree-repo-refs.c +++ b/src/libostree/ostree-repo-refs.c @@ -472,6 +472,7 @@ ostree_repo_resolve_rev_ext (OstreeRepo *self, static gboolean enumerate_refs_recurse (OstreeRepo *repo, const char *remote, + OstreeRepoListRefsExtFlags flags, const char *collection_id, int base_dfd, GString *base_path, @@ -482,6 +483,7 @@ enumerate_refs_recurse (OstreeRepo *repo, GError **error) { g_auto(GLnxDirFdIterator) dfd_iter = { 0, }; + const gboolean aliases_only = (flags & OSTREE_REPO_LIST_REFS_EXT_ALIASES) > 0; if (!glnx_dirfd_iterator_init_at (child_dfd, path, FALSE, &dfd_iter, error)) return FALSE; @@ -502,16 +504,30 @@ enumerate_refs_recurse (OstreeRepo *repo, { g_string_append_c (base_path, '/'); - if (!enumerate_refs_recurse (repo, remote, collection_id, base_dfd, base_path, + if (!enumerate_refs_recurse (repo, remote, flags, collection_id, base_dfd, base_path, dfd_iter.fd, dent->d_name, refs, cancellable, error)) return FALSE; } - else if (dent->d_type == DT_REG) + else { - if (!add_ref_to_set (remote, collection_id, base_dfd, base_path->str, refs, - cancellable, error)) - return FALSE; + if (aliases_only && dent->d_type == DT_LNK) + { + g_autofree char *target = glnx_readlinkat_malloc (base_dfd, base_path->str, + cancellable, error); + const char *resolved_target = target; + if (!target) + return FALSE; + while (g_str_has_prefix (resolved_target, "../")) + resolved_target += 3; + g_hash_table_insert (refs, g_strdup (base_path->str), g_strdup (resolved_target)); + } + else if ((!aliases_only && dent->d_type == DT_REG) || dent->d_type == DT_LNK) + { + if (!add_ref_to_set (remote, collection_id, base_dfd, base_path->str, refs, + cancellable, error)) + return FALSE; + } } g_string_truncate (base_path, len); @@ -523,6 +539,7 @@ enumerate_refs_recurse (OstreeRepo *repo, static gboolean _ostree_repo_list_refs_internal (OstreeRepo *self, gboolean cut_prefix, + OstreeRepoListRefsExtFlags flags, const char *refspec_prefix, GHashTable **out_all_refs, GCancellable *cancellable, @@ -571,7 +588,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self, if (!glnx_opendirat (self->repo_dir_fd, cut_prefix ? path : prefix_path, TRUE, &base_fd, error)) return FALSE; - if (!enumerate_refs_recurse (self, remote, NULL, base_fd, base_path, + if (!enumerate_refs_recurse (self, remote, flags, NULL, base_fd, base_path, base_fd, cut_prefix ? "." : ref_prefix, ret_all_refs, cancellable, error)) return FALSE; @@ -598,7 +615,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self, if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) return FALSE; - if (!enumerate_refs_recurse (self, NULL, NULL, refs_heads_dfd, base_path, + if (!enumerate_refs_recurse (self, NULL, flags, NULL, refs_heads_dfd, base_path, refs_heads_dfd, ".", ret_all_refs, cancellable, error)) return FALSE; @@ -624,7 +641,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self, if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error)) return FALSE; - if (!enumerate_refs_recurse (self, dent->d_name, NULL, remote_dfd, base_path, + if (!enumerate_refs_recurse (self, dent->d_name, flags, NULL, remote_dfd, base_path, remote_dfd, ".", ret_all_refs, cancellable, error)) @@ -655,7 +672,10 @@ ostree_repo_list_refs (OstreeRepo *self, GCancellable *cancellable, GError **error) { - return _ostree_repo_list_refs_internal (self, TRUE, refspec_prefix, out_all_refs, cancellable, error); + return _ostree_repo_list_refs_internal (self, TRUE, + OSTREE_REPO_LIST_REFS_EXT_NONE, + refspec_prefix, out_all_refs, + cancellable, error); } /** @@ -681,7 +701,9 @@ ostree_repo_list_refs_ext (OstreeRepo *self, GCancellable *cancellable, GError **error) { - return _ostree_repo_list_refs_internal (self, FALSE, refspec_prefix, out_all_refs, cancellable, error); + return _ostree_repo_list_refs_internal (self, FALSE, flags, + refspec_prefix, out_all_refs, + cancellable, error); } /** @@ -757,17 +779,163 @@ ostree_repo_remote_list_refs (OstreeRepo *self, return TRUE; } +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +static gboolean +remote_list_collection_refs_process_refs (OstreeRepo *self, + const gchar *remote_name, + const gchar *summary_collection_id, + GVariant *summary_refs, + GHashTable *ret_all_refs, + GError **error) +{ + gsize j, n; + + for (j = 0, n = g_variant_n_children (summary_refs); j < n; j++) + { + const guchar *csum_bytes; + g_autoptr(GVariant) ref_v = NULL, csum_v = NULL; + gchar tmp_checksum[OSTREE_SHA256_STRING_LEN + 1]; + const gchar *ref_name; + + /* Check the ref name. */ + ref_v = g_variant_get_child_value (summary_refs, j); + g_variant_get_child (ref_v, 0, "&s", &ref_name); + + if (!ostree_validate_rev (ref_name, error)) + return FALSE; + + /* Check the commit checksum. */ + g_variant_get_child (ref_v, 1, "(t@ay@a{sv})", NULL, &csum_v, NULL); + + csum_bytes = ostree_checksum_bytes_peek_validate (csum_v, error); + if (csum_bytes == NULL) + return FALSE; + + ostree_checksum_inplace_from_bytes (csum_bytes, tmp_checksum); + + g_hash_table_insert (ret_all_refs, + ostree_collection_ref_new (summary_collection_id, ref_name), + g_strdup (tmp_checksum)); + } + + return TRUE; +} + +/** + * ostree_repo_remote_list_collection_refs: + * @self: Repo + * @remote_name: Name of the remote. + * @out_all_refs: (out) (element-type OstreeCollectionRef utf8): Mapping from collection–ref to checksum + * @cancellable: Cancellable + * @error: Error + * + * List refs advertised by @remote_name, including refs which are part of + * collections. If the repository at @remote_name has a collection ID set, its + * refs will be returned with that collection ID; otherwise, they will be returned + * with a %NULL collection ID in each #OstreeCollectionRef key in @out_all_refs. + * Any refs for other collections stored in the repository will also be returned. + * No filtering is performed. + * + * Since: 2017.10 + */ +gboolean +ostree_repo_remote_list_collection_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GBytes) summary_bytes = NULL; + g_autoptr(GHashTable) ret_all_refs = NULL; /* (element-type OstreeCollectionRef utf8) */ + g_autoptr(GVariant) summary_v = NULL; + g_autoptr(GVariant) additional_metadata_v = NULL; + g_autoptr(GVariant) summary_refs = NULL; + const char *summary_collection_id; + g_autoptr(GVariantIter) summary_collection_map = NULL; + + if (!ostree_repo_remote_fetch_summary (self, remote_name, + &summary_bytes, NULL, + cancellable, error)) + return FALSE; + + if (summary_bytes == NULL) + return glnx_throw (error, "Remote refs not available; server has no summary file"); + + ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash, + ostree_collection_ref_equal, + (GDestroyNotify) ostree_collection_ref_free, + g_free); + + summary_v = g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE); + additional_metadata_v = g_variant_get_child_value (summary_v, 1); + + /* List the refs in the main map. */ + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_ID, "&s", &summary_collection_id)) + summary_collection_id = NULL; + + summary_refs = g_variant_get_child_value (summary_v, 0); + + if (!remote_list_collection_refs_process_refs (self, remote_name, + summary_collection_id, summary_refs, + ret_all_refs, error)) + return FALSE; + + /* List the refs in the collection map. */ + if (!g_variant_lookup (additional_metadata_v, OSTREE_SUMMARY_COLLECTION_MAP, "a{sa(s(taya{sv}))}", &summary_collection_map)) + summary_collection_map = NULL; + + while (summary_collection_map != NULL && + g_variant_iter_loop (summary_collection_map, "{s@a(s(taya{sv}))}", &summary_collection_id, &summary_refs)) + { + if (!remote_list_collection_refs_process_refs (self, remote_name, + summary_collection_id, summary_refs, + ret_all_refs, error)) + return FALSE; + } + + ot_transfer_out_value (out_all_refs, &ret_all_refs); + return TRUE; +} +#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ + +static char * +relative_symlink_to (const char *relpath, + const char *target) +{ + g_assert (*relpath); + g_assert (*target && *target != '/'); + + g_autoptr(GString) buf = g_string_new (""); + + while (TRUE) + { + const char *slash = strchr (relpath, '/'); + if (!slash) + break; + relpath = slash + 1; + g_string_append (buf, "../"); + } + + g_string_append (buf, target); + + return g_string_free (g_steal_pointer (&buf), FALSE); +} + +/* May specify @rev or @alias */ gboolean _ostree_repo_write_ref (OstreeRepo *self, const char *remote, const OstreeCollectionRef *ref, const char *rev, + const char *alias, GCancellable *cancellable, GError **error) { glnx_fd_close int dfd = -1; g_return_val_if_fail (remote == NULL || ref->collection_id == NULL, FALSE); + g_return_val_if_fail (!(rev != NULL && alias != NULL), FALSE); if (remote != NULL && !ostree_validate_remote_name (remote, error)) return FALSE; @@ -832,7 +1000,7 @@ _ostree_repo_write_ref (OstreeRepo *self, return glnx_throw_errno_prefix (error, "Opening remotes/ dir %s", remote); } - if (rev == NULL) + if (rev == NULL && alias == NULL) { if (dfd >= 0) { @@ -843,11 +1011,32 @@ _ostree_repo_write_ref (OstreeRepo *self, } } } - else + else if (rev != NULL) { if (!write_checksum_file_at (self, dfd, ref->ref_name, rev, cancellable, error)) return FALSE; } + else if (alias != NULL) + { + const char *lastslash = strrchr (ref->ref_name, '/'); + + if (lastslash) + { + char *parent = strdupa (ref->ref_name); + parent[lastslash - ref->ref_name] = '\0'; + + if (!glnx_shutil_mkdir_p_at (dfd, parent, 0755, cancellable, error)) + return FALSE; + } + + g_autofree char *reltarget = relative_symlink_to (ref->ref_name, alias); + g_autofree char *tmplink = NULL; + if (!_ostree_make_temporary_symlink_at (self->tmp_dir_fd, reltarget, + &tmplink, cancellable, error)) + return FALSE; + if (!glnx_renameat (self->tmp_dir_fd, tmplink, dfd, ref->ref_name, error)) + return FALSE; + } if (!_ostree_repo_update_mtime (self, error)) return FALSE; @@ -876,7 +1065,7 @@ _ostree_repo_update_refs (OstreeRepo *self, return FALSE; const OstreeCollectionRef ref = { NULL, ref_name }; - if (!_ostree_repo_write_ref (self, remote, &ref, rev, + if (!_ostree_repo_write_ref (self, remote, &ref, rev, NULL, cancellable, error)) return FALSE; } @@ -899,7 +1088,7 @@ _ostree_repo_update_collection_refs (OstreeRepo *self, const OstreeCollectionRef *ref = key; const char *rev = value; - if (!_ostree_repo_write_ref (self, NULL, ref, rev, + if (!_ostree_repo_write_ref (self, NULL, ref, rev, NULL, cancellable, error)) return FALSE; } @@ -961,7 +1150,8 @@ ostree_repo_list_collection_refs (OstreeRepo *self, if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error)) return FALSE; - if (!enumerate_refs_recurse (self, NULL, main_collection_id, refs_heads_dfd, base_path, + if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE, + main_collection_id, refs_heads_dfd, base_path, refs_heads_dfd, ".", ret_all_refs, cancellable, error)) return FALSE; @@ -993,7 +1183,8 @@ ostree_repo_list_collection_refs (OstreeRepo *self, if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &collection_dfd, error)) return FALSE; - if (!enumerate_refs_recurse (self, NULL, dent->d_name, collection_dfd, base_path, + if (!enumerate_refs_recurse (self, NULL, OSTREE_REPO_LIST_REFS_EXT_NONE, + dent->d_name, collection_dfd, base_path, collection_dfd, ".", ret_all_refs, cancellable, error)) diff --git a/src/libostree/ostree-repo-static-delta-core.c b/src/libostree/ostree-repo-static-delta-core.c index c8cefdef..b8a2c590 100644 --- a/src/libostree/ostree-repo-static-delta-core.c +++ b/src/libostree/ostree-repo-static-delta-core.c @@ -649,7 +649,7 @@ _ostree_delta_get_endianness (GVariant *superblock, * deltas, period. Past the gigabyte scale you really want * bittorrent or something. */ - if ((total_size / total_objects) > G_MAXUINT32) + if (total_objects > 0 && (total_size / total_objects) > G_MAXUINT32) { is_byteswapped = TRUE; } diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 896c57bc..795016ce 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -456,6 +456,7 @@ ostree_repo_finalize (GObject *object) g_clear_object (&self->parent_repo); g_free (self->stagedir_prefix); + g_clear_object (&self->repodir_fdrel); g_clear_object (&self->repodir); if (self->repo_dir_fd != -1) (void) close (self->repo_dir_fd); @@ -546,22 +547,11 @@ ostree_repo_get_property(GObject *object, } } -static void -ostree_repo_constructed (GObject *object) -{ - OstreeRepo *self = OSTREE_REPO (object); - - g_assert (self->repodir != NULL); - - G_OBJECT_CLASS (ostree_repo_parent_class)->constructed (object); -} - static void ostree_repo_class_init (OstreeRepoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->constructed = ostree_repo_constructed; object_class->get_property = ostree_repo_get_property; object_class->set_property = ostree_repo_set_property; object_class->finalize = ostree_repo_finalize; @@ -581,6 +571,7 @@ ostree_repo_class_init (OstreeRepoClass *klass) "", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_REMOTES_CONFIG_DIR, g_param_spec_string ("remotes-config-dir", @@ -662,6 +653,43 @@ ostree_repo_new (GFile *path) return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL); } +static OstreeRepo * +repo_open_at_take_fd (int *dfd, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(OstreeRepo) repo = g_object_new (OSTREE_TYPE_REPO, NULL); + repo->repo_dir_fd = glnx_steal_fd (dfd); + + if (!ostree_repo_open (repo, cancellable, error)) + return NULL; + return g_steal_pointer (&repo); +} + +/** + * ostree_repo_open_at: + * @dfd: Directory fd + * @path: Path + * + * This combines ostree_repo_new() (but using fd-relative access) with + * ostree_repo_open(). Use this when you know you should be operating on an + * already extant repository. If you want to create one, use ostree_repo_create_at(). + * + * Returns: (transfer full): An accessor object for an OSTree repository located at @dfd + @path + */ +OstreeRepo* +ostree_repo_open_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error) +{ + glnx_fd_close int repo_dfd = -1; + if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) + return NULL; + + return repo_open_at_take_fd (&repo_dfd, cancellable, error); +} + static GFile * get_default_repo_path (GFile *sysroot_path) { @@ -744,8 +772,16 @@ ostree_repo_is_system (OstreeRepo *repo) if (!repo->sysroot_dir) return FALSE; - g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir); - return g_file_equal (repo->repodir, default_repo_path); + /* If we created via ostree_repo_new(), we'll have a repo path. Compare + * it to the sysroot path in that case. + */ + if (repo->repodir) + { + g_autoptr(GFile) default_repo_path = get_default_repo_path (repo->sysroot_dir); + return g_file_equal (repo->repodir, default_repo_path); + } + /* Otherwise, not a system repo */ + return FALSE; } /** @@ -1331,9 +1367,9 @@ ostree_repo_remote_gpg_import (OstreeRepo *self, GError **error) { OstreeRemote *remote; - ot_auto_gpgme_ctx gpgme_ctx_t source_context = NULL; - ot_auto_gpgme_ctx gpgme_ctx_t target_context = NULL; - ot_auto_gpgme_data gpgme_data_t data_buffer = NULL; + g_auto(gpgme_ctx_t) source_context = NULL; + g_auto(gpgme_ctx_t) target_context = NULL; + g_auto(gpgme_data_t) data_buffer = NULL; gpgme_import_result_t import_result; gpgme_import_status_t import_status; g_autofree char *source_tmp_dir = NULL; @@ -1670,6 +1706,104 @@ ostree_repo_mode_from_string (const char *mode, #define DEFAULT_CONFIG_CONTENTS ("[core]\n" \ "repo_version=1\n") +/* Just write the dirs to disk, return a dfd */ +static gboolean +repo_create_at_internal (int dfd, + const char *path, + OstreeRepoMode mode, + GVariant *options, + int *out_dfd, + GCancellable *cancellable, + GError **error) +{ + struct stat stbuf; + /* We do objects/ last - if it exists we do nothing and exit successfully */ + const char *state_dirs[] = { "tmp", "extensions", "state", + "refs", "refs/heads", "refs/mirrors", + "refs/remotes", "objects" }; + + /* Early return if we have an existing repo */ + { g_autofree char *objects_path = g_build_filename (path, "objects", NULL); + + if (fstatat (dfd, objects_path, &stbuf, 0) == 0) + { + glnx_fd_close int repo_dfd = -1; + if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) + return FALSE; + + /* Note early return */ + *out_dfd = glnx_steal_fd (&repo_dfd); + return TRUE; + } + else if (errno != ENOENT) + return glnx_throw_errno_prefix (error, "fstatat"); + } + + if (mkdirat (dfd, path, 0755) != 0) + { + if (G_UNLIKELY (errno != EEXIST)) + return glnx_throw_errno_prefix (error, "mkdirat"); + } + + glnx_fd_close int repo_dfd = -1; + if (!glnx_opendirat (dfd, path, TRUE, &repo_dfd, error)) + return FALSE; + + if (fstatat (repo_dfd, "config", &stbuf, 0) < 0) + { + if (errno == ENOENT) + { + const char *mode_str = NULL; + g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS); + + if (!ostree_repo_mode_to_string (mode, &mode_str, error)) + return FALSE; + g_assert (mode_str); + + g_string_append_printf (config_data, "mode=%s\n", mode_str); + + const char *collection_id = NULL; + if (options) + g_variant_lookup (options, "collection-id", "&s", &collection_id); + if (collection_id != NULL) + g_string_append_printf (config_data, "collection-id=%s\n", collection_id); + + if (!glnx_file_replace_contents_at (repo_dfd, "config", + (guint8*)config_data->str, config_data->len, + 0, cancellable, error)) + return FALSE; + } + else + return glnx_throw_errno_prefix (error, "fstatat"); + } + + for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++) + { + const char *elt = state_dirs[i]; + if (mkdirat (repo_dfd, elt, 0755) == -1) + { + if (G_UNLIKELY (errno != EEXIST)) + return glnx_throw_errno_prefix (error, "mkdirat"); + } + } + + /* Test that the fs supports user xattrs now, so we get an error early rather + * than during an object write later. + */ + if (mode == OSTREE_REPO_MODE_BARE_USER) + { + g_auto(GLnxTmpfile) tmpf = { 0, }; + + if (!glnx_open_tmpfile_linkable_at (repo_dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error)) + return FALSE; + if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error)) + return FALSE; + } + + *out_dfd = glnx_steal_fd (&repo_dfd); + return TRUE; +} + /** * ostree_repo_create: * @self: An #OstreeRepo @@ -1686,6 +1820,11 @@ ostree_repo_mode_from_string (const char *mode, * of an existing repository, and will silently ignore an attempt to * do so. * + * Since 2017.9, "existing repository" is defined by the existence of an + * `objects` subdirectory. + * + * This function predates ostree_repo_create_at(). It is an error to call + * this function on a repository initialized via ostree_repo_open_at(). */ gboolean ostree_repo_create (OstreeRepo *self, @@ -1693,76 +1832,64 @@ ostree_repo_create (OstreeRepo *self, GCancellable *cancellable, GError **error) { + g_return_val_if_fail (self->repodir, FALSE); const char *repopath = gs_file_get_path_cached (self->repodir); - glnx_fd_close int dfd = -1; - struct stat stbuf; - const char *state_dirs[] = { "objects", "tmp", "extensions", "state", - "refs", "refs/heads", "refs/mirrors", - "refs/remotes" }; + g_autoptr(GVariantBuilder) builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + if (self->collection_id) + g_variant_builder_add (builder, "{s@v}", "collection-id", + g_variant_new_variant (g_variant_new_string (self->collection_id))); - if (mkdir (repopath, 0755) != 0) - { - if (G_UNLIKELY (errno != EEXIST)) - return glnx_throw_errno (error); - } - - if (!glnx_opendirat (AT_FDCWD, repopath, TRUE, &dfd, error)) + glnx_fd_close int repo_dir_fd = -1; + if (!repo_create_at_internal (AT_FDCWD, repopath, mode, + g_variant_builder_end (builder), + &repo_dir_fd, + cancellable, error)) return FALSE; - - if (fstatat (dfd, "config", &stbuf, 0) < 0) - { - if (errno == ENOENT) - { - const char *mode_str = NULL; - g_autoptr(GString) config_data = g_string_new (DEFAULT_CONFIG_CONTENTS); - - if (!ostree_repo_mode_to_string (mode, &mode_str, error)) - return FALSE; - g_assert (mode_str); - - g_string_append_printf (config_data, "mode=%s\n", mode_str); - - if (self->collection_id != NULL) - g_string_append_printf (config_data, "collection-id=%s\n", self->collection_id); - - if (!glnx_file_replace_contents_at (dfd, "config", - (guint8*)config_data->str, config_data->len, - 0, cancellable, error)) - return FALSE; - } - else - return glnx_throw_errno (error); - } - - for (guint i = 0; i < G_N_ELEMENTS (state_dirs); i++) - { - const char *elt = state_dirs[i]; - if (mkdirat (dfd, elt, 0755) == -1) - { - if (G_UNLIKELY (errno != EEXIST)) - return glnx_throw_errno (error); - } - } - - /* Test that the fs supports user xattrs now, so we get an error early rather - * than during an object write later. - */ - if (mode == OSTREE_REPO_MODE_BARE_USER) - { - g_auto(GLnxTmpfile) tmpf = { 0, }; - - if (!glnx_open_tmpfile_linkable_at (dfd, ".", O_RDWR|O_CLOEXEC, &tmpf, error)) - return FALSE; - if (!_ostree_write_bareuser_metadata (tmpf.fd, 0, 0, 644, NULL, error)) - return FALSE; - } - + self->repo_dir_fd = glnx_steal_fd (&repo_dir_fd); if (!ostree_repo_open (self, cancellable, error)) return FALSE; - return TRUE; } +/** + * ostree_repo_create_at: + * @dfd: Directory fd + * @path: Path + * @mode: The mode to store the repository in + * @options: a{sv}: See below for accepted keys + * @cancellable: Cancellable + * @error: Error + * + * This is a file-descriptor relative version of ostree_repo_create(). + * Create the underlying structure on disk for the repository, and call + * ostree_repo_open_at() on the result, preparing it for use. + * + * If a repository already exists at @dfd + @path (defined by an `objects/` + * subdirectory existing), then this function will simply call + * ostree_repo_open_at(). In other words, this function cannot be used to change + * the mode or configuration (`repo/config`) of an existing repo. + * + * The @options dict may contain: + * + * - collection-id: s: Set as collection ID in repo/config (Since 2017.9) + * + * Returns: (transfer full): A new OSTree repository reference + */ +OstreeRepo * +ostree_repo_create_at (int dfd, + const char *path, + OstreeRepoMode mode, + GVariant *options, + GCancellable *cancellable, + GError **error) +{ + glnx_fd_close int repo_dfd = -1; + if (!repo_create_at_internal (dfd, path, mode, options, &repo_dfd, + cancellable, error)) + return NULL; + return repo_open_at_take_fd (&repo_dfd, cancellable, error); +} + static gboolean enumerate_directory_allow_noent (GFile *dirpath, const char *queryargs, @@ -2132,7 +2259,6 @@ ostree_repo_open (OstreeRepo *self, GCancellable *cancellable, GError **error) { - struct stat self_stbuf; struct stat stbuf; g_return_val_if_fail (error == NULL || *error == NULL, FALSE); @@ -2162,22 +2288,25 @@ ostree_repo_open (OstreeRepo *self, self->stagedir_prefix = g_strconcat (OSTREE_REPO_TMPDIR_STAGING, boot_id, "-", NULL); } - if (!glnx_opendirat (AT_FDCWD, gs_file_get_path_cached (self->repodir), TRUE, - &self->repo_dir_fd, error)) + if (self->repo_dir_fd == -1) { - g_prefix_error (error, "%s: ", gs_file_get_path_cached (self->repodir)); - return FALSE; + g_assert (self->repodir); + 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)); + return FALSE; + } } - if (!glnx_fstat (self->repo_dir_fd, &self_stbuf, error)) + if (!glnx_fstat (self->repo_dir_fd, &stbuf, error)) return FALSE; + self->device = stbuf.st_dev; + self->inode = stbuf.st_ino; if (!glnx_opendirat (self->repo_dir_fd, "objects", TRUE, &self->objects_dir_fd, error)) - { - g_prefix_error (error, "Opening objects/ directory: "); - return FALSE; - } + return FALSE; self->writable = faccessat (self->objects_dir_fd, ".", W_OK, 0) == 0; if (!self->writable) @@ -2238,8 +2367,8 @@ ostree_repo_open (OstreeRepo *self, if (fstatat (AT_FDCWD, "/ostree/repo", &system_stbuf, 0) == 0) { /* Are we the same as /ostree/repo? */ - if (self_stbuf.st_dev == system_stbuf.st_dev && - self_stbuf.st_ino == system_stbuf.st_ino) + if (self->device == system_stbuf.st_dev && + self->inode == system_stbuf.st_ino) self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_IS_SYSROOT_OSTREE; else self->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_NO; @@ -2349,14 +2478,24 @@ _ostree_repo_file_replace_contents (OstreeRepo *self, /** * ostree_repo_get_path: - * @self: + * @self: Repo + * + * Note that since the introduction of ostree_repo_open_at(), this function may + * return a process-specific path in `/proc` if the repository was created using + * that API. In general, you should avoid use of this API. * * Returns: (transfer none): Path to repo */ GFile * ostree_repo_get_path (OstreeRepo *self) { - return self->repodir; + /* Did we have an abspath? Return it */ + if (self->repodir) + return self->repodir; + /* Lazily create a fd-relative path */ + if (!self->repodir_fdrel) + self->repodir_fdrel = ot_fdrel_to_gfile (self->repo_dir_fd, "."); + return self->repodir_fdrel; } /** @@ -4082,14 +4221,14 @@ ostree_repo_sign_commit (OstreeRepo *self, * check if the commit has already been signed with the given key ID. * We want to avoid storing duplicate signatures in the metadata. */ g_autoptr(GError) local_error = NULL; - glnx_unref_object OstreeGpgVerifyResult *result + g_autoptr(OstreeGpgVerifyResult) result =_ostree_repo_gpg_verify_with_metadata (self, commit_data, old_metadata, NULL, NULL, NULL, cancellable, &local_error); if (!result) { /* "Not found" just means the commit is not yet signed. That's okay. */ - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + if (g_error_matches (local_error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE)) { g_clear_error (&local_error); } @@ -4202,31 +4341,52 @@ ostree_repo_add_gpg_signature_summary (OstreeRepo *self, /* Special remote for _ostree_repo_gpg_verify_with_metadata() */ static const char *OSTREE_ALL_REMOTES = "__OSTREE_ALL_REMOTES__"; -static GFile * +/* Look for a keyring for @remote in the repo itself, or in + * /etc/ostree/remotes.d. + */ +static gboolean find_keyring (OstreeRepo *self, OstreeRemote *remote, - GCancellable *cancellable) + GBytes **ret_bytes, + GCancellable *cancellable, + GError **error) { - g_autoptr(GFile) file = g_file_get_child (self->repodir, remote->keyring); + glnx_fd_close int fd = -1; + if (!ot_openat_ignore_enoent (self->repo_dir_fd, remote->keyring, &fd, error)) + return FALSE; - if (g_file_query_exists (file, cancellable)) + if (fd != -1) { - return g_steal_pointer (&file); + GBytes *ret = glnx_fd_readall_bytes (fd, cancellable, error); + if (!ret) + return FALSE; + *ret_bytes = ret; + return TRUE; } g_autoptr(GFile) remotes_d = get_remotes_d_dir (self, NULL); if (remotes_d) { - g_autoptr(GFile) file2 = g_file_get_child (remotes_d, remote->keyring); + g_autoptr(GFile) child = g_file_get_child (remotes_d, remote->keyring); - if (g_file_query_exists (file2, cancellable)) - return g_steal_pointer (&file2); + if (!ot_openat_ignore_enoent (AT_FDCWD, gs_file_get_path_cached (child), &fd, error)) + return FALSE; + + if (fd != -1) + { + GBytes *ret = glnx_fd_readall_bytes (fd, cancellable, error); + if (!ret) + return FALSE; + *ret_bytes = ret; + return TRUE; + } } if (self->parent_repo) - return find_keyring (self->parent_repo, remote, cancellable); + return find_keyring (self->parent_repo, remote, ret_bytes, cancellable, error); - return NULL; + *ret_bytes = NULL; + return TRUE; } static OstreeGpgVerifyResult * @@ -4239,7 +4399,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, GCancellable *cancellable, GError **error) { - glnx_unref_object OstreeGpgVerifier *verifier = NULL; + g_autoptr(OstreeGpgVerifier) verifier = NULL; gboolean add_global_keyring_dir = TRUE; verifier = _ostree_gpg_verifier_new (); @@ -4248,8 +4408,8 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, { /* Add all available remote keyring files. */ - if (!_ostree_gpg_verifier_add_keyring_dir (verifier, self->repodir, - cancellable, error)) + if (!_ostree_gpg_verifier_add_keyring_dir_at (verifier, self->repo_dir_fd, ".", + cancellable, error)) return NULL; } else if (remote_name != NULL) @@ -4258,17 +4418,18 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, /* Add the remote's keyring file if it exists. */ OstreeRemote *remote; - g_autoptr(GFile) file = NULL; remote = _ostree_repo_get_remote_inherited (self, remote_name, error); if (remote == NULL) return NULL; - file = find_keyring (self, remote, cancellable); + g_autoptr(GBytes) keyring_data = NULL; + if (!find_keyring (self, remote, &keyring_data, cancellable, error)) + return NULL; - if (file != NULL) + if (keyring_data != NULL) { - _ostree_gpg_verifier_add_keyring (verifier, file); + _ostree_gpg_verifier_add_keyring_data (verifier, keyring_data); add_global_keyring_dir = FALSE; } @@ -4297,7 +4458,7 @@ _ostree_repo_gpg_verify_data_internal (OstreeRepo *self, } if (extra_keyring != NULL) { - _ostree_gpg_verifier_add_keyring (verifier, extra_keyring); + _ostree_gpg_verifier_add_keyring_file (verifier, extra_keyring); } return _ostree_gpg_verifier_check_signature (verifier, @@ -4329,7 +4490,7 @@ _ostree_repo_gpg_verify_with_metadata (OstreeRepo *self, _OSTREE_METADATA_GPGSIGS_TYPE); if (!signaturedata) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + g_set_error_literal (error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE, "GPG verification enabled, but no signatures found (use gpg-verify=false in remote config to disable)"); return NULL; } @@ -4441,7 +4602,7 @@ ostree_repo_verify_commit (OstreeRepo *self, GCancellable *cancellable, GError **error) { - glnx_unref_object OstreeGpgVerifyResult *result = NULL; + g_autoptr(OstreeGpgVerifyResult) result = NULL; result = ostree_repo_verify_commit_ext (self, commit_checksum, keyringdir, extra_keyring, diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index f1e964b7..8766e6df 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -63,6 +63,13 @@ gboolean ostree_repo_open (OstreeRepo *self, GCancellable *cancellable, GError **error); +_OSTREE_PUBLIC +OstreeRepo* +ostree_repo_open_at (int dfd, + const char *path, + GCancellable *cancellable, + GError **error); + _OSTREE_PUBLIC void ostree_repo_set_disable_fsync (OstreeRepo *self, gboolean disable_fsync); @@ -89,6 +96,13 @@ gboolean ostree_repo_create (OstreeRepo *self, OstreeRepoMode mode, GCancellable *cancellable, GError **error); +_OSTREE_PUBLIC +OstreeRepo * ostree_repo_create_at (int dfd, + const char *path, + OstreeRepoMode mode, + GVariant *options, + GCancellable *cancellable, + GError **error); #ifdef OSTREE_ENABLE_EXPERIMENTAL_API @@ -327,6 +341,14 @@ gboolean ostree_repo_set_ref_immediate (OstreeRepo *self, GCancellable *cancellable, GError **error); +_OSTREE_PUBLIC +gboolean ostree_repo_set_alias_ref_immediate (OstreeRepo *self, + const char *remote, + const char *ref, + const char *target, + GCancellable *cancellable, + GError **error); + #ifdef OSTREE_ENABLE_EXPERIMENTAL_API _OSTREE_PUBLIC @@ -452,9 +474,11 @@ gboolean ostree_repo_list_refs (OstreeRepo *self, /** * OstreeRepoListRefsExtFlags: * @OSTREE_REPO_LIST_REFS_EXT_NONE: No flags. + * @OSTREE_REPO_LIST_REFS_EXT_ALIASES: Only list aliases. Since: 2017.10 */ typedef enum { OSTREE_REPO_LIST_REFS_EXT_NONE = 0, + OSTREE_REPO_LIST_REFS_EXT_ALIASES = 1, } OstreeRepoListRefsExtFlags; _OSTREE_PUBLIC @@ -472,6 +496,15 @@ gboolean ostree_repo_remote_list_refs (OstreeRepo *self, GCancellable *cancellable, GError **error); +#ifdef OSTREE_ENABLE_EXPERIMENTAL_API +_OSTREE_PUBLIC +gboolean ostree_repo_remote_list_collection_refs (OstreeRepo *self, + const char *remote_name, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error); +#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ + _OSTREE_PUBLIC gboolean ostree_repo_load_variant (OstreeRepo *self, OstreeObjectType objtype, diff --git a/src/libostree/ostree-sepolicy.c b/src/libostree/ostree-sepolicy.c index 7387ea0f..6012d9da 100644 --- a/src/libostree/ostree-sepolicy.c +++ b/src/libostree/ostree-sepolicy.c @@ -328,7 +328,7 @@ initable_init (GInitable *initable, g_autoptr(GFile) policy_root = NULL; if (g_file_query_exists (policy_config_path, NULL)) { - g_autoptr(GFileInputStream) filein = filein = g_file_read (policy_config_path, cancellable, error); + g_autoptr(GFileInputStream) filein = g_file_read (policy_config_path, cancellable, error); if (!filein) return FALSE; diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index b2b46b36..60fbc1d3 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -22,24 +22,36 @@ #include #include +#include #include #include +#include +#include +#include +#include +#include #ifdef HAVE_LIBMOUNT #include #endif +#ifdef HAVE_LIBSYSTEMD +#include +#endif +#include "otutil.h" +#include "ostree.h" #include "ostree-sysroot-private.h" #include "ostree-sepolicy-private.h" #include "ostree-deployment-private.h" #include "ostree-core-private.h" #include "ostree-linuxfsutil.h" -#include "otutil.h" #include "libglnx.h" -#define OSTREE_VARRELABEL_ID "da679b08acd34504b789d96f818ea781" -#define OSTREE_CONFIGMERGE_ID "d3863baec13e4449ab0384684a8af3a7" -#define OSTREE_DEPLOYMENT_COMPLETE_ID "dd440e3e549083b63d0efc7dc15255f1" +#ifdef HAVE_LIBSYSTEMD +#define OSTREE_VARRELABEL_ID SD_ID128_MAKE(da,67,9b,08,ac,d3,45,04,b7,89,d9,6f,81,8e,a7,81) +#define OSTREE_CONFIGMERGE_ID SD_ID128_MAKE(d3,86,3b,ae,c1,3e,44,49,ab,03,84,68,4a,8a,f3,a7) +#define OSTREE_DEPLOYMENT_COMPLETE_ID SD_ID128_MAKE(dd,44,0e,3e,54,90,83,b6,3d,0e,fc,7d,c1,52,55,f1) +#endif /* * Like symlinkat() but overwrites (atomically) an existing @@ -101,7 +113,7 @@ hardlink_or_copy_at (int src_dfd, sysroot_flags_to_copy_flags (0, flags), cancellable, error); else - return glnx_throw_errno_prefix (error, "linkat"); + return glnx_throw_errno_prefix (error, "linkat(%s)", dest_subpath); } return TRUE; @@ -417,11 +429,19 @@ merge_configuration_from (OstreeSysroot *sysroot, cancellable, error)) return glnx_prefix_error (error, "While computing configuration diff"); - ot_log_structured_print_id_v (OSTREE_CONFIGMERGE_ID, - "Copying /etc changes: %u modified, %u removed, %u added", - modified->len, - removed->len, - added->len); + { g_autofree char *msg = + g_strdup_printf ("Copying /etc changes: %u modified, %u removed, %u added", + modified->len, removed->len, added->len); +#ifdef HAVE_LIBSYSTEMD + sd_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_CONFIGMERGE_ID), + "MESSAGE=%s", msg, + "ETC_N_MODIFIED=%u", modified->len, + "ETC_N_REMOVED=%u", removed->len, + "ETC_N_ADDED=%u", added->len, + NULL); +#endif + _ostree_sysroot_emit_journal_msg (sysroot, msg); + } glnx_fd_close int orig_etc_fd = -1; if (!glnx_opendirat (merge_deployment_dfd, "usr/etc", TRUE, &orig_etc_fd, error)) @@ -676,9 +696,15 @@ selinux_relabel_var_if_needed (OstreeSysroot *sysroot, if (!deployment_var_labeled) { - ot_log_structured_print_id_v (OSTREE_VARRELABEL_ID, - "Relabeling /var (no stamp file '%s' found)", - selabeled); + { g_autofree char *msg = + g_strdup_printf ("Relabeling /var (no stamp file '%s' found)", selabeled); +#ifdef HAVE_LIBSYSTEMD + sd_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_VARRELABEL_ID), + "MESSAGE=%s", msg, + NULL); +#endif + _ostree_sysroot_emit_journal_msg (sysroot, msg); + } g_autoptr(GFile) deployment_var_path = ot_fdrel_to_gfile (os_deploy_dfd, "var"); if (!selinux_relabel_dir (sysroot, sepolicy, @@ -717,7 +743,7 @@ merge_configuration (OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) { - glnx_unref_object OstreeSePolicy *sepolicy = NULL; + g_autoptr(OstreeSePolicy) sepolicy = NULL; if (previous_deployment) { @@ -856,131 +882,253 @@ ostree_sysroot_write_origin_file (OstreeSysroot *sysroot, cancellable, error); } +/* Originally OSTree defined kernels to be found underneath /boot + * in the tree. But that means when mounting /boot at runtime + * we end up masking the content underneath, triggering a warning. + * + * For that reason, and also consistency with the "/usr defines the OS" model we + * later switched to defining the in-tree kernels to be found under + * /usr/lib/ostree-boot. + */ static gboolean get_kernel_from_tree (int deployment_dfd, int *out_boot_dfd, - char **out_kernel_name, - char **out_initramfs_name, + char **out_kernel_srcpath, + char **out_kernel_namever, + char **out_initramfs_srcpath, + char **out_initramfs_namever, + char **out_bootcsum, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - glnx_fd_close int ret_boot_dfd = -1; - g_auto(GLnxDirFdIterator) dfditer = { 0, }; - g_autofree char *ret_kernel_name = NULL; - g_autofree char *ret_initramfs_name = NULL; + g_autofree char *ret_kernel_srcpath = NULL; + g_autofree char *ret_kernel_namever = NULL; + g_autofree char *ret_initramfs_srcpath = NULL; + g_autofree char *ret_initramfs_namever = NULL; g_autofree char *kernel_checksum = NULL; g_autofree char *initramfs_checksum = NULL; - ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE); + glnx_fd_close int ret_boot_dfd = glnx_opendirat_with_errno (deployment_dfd, "usr/lib/ostree-boot", TRUE); if (ret_boot_dfd == -1) { if (errno != ENOENT) - { - glnx_set_prefix_error_from_errno (error, "%s", "openat"); - goto out; - } + return glnx_throw_errno_prefix (error, "%s", "openat(usr/lib/ostree-boot)"); else { if (!glnx_opendirat (deployment_dfd, "boot", TRUE, &ret_boot_dfd, error)) - goto out; + return FALSE; } } + g_auto(GLnxDirFdIterator) dfditer = { 0, }; if (!glnx_dirfd_iterator_init_at (ret_boot_dfd, ".", FALSE, &dfditer, error)) - goto out; + return FALSE; while (TRUE) { struct dirent *dent; if (!glnx_dirfd_iterator_next_dent (&dfditer, &dent, cancellable, error)) - goto out; + return FALSE; if (dent == NULL) break; - if (ret_kernel_name == NULL && g_str_has_prefix (dent->d_name, "vmlinuz-")) + const char *name = dent->d_name; + if (ret_kernel_srcpath == NULL && g_str_has_prefix (name, "vmlinuz-")) { - const char *dash = strrchr (dent->d_name, '-'); + const char *dash = strrchr (name, '-'); g_assert (dash); if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { kernel_checksum = g_strdup (dash + 1); - ret_kernel_name = g_strdup (dent->d_name); + ret_kernel_srcpath = g_strdup (name); + ret_kernel_namever = g_strndup (name, dash - name); } } - else if (ret_initramfs_name == NULL && g_str_has_prefix (dent->d_name, "initramfs-")) + else if (ret_initramfs_srcpath == NULL && g_str_has_prefix (name, "initramfs-")) { - const char *dash = strrchr (dent->d_name, '-'); + const char *dash = strrchr (name, '-'); g_assert (dash); if (ostree_validate_structureof_checksum_string (dash + 1, NULL)) { initramfs_checksum = g_strdup (dash + 1); - ret_initramfs_name = g_strdup (dent->d_name); + ret_initramfs_srcpath = g_strdup (name); + ret_initramfs_namever = g_strndup (name, dash - name); } } - if (ret_kernel_name != NULL && ret_initramfs_name != NULL) + if (ret_kernel_srcpath != NULL && ret_initramfs_srcpath != NULL) break; } - if (ret_kernel_name == NULL) + if (ret_kernel_srcpath == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Failed to find boot/vmlinuz- in tree"); - goto out; + "Failed to find kernel in /usr/lib/ostree-boot or /boot"); + return FALSE; } - if (ret_initramfs_name != NULL) + if (ret_initramfs_srcpath != NULL) { if (strcmp (kernel_checksum, initramfs_checksum) != 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, - "Mismatched kernel checksum vs initrd in tree"); - goto out; + "Mismatched kernel checksum vs initrd"); + return FALSE; } } - *out_boot_dfd = ret_boot_dfd; - ret_boot_dfd = -1; - *out_kernel_name = g_steal_pointer (&ret_kernel_name); - *out_initramfs_name = g_steal_pointer (&ret_initramfs_name); - ret = TRUE; - out: - return ret; + *out_boot_dfd = glnx_steal_fd (&ret_boot_dfd); + *out_kernel_srcpath = g_steal_pointer (&ret_kernel_srcpath); + *out_kernel_namever = g_steal_pointer (&ret_kernel_namever); + *out_initramfs_srcpath = g_steal_pointer (&ret_initramfs_srcpath); + *out_initramfs_namever = g_steal_pointer (&ret_initramfs_namever); + *out_bootcsum = g_steal_pointer (&kernel_checksum); + return TRUE; } +/* We used to syncfs(), but that doesn't flush the journal on XFS, + * and since GRUB2 can't read the XFS journal, the system + * could fail to boot. + * + * http://marc.info/?l=linux-fsdevel&m=149520244919284&w=2 + * https://github.com/ostreedev/ostree/pull/1049 + */ static gboolean -checksum_from_kernel_src (const char *name, - char **out_checksum, - GError **error) +fsfreeze_thaw_cycle (OstreeSysroot *self, + int rootfs_dfd, + GCancellable *cancellable, + GError **error) { - const char *last_dash = strrchr (name, '-'); - if (!last_dash) + GLNX_AUTO_PREFIX_ERROR ("During fsfreeze-thaw", error); + + int sockpair[2]; + if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockpair) < 0) + return glnx_throw_errno_prefix (error, "socketpair"); + glnx_fd_close int sock_parent = sockpair[0]; + glnx_fd_close int sock_watchdog = sockpair[1]; + + pid_t pid = fork (); + if (pid < 0) + return glnx_throw_errno_prefix (error, "fork"); + + const gboolean debug_fifreeze = (self->debug_flags & OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE)>0; + char c = '!'; + if (pid == 0) /* Child watchdog/unfreezer process. */ { - return glnx_throw (error, - "Malformed kernel/initramfs name '%s', missing '-'", - name); + (void) close (glnx_steal_fd (&sock_parent)); + /* Daemonize, and mask SIGINT/SIGTERM, so we're likely to survive e.g. + * someone doing a `systemctl restart rpm-ostreed` or a Ctrl-C of + * `ostree admin upgrade`. We don't daemonize though if testing so + * that we can waitpid(). + */ + if (!debug_fifreeze) + { + if (daemon (0, 0) < 0) + err (1, "daemon"); + } + int sigs[] = { SIGINT, SIGTERM }; + for (guint i = 0; i < G_N_ELEMENTS (sigs); i++) + { + if (signal (sigs[i], SIG_IGN) == SIG_ERR) + err (1, "signal"); + } + /* Tell the parent we're ready */ + if (write (sock_watchdog, &c, sizeof (c)) != 1) + err (1, "write"); + /* Wait for the parent to say it's going to freeze. */ + ssize_t bytes_read = TEMP_FAILURE_RETRY (read (sock_watchdog, &c, sizeof (c))); + if (bytes_read < 0) + err (1, "read"); + if (bytes_read != 1) + errx (1, "failed to read from parent"); + /* Now we wait for the second message from the parent saying the freeze is + * complete. We have a 30 second timeout; if somehow the parent hasn't + * signaled completion, go ahead and unfreeze. But for debugging, just 1 + * second to avoid exessively lengthining the test suite. + */ + const int timeout_ms = debug_fifreeze ? 1000 : 30000; + struct pollfd pfds[1]; + pfds[0].fd = sock_watchdog; + pfds[0].events = POLLIN | POLLHUP; + int r = TEMP_FAILURE_RETRY (poll (pfds, 1, timeout_ms)); + /* Do a thaw if we hit an error, or if the poll timed out */ + if (r <= 0) + { + /* Ignore errors: + * EINVAL: Not frozen + * EPERM: For running the test suite as non-root + * EOPNOTSUPP: If the filesystem doesn't support it + */ + int saved_errno = errno; + (void) TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0)); + errno = saved_errno; + /* But if we got an error from poll, let's log it */ + if (r < 0) + err (1, "poll"); + } + if (debug_fifreeze) + g_printerr ("fifreeze watchdog was run\n"); + exit (EXIT_SUCCESS); + } + else /* Parent process. */ + { + (void) close (glnx_steal_fd (&sock_watchdog)); + /* Wait for the watchdog to say it's set up; mainly that it's + * masked SIGTERM successfully. + */ + ssize_t bytes_read = TEMP_FAILURE_RETRY (read (sock_parent, &c, sizeof (c))); + if (bytes_read < 0) + return glnx_throw_errno_prefix (error, "read(watchdog init)"); + if (bytes_read != 1) + return glnx_throw (error, "read(watchdog init)"); + /* And tell the watchdog that we're ready to start */ + if (write (sock_parent, &c, sizeof (c)) != sizeof (c)) + return glnx_throw_errno_prefix (error, "write(watchdog start)"); + /* Testing infrastructure */ + if (debug_fifreeze) + { + int wstatus; + /* Ensure the child has written its data */ + if (TEMP_FAILURE_RETRY (waitpid (pid, &wstatus, 0)) < 0) + return glnx_throw_errno_prefix (error, "waitpid(test-fifreeze)"); + if (!g_spawn_check_exit_status (wstatus, error)) + return glnx_prefix_error (error, "test-fifreeze: "); + return glnx_throw (error, "aborting due to test-fifreeze"); + } + /* Do a freeze/thaw cycle; TODO add a FIFREEZETHAW ioctl */ + if (ioctl (rootfs_dfd, FIFREEZE, 0) != 0) + { + /* Not supported, or we're running in the unit tests (as non-root)? + * OK, let's just do a syncfs. + */ + if (G_IN_SET (errno, EOPNOTSUPP, EPERM)) + { + if (TEMP_FAILURE_RETRY (syncfs (rootfs_dfd)) != 0) + return glnx_throw_errno_prefix (error, "syncfs"); + /* Write the completion, and return */ + if (write (sock_parent, &c, sizeof (c)) != sizeof (c)) + return glnx_throw_errno_prefix (error, "write(watchdog syncfs complete)"); + return TRUE; + } + else + return glnx_throw_errno_prefix (error, "ioctl(FIFREEZE)"); + } + /* And finally thaw, then signal our completion to the watchdog */ + if (TEMP_FAILURE_RETRY (ioctl (rootfs_dfd, FITHAW, 0)) != 0) + return glnx_throw_errno_prefix (error, "ioctl(FITHAW)"); + if (write (sock_parent, &c, sizeof (c)) != sizeof (c)) + return glnx_throw_errno_prefix (error, "write(watchdog FITHAW complete)"); } - *out_checksum = g_strdup (last_dash + 1); return TRUE; } -static gboolean -syncfs_dir_at (int dfd, - const char *path, - GCancellable *cancellable, - GError **error) -{ - glnx_fd_close int child_dfd = -1; - if (!glnx_opendirat (dfd, path, TRUE, &child_dfd, error)) - return FALSE; - if (syncfs (child_dfd) != 0) - return glnx_throw_errno (error); - - return TRUE; -} +typedef struct { + guint64 root_syncfs_msec; + guint64 boot_syncfs_msec; + guint64 extra_syncfs_msec; +} SyncStats; /* First, sync the root directory as well as /var and /boot which may * be separate mount points. Then *in addition*, do a global @@ -988,14 +1136,25 @@ syncfs_dir_at (int dfd, */ static gboolean full_system_sync (OstreeSysroot *self, + SyncStats *out_stats, GCancellable *cancellable, GError **error) { + guint64 start_msec = g_get_monotonic_time () / 1000; if (syncfs (self->sysroot_fd) != 0) - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "syncfs(sysroot)"); + guint64 end_msec = g_get_monotonic_time () / 1000; - if (!syncfs_dir_at (self->sysroot_fd, "boot", cancellable, error)) + out_stats->root_syncfs_msec = (end_msec - start_msec); + + start_msec = g_get_monotonic_time () / 1000; + glnx_fd_close int boot_dfd = -1; + if (!glnx_opendirat (self->sysroot_fd, "boot", TRUE, &boot_dfd, error)) return FALSE; + if (!fsfreeze_thaw_cycle (self, boot_dfd, cancellable, error)) + return FALSE; + end_msec = g_get_monotonic_time () / 1000; + out_stats->boot_syncfs_msec = (end_msec - start_msec); /* And now out of an excess of conservativism, we still invoke * sync(). The advantage of still using `syncfs()` above is that we @@ -1003,7 +1162,10 @@ full_system_sync (OstreeSysroot *self, * delineate what we actually want to sync in the future when this * global sync call is removed. */ + start_msec = g_get_monotonic_time () / 1000; sync (); + end_msec = g_get_monotonic_time () / 1000; + out_stats->extra_syncfs_msec = (end_msec - start_msec); return TRUE; } @@ -1099,15 +1261,6 @@ swap_bootlinks (OstreeSysroot *self, return TRUE; } -static char * -remove_checksum_from_kernel_name (const char *name, - const char *csum) -{ - const char *p = strrchr (name, '-'); - g_assert_cmpstr (p+1, ==, csum); - return g_strndup (name, p-name); -} - static GHashTable * parse_os_release (const char *contents, const char *split) @@ -1161,11 +1314,19 @@ install_deployment_kernel (OstreeSysroot *sysroot, &deployment_dfd, error)) return FALSE; + /* Find the kernel/initramfs in the tree */ glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_name = NULL; - g_autofree char *tree_initramfs_name = NULL; + g_autofree char *tree_kernel_srcpath = NULL; + g_autofree char *tree_kernel_namever = NULL; + g_autofree char *tree_initramfs_srcpath = NULL; + g_autofree char *tree_initramfs_namever = NULL; + g_autofree char *tree_bootcsum = NULL; if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_name, &tree_initramfs_name, + &tree_kernel_srcpath, + &tree_kernel_namever, + &tree_initramfs_srcpath, + &tree_initramfs_namever, + &tree_bootcsum, cancellable, error)) return FALSE; @@ -1175,6 +1336,7 @@ install_deployment_kernel (OstreeSysroot *sysroot, const char *osname = ostree_deployment_get_osname (deployment); const char *bootcsum = ostree_deployment_get_bootcsum (deployment); + g_assert_cmpstr (bootcsum, ==, tree_bootcsum); g_autofree char *bootcsumdir = g_strdup_printf ("ostree/%s-%s", osname, bootcsum); g_autofree char *bootconfdir = g_strdup_printf ("loader.%d/entries", new_bootversion); g_autofree char *bootconf_name = g_strdup_printf ("ostree-%s-%d.conf", osname, @@ -1189,30 +1351,33 @@ install_deployment_kernel (OstreeSysroot *sysroot, if (!glnx_shutil_mkdir_p_at (boot_dfd, bootconfdir, 0775, cancellable, error)) return FALSE; - g_autofree char *dest_kernel_name = remove_checksum_from_kernel_name (tree_kernel_name, bootcsum); + /* Install (hardlink/copy) the kernel into /boot/ostree/osname-${bootcsum} if + * it doesn't exist already. + */ struct stat stbuf; - if (fstatat (bootcsum_dfd, dest_kernel_name, &stbuf, 0) != 0) + if (fstatat (bootcsum_dfd, tree_kernel_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", dest_kernel_name); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_name, - bootcsum_dfd, dest_kernel_name, + return glnx_throw_errno_prefix (error, "fstat %s", tree_kernel_namever); + if (!hardlink_or_copy_at (tree_boot_dfd, tree_kernel_srcpath, + bootcsum_dfd, tree_kernel_namever, sysroot->debug_flags, cancellable, error)) return FALSE; } - g_autofree char *dest_initramfs_name = NULL; - if (tree_initramfs_name) + /* If we have an initramfs, then install it into + * /boot/ostree/osname-${bootcsum} if it doesn't exist already. + */ + if (tree_initramfs_srcpath) { - dest_initramfs_name = remove_checksum_from_kernel_name (tree_initramfs_name, bootcsum); - - if (fstatat (bootcsum_dfd, dest_initramfs_name, &stbuf, 0) != 0) + g_assert (tree_initramfs_namever); + if (fstatat (bootcsum_dfd, tree_initramfs_namever, &stbuf, 0) != 0) { if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "fstat %s", dest_initramfs_name); - if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_name, - bootcsum_dfd, dest_initramfs_name, + return glnx_throw_errno_prefix (error, "fstat %s", tree_initramfs_namever); + if (!hardlink_or_copy_at (tree_boot_dfd, tree_initramfs_srcpath, + bootcsum_dfd, tree_initramfs_namever, sysroot->debug_flags, cancellable, error)) return FALSE; @@ -1293,12 +1458,12 @@ install_deployment_kernel (OstreeSysroot *sysroot, g_autofree char *version_key = g_strdup_printf ("%d", n_deployments - ostree_deployment_get_index (deployment)); ostree_bootconfig_parser_set (bootconfig, OSTREE_COMMIT_META_KEY_VERSION, version_key); - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", dest_kernel_name, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_kernel_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "linux", boot_relpath); - if (dest_initramfs_name) + if (tree_initramfs_namever) { - g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", dest_initramfs_name, NULL); + g_autofree char * boot_relpath = g_strconcat ("/", bootcsumdir, "/", tree_initramfs_namever, NULL); ostree_bootconfig_parser_set (bootconfig, "initrd", boot_relpath); } @@ -1379,7 +1544,7 @@ swap_bootloader (OstreeSysroot *sysroot, * admin by going back to the previous session. */ if (fsync (boot_dfd) != 0) - return glnx_throw_errno (error); + return glnx_throw_errno_prefix (error, "fsync(boot)"); return TRUE; } @@ -1452,10 +1617,9 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - guint i; g_autoptr(GString) buf = g_string_new (""); - for (i = 0; i < self->deployments->len; i++) + for (guint i = 0; i < self->deployments->len; i++) { OstreeDeployment *deployment = self->deployments->pdata[i]; const char *osname = ostree_deployment_get_osname (deployment); @@ -1463,11 +1627,8 @@ cleanup_legacy_current_symlinks (OstreeSysroot *self, g_string_truncate (buf, 0); g_string_append_printf (buf, "ostree/deploy/%s/current", osname); - if (unlinkat (self->sysroot_fd, buf->str, 0) < 0) - { - if (errno != ENOENT) - return glnx_throw_errno (error); - } + if (!ot_ensure_unlinked_at (self->sysroot_fd, buf->str, error)) + return FALSE; } return TRUE; @@ -1568,6 +1729,8 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, gboolean found_booted_deployment = FALSE; gboolean bootloader_is_atomic = FALSE; gboolean boot_was_ro_mount = FALSE; + SyncStats syncstats = { 0, }; + g_autoptr(OstreeBootloader) bootloader = NULL; g_assert (self->loaded); @@ -1631,7 +1794,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, goto out; } - if (!full_system_sync (self, cancellable, error)) + if (!full_system_sync (self, &syncstats, cancellable, error)) { g_prefix_error (error, "Full sync: "); goto out; @@ -1650,9 +1813,8 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, else { int new_bootversion = self->bootversion ? 0 : 1; - glnx_unref_object OstreeBootloader *bootloader = NULL; g_autofree char* new_loader_entries_dir = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean show_osname = FALSE; if (self->booted_deployment) @@ -1751,7 +1913,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, goto out; } - if (!full_system_sync (self, cancellable, error)) + if (!full_system_sync (self, &syncstats, cancellable, error)) { g_prefix_error (error, "Full sync: "); goto out; @@ -1765,11 +1927,25 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self, } } - ot_log_structured_print_id_v (OSTREE_DEPLOYMENT_COMPLETE_ID, - "%s; bootconfig swap: %s deployment count change: %i", - (bootloader_is_atomic ? "Transaction complete" : "Bootloader updated"), - requires_new_bootversion ? "yes" : "no", - new_deployments->len - self->deployments->len); + { g_autofree char *msg = + g_strdup_printf ("%s; bootconfig swap: %s deployment count change: %i", + (bootloader_is_atomic ? "Transaction complete" : "Bootloader updated"), + requires_new_bootversion ? "yes" : "no", + new_deployments->len - self->deployments->len); +#ifdef HAVE_LIBSYSTEMD + sd_journal_send ("MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(OSTREE_DEPLOYMENT_COMPLETE_ID), + "MESSAGE=%s", msg, + "OSTREE_BOOTLOADER=%s", bootloader ? _ostree_bootloader_get_name (bootloader) : "none", + "OSTREE_BOOTLOADER_ATOMIC=%s", bootloader_is_atomic ? "yes" : "no", + "OSTREE_DID_BOOTSWAP=%s", requires_new_bootversion ? "yes" : "no", + "OSTREE_N_DEPLOYMENTS=%u", new_deployments->len, + "OSTREE_SYNCFS_ROOT_MSEC=%" G_GUINT64_FORMAT, syncstats.root_syncfs_msec, + "OSTREE_SYNCFS_BOOT_MSEC=%" G_GUINT64_FORMAT, syncstats.boot_syncfs_msec, + "OSTREE_SYNCFS_EXTRA_MSEC=%" G_GUINT64_FORMAT, syncstats.extra_syncfs_msec, + NULL); +#endif + _ostree_sysroot_emit_journal_msg (self, msg); + } if (!_ostree_sysroot_bump_mtime (self, error)) goto out; @@ -1884,7 +2060,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, return FALSE; OstreeRepo *repo = ostree_sysroot_repo (self); - glnx_unref_object OstreeDeployment *merge_deployment = NULL; + g_autoptr(OstreeDeployment) merge_deployment = NULL; if (provided_merge_deployment != NULL) merge_deployment = g_object_ref (provided_merge_deployment); @@ -1894,7 +2070,7 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, return FALSE; g_autofree char *new_bootcsum = NULL; - glnx_unref_object OstreeDeployment *new_deployment = + g_autoptr(OstreeDeployment) new_deployment = ostree_deployment_new (0, osname, revision, new_deployserial, new_bootcsum, -1); ostree_deployment_set_origin (new_deployment, origin); @@ -1909,33 +2085,29 @@ ostree_sysroot_deploy_tree (OstreeSysroot *self, } glnx_fd_close int tree_boot_dfd = -1; - g_autofree char *tree_kernel_path = NULL; - g_autofree char *tree_initramfs_path = NULL; + g_autofree char *tree_kernel_srcpath = NULL; + g_autofree char *tree_kernel_namever = NULL; + g_autofree char *tree_initramfs_srcpath = NULL; + g_autofree char *tree_initramfs_namever = NULL; + g_autofree char *tree_bootcsum = NULL; if (!get_kernel_from_tree (deployment_dfd, &tree_boot_dfd, - &tree_kernel_path, &tree_initramfs_path, + &tree_kernel_srcpath, + &tree_kernel_namever, + &tree_initramfs_srcpath, + &tree_initramfs_namever, + &new_bootcsum, cancellable, error)) return FALSE; - if (tree_initramfs_path != NULL) - { - if (!checksum_from_kernel_src (tree_initramfs_path, &new_bootcsum, error)) - return FALSE; - } - else - { - if (!checksum_from_kernel_src (tree_kernel_path, &new_bootcsum, error)) - return FALSE; - } - _ostree_deployment_set_bootcsum (new_deployment, new_bootcsum); /* Create an empty boot configuration; we will merge things into * it as we go. */ - glnx_unref_object OstreeBootconfigParser *bootconfig = ostree_bootconfig_parser_new (); + g_autoptr(OstreeBootconfigParser) bootconfig = ostree_bootconfig_parser_new (); ostree_deployment_set_bootconfig (new_deployment, bootconfig); - glnx_unref_object OstreeSePolicy *sepolicy = NULL; + g_autoptr(OstreeSePolicy) sepolicy = NULL; if (!merge_configuration (self, repo, merge_deployment, new_deployment, deployment_dfd, &sepolicy, @@ -2013,7 +2185,7 @@ ostree_sysroot_deployment_set_kargs (OstreeSysroot *self, { guint i; g_autoptr(GPtrArray) new_deployments = g_ptr_array_new_with_free_func (g_object_unref); - glnx_unref_object OstreeDeployment *new_deployment = NULL; + g_autoptr(OstreeDeployment) new_deployment = NULL; __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; g_autofree char *new_options = NULL; OstreeBootconfigParser *new_bootconfig; diff --git a/src/libostree/ostree-sysroot-private.h b/src/libostree/ostree-sysroot-private.h index 82abc8e7..8c4de9e0 100644 --- a/src/libostree/ostree-sysroot-private.h +++ b/src/libostree/ostree-sysroot-private.h @@ -33,7 +33,8 @@ typedef enum { OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS = 1 << 0, /* See https://github.com/ostreedev/ostree/pull/759 */ OSTREE_SYSROOT_DEBUG_NO_XATTRS = 1 << 1, - + /* https://github.com/ostreedev/ostree/pull/1049 */ + OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE = 1 << 2, } OstreeSysrootDebugFlags; /** @@ -56,9 +57,8 @@ struct OstreeSysroot { OstreeDeployment *booted_deployment; struct timespec loaded_ts; - /* Only access through ostree_sysroot_get_repo() */ + /* Only access through ostree_sysroot_[_get]repo() */ OstreeRepo *repo; - gboolean repo_opened; OstreeSysrootDebugFlags debug_flags; }; @@ -68,6 +68,10 @@ struct OstreeSysroot { #define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_DIR "/run/ostree/deployment-state/" #define _OSTREE_SYSROOT_DEPLOYMENT_RUNSTATE_FLAG_DEVELOPMENT "unlocked-development" +void +_ostree_sysroot_emit_journal_msg (OstreeSysroot *self, + const char *msg); + gboolean _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, int bootversion, diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index d262a903..86a4f37a 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -25,6 +25,7 @@ #include #include +#include "ostree.h" #include "ostree-core-private.h" #include "ostree-repo-private.h" #include "ostree-sepolicy-private.h" @@ -57,8 +58,18 @@ find_booted_deployment (OstreeSysroot *self, */ typedef struct { GObjectClass parent_class; + + /* Signals */ + void (*journal_msg) (OstreeSysroot *sysroot, + const char *msg); } OstreeSysrootClass; +enum { + JOURNAL_MSG_SIGNAL, + LAST_SIGNAL, +}; +static guint signals[LAST_SIGNAL] = { 0 }; + enum { PROP_0, @@ -126,18 +137,11 @@ static void ostree_sysroot_constructed (GObject *object) { OstreeSysroot *self = OSTREE_SYSROOT (object); - g_autoptr(GFile) repo_path = NULL; /* Ensure the system root path is set. */ if (self->path == NULL) self->path = g_object_ref (_ostree_get_default_sysroot_path ()); - repo_path = g_file_resolve_relative_path (self->path, "ostree/repo"); - self->repo = ostree_repo_new_for_sysroot_path (repo_path, self->path); - self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT; - /* Hold a weak ref for the remote-add handling */ - g_weak_ref_init (&self->repo->sysroot, object); - G_OBJECT_CLASS (ostree_sysroot_parent_class)->constructed (object); } @@ -158,6 +162,27 @@ ostree_sysroot_class_init (OstreeSysrootClass *klass) "", G_TYPE_FILE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + + /** + * OstreeSysroot::journal-msg: + * @self: Self + * @msg: Human-readable string (should not contain newlines) + * + * libostree will log to the journal various events, such as the /etc merge + * status, and transaction completion. Connect to this signal to also + * synchronously receive the text for those messages. This is intended to be + * used by command line tools which link to libostree as a library. + * + * Currently, the structured data is only available via the systemd journal. + * + * Since: 2017.10 + */ + signals[JOURNAL_MSG_SIGNAL] = + g_signal_new ("journal-msg", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (OstreeSysrootClass, journal_msg), + NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_STRING); } static void @@ -165,6 +190,7 @@ ostree_sysroot_init (OstreeSysroot *self) { const GDebugKey keys[] = { { "mutable-deployments", OSTREE_SYSROOT_DEBUG_MUTABLE_DEPLOYMENTS }, + { "test-fifreeze", OSTREE_SYSROOT_DEBUG_TEST_FIFREEZE }, { "no-xattrs", OSTREE_SYSROOT_DEBUG_NO_XATTRS }, }; @@ -299,24 +325,22 @@ ostree_sysroot_ensure_initialized (OstreeSysroot *self, cancellable, error)) return FALSE; - struct stat stbuf; - if (fstatat (self->sysroot_fd, "ostree/repo/objects", &stbuf, 0) != 0) - { - if (errno != ENOENT) - return glnx_throw_errno_prefix (error, "stat(ostree/repo/objects)"); - else - { - g_autoptr(GFile) repo_dir = g_file_resolve_relative_path (self->path, "ostree/repo"); - glnx_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir); - if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE, - cancellable, error)) - return FALSE; - } - } - + g_autoptr(OstreeRepo) repo = + ostree_repo_create_at (self->sysroot_fd, "ostree/repo", + OSTREE_REPO_MODE_BARE, NULL, + cancellable, error); + if (!repo) + return FALSE; return TRUE; } +void +_ostree_sysroot_emit_journal_msg (OstreeSysroot *self, + const char *msg) +{ + g_signal_emit (self, signals[JOURNAL_MSG_SIGNAL], 0, msg); +} + gboolean _ostree_sysroot_parse_deploy_path_name (const char *name, char **out_csum, @@ -454,7 +478,7 @@ _ostree_sysroot_read_boot_loader_configs (OstreeSysroot *self, g_str_has_suffix (dent->d_name, ".conf") && S_ISREG (stbuf.st_mode)) { - glnx_unref_object OstreeBootconfigParser *config = ostree_bootconfig_parser_new (); + g_autoptr(OstreeBootconfigParser) config = ostree_bootconfig_parser_new (); if (!ostree_bootconfig_parser_parse_at (config, dfd_iter.fd, dent->d_name, cancellable, error)) return glnx_prefix_error (error, "Parsing %s", dent->d_name); @@ -624,7 +648,7 @@ parse_deployment (OstreeSysroot *self, cancellable, error)) return FALSE; - glnx_unref_object OstreeDeployment *ret_deployment + g_autoptr(OstreeDeployment) ret_deployment = ostree_deployment_new (-1, osname, treecsum, deployserial, bootcsum, treebootserial); if (origin) @@ -691,7 +715,7 @@ list_deployments_process_one_boot_entry (OstreeSysroot *self, if (ostree_arg == NULL) return glnx_throw (error, "No ostree= kernel argument found"); - glnx_unref_object OstreeDeployment *deployment = NULL; + g_autoptr(OstreeDeployment) deployment = NULL; if (!parse_deployment (self, ostree_arg, &deployment, cancellable, error)) return FALSE; @@ -732,14 +756,22 @@ ostree_sysroot_load (OstreeSysroot *self, } static gboolean -ensure_repo_opened (OstreeSysroot *self, - GError **error) +ensure_repo (OstreeSysroot *self, + GError **error) { - if (self->repo_opened) + if (self->repo != NULL) return TRUE; - if (!ostree_repo_open (self->repo, NULL, error)) + if (!ensure_sysroot_fd (self, error)) return FALSE; - self->repo_opened = TRUE; + self->repo = ostree_repo_open_at (self->sysroot_fd, "ostree/repo", NULL, error); + if (!self->repo) + return FALSE; + + /* Flag it as having been created via ostree_sysroot_get_repo(), and hold a + * weak ref for the remote-add handling. + */ + g_weak_ref_init (&self->repo->sysroot, self); + self->repo->sysroot_kind = OSTREE_REPO_SYSROOT_KIND_VIA_SYSROOT; return TRUE; } @@ -756,7 +788,7 @@ ostree_sysroot_load_if_changed (OstreeSysroot *self, * previous to v2017.6, but we do now to support the error-free * ostree_sysroot_repo() API. */ - if (!ensure_repo_opened (self, error)) + if (!ensure_repo (self, error)) return FALSE; int bootversion = 0; @@ -959,9 +991,8 @@ ostree_sysroot_get_repo (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - if (!ensure_repo_opened (self, error)) + if (!ensure_repo (self, error)) return FALSE; - if (out_repo != NULL) *out_repo = g_object_ref (self->repo); return TRUE; @@ -999,7 +1030,7 @@ _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot, GError **error) { gboolean is_active; - glnx_unref_object OstreeBootloader *ret_loader = + g_autoptr(OstreeBootloader) ret_loader = (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot); if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error)) @@ -1078,7 +1109,7 @@ find_booted_deployment (OstreeSysroot *self, { struct stat root_stbuf; struct stat self_stbuf; - glnx_unref_object OstreeDeployment *ret_deployment = NULL; + g_autoptr(OstreeDeployment) ret_deployment = NULL; if (stat ("/", &root_stbuf) != 0) return glnx_throw_errno_prefix (error, "stat /"); @@ -1540,6 +1571,7 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot, return ret; } +/* Deploy a copy of @target_deployment */ static gboolean clone_deployment (OstreeSysroot *sysroot, OstreeDeployment *target_deployment, @@ -1547,38 +1579,26 @@ clone_deployment (OstreeSysroot *sysroot, 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; - } + return glnx_prefix_error (error, "Performing initial cleanup"); - kargs = _ostree_kernel_args_new (); + /* Copy the bootloader config options */ + OstreeBootconfigParser *bootconfig = ostree_deployment_get_bootconfig (merge_deployment); + g_auto(GStrv) previous_args = g_strsplit (ostree_bootconfig_parser_get (bootconfig, "options"), " ", -1); + __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = _ostree_kernel_args_new (); + _ostree_kernel_args_append_argv (kargs, previous_args); - { 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; - } + /* Deploy the copy */ + g_autoptr(OstreeDeployment) new_deployment = NULL; + 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)) + return FALSE; /* Hotfixes push the deployment as rollback target, so it shouldn't * be the default. @@ -1587,11 +1607,9 @@ clone_deployment (OstreeSysroot *sysroot, new_deployment, merge_deployment, OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT, cancellable, error)) - goto out; - - ret = TRUE; - out: - return ret; + return FALSE; + + return TRUE; } /** @@ -1616,59 +1634,41 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, GCancellable *cancellable, GError **error) { - gboolean ret = FALSE; - glnx_unref_object OstreeSePolicy *sepolicy = NULL; - 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); + OstreeDeploymentUnlockedState current_unlocked = ostree_deployment_get_unlocked (deployment); 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; - } + return glnx_throw (error, "Deployment is already in unlocked state: %s", + ostree_deployment_unlocked_state_to_string (current_unlocked)); - merge_deployment = ostree_sysroot_get_merge_deployment (self, ostree_deployment_get_osname (deployment)); + g_autoptr(OstreeDeployment) 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; - } + return glnx_throw (error, "No previous deployment to duplicate"); /* 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; + return FALSE; } /* 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); + return FALSE; + g_autofree char *deployment_path = ostree_sysroot_get_deployment_dirpath (self, deployment); + glnx_fd_close int deployment_dfd = -1; if (!glnx_opendirat (self->sysroot_fd, deployment_path, TRUE, &deployment_dfd, error)) - goto out; + return FALSE; - sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); + g_autoptr(OstreeSePolicy) sepolicy = ostree_sepolicy_new_at (deployment_dfd, cancellable, error); if (!sepolicy) - goto out; + return FALSE; + const char *ovl_options = NULL; switch (unlocked_state) { case OSTREE_DEPLOYMENT_UNLOCKED_NONE: @@ -1676,14 +1676,15 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, break; case OSTREE_DEPLOYMENT_UNLOCKED_HOTFIX: { + const char hotfix_ovl_options[] = "lowerdir=usr,upperdir=.usr-ovl-upper,workdir=.usr-ovl-work"; /* 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; + return FALSE; if (!glnx_shutil_mkdir_p_at (deployment_dfd, ".usr-ovl-work", 0755, cancellable, error)) - goto out; + return FALSE; ovl_options = hotfix_ovl_options; } break; @@ -1701,18 +1702,18 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, if (!_ostree_sepolicy_preparefscreatecon (&con, sepolicy, "/usr", 0755, error)) - goto out; + return FALSE; if (!glnx_mkdtempat (AT_FDCWD, development_ovldir, 0755, error)) - goto out; + return FALSE; } development_ovl_upper = glnx_strjoina (development_ovldir, "/upper"); if (!glnx_shutil_mkdir_p_at (AT_FDCWD, development_ovl_upper, 0755, cancellable, error)) - goto out; + return FALSE; development_ovl_work = glnx_strjoina (development_ovldir, "/work"); if (!glnx_shutil_mkdir_p_at (AT_FDCWD, development_ovl_work, 0755, cancellable, error)) - goto out; + return FALSE; ovl_options = glnx_strjoina ("lowerdir=usr,upperdir=", development_ovl_upper, ",workdir=", development_ovl_work); } @@ -1728,12 +1729,9 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, * threads, etc. */ { - mount_child = fork (); + pid_t mount_child = fork (); if (mount_child < 0) - { - glnx_set_prefix_error_from_errno (error, "%s", "fork"); - goto out; - } + return glnx_throw_errno_prefix (error, "fork"); else if (mount_child == 0) { /* Child process. Do NOT use any GLib API here. */ @@ -1749,18 +1747,15 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, 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; - } + return glnx_throw_errno_prefix (error, "waitpid() on mount helper"); if (!g_spawn_check_exit_status (estatus, error)) - { - g_prefix_error (error, "overlayfs mount helper: "); - goto out; - } + return glnx_throw_errno_prefix (error, "overlayfs mount helper"); } } + g_autoptr(OstreeDeployment) deployment_clone = ostree_deployment_clone (deployment); + GKeyFile *origin_clone = ostree_deployment_get_origin (deployment_clone); + /* Now, write out the flag saying what we did */ switch (unlocked_state) { @@ -1772,7 +1767,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, ostree_deployment_unlocked_state_to_string (unlocked_state)); if (!ostree_sysroot_write_origin_file (self, deployment, origin_clone, cancellable, error)) - goto out; + return FALSE; break; case OSTREE_DEPLOYMENT_UNLOCKED_DEVELOPMENT: { @@ -1780,10 +1775,10 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, g_autofree char *devpath_parent = dirname (g_strdup (devpath)); if (!glnx_shutil_mkdir_p_at (AT_FDCWD, devpath_parent, 0755, cancellable, error)) - goto out; - + return FALSE; + if (!g_file_set_contents (devpath, "", 0, error)) - goto out; + return FALSE; } } @@ -1793,9 +1788,7 @@ ostree_sysroot_deployment_unlock (OstreeSysroot *self, * regardless. */ if (!_ostree_sysroot_bump_mtime (self, error)) - goto out; + return FALSE; - ret = TRUE; - out: - return ret; + return TRUE; } diff --git a/src/libostree/ostree-tls-cert-interaction.h b/src/libostree/ostree-tls-cert-interaction.h index ae4532f7..09a8ad0d 100644 --- a/src/libostree/ostree-tls-cert-interaction.h +++ b/src/libostree/ostree-tls-cert-interaction.h @@ -18,6 +18,7 @@ #pragma once +#include "otutil.h" #include G_BEGIN_DECLS @@ -31,6 +32,7 @@ G_BEGIN_DECLS typedef struct _OstreeTlsCertInteraction OstreeTlsCertInteraction; typedef struct _OstreeTlsCertInteractionClass OstreeTlsCertInteractionClass; +G_DEFINE_AUTOPTR_CLEANUP_FUNC(OstreeTlsCertInteraction, g_object_unref) GType _ostree_tls_cert_interaction_get_type (void) G_GNUC_CONST; diff --git a/src/libostree/ostree-version.h b/src/libostree/ostree-version.h index 0b7dc92d..32b401e9 100644 --- a/src/libostree/ostree-version.h +++ b/src/libostree/ostree-version.h @@ -44,7 +44,7 @@ * * Since: 2017.4 */ -#define OSTREE_RELEASE_VERSION (9) +#define OSTREE_RELEASE_VERSION (10) /** * OSTREE_VERSION @@ -53,7 +53,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION (2017.9) +#define OSTREE_VERSION (2017.10) /** * OSTREE_VERSION_S: @@ -63,7 +63,7 @@ * * Since: 2017.4 */ -#define OSTREE_VERSION_S "2017.9" +#define OSTREE_VERSION_S "2017.10" #define OSTREE_ENCODE_VERSION(year,release) \ ((year) << 16 | (release)) diff --git a/src/libotutil/ot-fs-utils.h b/src/libotutil/ot-fs-utils.h index 43bc6942..e25522db 100644 --- a/src/libotutil/ot-fs-utils.h +++ b/src/libotutil/ot-fs-utils.h @@ -49,7 +49,7 @@ ot_cleanup_unlinkat (OtCleanupUnlinkat *cleanup) ot_cleanup_unlinkat_clear (cleanup); } } -G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtCleanupUnlinkat, ot_cleanup_unlinkat); +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(OtCleanupUnlinkat, ot_cleanup_unlinkat) GFile * ot_fdrel_to_gfile (int dfd, const char *path); diff --git a/src/libotutil/ot-gpg-utils.c b/src/libotutil/ot-gpg-utils.c index 001daa0a..99f4879e 100644 --- a/src/libotutil/ot-gpg-utils.c +++ b/src/libotutil/ot-gpg-utils.c @@ -413,7 +413,7 @@ ot_gpgme_new_ctx (const char *homedir, GError **error) { gpgme_error_t err; - ot_auto_gpgme_ctx gpgme_ctx_t context = NULL; + g_auto(gpgme_ctx_t) context = NULL; if ((err = gpgme_new (&context)) != GPG_ERR_NO_ERROR) { diff --git a/src/libotutil/ot-gpg-utils.h b/src/libotutil/ot-gpg-utils.h index 184a8d64..b639e5ac 100644 --- a/src/libotutil/ot-gpg-utils.h +++ b/src/libotutil/ot-gpg-utils.h @@ -26,10 +26,9 @@ G_BEGIN_DECLS -GLNX_DEFINE_CLEANUP_FUNCTION0(gpgme_data_t, ot_cleanup_gpgme_data, gpgme_data_release) -#define ot_auto_gpgme_data __attribute__((cleanup(ot_cleanup_gpgme_data))) -GLNX_DEFINE_CLEANUP_FUNCTION0(gpgme_ctx_t, ot_cleanup_gpgme_ctx, gpgme_release) -#define ot_auto_gpgme_ctx __attribute__((cleanup(ot_cleanup_gpgme_ctx))) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_data_t, gpgme_data_release, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_ctx_t, gpgme_release, NULL) +G_DEFINE_AUTO_CLEANUP_FREE_FUNC(gpgme_key_t, gpgme_key_unref, NULL) void ot_gpgme_error_to_gio_error (gpgme_error_t gpg_error, GError **error); diff --git a/src/libotutil/ot-log-utils.c b/src/libotutil/ot-log-utils.c deleted file mode 100644 index e1ce1690..00000000 --- a/src/libotutil/ot-log-utils.c +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2016 Colin Walters - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Author: Colin Walters - */ - -#include "config.h" - -#include - -#include - -#include "otutil.h" -#include "libglnx.h" - -#ifdef HAVE_LIBSYSTEMD -#define SD_JOURNAL_SUPPRESS_LOCATION -#include -#endif -#include - -/** - * ot_log_structured: - * @message: Text message to send - * @keys: (allow-none) (array zero-terminated=1) (element-type utf8): Optional structured data - * - * Log structured data in an operating-system specific fashion. The - * parameter @opts should be an array of UTF-8 KEY=VALUE strings. - * This function does not support binary data. See - * http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html - * for more information about fields that can be used on a systemd - * system. - */ -static void -ot_log_structured (const char *message, - const char *const *keys) -{ -#ifdef HAVE_LIBSYSTEMD - const char *const*iter; - g_autofree char *msgkey = NULL; - guint i, n_opts; - struct iovec *iovs; - - for (n_opts = 0, iter = keys; *iter; iter++, n_opts++) - ; - - n_opts++; /* Add one for MESSAGE= */ - iovs = g_alloca (sizeof (struct iovec) * n_opts); - - for (i = 0, iter = keys; *iter; iter++, i++) { - iovs[i].iov_base = (char*)keys[i]; - iovs[i].iov_len = strlen (keys[i]); - } - g_assert(i == n_opts-1); - msgkey = g_strconcat ("MESSAGE=", message, NULL); - iovs[i].iov_base = msgkey; - iovs[i].iov_len = strlen (msgkey); - - // The code location isn't useful since we're wrapping - sd_journal_sendv (iovs, n_opts); -#else - g_print ("%s\n", message); -#endif -} - -/** - * ot_stdout_is_journal: - * - * Use this function when you want your code to behave differently - * depeneding on whether your program was started as a systemd unit, - * or e.g. interactively at a terminal. - * - * Returns: %TRUE if stdout is (probably) connnected to the systemd journal - */ -static gboolean -ot_stdout_is_journal (void) -{ - static gsize initialized; - static gboolean stdout_is_socket; - - if (g_once_init_enter (&initialized)) - { - guint64 pid = (guint64) getpid (); - g_autofree char *fdpath = g_strdup_printf ("/proc/%" G_GUINT64_FORMAT "/fd/1", pid); - char buf[1024]; - ssize_t bytes_read; - - if ((bytes_read = readlink (fdpath, buf, sizeof(buf) - 1)) != -1) - { - buf[bytes_read] = '\0'; - stdout_is_socket = g_str_has_prefix (buf, "socket:"); - } - else - stdout_is_socket = FALSE; - - g_once_init_leave (&initialized, TRUE); - } - - return stdout_is_socket; -} - -/** - * gs_log_structured_print: - * @message: A message to log - * @keys: (allow-none) (array zero-terminated=1) (element-type utf8): Optional structured data - * - * Like gs_log_structured(), but also print to standard output (if it - * is not already connected to the system log). - */ -static void -ot_log_structured_print (const char *message, - const char *const *keys) -{ - ot_log_structured (message, keys); - -#ifdef HAVE_LIBSYSTEMD - if (!ot_stdout_is_journal ()) - g_print ("%s\n", message); -#endif -} - -/** - * ot_log_structured_print_id_v: - * @message_id: A unique MESSAGE_ID - * @format: A format string - * - * The provided @message_id is a unique MESSAGE_ID (see for more information). - * - * This function otherwise acts as ot_log_structured_print(), taking - * @format as a format string. - */ -void -ot_log_structured_print_id_v (const char *message_id, - const char *format, - ...) -{ - const char *key0 = glnx_strjoina ("MESSAGE_ID=", message_id); - const char *keys[] = { key0, NULL }; - g_autofree char *msg = NULL; - va_list args; - - va_start (args, format); - msg = g_strdup_vprintf (format, args); - va_end (args); - - ot_log_structured_print (msg, (const char *const *)keys); -} diff --git a/src/libotutil/ot-log-utils.h b/src/libotutil/ot-log-utils.h deleted file mode 100644 index 8d9786de..00000000 --- a/src/libotutil/ot-log-utils.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2016 Colin Walters . - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#pragma once - -#include "ot-unix-utils.h" - -G_BEGIN_DECLS - -void ot_log_structured_print_id_v (const char *message_id, - const char *format, - ...) G_GNUC_PRINTF(2, 3); - -G_END_DECLS diff --git a/src/libotutil/otutil.h b/src/libotutil/otutil.h index dfe951d0..0647515c 100644 --- a/src/libotutil/otutil.h +++ b/src/libotutil/otutil.h @@ -51,7 +51,6 @@ #include #include #include -#include #include void ot_ptrarray_add_many (GPtrArray *a, ...) G_GNUC_NULL_TERMINATED; diff --git a/src/ostree/ostree-trivial-httpd.c b/src/ostree/ostree-trivial-httpd.c index 176f5ec7..f3fd0c6c 100644 --- a/src/ostree/ostree-trivial-httpd.c +++ b/src/ostree/ostree-trivial-httpd.c @@ -56,6 +56,11 @@ typedef struct { GOutputStream *log; } OtTrivialHttpd; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-trivial-httpd.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "daemonize", 'd', 0, G_OPTION_ARG_NONE, &opt_daemonize, "Fork into background when ready", NULL }, { "autoexit", 0, 0, G_OPTION_ARG_NONE, &opt_autoexit, "Automatically exit when directory is deleted", NULL }, @@ -94,7 +99,7 @@ httpd_log (OtTrivialHttpd *httpd, const gchar *format, ...) g_string_append_vprintf (str, format, args); va_end (args); - g_output_stream_write_all (httpd->log, str->str, str->len, &written, NULL, NULL); + (void)g_output_stream_write_all (httpd->log, str->str, str->len, &written, NULL, NULL); } static int diff --git a/src/ostree/ot-admin-builtin-cleanup.c b/src/ostree/ot-admin-builtin-cleanup.c index a6f74e38..13caa7f4 100644 --- a/src/ostree/ot-admin-builtin-cleanup.c +++ b/src/ostree/ot-admin-builtin-cleanup.c @@ -29,6 +29,11 @@ #include +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-cleanup.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -37,7 +42,7 @@ gboolean ot_admin_builtin_cleanup (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; gboolean ret = FALSE; context = g_option_context_new ("Delete untagged deployments and repository objects"); diff --git a/src/ostree/ot-admin-builtin-deploy.c b/src/ostree/ot-admin-builtin-deploy.c index 709c635e..5df4923c 100644 --- a/src/ostree/ot-admin-builtin-deploy.c +++ b/src/ostree/ot-admin-builtin-deploy.c @@ -39,6 +39,11 @@ static gboolean opt_kernel_proc_cmdline; static char *opt_osname; static char *opt_origin_path; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-deploy.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, { "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" }, @@ -55,11 +60,11 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro gboolean ret = FALSE; const char *refspec; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; g_autoptr(GKeyFile) origin = NULL; - glnx_unref_object OstreeRepo *repo = NULL; - glnx_unref_object OstreeDeployment *new_deployment = NULL; - glnx_unref_object OstreeDeployment *merge_deployment = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(OstreeDeployment) new_deployment = NULL; + g_autoptr(OstreeDeployment) merge_deployment = NULL; g_autofree char *revision = NULL; __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; diff --git a/src/ostree/ot-admin-builtin-diff.c b/src/ostree/ot-admin-builtin-diff.c index 2615f24c..0419f2e1 100644 --- a/src/ostree/ot-admin-builtin-diff.c +++ b/src/ostree/ot-admin-builtin-diff.c @@ -31,6 +31,11 @@ static char *opt_osname; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-config-diff.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, { NULL } @@ -40,9 +45,9 @@ gboolean ot_admin_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; gboolean ret = FALSE; - glnx_unref_object OstreeDeployment *deployment = NULL; + g_autoptr(OstreeDeployment) deployment = NULL; g_autoptr(GFile) deployment_dir = NULL; g_autoptr(GPtrArray) modified = NULL; g_autoptr(GPtrArray) removed = NULL; diff --git a/src/ostree/ot-admin-builtin-init-fs.c b/src/ostree/ot-admin-builtin-init-fs.c index 9c08630d..c1fa16b0 100644 --- a/src/ostree/ot-admin-builtin-init-fs.c +++ b/src/ostree/ot-admin-builtin-init-fs.c @@ -29,6 +29,11 @@ #include +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-init-fs.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -37,10 +42,10 @@ gboolean ot_admin_builtin_init_fs (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; gboolean ret = FALSE; glnx_fd_close int root_dfd = -1; - glnx_unref_object OstreeSysroot *target_sysroot = NULL; + g_autoptr(OstreeSysroot) target_sysroot = NULL; guint i; const char *normal_toplevels[] = {"boot", "dev", "home", "proc", "run", "sys"}; diff --git a/src/ostree/ot-admin-builtin-os-init.c b/src/ostree/ot-admin-builtin-os-init.c index cb95bebd..0abb8e39 100644 --- a/src/ostree/ot-admin-builtin-os-init.c +++ b/src/ostree/ot-admin-builtin-os-init.c @@ -29,6 +29,11 @@ #include +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-os-init.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -37,7 +42,7 @@ gboolean ot_admin_builtin_os_init (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; gboolean ret = FALSE; const char *osname = NULL; diff --git a/src/ostree/ot-admin-builtin-set-origin.c b/src/ostree/ot-admin-builtin-set-origin.c index a814d9d5..c49f575a 100644 --- a/src/ostree/ot-admin-builtin-set-origin.c +++ b/src/ostree/ot-admin-builtin-set-origin.c @@ -34,6 +34,11 @@ static int opt_index = -1; static char **opt_set; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-set-origin.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "set", 's', 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" }, { "index", 0, 0, G_OPTION_ARG_INT, &opt_index, "Operate on the deployment INDEX, starting from zero", "INDEX" }, @@ -48,9 +53,9 @@ ot_admin_builtin_set_origin (int argc, char **argv, GCancellable *cancellable, G const char *remotename = NULL; const char *url = NULL; const char *branch = NULL; - glnx_unref_object OstreeRepo *repo = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; - glnx_unref_object OstreeDeployment *target_deployment = NULL; + g_autoptr(OstreeRepo) repo = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(OstreeDeployment) target_deployment = NULL; context = g_option_context_new ("REMOTENAME URL [BRANCH]"); diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c index a437e7cf..3dd7aec5 100644 --- a/src/ostree/ot-admin-builtin-status.c +++ b/src/ostree/ot-admin-builtin-status.c @@ -29,6 +29,11 @@ #include +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-status.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -84,9 +89,9 @@ gboolean ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; gboolean ret = FALSE; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; OstreeDeployment *booted_deployment = NULL; g_autoptr(OstreeDeployment) pending_deployment = NULL; g_autoptr(OstreeDeployment) rollback_deployment = NULL; @@ -129,7 +134,7 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro 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; + g_autoptr(OstreeGpgVerifyResult) result = NULL; guint jj, n_signatures; GError *local_error = NULL; diff --git a/src/ostree/ot-admin-builtin-switch.c b/src/ostree/ot-admin-builtin-switch.c index 9df77f05..f85e39e1 100644 --- a/src/ostree/ot-admin-builtin-switch.c +++ b/src/ostree/ot-admin-builtin-switch.c @@ -33,6 +33,11 @@ static gboolean opt_reboot; static char *opt_osname; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-switch.xml) when changing the option list. + */ + 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" }, @@ -44,9 +49,9 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; const char *new_provided_refspec = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; g_autofree char *origin_refspec = NULL; g_autofree char *origin_remote = NULL; g_autofree char *origin_ref = NULL; @@ -54,8 +59,8 @@ ot_admin_builtin_switch (int argc, char **argv, GCancellable *cancellable, GErro g_autofree char *new_ref = NULL; g_autofree char *new_refspec = NULL; const char* remote; - glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL; - glnx_unref_object OstreeAsyncProgress *progress = NULL; + g_autoptr(OstreeSysrootUpgrader) upgrader = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; gboolean changed; GKeyFile *old_origin; g_autoptr(GKeyFile) new_origin = NULL; diff --git a/src/ostree/ot-admin-builtin-undeploy.c b/src/ostree/ot-admin-builtin-undeploy.c index 00252c80..c0ff89ef 100644 --- a/src/ostree/ot-admin-builtin-undeploy.c +++ b/src/ostree/ot-admin-builtin-undeploy.c @@ -28,6 +28,11 @@ #include "ostree.h" #include "otutil.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-undeploy.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -36,11 +41,11 @@ gboolean ot_admin_builtin_undeploy (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; const char *deploy_index_str; int deploy_index; g_autoptr(GPtrArray) current_deployments = NULL; - glnx_unref_object OstreeDeployment *target_deployment = NULL; + g_autoptr(OstreeDeployment) target_deployment = NULL; context = g_option_context_new ("INDEX - Delete deployment INDEX"); diff --git a/src/ostree/ot-admin-builtin-unlock.c b/src/ostree/ot-admin-builtin-unlock.c index aecba51b..05397414 100644 --- a/src/ostree/ot-admin-builtin-unlock.c +++ b/src/ostree/ot-admin-builtin-unlock.c @@ -33,6 +33,11 @@ static gboolean opt_hotfix; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-unlock.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "hotfix", 0, 0, G_OPTION_ARG_NONE, &opt_hotfix, "Retain changes across reboots", NULL }, { NULL } @@ -43,7 +48,7 @@ ot_admin_builtin_unlock (int argc, char **argv, GCancellable *cancellable, GErro { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; OstreeDeployment *booted_deployment = NULL; OstreeDeploymentUnlockedState target_state; diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c index 7c710ffc..b939278c 100644 --- a/src/ostree/ot-admin-builtin-upgrade.c +++ b/src/ostree/ot-admin-builtin-upgrade.c @@ -39,6 +39,11 @@ static gboolean opt_deploy_only; static char *opt_osname; static char *opt_override_commit; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-upgrade.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" }, { "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Reboot after a successful upgrade", NULL }, @@ -54,10 +59,10 @@ ot_admin_builtin_upgrade (int argc, char **argv, GCancellable *cancellable, GErr { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; - glnx_unref_object OstreeSysrootUpgrader *upgrader = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; + g_autoptr(OstreeSysrootUpgrader) upgrader = NULL; g_autoptr(GKeyFile) origin = NULL; - glnx_unref_object OstreeAsyncProgress *progress = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; gboolean changed; OstreeSysrootUpgraderPullFlags upgraderpullflags = 0; diff --git a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c index 4b8b581b..07bd1eaa 100644 --- a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c +++ b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c @@ -29,6 +29,11 @@ #include "otutil.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-instutil.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -39,7 +44,7 @@ ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, GCancellable *c gboolean ret = FALSE; guint bootversion; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; context = g_option_context_new ("[BOOTVERSION] - generate GRUB2 configuration from given BLS entries"); diff --git a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c index 424c7645..c754b18a 100644 --- a/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c +++ b/src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c @@ -174,6 +174,11 @@ selinux_relabel_dir (OstreeSePolicy *sepolicy, return ret; } +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-instutil.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -185,11 +190,11 @@ ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, GCancel const char *policy_name; g_autoptr(GFile) subpath = NULL; const char *prefix = NULL; - glnx_unref_object OstreeSePolicy *sepolicy = NULL; + g_autoptr(OstreeSePolicy) sepolicy = NULL; g_autoptr(GPtrArray) deployments = NULL; OstreeDeployment *first_deployment; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; g_autoptr(GFile) deployment_path = NULL; context = g_option_context_new ("[SUBPATH PREFIX] - relabel all or part of a deployment"); diff --git a/src/ostree/ot-admin-instutil-builtin-set-kargs.c b/src/ostree/ot-admin-instutil-builtin-set-kargs.c index ad792a3a..1a37022c 100644 --- a/src/ostree/ot-admin-instutil-builtin-set-kargs.c +++ b/src/ostree/ot-admin-instutil-builtin-set-kargs.c @@ -35,6 +35,11 @@ static gboolean opt_merge; static char **opt_replace; static char **opt_append; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-admin-instutil.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "import-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_proc_cmdline, "Import current /proc/cmdline", NULL }, { "merge", 0, 0, G_OPTION_ARG_NONE, &opt_merge, "Merge with previous command line", NULL }, @@ -51,7 +56,7 @@ ot_admin_instutil_builtin_set_kargs (int argc, char **argv, GCancellable *cancel g_autoptr(GPtrArray) deployments = NULL; OstreeDeployment *first_deployment = NULL; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeSysroot *sysroot = NULL; + g_autoptr(OstreeSysroot) sysroot = NULL; __attribute__((cleanup(_ostree_kernel_args_cleanup))) OstreeKernelArgs *kargs = NULL; context = g_option_context_new ("ARGS - set new kernel command line arguments"); diff --git a/src/ostree/ot-builtin-cat.c b/src/ostree/ot-builtin-cat.c index db0ffab3..9aedeb4e 100644 --- a/src/ostree/ot-builtin-cat.c +++ b/src/ostree/ot-builtin-cat.c @@ -29,6 +29,11 @@ #include +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-cat.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL }, }; diff --git a/src/ostree/ot-builtin-checkout.c b/src/ostree/ot-builtin-checkout.c index 937c5b96..a31d3685 100644 --- a/src/ostree/ot-builtin-checkout.c +++ b/src/ostree/ot-builtin-checkout.c @@ -61,6 +61,11 @@ parse_fsync_cb (const char *option_name, return TRUE; } +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-checkout.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "user-mode", 'U', 0, G_OPTION_ARG_NONE, &opt_user_mode, "Do not change file ownership or initialize extended attributes", NULL }, { "disable-cache", 0, 0, G_OPTION_ARG_NONE, &opt_disable_cache, "Do not update or use the internal repository uncompressed object cache", NULL }, @@ -254,7 +259,7 @@ gboolean ostree_builtin_checkout (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; const char *commit; const char *destination; diff --git a/src/ostree/ot-builtin-checksum.c b/src/ostree/ot-builtin-checksum.c index 540b02a1..8c44de9e 100644 --- a/src/ostree/ot-builtin-checksum.c +++ b/src/ostree/ot-builtin-checksum.c @@ -28,6 +28,11 @@ #include +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-checksum.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c index 8f359380..6d1ce060 100644 --- a/src/ostree/ot-builtin-commit.c +++ b/src/ostree/ot-builtin-commit.c @@ -72,6 +72,11 @@ parse_fsync_cb (const char *option_name, return TRUE; } +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-commit.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "parent", 0, 0, G_OPTION_ARG_STRING, &opt_parent, "Parent ref, or \"none\"", "REF" }, { "subject", 's', 0, G_OPTION_ARG_STRING, &opt_subject, "One line subject", "SUBJECT" }, @@ -375,7 +380,7 @@ gboolean ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; gboolean skip_commit = FALSE; g_autoptr(GFile) object_to_commit = NULL; @@ -384,7 +389,7 @@ ostree_builtin_commit (int argc, char **argv, GCancellable *cancellable, GError g_autoptr(GFile) root = NULL; g_autoptr(GVariant) metadata = NULL; g_autoptr(GVariant) detached_metadata = NULL; - glnx_unref_object OstreeMutableTree *mtree = NULL; + g_autoptr(OstreeMutableTree) mtree = NULL; g_autofree char *tree_type = NULL; g_autoptr(GHashTable) mode_adds = NULL; g_autoptr(GHashTable) mode_overrides = NULL; diff --git a/src/ostree/ot-builtin-config.c b/src/ostree/ot-builtin-config.c index a9a5f52a..6163b3b1 100644 --- a/src/ostree/ot-builtin-config.c +++ b/src/ostree/ot-builtin-config.c @@ -27,6 +27,11 @@ #include "ostree.h" #include "otutil.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-config.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -55,7 +60,7 @@ gboolean ostree_builtin_config (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; const char *op; const char *section_key; diff --git a/src/ostree/ot-builtin-diff.c b/src/ostree/ot-builtin-diff.c index a7e2aad2..e00a20fd 100644 --- a/src/ostree/ot-builtin-diff.c +++ b/src/ostree/ot-builtin-diff.c @@ -33,6 +33,11 @@ static gboolean opt_no_xattrs; static gint opt_owner_uid = -1; static gint opt_owner_gid = -1; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-diff.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "stats", 0, 0, G_OPTION_ARG_NONE, &opt_stats, "Print various statistics", NULL }, { "fs-diff", 0, 0, G_OPTION_ARG_NONE, &opt_fs_diff, "Print filesystem diff", NULL }, @@ -126,7 +131,7 @@ ostree_builtin_diff (int argc, char **argv, GCancellable *cancellable, GError ** { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; const char *src; const char *target; g_autofree char *src_prev = NULL; diff --git a/src/ostree/ot-builtin-export.c b/src/ostree/ot-builtin-export.c index 2d40112a..aa79824e 100644 --- a/src/ostree/ot-builtin-export.c +++ b/src/ostree/ot-builtin-export.c @@ -20,12 +20,12 @@ #include "config.h" +#include "otutil.h" #include "ot-main.h" #include "ot-builtins.h" +#include "ostree-libarchive-private.h" #include "ostree.h" #include "ostree-repo-file.h" -#include "ostree-libarchive-private.h" -#include "otutil.h" #ifdef HAVE_LIBARCHIVE #include @@ -37,6 +37,11 @@ static char *opt_subpath; static char *opt_prefix; static gboolean opt_no_xattrs; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-export.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Skip output of extended attributes", NULL }, { "subpath", 0, 0, G_OPTION_ARG_FILENAME, &opt_subpath, "Checkout sub-directory PATH", "PATH" }, @@ -61,14 +66,16 @@ gboolean ostree_builtin_export (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; const char *rev; g_autoptr(GFile) root = NULL; g_autoptr(GFile) subtree = NULL; g_autofree char *commit = NULL; g_autoptr(GVariant) commit_data = NULL; - ot_cleanup_write_archive struct archive *a = NULL; +#ifdef HAVE_LIBARCHIVE + g_autoptr(OtAutoArchiveWrite) a = NULL; +#endif OstreeRepoExportArchiveOptions opts = { 0, }; context = g_option_context_new ("COMMIT - Stream COMMIT to stdout in tar format"); diff --git a/src/ostree/ot-builtin-find-remotes.c b/src/ostree/ot-builtin-find-remotes.c index 344febb5..10c310b2 100644 --- a/src/ostree/ot-builtin-find-remotes.c +++ b/src/ostree/ot-builtin-find-remotes.c @@ -125,9 +125,9 @@ ostree_builtin_find_remotes (int argc, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; g_autoptr(GPtrArray) refs = NULL; /* (element-type OstreeCollectionRef) */ - glnx_unref_object OstreeAsyncProgress *progress = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; gsize i; g_autoptr(GAsyncResult) find_result = NULL, pull_result = NULL; g_auto(OstreeRepoFinderResultv) results = NULL; diff --git a/src/ostree/ot-builtin-fsck.c b/src/ostree/ot-builtin-fsck.c index 66f5536d..795fe098 100644 --- a/src/ostree/ot-builtin-fsck.c +++ b/src/ostree/ot-builtin-fsck.c @@ -32,6 +32,11 @@ static gboolean opt_quiet; static gboolean opt_delete; static gboolean opt_add_tombstones; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-fsck.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "add-tombstones", 0, 0, G_OPTION_ARG_NONE, &opt_add_tombstones, "Add tombstones for missing commits", NULL }, { "quiet", 'q', 0, G_OPTION_ARG_NONE, &opt_quiet, "Only print error messages", NULL }, @@ -212,7 +217,7 @@ fsck_reachable_objects_from_commits (OstreeRepo *repo, gboolean ostree_builtin_fsck (int argc, char **argv, GCancellable *cancellable, GError **error) { - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean found_corruption = FALSE; g_autoptr(GOptionContext) context = g_option_context_new ("- Check the repository for consistency"); diff --git a/src/ostree/ot-builtin-gpg-sign.c b/src/ostree/ot-builtin-gpg-sign.c index e14eba68..8969fe86 100644 --- a/src/ostree/ot-builtin-gpg-sign.c +++ b/src/ostree/ot-builtin-gpg-sign.c @@ -31,6 +31,11 @@ static gboolean opt_delete; static char *opt_gpg_homedir; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-gpg-sign.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "delete", 'd', 0, G_OPTION_ARG_NONE, &opt_delete, "Delete signatures having any of the GPG KEY-IDs" }, { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR" }, @@ -55,7 +60,7 @@ delete_signatures (OstreeRepo *repo, GError **error) { GVariantDict metadata_dict; - glnx_unref_object OstreeGpgVerifyResult *result = NULL; + g_autoptr(OstreeGpgVerifyResult) result = NULL; g_autoptr(GVariant) old_metadata = NULL; g_autoptr(GVariant) new_metadata = NULL; g_autoptr(GVariant) signature_data = NULL; @@ -199,7 +204,7 @@ gboolean ostree_builtin_gpg_sign (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; g_autofree char *resolved_commit = NULL; const char *commit; char **key_ids; diff --git a/src/ostree/ot-builtin-init.c b/src/ostree/ot-builtin-init.c index 0dabd458..28f96829 100644 --- a/src/ostree/ot-builtin-init.c +++ b/src/ostree/ot-builtin-init.c @@ -31,6 +31,11 @@ static char *opt_mode = "bare"; static char *opt_collection_id = NULL; #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-init.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "mode", 0, 0, G_OPTION_ARG_STRING, &opt_mode, "Initialize repository in given mode (bare, archive-z2)", NULL }, #ifdef OSTREE_ENABLE_EXPERIMENTAL_API diff --git a/src/ostree/ot-builtin-log.c b/src/ostree/ot-builtin-log.c index ca1cdc68..626793bc 100644 --- a/src/ostree/ot-builtin-log.c +++ b/src/ostree/ot-builtin-log.c @@ -30,6 +30,11 @@ static gboolean opt_raw; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-log.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" }, { NULL } @@ -82,7 +87,7 @@ ostree_builtin_log (int argc, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; const char *rev; g_autofree char *checksum = NULL; diff --git a/src/ostree/ot-builtin-ls.c b/src/ostree/ot-builtin-ls.c index 3e0336f6..9cd82eb1 100644 --- a/src/ostree/ot-builtin-ls.c +++ b/src/ostree/ot-builtin-ls.c @@ -34,6 +34,11 @@ static gboolean opt_checksum; static gboolean opt_xattrs; static gboolean opt_nul_filenames_only; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-ls.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "dironly", 'd', 0, G_OPTION_ARG_NONE, &opt_dironly, "Do not recurse into directory arguments", NULL }, { "recursive", 'R', 0, G_OPTION_ARG_NONE, &opt_recursive, "Print directories recursively", NULL }, @@ -239,7 +244,7 @@ gboolean ostree_builtin_ls (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; const char *rev; int i; diff --git a/src/ostree/ot-builtin-prune.c b/src/ostree/ot-builtin-prune.c index 8c595b73..997d848d 100644 --- a/src/ostree/ot-builtin-prune.c +++ b/src/ostree/ot-builtin-prune.c @@ -36,6 +36,11 @@ static char *opt_delete_commit; static char *opt_keep_younger_than; static char **opt_retain_branch_depth; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-prune.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "no-prune", 0, 0, G_OPTION_ARG_NONE, &opt_no_prune, "Only display unreachable objects; don't delete", NULL }, { "refs-only", 0, 0, G_OPTION_ARG_NONE, &opt_refs_only, "Only compute reachability via refs", NULL }, @@ -162,7 +167,7 @@ ostree_builtin_prune (int argc, char **argv, GCancellable *cancellable, GError * { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; g_autofree char *formatted_freed_size = NULL; OstreeRepoPruneFlags pruneflags = 0; gint n_objects_total; diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c index 66e189bc..a4595768 100644 --- a/src/ostree/ot-builtin-pull-local.c +++ b/src/ostree/ot-builtin-pull-local.c @@ -39,6 +39,11 @@ static gboolean opt_gpg_verify; static gboolean opt_gpg_verify_summary; static int opt_depth = 0; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-pull-local.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "remote", 0, 0, G_OPTION_ARG_STRING, &opt_remote, "Add REMOTE to refspec", "REMOTE" }, { "disable-fsync", 0, 0, G_OPTION_ARG_NONE, &opt_disable_fsync, "Do not invoke fsync()", NULL }, @@ -56,11 +61,11 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; int i; const char *src_repo_arg; g_autofree char *src_repo_uri = NULL; - glnx_unref_object OstreeAsyncProgress *progress = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; g_autoptr(GPtrArray) refs_to_fetch = NULL; OstreeRepoPullFlags pullflags = 0; @@ -103,7 +108,7 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr if (argc == 2) { g_autoptr(GFile) src_repo_path = g_file_new_for_path (src_repo_arg); - glnx_unref_object OstreeRepo *src_repo = ostree_repo_new (src_repo_path); + g_autoptr(OstreeRepo) src_repo = ostree_repo_new (src_repo_path); g_autoptr(GHashTable) refs_to_clone = NULL; refs_to_fetch = g_ptr_array_new_with_free_func (g_free); diff --git a/src/ostree/ot-builtin-pull.c b/src/ostree/ot-builtin-pull.c index 7898e107..37cfd143 100644 --- a/src/ostree/ot-builtin-pull.c +++ b/src/ostree/ot-builtin-pull.c @@ -43,6 +43,11 @@ static int opt_frequency = 0; static char* opt_url; static char** opt_localcache_repos; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-pull.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "commit-metadata-only", 0, 0, G_OPTION_ARG_NONE, &opt_commit_only, "Fetch only the commit metadata", NULL }, { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, @@ -138,13 +143,13 @@ gboolean ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; g_autofree char *remote = NULL; OstreeRepoPullFlags pullflags = 0; g_autoptr(GPtrArray) refs_to_fetch = NULL; g_autoptr(GPtrArray) override_commit_ids = NULL; - glnx_unref_object OstreeAsyncProgress *progress = NULL; + g_autoptr(OstreeAsyncProgress) progress = NULL; gulong signal_handler_id = 0; context = g_option_context_new ("REMOTE [BRANCH...] - Download data from remote repository"); @@ -209,11 +214,13 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError ** goto out; if (!override_commit_ids) - override_commit_ids = g_ptr_array_new_with_free_func (g_free); + { + override_commit_ids = g_ptr_array_new_with_free_func (g_free); - /* Backfill */ - for (j = 2; j < i; i++) - g_ptr_array_add (override_commit_ids, g_strdup ("")); + /* Backfill */ + for (j = 2; j < i; j++) + g_ptr_array_add (override_commit_ids, g_strdup ("")); + } g_ptr_array_add (override_commit_ids, g_strdup (override_commit_id)); g_ptr_array_add (refs_to_fetch, g_strndup (argv[i], at - argv[i])); @@ -221,6 +228,8 @@ ostree_builtin_pull (int argc, char **argv, GCancellable *cancellable, GError ** else { g_ptr_array_add (refs_to_fetch, g_strdup (argv[i])); + if (override_commit_ids) + g_ptr_array_add (override_commit_ids, g_strdup ("")); } } diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c index 19420842..ead4ba48 100644 --- a/src/ostree/ot-builtin-refs.c +++ b/src/ostree/ot-builtin-refs.c @@ -28,14 +28,21 @@ static gboolean opt_delete; static gboolean opt_list; +static gboolean opt_alias; static char *opt_create; #ifdef OSTREE_ENABLE_EXPERIMENTAL_API static gboolean opt_collections; #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-refs.xml) when changing the option 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 }, + { "alias", 'A', 0, G_OPTION_ARG_NONE, &opt_alias, "If used with --create, create an alias, otherwise just list aliases", NULL }, { "create", 0, 0, G_OPTION_ARG_STRING, &opt_create, "Create a new ref for an existing commit", "NEWREF" }, #ifdef OSTREE_ENABLE_EXPERIMENTAL_API { "collections", 'c', 0, G_OPTION_ARG_NONE, &opt_collections, "Enable listing collection IDs for refs", NULL }, @@ -132,18 +139,36 @@ do_ref_with_collections (OstreeRepo *repo, static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellable *cancellable, GError **error) { g_autoptr(GHashTable) refs = NULL; + g_autoptr(GHashTable) ref_aliases = NULL; GHashTableIter hashiter; gpointer hashkey, hashvalue; gboolean ret = FALSE; + gboolean is_list; #ifdef OSTREE_ENABLE_EXPERIMENTAL_API if (opt_collections) return do_ref_with_collections (repo, refspec_prefix, cancellable, error); #endif /* OSTREE_ENABLE_EXPERIMENTAL_API */ - if (opt_delete || opt_list) + /* If we're doing aliasing, we need the full list of aliases mostly to allow + * replacing existing aliases. + */ + if (opt_alias) { - if (!ostree_repo_list_refs_ext (repo, refspec_prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE, + if (!ostree_repo_list_refs_ext (repo, NULL, &ref_aliases, + OSTREE_REPO_LIST_REFS_EXT_ALIASES, + cancellable, error)) + goto out; + } + + is_list = !(opt_delete || opt_create); + + if (opt_delete || opt_list || (!opt_create && opt_alias)) + { + OstreeRepoListRefsExtFlags flags = OSTREE_REPO_LIST_REFS_EXT_NONE; + if (opt_alias) + flags |= OSTREE_REPO_LIST_REFS_EXT_ALIASES; + if (!ostree_repo_list_refs_ext (repo, refspec_prefix, &refs, flags, cancellable, error)) goto out; } @@ -156,13 +181,14 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab else if (!ostree_repo_list_refs (repo, refspec_prefix, &refs, cancellable, error)) goto out; - if (!opt_delete && !opt_create) + if (is_list) { - g_hash_table_iter_init (&hashiter, refs); - while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + GLNX_HASH_TABLE_FOREACH_KV (refs, const char *, ref, const char *, value) { - const char *ref = hashkey; - g_print ("%s\n", ref); + if (opt_alias) + g_print ("%s -> %s\n", ref, value); + else + g_print ("%s\n", ref); } } else if (opt_create) @@ -183,22 +209,33 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab else goto out; } - if (checksum_existing != NULL) + /* We want to allow replacing an existing alias */ + gboolean replacing_alias = opt_alias && g_hash_table_contains (ref_aliases, opt_create); + if (!replacing_alias && checksum_existing != NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "--create specified but ref %s already exists", opt_create); goto out; } - if (!ostree_repo_resolve_rev (repo, refspec_prefix, FALSE, &checksum, error)) - goto out; - if (!ostree_parse_refspec (opt_create, &remote, &ref, error)) goto out; - if (!ostree_repo_set_ref_immediate (repo, remote, ref, checksum, - cancellable, error)) - goto out; + if (opt_alias) + { + if (!ostree_repo_set_alias_ref_immediate (repo, remote, ref, refspec_prefix, + cancellable, error)) + goto out; + } + else + { + if (!ostree_repo_resolve_rev (repo, refspec_prefix, FALSE, &checksum, error)) + goto out; + + if (!ostree_repo_set_ref_immediate (repo, remote, ref, checksum, + cancellable, error)) + goto out; + } } else /* delete */ @@ -228,7 +265,7 @@ ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError ** { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; int i; context = g_option_context_new ("[PREFIX] - List refs"); @@ -264,7 +301,8 @@ ostree_builtin_refs (int argc, char **argv, GCancellable *cancellable, GError ** goto out; } - ret = do_ref (repo, NULL, cancellable, error); + if (!do_ref (repo, NULL, cancellable, error)) + goto out; } ret = TRUE; diff --git a/src/ostree/ot-builtin-reset.c b/src/ostree/ot-builtin-reset.c index 344d692c..744d297c 100644 --- a/src/ostree/ot-builtin-reset.c +++ b/src/ostree/ot-builtin-reset.c @@ -27,6 +27,11 @@ #include "ostree.h" #include "otutil.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-reset.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -38,7 +43,7 @@ ostree_builtin_reset (int argc, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; g_autoptr(GHashTable) known_refs = NULL; gboolean ret = FALSE; const char *ref; diff --git a/src/ostree/ot-builtin-rev-parse.c b/src/ostree/ot-builtin-rev-parse.c index bedcc79d..c339a9cf 100644 --- a/src/ostree/ot-builtin-rev-parse.c +++ b/src/ostree/ot-builtin-rev-parse.c @@ -27,6 +27,11 @@ #include "ostree.h" #include "otutil.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-rev-parse.xml) when changing the option list. + */ + static GOptionEntry options[] = { { NULL } }; @@ -35,7 +40,7 @@ gboolean ostree_builtin_rev_parse (int argc, char **argv, GCancellable *cancellable, GError **error) { g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; gboolean ret = FALSE; const char *rev = "master"; int i; diff --git a/src/ostree/ot-builtin-show.c b/src/ostree/ot-builtin-show.c index dcd9090c..30375600 100644 --- a/src/ostree/ot-builtin-show.c +++ b/src/ostree/ot-builtin-show.c @@ -36,6 +36,11 @@ static gboolean opt_raw; static char *opt_gpg_homedir; static char *opt_gpg_verify_remote; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-show.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "print-related", 0, 0, G_OPTION_ARG_NONE, &opt_print_related, "Show the \"related\" commits", NULL }, { "print-variant-type", 0, 0, G_OPTION_ARG_STRING, &opt_print_variant_type, "Memory map OBJECT (in this case a filename) to the GVariant type string", "TYPE" }, @@ -147,7 +152,7 @@ print_object (OstreeRepo *repo, if (objtype == OSTREE_OBJECT_TYPE_COMMIT) { - glnx_unref_object OstreeGpgVerifyResult *result = NULL; + g_autoptr(OstreeGpgVerifyResult) result = NULL; g_autoptr(GError) local_error = NULL; g_autoptr(GFile) gpg_homedir = opt_gpg_homedir ? g_file_new_for_path (opt_gpg_homedir) : NULL; @@ -163,7 +168,7 @@ print_object (OstreeRepo *repo, &local_error); } - if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + if (g_error_matches (local_error, OSTREE_GPG_ERROR, OSTREE_GPG_ERROR_NO_SIGNATURE)) { /* Ignore */ } @@ -223,7 +228,7 @@ ostree_builtin_show (int argc, char **argv, GCancellable *cancellable, GError ** { g_autoptr(GOptionContext) context = g_option_context_new ("OBJECT - Output a metadata object"); - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) return FALSE; diff --git a/src/ostree/ot-builtin-static-delta.c b/src/ostree/ot-builtin-static-delta.c index c98436af..7fbb1c7f 100644 --- a/src/ostree/ot-builtin-static-delta.c +++ b/src/ostree/ot-builtin-static-delta.c @@ -59,6 +59,10 @@ static OstreeCommand static_delta_subcommands[] = { { NULL, NULL } }; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-static-delta.xml) when changing the option list(s). + */ static GOptionEntry generate_options[] = { { "from", 0, 0, G_OPTION_ARG_STRING, &opt_from_rev, "Create delta from revision REV", "REV" }, @@ -113,7 +117,7 @@ ot_static_delta_builtin_list (int argc, char **argv, GCancellable *cancellable, g_autoptr(GPtrArray) delta_names = NULL; guint i; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; context = g_option_context_new ("LIST - list static delta files"); @@ -145,7 +149,7 @@ ot_static_delta_builtin_show (int argc, char **argv, GCancellable *cancellable, { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; const char *delta_id = NULL; context = g_option_context_new ("SHOW - Dump information on a delta"); @@ -175,7 +179,7 @@ ot_static_delta_builtin_delete (int argc, char **argv, GCancellable *cancellable { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; const char *delta_id = NULL; context = g_option_context_new ("DELETE - Remove a delta"); @@ -206,7 +210,7 @@ ot_static_delta_builtin_generate (int argc, char **argv, GCancellable *cancellab { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; context = g_option_context_new ("GENERATE [TO] - Generate static delta files"); if (!ostree_option_context_parse (context, generate_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) @@ -357,7 +361,7 @@ ot_static_delta_builtin_apply_offline (int argc, char **argv, GCancellable *canc const char *patharg; g_autoptr(GFile) path = NULL; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; context = g_option_context_new ("APPLY-OFFLINE - Apply static delta file"); if (!ostree_option_context_parse (context, apply_offline_options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) diff --git a/src/ostree/ot-builtin-summary.c b/src/ostree/ot-builtin-summary.c index f2e687ec..c983a83e 100644 --- a/src/ostree/ot-builtin-summary.c +++ b/src/ostree/ot-builtin-summary.c @@ -32,6 +32,11 @@ static char **opt_key_ids; static char *opt_gpg_homedir; static char **opt_metadata; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-summary.xml) when changing the option list. + */ + static GOptionEntry options[] = { { "update", 'u', 0, G_OPTION_ARG_NONE, &opt_update, "Update the summary", NULL }, { "view", 'v', 0, G_OPTION_ARG_NONE, &opt_view, "View the local summary file", NULL }, @@ -81,7 +86,7 @@ ostree_builtin_summary (int argc, char **argv, GCancellable *cancellable, GError { gboolean ret = FALSE; g_autoptr(GOptionContext) context = NULL; - glnx_unref_object OstreeRepo *repo = NULL; + g_autoptr(OstreeRepo) repo = NULL; OstreeDumpFlags flags = OSTREE_DUMP_NONE; context = g_option_context_new ("Manage summary metadata"); diff --git a/src/ostree/ot-main.c b/src/ostree/ot-main.c index ca4f1592..4d47985b 100644 --- a/src/ostree/ot-main.c +++ b/src/ostree/ot-main.c @@ -117,6 +117,9 @@ ostree_run (int argc, OstreeCommand *command; GError *error = NULL; GCancellable *cancellable = NULL; +#ifndef BUILDOPT_TSAN + g_autofree char *prgname = NULL; +#endif const char *command_name = NULL; gboolean success = FALSE; int in, out; @@ -192,6 +195,11 @@ ostree_run (int argc, goto out; } +#ifndef BUILDOPT_TSAN + prgname = g_strdup_printf ("%s %s", g_get_prgname (), command_name); + g_set_prgname (prgname); +#endif + if (!command->fn (argc, argv, cancellable, &error)) goto out; @@ -350,6 +358,14 @@ ostree_option_context_parse (GOptionContext *context, return TRUE; } +static void +on_sysroot_journal_msg (OstreeSysroot *sysroot, + const char *msg, + void *dummy) +{ + g_print ("%s\n", msg); +} + gboolean ostree_admin_option_context_parse (GOptionContext *context, const GOptionEntry *main_entries, @@ -372,7 +388,8 @@ ostree_admin_option_context_parse (GOptionContext *context, if (opt_sysroot != NULL) sysroot_path = g_file_new_for_path (opt_sysroot); - glnx_unref_object OstreeSysroot *sysroot = ostree_sysroot_new (sysroot_path); + g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (sysroot_path); + g_signal_connect (sysroot, "journal-msg", G_CALLBACK (on_sysroot_journal_msg), NULL); if (flags & OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER) { diff --git a/src/ostree/ot-remote-builtin-add-cookie.c b/src/ostree/ot-remote-builtin-add-cookie.c index 68d5590c..4edecaf9 100644 --- a/src/ostree/ot-remote-builtin-add-cookie.c +++ b/src/ostree/ot-remote-builtin-add-cookie.c @@ -28,6 +28,10 @@ #include "ostree-repo-private.h" #include "ot-remote-cookie-util.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ static GOptionEntry option_entries[] = { { NULL } diff --git a/src/ostree/ot-remote-builtin-add.c b/src/ostree/ot-remote-builtin-add.c index c1f48969..efa9431f 100644 --- a/src/ostree/ot-remote-builtin-add.c +++ b/src/ostree/ot-remote-builtin-add.c @@ -37,6 +37,11 @@ static char *opt_collection_id; static char *opt_sysroot; static char *opt_repo; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { "set", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_set, "Set config option KEY=VALUE for remote", "KEY=VALUE" }, { "no-gpg-verify", 0, 0, G_OPTION_ARG_NONE, &opt_no_gpg_verify, "Disable GPG verification", NULL }, diff --git a/src/ostree/ot-remote-builtin-delete-cookie.c b/src/ostree/ot-remote-builtin-delete-cookie.c index 79778f77..0838e7bf 100644 --- a/src/ostree/ot-remote-builtin-delete-cookie.c +++ b/src/ostree/ot-remote-builtin-delete-cookie.c @@ -29,6 +29,11 @@ #include "ostree-repo-private.h" #include "ot-remote-cookie-util.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { NULL } }; diff --git a/src/ostree/ot-remote-builtin-delete.c b/src/ostree/ot-remote-builtin-delete.c index 65a7ada3..f10d793a 100644 --- a/src/ostree/ot-remote-builtin-delete.c +++ b/src/ostree/ot-remote-builtin-delete.c @@ -29,6 +29,11 @@ static gboolean opt_if_exists = FALSE; static char *opt_sysroot; static char *opt_repo; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { "if-exists", 0, 0, G_OPTION_ARG_NONE, &opt_if_exists, "Do nothing if the provided remote does not exist", NULL }, { "repo", 0, 0, G_OPTION_ARG_FILENAME, &opt_repo, "Path to OSTree repository (defaults to /sysroot/ostree/repo)", "PATH" }, diff --git a/src/ostree/ot-remote-builtin-gpg-import.c b/src/ostree/ot-remote-builtin-gpg-import.c index 4df0dfe7..78a57fdf 100644 --- a/src/ostree/ot-remote-builtin-gpg-import.c +++ b/src/ostree/ot-remote-builtin-gpg-import.c @@ -34,6 +34,11 @@ static gboolean opt_stdin; static char **opt_keyrings; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { "keyring", 'k', 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_keyrings, "Import keys from a keyring file (repeatable)", "FILE" }, { "stdin", 0, 0, G_OPTION_ARG_NONE, &opt_stdin, "Import keys from standard input", NULL }, diff --git a/src/ostree/ot-remote-builtin-list-cookies.c b/src/ostree/ot-remote-builtin-list-cookies.c index 18c69035..3a83eef4 100644 --- a/src/ostree/ot-remote-builtin-list-cookies.c +++ b/src/ostree/ot-remote-builtin-list-cookies.c @@ -28,6 +28,11 @@ #include "ostree-repo-private.h" #include "ot-remote-cookie-util.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { NULL } }; diff --git a/src/ostree/ot-remote-builtin-list.c b/src/ostree/ot-remote-builtin-list.c index 0769ece7..772e212f 100644 --- a/src/ostree/ot-remote-builtin-list.c +++ b/src/ostree/ot-remote-builtin-list.c @@ -25,6 +25,11 @@ static gboolean opt_show_urls; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { "show-urls", 'u', 0, G_OPTION_ARG_NONE, &opt_show_urls, "Show remote URLs in list", NULL }, { NULL } diff --git a/src/ostree/ot-remote-builtin-refs.c b/src/ostree/ot-remote-builtin-refs.c index 9e6ee144..66c6bea0 100644 --- a/src/ostree/ot-remote-builtin-refs.c +++ b/src/ostree/ot-remote-builtin-refs.c @@ -27,6 +27,11 @@ static char* opt_cache_dir; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { NULL } diff --git a/src/ostree/ot-remote-builtin-show-url.c b/src/ostree/ot-remote-builtin-show-url.c index c1666558..16215c62 100644 --- a/src/ostree/ot-remote-builtin-show-url.c +++ b/src/ostree/ot-remote-builtin-show-url.c @@ -25,6 +25,11 @@ #include "ot-main.h" #include "ot-remote-builtins.h" +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { NULL } }; diff --git a/src/ostree/ot-remote-builtin-summary.c b/src/ostree/ot-remote-builtin-summary.c index 5ddcf69b..ca9173ea 100644 --- a/src/ostree/ot-remote-builtin-summary.c +++ b/src/ostree/ot-remote-builtin-summary.c @@ -30,6 +30,11 @@ static gboolean opt_raw; static char* opt_cache_dir; +/* ATTENTION: + * Please remember to update the bash-completion script (bash/ostree) and + * man page (man/ostree-remote.xml) when changing the option list. + */ + static GOptionEntry option_entries[] = { { "cache-dir", 0, 0, G_OPTION_ARG_FILENAME, &opt_cache_dir, "Use custom cache dir", NULL }, { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data", NULL }, @@ -101,7 +106,7 @@ ot_remote_builtin_summary (int argc, char **argv, GCancellable *cancellable, GEr * option for raw signature data like "--raw-signatures". */ if (signature_bytes != NULL && !opt_raw) { - glnx_unref_object OstreeGpgVerifyResult *result = NULL; + g_autoptr(OstreeGpgVerifyResult) result = NULL; /* The actual signed summary verification happens above in * ostree_repo_remote_fetch_summary(). Here we just parse diff --git a/src/ostree/parse-datetime.c b/src/ostree/parse-datetime.c index b96201fd..c3005dd6 100644 --- a/src/ostree/parse-datetime.c +++ b/src/ostree/parse-datetime.c @@ -3004,8 +3004,8 @@ parse_datetime (struct timespec *result, char const *p, time_t Start; long int Start_ns; struct tm const *tmp; - struct tm tm; - struct tm tm0; + struct tm tm = { 0, }; + struct tm tm0 = { 0, }; parser_control pc; struct timespec gettime_buffer; unsigned char c; diff --git a/src/ostree/parse-datetime.y b/src/ostree/parse-datetime.y index f5688d30..50917354 100644 --- a/src/ostree/parse-datetime.y +++ b/src/ostree/parse-datetime.y @@ -1280,8 +1280,8 @@ parse_datetime (struct timespec *result, char const *p, time_t Start; long int Start_ns; struct tm const *tmp; - struct tm tm; - struct tm tm0; + struct tm tm = { 0, }; + struct tm tm0 = { 0, }; parser_control pc; struct timespec gettime_buffer; unsigned char c; diff --git a/src/rofiles-fuse/main.c b/src/rofiles-fuse/main.c index 12a9d886..88cdba6c 100644 --- a/src/rofiles-fuse/main.c +++ b/src/rofiles-fuse/main.c @@ -96,6 +96,8 @@ callback_readdir (const char *path, void *buf, fuse_fill_dir_t filler, if (!*path) { dfd = fcntl (basefd, F_DUPFD_CLOEXEC, 3); + if (dfd < 0) + return -errno; lseek (dfd, 0, SEEK_SET); } else diff --git a/tests/admin-test.sh b/tests/admin-test.sh index 6001ceea..55de7235 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -249,3 +249,11 @@ ${CMD_PREFIX} ostree --sysroot=${deployment} remote add --set=gpg-verify=false r assert_not_file_has_content sysroot/ostree/repo/config remote-test-nonphysical assert_file_has_content ${deployment}/etc/ostree/remotes.d/remote-test-nonphysical.conf testos-repo echo "ok remote add nonphysical sysroot" + +if env OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},test-fifreeze" \ + ${CMD_PREFIX} ostree admin deploy --os=testos testos:testos/buildmaster/x86_64-runtime 2>err.txt; then + fatal "fifreeze-test exited successfully?" +fi +assert_file_has_content err.txt "fifreeze watchdog was run" +assert_file_has_content err.txt "During fsfreeze-thaw: aborting due to test-fifreeze" +echo "ok fifreeze test" diff --git a/tests/libtest-core.sh b/tests/libtest-core.sh index de850544..d0b7d372 100644 --- a/tests/libtest-core.sh +++ b/tests/libtest-core.sh @@ -1,6 +1,9 @@ -# Core source library for shell script tests; this -# file is intended to be the canonical source, which at -# is copied at least into: +# Core source library for shell script tests; the +# canonical version lives in: +# +# https://github.com/ostreedev/ostree +# +# Known copies are in the following repos: # # - https://github.com/projectatomic/rpm-ostree # diff --git a/tests/libtest.sh b/tests/libtest.sh index 6f33c5b5..ff096505 100755 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -363,8 +363,10 @@ setup_os_boot_grub2() { setup_os_repository () { mode=$1 - bootmode=$2 shift + bootmode=$1 + shift + bootdir=${1:-usr/lib/ostree-boot} oldpwd=`pwd` @@ -379,14 +381,19 @@ setup_os_repository () { cd ${test_tmpdir} mkdir osdata cd osdata - mkdir -p boot usr/bin usr/lib/modules/3.6.0 usr/share usr/etc - echo "a kernel" > boot/vmlinuz-3.6.0 - echo "an initramfs" > boot/initramfs-3.6.0 - bootcsum=$(cat boot/vmlinuz-3.6.0 boot/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + mkdir -p usr/bin usr/lib/modules/3.6.0 usr/share usr/etc + mkdir -p ${bootdir} + echo "a kernel" > ${bootdir}/vmlinuz-3.6.0 + echo "an initramfs" > ${bootdir}/initramfs-3.6.0 + bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') export bootcsum - mv boot/vmlinuz-3.6.0 boot/vmlinuz-3.6.0-${bootcsum} - mv boot/initramfs-3.6.0 boot/initramfs-3.6.0-${bootcsum} - + # Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not + # /usr/lib/modules. + if [[ $bootdir != usr/lib/modules ]]; then + mv ${bootdir}/vmlinuz-3.6.0{,-${bootcsum}} + mv ${bootdir}/initramfs-3.6.0{,-${bootcsum}} + fi + echo "an executable" > usr/bin/sh echo "some shared data" > usr/share/langs.txt echo "a library" > usr/lib/libfoo.so.0 @@ -458,13 +465,17 @@ os_repository_new_commit () branch=${3:-testos/buildmaster/x86_64-runtime} echo "BOOT ITERATION: $boot_checksum_iteration" cd ${test_tmpdir}/osdata - rm boot/* - echo "new: a kernel ${boot_checksum_iteration}" > boot/vmlinuz-3.6.0 - echo "new: an initramfs ${boot_checksum_iteration}" > boot/initramfs-3.6.0 - bootcsum=$(cat boot/vmlinuz-3.6.0 boot/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') + bootdir=usr/lib/ostree-boot + if ! test -d ${bootdir}; then + bootdir=boot + fi + rm ${bootdir}/* + echo "new: a kernel ${boot_checksum_iteration}" > ${bootdir}/vmlinuz-3.6.0 + echo "new: an initramfs ${boot_checksum_iteration}" > ${bootdir}/initramfs-3.6.0 + bootcsum=$(cat ${bootdir}/vmlinuz-3.6.0 ${bootdir}/initramfs-3.6.0 | sha256sum | cut -f 1 -d ' ') export bootcsum - mv boot/vmlinuz-3.6.0 boot/vmlinuz-3.6.0-${bootcsum} - mv boot/initramfs-3.6.0 boot/initramfs-3.6.0-${bootcsum} + mv ${bootdir}/vmlinuz-3.6.0 ${bootdir}/vmlinuz-3.6.0-${bootcsum} + mv ${bootdir}/initramfs-3.6.0 ${bootdir}/initramfs-3.6.0-${bootcsum} echo "a new default config file" > usr/etc/a-new-default-config-file mkdir -p usr/etc/new-default-dir diff --git a/tests/pull-test.sh b/tests/pull-test.sh index 9bbe0fa2..f51d4445 100644 --- a/tests/pull-test.sh +++ b/tests/pull-test.sh @@ -35,7 +35,7 @@ function verify_initial_contents() { assert_file_has_content baz/cow '^moo$' } -echo "1..27" +echo "1..28" # Try both syntaxes repo_init --no-gpg-verify @@ -364,6 +364,10 @@ assert_not_has_file baz/saucer echo "ok static delta 2" +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=repo pull origin main main@${rev} main@${rev} main main@${rev} main +echo "ok pull specific commit array" + cd ${test_tmpdir} ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false --set=unconfigured-state="Access to ExampleOS requires ONE BILLION DOLLARS." origin-subscription file://$(pwd)/ostree-srv/gnomerepo if ${CMD_PREFIX} ostree --repo=repo pull origin-subscription main 2>err.txt; then diff --git a/tests/test-admin-deploy-grub2.sh b/tests/test-admin-deploy-grub2.sh index d7c1c6db..6f785df5 100755 --- a/tests/test-admin-deploy-grub2.sh +++ b/tests/test-admin-deploy-grub2.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..18" +echo "1..19" . $(dirname $0)/libtest.sh diff --git a/tests/test-admin-deploy-syslinux.sh b/tests/test-admin-deploy-syslinux.sh index 797836f0..b19a74f0 100755 --- a/tests/test-admin-deploy-syslinux.sh +++ b/tests/test-admin-deploy-syslinux.sh @@ -19,7 +19,7 @@ set -euo pipefail -echo "1..18" +echo "1..20" . $(dirname $0)/libtest.sh @@ -27,3 +27,23 @@ echo "1..18" setup_os_repository "archive-z2" "syslinux" . $(dirname $0)/admin-test.sh + +cd ${test_tmpdir} +rm httpd osdata testos-repo sysroot -rf +setup_os_repository "archive-z2" "syslinux" "boot" + +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull-local --remote=testos testos-repo testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* root=LABEL=MOO' +assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf 'options.* quiet' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/vmlinuz-3.6.0 'a kernel' +assert_file_has_content sysroot/boot/ostree/testos-${bootcsum}/initramfs-3.6.0 'an initramfs' +# kernel/initrams should also be in the tree's /boot with the checksum +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/vmlinuz-3.6.0-${bootcsum} 'a kernel' +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/boot/initramfs-3.6.0-${bootcsum} 'an initramfs' +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/etc/os-release 'NAME=TestOS' +assert_file_has_content sysroot/ostree/boot.1/testos/${bootcsum}/0/etc/os-release 'NAME=TestOS' +${CMD_PREFIX} ostree admin status +validate_bootloader +echo "ok kernel in tree's /boot" diff --git a/tests/test-admin-deploy-uboot.sh b/tests/test-admin-deploy-uboot.sh index d9104f8c..3685e31e 100755 --- a/tests/test-admin-deploy-uboot.sh +++ b/tests/test-admin-deploy-uboot.sh @@ -20,7 +20,7 @@ set -euo pipefail -echo "1..19" +echo "1..20" . $(dirname $0)/libtest.sh @@ -30,8 +30,7 @@ setup_os_repository "archive-z2" "uboot" . $(dirname $0)/admin-test.sh cd ${test_tmpdir} -ln -s ../../boot/ osdata/usr/lib/ostree-boot -cat << 'EOF' > osdata/boot/uEnv.txt +cat << 'EOF' > osdata/usr/lib/ostree-boot/uEnv.txt loaduimage=load mmc ${bootpart} ${loadaddr} ${kernel_image} loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}${fdtfile} loadramdisk=load mmc ${bootpart} ${rdaddr} ${ramdisk_image} diff --git a/tests/test-bsdiff.c b/tests/test-bsdiff.c index 24772a1e..0bf500da 100644 --- a/tests/test-bsdiff.c +++ b/tests/test-bsdiff.c @@ -86,7 +86,7 @@ test_bsdiff (void) bsdiff_stream.opaque = out; g_assert_cmpint (bsdiff (old, OLD_SIZE, new, NEW_SIZE, &bsdiff_stream), ==, 0); - g_output_stream_close (out, NULL, NULL); + g_assert (g_output_stream_close (out, NULL, NULL)); /* Now generate NEW_GENERATED from OLD and OUT. */ { g_autoptr(GBytes) bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out)); diff --git a/tests/test-find-remotes.sh b/tests/test-find-remotes.sh index 0b887664..0cf0127f 100755 --- a/tests/test-find-remotes.sh +++ b/tests/test-find-remotes.sh @@ -71,11 +71,16 @@ ${CMD_PREFIX} ostree --repo=local-mirror pull --mirror os-remote os/amd64/master ${CMD_PREFIX} ostree --repo=local-mirror refs | wc -l > refscount assert_file_has_content refscount "^0$" +ls -1 local-mirror/refs/remotes | wc -l > remotescount +assert_file_has_content remotescount "^0$" ${CMD_PREFIX} ostree --repo=local-mirror refs --collections > refs assert_file_has_content refs "^(org.example.AppsCollection, app1)$" assert_file_has_content refs "^(org.example.OsCollection, os/amd64/master)$" +assert_file_has_content local-mirror/refs/mirrors/org.example.AppsCollection/app1 "^$(cat app1-checksum)$" +assert_file_has_content local-mirror/refs/mirrors/org.example.OsCollection/os/amd64/master "^$(cat os-checksum)$" + for repo in local local-mirror; do # Try finding an update for an existing branch. ${CMD_PREFIX} ostree --repo=$repo find-remotes org.example.AppsCollection app1 > find @@ -169,14 +174,16 @@ for repo in local-mirror; do assert_file_has_content pull "^Pulled 1/1 refs successfully.$" assert_not_file_has_content pull "Failed to pull some refs from the remotes" assert_ref $repo os/amd64/master $(cat os-checksum-2) + + # We need to manually update the refs afterwards, since the original pull + # into the local-mirror was a --mirror pull — so it wrote refs/mirrors/blah. + # This pull was not, so it wrote refs/remotes/blah. + ${CMD_PREFIX} ostree --repo=$repo refs --collections --create org.example.OsCollection:os/amd64/master os-remote:os/amd64/master done # Add the local mirror to the local repository as a remote, so that the local repo # has two configured remotes for the os-collection. Ensure its summary is up to date first. -#${CMD_PREFIX} ostree --repo=local-mirror summary --update -# FIXME: This `cp` can be changed to `ostree summary --update` once PR #946 lands. -# Prior to that, we need to preserve the signatures. -cp os-collection/summary{,.sig} local-mirror/ +${CMD_PREFIX} ostree --repo=local-mirror summary --update ${CMD_PREFIX} ostree --repo=local remote add os-remote-local-mirror file://$(pwd)/local-mirror --collection-id org.example.OsCollection --gpg-import=${test_tmpdir}/gpghome/key2.asc for repo in local; do @@ -212,9 +219,6 @@ for repo in local; do assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/os-collection$" assert_file_has_content find "^ - Keyring: os-remote.trustedkeys.gpg$" assert_file_has_content find "^ - (org.example.OsCollection, os/amd64/master) = $(cat os-checksum-3)$" - assert_file_has_content find "^Result [0-9]\+: file://$(pwd)/local-mirror$" - assert_file_has_content find "^ - Keyring: os-remote-local-mirror.trustedkeys.gpg$" - assert_file_has_content find "^ - (org.example.OsCollection, os/amd64/master) = $(cat os-checksum-3)$" assert_file_has_content find "^1/1 refs were found.$" assert_not_file_has_content find "^No results.$" diff --git a/tests/test-libarchive-import.c b/tests/test-libarchive-import.c index e9be7f66..8f884a66 100644 --- a/tests/test-libarchive-import.c +++ b/tests/test-libarchive-import.c @@ -41,7 +41,7 @@ static void test_data_init (TestData *td) { GError *error = NULL; - ot_cleanup_write_archive struct archive *a = archive_write_new (); + g_autoptr(OtAutoArchiveWrite) a = archive_write_new (); struct archive_entry *ae; uid_t uid = getuid (); gid_t gid = getgid (); @@ -165,7 +165,7 @@ test_libarchive_noautocreate_empty (gconstpointer data) { TestData *td = (void*)data; GError *error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); @@ -181,7 +181,7 @@ test_libarchive_autocreate_empty (gconstpointer data) { TestData *td = (void*)data; g_autoptr(GError) error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); @@ -199,7 +199,7 @@ test_libarchive_error_device_file (gconstpointer data) { TestData *td = (void*)data; g_autoptr(GError) error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; glnx_unref_object OstreeMutableTree *mtree = ostree_mutable_tree_new (); @@ -270,7 +270,7 @@ test_libarchive_ignore_device_file (gconstpointer data) { TestData *td = (void*)data; g_autoptr(GError) error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; if (skip_if_no_xattr (td)) @@ -332,7 +332,7 @@ test_libarchive_ostree_convention (gconstpointer data) { TestData *td = (void*)data; GError *error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; if (skip_if_no_xattr (td)) @@ -374,7 +374,7 @@ test_libarchive_xattr_callback (gconstpointer data) { TestData *td = (void*)data; GError *error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0 }; OstreeRepoCommitModifier *modifier = NULL; char buf[7] = { 0 }; @@ -429,7 +429,7 @@ static void entry_pathname_test_helper (gconstpointer data, gboolean on) { TestData *td = (void*)data; GError *error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0, }; OstreeRepoCommitModifier *modifier = NULL; gboolean met_etc_file = FALSE; @@ -491,7 +491,7 @@ test_libarchive_selinux (gconstpointer data) { TestData *td = (void*)data; GError *error = NULL; - ot_cleanup_read_archive struct archive *a = archive_read_new (); + g_autoptr(OtAutoArchiveRead) a = archive_read_new (); OstreeRepoImportArchiveOptions opts = { 0 }; glnx_unref_object OstreeSePolicy *sepol = NULL; OstreeRepoCommitModifier *modifier = NULL; diff --git a/tests/test-lzma.c b/tests/test-lzma.c index 1f7d2559..559e9ad4 100644 --- a/tests/test-lzma.c +++ b/tests/test-lzma.c @@ -79,13 +79,12 @@ static void test_lzma_random (void) { gssize i; - const guint32 buffer_size = 4096 + 1; - guint8 buffer[buffer_size]; - srandom (1); - for (i = 0; i < buffer_size; i++) - buffer[i] = random (); + guint8 buffer[4096]; + g_autoptr(GRand) r = g_rand_new (); + for (i = 0; i < sizeof(buffer); i++) + buffer[i] = g_rand_int (r); - for (i = 2; i <= buffer_size; i *= 2) + for (i = 2; i < (sizeof(buffer) - 1); i *= 2) { helper_test_compress_decompress (buffer, i - 1); helper_test_compress_decompress (buffer, i); diff --git a/tests/test-mutable-tree.c b/tests/test-mutable-tree.c index 9df36ac6..f878f116 100644 --- a/tests/test-mutable-tree.c +++ b/tests/test-mutable-tree.c @@ -72,8 +72,10 @@ test_mutable_tree_walk (void) glnx_unref_object OstreeMutableTree *subdir = NULL; glnx_unref_object OstreeMutableTree *a = NULL; g_autofree char *source_checksum = NULL; - ostree_mutable_tree_lookup (tree, "a", &source_checksum, &a, &error); + g_assert (ostree_mutable_tree_lookup (tree, "a", &source_checksum, &a, &error)); + g_assert_no_error (error); g_assert (ostree_mutable_tree_walk (a, split_path, 1, &subdir, &error)); + g_assert_no_error (error); g_assert (subdir); } } diff --git a/tests/test-pull-localcache.sh b/tests/test-pull-localcache.sh index 5f810acb..44403f92 100755 --- a/tests/test-pull-localcache.sh +++ b/tests/test-pull-localcache.sh @@ -23,23 +23,43 @@ set -euo pipefail setup_fake_remote_repo1 "archive" -echo '1..1' +echo '1..2' cd ${test_tmpdir} gnomerepo_url="$(cat httpd-address)/ostree/gnomerepo" -ostree_repo_init repo --mode "archive" + +# Set up our local cache ostree_repo_init repo-local --mode "archive" -for repo in repo{,-local}; do - ${CMD_PREFIX} ostree --repo=${repo} remote add --set=gpg-verify=false origin ${gnomerepo_url} -done +${CMD_PREFIX} ostree --repo=repo-local remote add --set=gpg-verify=false origin ${gnomerepo_url} + +init_repo() { + ostree_repo_init repo --mode "archive" + ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin ${gnomerepo_url} +} # Pull the contents to our local cache ${CMD_PREFIX} ostree --repo=repo-local pull origin main rm files -rf ${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo checkout main files echo anewfile > files/anewfile -${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main --tree=dir=files +commit=$(${CMD_PREFIX} ostree --repo=ostree-srv/gnomerepo commit -b main --tree=dir=files) -${CMD_PREFIX} ostree --repo=repo pull -L repo-local origin main >out.txt +# Check that pulling a new commit of the same tree hits our cache +rm -rf repo +init_repo +${CMD_PREFIX} ostree --repo=repo pull --localcache-repo repo-local origin main >out.txt assert_file_has_content out.txt '3 metadata, 1 content objects fetched (4 meta, 5 content local)' -echo "ok pull --reference" +echo "ok pull --localcache-repo" + +# Check that pulling the same commit works as well +rm -rf repo +init_repo +${CMD_PREFIX} ostree --repo=repo-local pull origin $commit +${CMD_PREFIX} ostree --repo=repo pull -L repo-local origin main +commit2=$(${CMD_PREFIX} ostree --repo=repo rev-parse main) +[[ $commit == $commit2 ]] +# and check that it's not partial +rm -rf files +${CMD_PREFIX} ostree --repo=repo checkout main files +test -f files/anewfile +echo "ok pull --localcache-repo same commit" diff --git a/tests/test-refs.sh b/tests/test-refs.sh index d4db0013..e48784aa 100755 --- a/tests/test-refs.sh +++ b/tests/test-refs.sh @@ -23,7 +23,7 @@ set -euo pipefail setup_fake_remote_repo1 "archive-z2" -echo '1..1' +echo '1..2' cd ${test_tmpdir} mkdir repo @@ -117,3 +117,43 @@ ${CMD_PREFIX} ostree --repo=repo refs | wc -l > refscount.create6 assert_file_has_content refscount.create6 "^11$" echo "ok refs" + +# Test symlinking a ref +${CMD_PREFIX} ostree --repo=repo refs ctest --create=exampleos/x86_64/26/server +${CMD_PREFIX} ostree --repo=repo refs -A exampleos/x86_64/26/server --create=exampleos/x86_64/stable/server +${CMD_PREFIX} ostree --repo=repo summary -u +${CMD_PREFIX} ostree --repo=repo refs > refs.txt +for v in 26 stable; do + assert_file_has_content refs.txt exampleos/x86_64/${v}/server +done +${CMD_PREFIX} ostree --repo=repo refs -A > refs.txt +assert_file_has_content_literal refs.txt 'exampleos/x86_64/stable/server -> exampleos/x86_64/26/server' +assert_not_file_has_content refs.txt '^exampleos/x86_64/26/server' +stable=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/stable/server) +current=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/26/server) +assert_streq "${stable}" "${current}" +${CMD_PREFIX} ostree --repo=repo commit -b exampleos/x86_64/26/server --tree=dir=tree +${CMD_PREFIX} ostree --repo=repo summary -u +newcurrent=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/26/server) +assert_not_streq "${newcurrent}" "${current}" +newstable=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/stable/server) +assert_streq "${newcurrent}" "${newstable}" + +# Test that we can swap the symlink +${CMD_PREFIX} ostree --repo=repo commit -b exampleos/x86_64/27/server --tree=dir=tree +newcurrent=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/27/server) +assert_not_streq "${newcurrent}" "${newstable}" +${CMD_PREFIX} ostree --repo=repo refs -A exampleos/x86_64/27/server --create=exampleos/x86_64/stable/server +newnewstable=$(${CMD_PREFIX} ostree --repo=repo rev-parse exampleos/x86_64/stable/server) +assert_not_streq "${newnewstable}" "${newstable}" +assert_streq "${newnewstable}" "${newcurrent}" +${CMD_PREFIX} ostree --repo=repo refs > refs.txt +for v in 26 27 stable; do + assert_file_has_content refs.txt exampleos/x86_64/${v}/server +done +${CMD_PREFIX} ostree --repo=repo refs -A > refs.txt +assert_file_has_content_literal refs.txt 'exampleos/x86_64/stable/server -> exampleos/x86_64/27/server' + +${CMD_PREFIX} ostree --repo=repo summary -u + +echo "ok ref symlink" diff --git a/tests/test-repo-finder-config.c b/tests/test-repo-finder-config.c index dc083754..ba7191ec 100644 --- a/tests/test-repo-finder-config.c +++ b/tests/test-repo-finder-config.c @@ -70,7 +70,6 @@ static void teardown (Fixture *fixture, gconstpointer test_data) { - glnx_fd_close int parent_repo_dfd = -1; g_autoptr(GError) error = NULL; /* Recursively remove the temporary directory. */ @@ -81,10 +80,7 @@ teardown (Fixture *fixture, /* The repo also needs its source files to be removed. This is the inverse * of setup_test_repository() in libtest.sh. */ - g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (fixture->parent_repo)); - glnx_opendirat (-1, parent_repo_path, TRUE, &parent_repo_dfd, &error); - g_assert_no_error (error); - + int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo); glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL); glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL); diff --git a/tests/test-repo-finder-mount.c b/tests/test-repo-finder-mount.c index c84feb52..f51fb3bb 100644 --- a/tests/test-repo-finder-mount.c +++ b/tests/test-repo-finder-mount.c @@ -73,7 +73,6 @@ static void teardown (Fixture *fixture, gconstpointer test_data) { - glnx_fd_close int parent_repo_dfd = -1; g_autoptr(GError) error = NULL; /* Recursively remove the temporary directory. */ @@ -84,10 +83,7 @@ teardown (Fixture *fixture, /* The repo also needs its source files to be removed. This is the inverse * of setup_test_repository() in libtest.sh. */ - g_autofree gchar *parent_repo_path = g_file_get_path (ostree_repo_get_path (fixture->parent_repo)); - glnx_opendirat (-1, parent_repo_path, TRUE, &parent_repo_dfd, &error); - g_assert_no_error (error); - + int parent_repo_dfd = ostree_repo_get_dfd (fixture->parent_repo); glnx_shutil_rm_rf_at (parent_repo_dfd, "../files", NULL, NULL); glnx_shutil_rm_rf_at (parent_repo_dfd, "../repo", NULL, NULL); diff --git a/tests/test-symbols.sh b/tests/test-symbols.sh index e6504c93..b324d1bf 100755 --- a/tests/test-symbols.sh +++ b/tests/test-symbols.sh @@ -52,7 +52,7 @@ echo 'ok documented symbols' # ONLY update this checksum in release commits! cat > released-sha256.txt <