diff --git a/Makefile-libostree-defines.am b/Makefile-libostree-defines.am
index 43e09281..4d290a88 100644
--- a/Makefile-libostree-defines.am
+++ b/Makefile-libostree-defines.am
@@ -28,6 +28,7 @@ libostree_public_headers = \
src/libostree/ostree-dummy-enumtypes.h \
src/libostree/ostree-mutable-tree.h \
src/libostree/ostree-repo.h \
+ src/libostree/ostree-repo-os.h \
src/libostree/ostree-types.h \
src/libostree/ostree-repo-file.h \
src/libostree/ostree-diff.h \
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index 7f9d7e67..98fbb289 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -92,6 +92,7 @@ libostree_1_la_SOURCES = \
src/libostree/ostree-ref.c \
src/libostree/ostree-remote.c \
src/libostree/ostree-remote-private.h \
+ src/libostree/ostree-repo-os.c \
src/libostree/ostree-repo.c \
src/libostree/ostree-repo-checkout.c \
src/libostree/ostree-repo-commit.c \
@@ -186,10 +187,10 @@ endif # USE_GPGME
symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym
-## Uncomment this include when adding new development symbols.
-#if BUILDOPT_IS_DEVEL_BUILD
-#symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
-#endif
+# Uncomment this include when adding new development symbols.
+if BUILDOPT_IS_DEVEL_BUILD
+symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
+endif
# http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html
wl_versionscript_arg = -Wl,--version-script=
diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt
index 64bc68d2..400eb53a 100644
--- a/apidoc/ostree-sections.txt
+++ b/apidoc/ostree-sections.txt
@@ -152,6 +152,7 @@ ostree_validate_structureof_dirtree
ostree_validate_structureof_dirmeta
ostree_commit_get_parent
ostree_commit_get_timestamp
+ostree_commit_metadata_for_bootable
ostree_commit_get_content_checksum
ostree_commit_get_object_sizes
OstreeCommitSizesEntry
diff --git a/bash/ostree b/bash/ostree
index 3cc2e04a..d1de8530 100644
--- a/bash/ostree
+++ b/bash/ostree
@@ -321,6 +321,7 @@ _ostree_commit() {
--canonical-permissions
--editor -e
--generate-sizes
+ --bootable
--link-checkout-speedup
--no-xattrs
--orphan
diff --git a/man/ostree-commit.xml b/man/ostree-commit.xml
index ab5d3415..81af7bf2 100644
--- a/man/ostree-commit.xml
+++ b/man/ostree-commit.xml
@@ -186,6 +186,13 @@ Boston, MA 02111-1307, USA.
+
+
+
+ Inject standard metadata for a bootable Linux filesystem tree.
+
+
+
diff --git a/src/libostree/libostree-devel.sym b/src/libostree/libostree-devel.sym
index e2d6efc4..541caaa2 100644
--- a/src/libostree/libostree-devel.sym
+++ b/src/libostree/libostree-devel.sym
@@ -22,6 +22,11 @@
- uncomment the include in Makefile-libostree.am
*/
+LIBOSTREE_2021.1 {
+global:
+ ostree_commit_metadata_for_bootable;
+} LIBOSTREE_2020.8;
+
/* Stub section for the stable release *after* this development one; don't
* edit this other than to update the year. This is just a copy/paste
* source. Replace $LASTSTABLE with the last stable version, and $NEWVERSION
diff --git a/src/libostree/ostree-repo-os.c b/src/libostree/ostree-repo-os.c
new file mode 100644
index 00000000..96beddda
--- /dev/null
+++ b/src/libostree/ostree-repo-os.c
@@ -0,0 +1,83 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.0+
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include
+#include
+#include
+#include
+#include
+#include "libglnx.h"
+#include "ostree.h"
+#include "ostree-core-private.h"
+#include "ostree-repo-os.h"
+#include "otutil.h"
+
+/**
+ * ostree_commit_metadata_for_bootable:
+ * @root: Root filesystem to be committed
+ * @dict: Dictionary to update
+ *
+ * Update provided @dict with standard metadata for bootable OSTree commits.
+ * Since: 2021.1
+ */
+_OSTREE_PUBLIC
+gboolean
+ostree_commit_metadata_for_bootable (GFile *root, GVariantDict *dict, GCancellable *cancellable, GError **error)
+{
+ g_autoptr(GFile) modules = g_file_resolve_relative_path (root, "usr/lib/modules");
+ g_autoptr(GFileEnumerator) dir_enum
+ = g_file_enumerate_children (modules, OSTREE_GIO_FAST_QUERYINFO,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ cancellable, error);
+ if (!dir_enum)
+ return glnx_prefix_error (error, "Opening usr/lib/modules");
+
+ g_autofree char *linux_release = NULL;
+ while (TRUE)
+ {
+ GFileInfo *child_info;
+ GFile *child_path;
+ if (!g_file_enumerator_iterate (dir_enum, &child_info, &child_path,
+ cancellable, error))
+ return FALSE;
+ if (child_info == NULL)
+ break;
+ if (g_file_info_get_file_type (child_info) != G_FILE_TYPE_DIRECTORY)
+ continue;
+
+ g_autoptr(GFile) kernel_path = g_file_resolve_relative_path (child_path, "vmlinuz");
+ if (!g_file_query_exists (kernel_path, NULL))
+ continue;
+
+ if (linux_release != NULL)
+ return glnx_throw (error, "Multiple kernels found in /usr/lib/modules");
+
+ linux_release = g_strdup (g_file_info_get_name (child_info));
+ }
+
+ if (linux_release)
+ {
+ g_variant_dict_insert (dict, OSTREE_METADATA_KEY_BOOTABLE, "b", TRUE);
+ g_variant_dict_insert (dict, OSTREE_METADATA_KEY_LINUX, "s", linux_release);
+ return TRUE;
+ }
+ return glnx_throw (error, "No kernel found in /usr/lib/modules");
+}
diff --git a/src/libostree/ostree-repo-os.h b/src/libostree/ostree-repo-os.h
new file mode 100644
index 00000000..b2443768
--- /dev/null
+++ b/src/libostree/ostree-repo-os.h
@@ -0,0 +1,47 @@
+/*
+ * SPDX-License-Identifier: LGPL-2.0+
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+G_BEGIN_DECLS
+
+/**
+ * OSTREE_METADATA_KEY_BOOTABLE:
+ *
+ * GVariant type `b`: Set if this commit is intended to be bootable
+ * Since: 2021.1
+ */
+#define OSTREE_METADATA_KEY_BOOTABLE "ostree.bootable"
+/**
+ * OSTREE_METADATA_KEY_LINUX:
+ *
+ * GVariant type `s`: Contains the Linux kernel release (i.e. `uname -r`)
+ * Since: 2021.1
+ */
+#define OSTREE_METADATA_KEY_LINUX "ostree.linux"
+
+_OSTREE_PUBLIC
+gboolean
+ostree_commit_metadata_for_bootable (GFile *root, GVariantDict *dict, GCancellable *cancellable, GError **error);
+
+G_END_DECLS
diff --git a/src/libostree/ostree.h b/src/libostree/ostree.h
index 0308d0ed..e4847dbe 100644
--- a/src/libostree/ostree.h
+++ b/src/libostree/ostree.h
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/src/ostree/ot-builtin-commit.c b/src/ostree/ot-builtin-commit.c
index 48fa2928..7a23741e 100644
--- a/src/ostree/ot-builtin-commit.c
+++ b/src/ostree/ot-builtin-commit.c
@@ -35,6 +35,7 @@
static char *opt_subject;
static char *opt_body;
+static char *opt_bootable;
static char *opt_body_file;
static gboolean opt_editor;
static char *opt_parent;
@@ -112,6 +113,7 @@ static GOptionEntry options[] = {
{ "owner-uid", 0, 0, G_OPTION_ARG_INT, &opt_owner_uid, "Set file ownership user id", "UID" },
{ "owner-gid", 0, 0, G_OPTION_ARG_INT, &opt_owner_gid, "Set file ownership group id", "GID" },
{ "canonical-permissions", 0, 0, G_OPTION_ARG_NONE, &opt_canonical_permissions, "Canonicalize permissions in the same way bare-user does for hardlinked files", NULL },
+ { "bootable", 0, 0, G_OPTION_ARG_NONE, &opt_bootable, "Flag this commit as a bootable OSTree (e.g. contains a Linux kernel)", NULL },
{ "mode-ro-executables", 0, 0, G_OPTION_ARG_NONE, &opt_ro_executables, "Ensure executable files are not writable", NULL },
{ "no-xattrs", 0, 0, G_OPTION_ARG_NONE, &opt_no_xattrs, "Do not import extended attributes", NULL },
{ "selinux-policy", 0, 0, G_OPTION_ARG_FILENAME, &opt_selinux_policy, "Set SELinux labels based on policy in root filesystem PATH (may be /)", "PATH" },
@@ -501,7 +503,7 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
goto out;
}
- if (opt_metadata_strings || opt_metadata_variants || opt_metadata_keep)
+ if (opt_metadata_strings || opt_metadata_variants || opt_metadata_keep || opt_bootable)
{
g_autoptr(GVariantBuilder) builder =
g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
@@ -841,6 +843,17 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
fill_bindings (repo, old_metadata, &metadata);
}
+ if (opt_bootable)
+ {
+ g_autoptr(GVariant) old_metadata = g_steal_pointer (&metadata);
+ g_auto(GVariantDict) bootmeta;
+ g_variant_dict_init (&bootmeta, old_metadata);
+ if (!ostree_commit_metadata_for_bootable (root, &bootmeta, cancellable, error))
+ goto out;
+
+ metadata = g_variant_ref_sink (g_variant_dict_end (&bootmeta));
+ }
+
if (!opt_timestamp)
{
if (!ostree_repo_write_commit (repo, parent, opt_subject, commit_body, metadata,
diff --git a/tests/admin-test.sh b/tests/admin-test.sh
index 3aab74cc..b05893ae 100644
--- a/tests/admin-test.sh
+++ b/tests/admin-test.sh
@@ -65,6 +65,12 @@ assert_not_file_has_content status.txt "pending"
assert_not_file_has_content status.txt "rollback"
validate_bootloader
+# Test the bootable and linux keys
+${CMD_PREFIX} ostree --repo=sysroot/ostree/repo --print-metadata-key=ostree.linux show testos:testos/buildmaster/x86_64-runtime >out.txt
+assert_file_has_content_literal out.txt 3.6.0
+${CMD_PREFIX} ostree --repo=sysroot/ostree/repo --print-metadata-key=ostree.bootable show testos:testos/buildmaster/x86_64-runtime >out.txt
+assert_file_has_content_literal out.txt true
+
echo "ok deploy command"
${CMD_PREFIX} ostree admin --print-current-dir > curdir
diff --git a/tests/basic-test.sh b/tests/basic-test.sh
index 9227b0cd..75333f4d 100644
--- a/tests/basic-test.sh
+++ b/tests/basic-test.sh
@@ -21,7 +21,7 @@
set -euo pipefail
-echo "1..$((86 + ${extra_basic_tests:-0}))"
+echo "1..$((87 + ${extra_basic_tests:-0}))"
CHECKOUT_U_ARG=""
CHECKOUT_H_ARGS="-H"
@@ -226,6 +226,13 @@ $OSTREE commit ${COMMIT_ARGS} -b test2-no-parent -s '' --parent=none $test_tmpdi
assert_streq $($OSTREE log test2-no-parent |grep '^commit' | wc -l) "1"
echo "ok commit no parent"
+cd ${test_tmpdir}
+if $OSTREE commit ${COMMIT_ARGS} -b test-bootable --bootable $test_tmpdir/checkout-test2-4 2>err.txt; then
+ fatal "committed non-bootable tree"
+fi
+assert_file_has_content err.txt "error: .*No such file or directory"
+echo "ok commit fails bootable if no kernel"
+
cd ${test_tmpdir}
# Do the --bind-ref=, so we store both branches sorted
# in metadata and thus the checksums remain the same.
diff --git a/tests/libtest.sh b/tests/libtest.sh
index 7b654c52..ffb05c7b 100755
--- a/tests/libtest.sh
+++ b/tests/libtest.sh
@@ -415,11 +415,14 @@ setup_os_repository () {
echo "an hmac file" > ${hmac_path}
bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ')
export bootcsum
+ bootable_flag=""
# Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not
# /usr/lib/modules.
if [[ $bootdir != usr/lib/modules/* ]]; then
mv ${kernel_path}{,-${bootcsum}}
mv ${initramfs_path}{,-${bootcsum}}
+ else
+ bootable_flag="--bootable"
fi
echo "an executable" > usr/bin/sh
@@ -439,12 +442,12 @@ EOF
mkdir -p usr/etc/testdirectory
echo "a default daemon file" > usr/etc/testdirectory/test
- ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build"
+ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit ${bootable_flag} --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-runtime -s "Build"
# Ensure these commits have distinct second timestamps
sleep 2
echo "a new executable" > usr/bin/sh
- ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.10 -b testos/buildmaster/x86_64-runtime -s "Build"
+ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit ${bootable_flag} --add-metadata-string version=1.0.10 -b testos/buildmaster/x86_64-runtime -s "Build"
cd ${test_tmpdir}
rm -rf osdata-devel
@@ -453,7 +456,7 @@ EOF
cd osdata-devel
mkdir -p usr/include
echo "a development header" > usr/include/foo.h
- ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-devel -s "Build"
+ ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit ${bootable_flag} --add-metadata-string version=1.0.9 -b testos/buildmaster/x86_64-devel -s "Build"
${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo fsck -q