diff --git a/man/ostree.repo-config.xml b/man/ostree.repo-config.xml
index e4984430..6fead168 100644
--- a/man/ostree.repo-config.xml
+++ b/man/ostree.repo-config.xml
@@ -373,7 +373,9 @@ Boston, MA 02111-1307, USA.
bootloader
Configure the bootloader that OSTree uses when
deploying the sysroot. This may take the values
- bootloader=none or bootloader=auto.
+ bootloader=none, bootloader=auto,
+ bootloader=grub2, bootloader=syslinux,
+ bootloader=uboot or bootloader=zipl.
Default is auto.
@@ -388,6 +390,11 @@ Boston, MA 02111-1307, USA.
then OSTree will generate a config for the bootloader found. For
example, grub2-mkconfig is run for the grub2 case.
+
+ A specific bootloader type may also be explicitly requested by choosing
+ grub2, syslinux, uboot or
+ zipl.
+
diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h
index cbbe6971..628f2b46 100644
--- a/src/libostree/ostree-repo-private.h
+++ b/src/libostree/ostree-repo-private.h
@@ -110,6 +110,28 @@ typedef enum {
_OSTREE_FEATURE_YES,
} _OstreeFeatureSupport;
+/* Possible values for the sysroot.bootloader configuration variable */
+typedef enum {
+ CFG_SYSROOT_BOOTLOADER_OPT_AUTO = 0,
+ CFG_SYSROOT_BOOTLOADER_OPT_NONE,
+ CFG_SYSROOT_BOOTLOADER_OPT_GRUB2,
+ CFG_SYSROOT_BOOTLOADER_OPT_SYSLINUX,
+ CFG_SYSROOT_BOOTLOADER_OPT_UBOOT,
+ CFG_SYSROOT_BOOTLOADER_OPT_ZIPL,
+ /* Non-exhaustive */
+} OstreeCfgSysrootBootloaderOpt;
+
+static const char* const CFG_SYSROOT_BOOTLOADER_OPTS_STR[] = {
+ /* This must be kept in the same order as the enum */
+ "auto",
+ "none",
+ "grub2",
+ "syslinux",
+ "uboot",
+ "zipl",
+ NULL,
+};
+
/**
* OstreeRepo:
*
@@ -193,7 +215,7 @@ struct OstreeRepo {
guint64 payload_link_threshold;
gint fs_support_reflink; /* The underlying filesystem has support for ioctl (FICLONE..) */
gchar **repo_finders;
- gchar *bootloader; /* Configure which bootloader to use. */
+ OstreeCfgSysrootBootloaderOpt bootloader; /* Configure which bootloader to use. */
OstreeRepo *parent_repo;
};
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 3bbf5ea0..11a209a4 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -1048,7 +1048,6 @@ ostree_repo_finalize (GObject *object)
g_mutex_clear (&self->txn_lock);
g_free (self->collection_id);
g_strfreev (self->repo_finders);
- g_free (self->bootloader);
g_clear_pointer (&self->remotes, g_hash_table_destroy);
g_mutex_clear (&self->remotes_lock);
@@ -3186,28 +3185,28 @@ reload_sysroot_config (OstreeRepo *self,
GCancellable *cancellable,
GError **error)
{
- { g_autofree char *bootloader = NULL;
+ g_autofree char *bootloader = NULL;
- if (!ot_keyfile_get_value_with_default_group_optional (self->config, "sysroot",
- "bootloader", "auto",
- &bootloader, error))
- return FALSE;
+ if (!ot_keyfile_get_value_with_default_group_optional (self->config, "sysroot",
+ "bootloader", "auto",
+ &bootloader, error))
+ return FALSE;
- /* TODO: possibly later add support for specifying a generic bootloader
- * binary "x" in /usr/lib/ostree/bootloaders/x). See:
- * https://github.com/ostreedev/ostree/issues/1719
- * https://github.com/ostreedev/ostree/issues/1801
- * Also, dedup these strings with the bootloader implementations
- */
- if (!(g_str_equal (bootloader, "auto") || g_str_equal (bootloader, "none")
- || g_str_equal (bootloader, "zipl")))
- return glnx_throw (error, "Invalid bootloader configuration: '%s'", bootloader);
+ /* TODO: possibly later add support for specifying a generic bootloader
+ * binary "x" in /usr/lib/ostree/bootloaders/x). See:
+ * https://github.com/ostreedev/ostree/issues/1719
+ * https://github.com/ostreedev/ostree/issues/1801
+ */
+ for (int i = 0; CFG_SYSROOT_BOOTLOADER_OPTS_STR[i]; i++)
+ {
+ if (g_str_equal (bootloader, CFG_SYSROOT_BOOTLOADER_OPTS_STR[i]))
+ {
+ self->bootloader = (OstreeCfgSysrootBootloaderOpt) i;
+ return TRUE;
+ }
+ }
- g_free (self->bootloader);
- self->bootloader = g_steal_pointer (&bootloader);
- }
-
- return TRUE;
+ return glnx_throw (error, "Invalid bootloader configuration: '%s'", bootloader);
}
/**
@@ -6323,7 +6322,7 @@ ostree_repo_get_default_repo_finders (OstreeRepo *self)
* Get the bootloader configured. See the documentation for the
* "sysroot.bootloader" config key.
*
- * Returns: bootloader configuration for the sysroot
+ * Returns: (transfer none): bootloader configuration for the sysroot
* Since: 2019.2
*/
const gchar *
@@ -6331,7 +6330,7 @@ ostree_repo_get_bootloader (OstreeRepo *self)
{
g_return_val_if_fail (OSTREE_IS_REPO (self), NULL);
- return self->bootloader;
+ return CFG_SYSROOT_BOOTLOADER_OPTS_STR[self->bootloader];
}
diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c
index 1a4a6369..900efe49 100644
--- a/src/libostree/ostree-sysroot-deploy.c
+++ b/src/libostree/ostree-sysroot-deploy.c
@@ -44,7 +44,6 @@
#include "ostree-repo-private.h"
#include "ostree-sysroot-private.h"
#include "ostree-sepolicy-private.h"
-#include "ostree-bootloader-zipl.h"
#include "ostree-deployment-private.h"
#include "ostree-core-private.h"
#include "ostree-linuxfsutil.h"
@@ -2561,7 +2560,6 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
gboolean bootloader_is_atomic = FALSE;
SyncStats syncstats = { 0, };
g_autoptr(OstreeBootloader) bootloader = NULL;
- const char *bootloader_config = NULL;
if (!requires_new_bootversion)
{
if (!create_new_bootlinks (self, self->bootversion,
@@ -2593,29 +2591,8 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
return glnx_throw_errno_prefix (error, "Remounting /boot read-write");
}
- OstreeRepo *repo = ostree_sysroot_repo (self);
-
- bootloader_config = ostree_repo_get_bootloader (repo);
-
- g_debug ("Using bootloader configuration: %s", bootloader_config);
-
- if (g_str_equal (bootloader_config, "auto"))
- {
- if (!_ostree_sysroot_query_bootloader (self, &bootloader, cancellable, error))
- return FALSE;
- }
- else if (g_str_equal (bootloader_config, "none"))
- {
- /* No bootloader specified; do not query bootloaders to run. */
- }
- else if (g_str_equal (bootloader_config, "zipl"))
- {
- /* Because we do not mark zipl as active by default, lets creating one here,
- * which is basically the same what _ostree_sysroot_query_bootloader() does
- * for other bootloaders if being activated.
- * */
- bootloader = (OstreeBootloader*) _ostree_bootloader_zipl_new (self);
- }
+ if (!_ostree_sysroot_query_bootloader (self, &bootloader, cancellable, error))
+ return FALSE;
bootloader_is_atomic = bootloader != NULL && _ostree_bootloader_is_atomic (bootloader);
@@ -2646,6 +2623,7 @@ ostree_sysroot_write_deployments_with_options (OstreeSysroot *self,
(bootloader_is_atomic ? "Transaction complete" : "Bootloader updated"),
requires_new_bootversion ? "yes" : "no",
new_deployments->len - self->deployments->len);
+ const gchar *bootloader_config = ostree_repo_get_bootloader (ostree_sysroot_repo (self));
ot_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",
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c
index e0813b55..7062a218 100644
--- a/src/libostree/ostree-sysroot.c
+++ b/src/libostree/ostree-sysroot.c
@@ -36,6 +36,7 @@
#include "ostree-bootloader-uboot.h"
#include "ostree-bootloader-syslinux.h"
#include "ostree-bootloader-grub2.h"
+#include "ostree-bootloader-zipl.h"
/**
* SECTION:ostree-sysroot
@@ -1324,6 +1325,34 @@ ostree_sysroot_repo (OstreeSysroot *self)
return self->repo;
}
+static OstreeBootloader*
+_ostree_sysroot_new_bootloader_by_type (
+ OstreeSysroot *sysroot,
+ OstreeCfgSysrootBootloaderOpt bl_type)
+{
+ switch (bl_type)
+ {
+ case CFG_SYSROOT_BOOTLOADER_OPT_NONE:
+ /* No bootloader specified; do not query bootloaders to run. */
+ return NULL;
+ case CFG_SYSROOT_BOOTLOADER_OPT_GRUB2:
+ return (OstreeBootloader*) _ostree_bootloader_grub2_new (sysroot);
+ case CFG_SYSROOT_BOOTLOADER_OPT_SYSLINUX:
+ return (OstreeBootloader*) _ostree_bootloader_syslinux_new (sysroot);
+ case CFG_SYSROOT_BOOTLOADER_OPT_UBOOT:
+ return (OstreeBootloader*) _ostree_bootloader_uboot_new (sysroot);
+ case CFG_SYSROOT_BOOTLOADER_OPT_ZIPL:
+ /* We never consider zipl as active by default, so it can only be created
+ * if it's explicitly requested in the config */
+ return (OstreeBootloader*) _ostree_bootloader_zipl_new (sysroot);
+ case CFG_SYSROOT_BOOTLOADER_OPT_AUTO:
+ /* "auto" is handled by ostree_sysroot_query_bootloader so we should
+ * never get here: Fallthrough */
+ default:
+ g_assert_not_reached ();
+ }
+}
+
/**
* ostree_sysroot_query_bootloader:
* @sysroot: Sysroot
@@ -1337,32 +1366,38 @@ _ostree_sysroot_query_bootloader (OstreeSysroot *sysroot,
GCancellable *cancellable,
GError **error)
{
- gboolean is_active;
- g_autoptr(OstreeBootloader) ret_loader =
- (OstreeBootloader*)_ostree_bootloader_syslinux_new (sysroot);
- if (!_ostree_bootloader_query (ret_loader, &is_active,
- cancellable, error))
- return FALSE;
+ OstreeRepo *repo = ostree_sysroot_repo (sysroot);
+ OstreeCfgSysrootBootloaderOpt bootloader_config = repo->bootloader;
- if (!is_active)
- {
- g_object_unref (ret_loader);
- ret_loader = (OstreeBootloader*)_ostree_bootloader_grub2_new (sysroot);
- if (!_ostree_bootloader_query (ret_loader, &is_active,
- cancellable, error))
- return FALSE;
- }
- if (!is_active)
- {
- g_object_unref (ret_loader);
- ret_loader = (OstreeBootloader*)_ostree_bootloader_uboot_new (sysroot);
- if (!_ostree_bootloader_query (ret_loader, &is_active, cancellable, error))
- return FALSE;
- }
- if (!is_active)
- g_clear_object (&ret_loader);
+ g_debug ("Using bootloader configuration: %s",
+ CFG_SYSROOT_BOOTLOADER_OPTS_STR[bootloader_config]);
- ot_transfer_out_value(out_bootloader, &ret_loader);
+ g_autoptr(OstreeBootloader) ret_loader = NULL;
+ if (bootloader_config == CFG_SYSROOT_BOOTLOADER_OPT_AUTO)
+ {
+ OstreeCfgSysrootBootloaderOpt probe[] = {
+ CFG_SYSROOT_BOOTLOADER_OPT_SYSLINUX,
+ CFG_SYSROOT_BOOTLOADER_OPT_GRUB2,
+ CFG_SYSROOT_BOOTLOADER_OPT_UBOOT,
+ };
+ for (int i = 0; i < G_N_ELEMENTS (probe); i++)
+ {
+ g_autoptr(OstreeBootloader) bl = _ostree_sysroot_new_bootloader_by_type (
+ sysroot, probe[i]);
+ gboolean is_active = FALSE;
+ if (!_ostree_bootloader_query (bl, &is_active, cancellable, error))
+ return FALSE;
+ if (is_active)
+ {
+ ret_loader = g_steal_pointer (&bl);
+ break;
+ }
+ }
+ }
+ else
+ ret_loader = _ostree_sysroot_new_bootloader_by_type (sysroot, bootloader_config);
+
+ ot_transfer_out_value (out_bootloader, &ret_loader)
return TRUE;
}
diff --git a/tests/bootloader-entries-crosscheck.py b/tests/bootloader-entries-crosscheck.py
index 605bd080..b5a02066 100755
--- a/tests/bootloader-entries-crosscheck.py
+++ b/tests/bootloader-entries-crosscheck.py
@@ -20,113 +20,118 @@
import os
import sys
-if len(sys.argv) == 1:
- sysroot = ''
-else:
- sysroot = sys.argv[1]
-bootloader = sys.argv[2]
-loaderpath = sysroot + '/boot/loader/entries'
-syslinuxpath = sysroot + '/boot/syslinux/syslinux.cfg'
+def main(argv):
+ _, sysroot, bootloader = argv
+
+ if bootloader == "grub2":
+ sys.stdout.write('GRUB2 configuration validation not implemented.\n')
+ return 0
+ else:
+ return validate_syslinux(sysroot)
-if bootloader == "grub2":
- sys.stdout.write('GRUB2 configuration validation not implemented.\n')
- sys.exit(0)
def fatal(msg):
sys.stderr.write(msg)
sys.stderr.write('\n')
sys.exit(1)
-def entry_get_version(entry):
- return int(entry['version'])
def get_ostree_option(optionstring):
for o in optionstring.split():
if o.startswith('ostree='):
return o[8:]
- raise ValueError('ostree= not found')
-
-entries = []
-syslinux_entries = []
+ raise ValueError('ostree= not found in %r' % (optionstring,))
-# Parse loader configs
-for fname in os.listdir(loaderpath):
- path = os.path.join(loaderpath, fname)
- with open(path) as f:
+
+def parse_loader_configs(sysroot):
+ loaderpath = sysroot + '/boot/loader/entries'
+ entries = []
+
+ # Parse loader configs
+ for fname in os.listdir(loaderpath):
+ path = os.path.join(loaderpath, fname)
entry = {}
- for line in f:
- line = line.strip()
- if (line == '' or line.startswith('#')):
- continue
- s = line.find(' ')
- assert s > 0
- k = line[0:s]
- v = line[s+1:]
- entry[k] = v
+ with open(path) as f:
+ for line in f:
+ line = line.strip()
+ if (line == '' or line.startswith('#')):
+ continue
+ k, v = line.split(' ', 1)
+ entry[k] = v
entries.append(entry)
- entries.sort(key=entry_get_version, reverse=True)
+ entries.sort(key=lambda e: int(e['version']), reverse=True)
+ return entries
-# Parse SYSLINUX config
-with open(syslinuxpath) as f:
- in_ostree_config = False
- syslinux_entry = None
- syslinux_default = None
- for line in f:
- try:
- k, v = line.strip().split(" ", 1)
- except ValueError:
- continue
- if k == 'DEFAULT':
- if syslinux_entry is not None:
- syslinux_default = v
- elif k == 'LABEL':
- if syslinux_entry is not None:
- syslinux_entries.append(syslinux_entry)
- syslinux_entry = {}
- syslinux_entry['title'] = v
- elif k == 'KERNEL':
- syslinux_entry['linux'] = v
- elif k == 'INITRD':
- syslinux_entry['initrd'] = v
- elif k == 'APPEND':
- syslinux_entry['options'] = v
- if syslinux_entry is not None:
- syslinux_entries.append(syslinux_entry)
-if len(entries) != len(syslinux_entries):
- fatal("Found {0} loader entries, but {1} SYSLINUX entries\n".format(len(entries), len(syslinux_entries)))
+def validate_syslinux(sysroot):
+ syslinuxpath = sysroot + '/boot/syslinux/syslinux.cfg'
+
+ entries = parse_loader_configs(sysroot)
+ syslinux_entries = []
+
+ # Parse SYSLINUX config
+ with open(syslinuxpath) as f:
+ syslinux_entry = None
+ for line in f:
+ try:
+ k, v = line.strip().split(" ", 1)
+ except ValueError:
+ continue
+ if k == 'DEFAULT':
+ if syslinux_entry is not None:
+ syslinux_default = v
+ elif k == 'LABEL':
+ if syslinux_entry is not None:
+ syslinux_entries.append(syslinux_entry)
+ syslinux_entry = {}
+ syslinux_entry['title'] = v
+ elif k == 'KERNEL':
+ syslinux_entry['linux'] = v
+ elif k == 'INITRD':
+ syslinux_entry['initrd'] = v
+ elif k == 'APPEND':
+ syslinux_entry['options'] = v
+ if syslinux_entry is not None:
+ syslinux_entries.append(syslinux_entry)
+
+ if len(entries) != len(syslinux_entries):
+ fatal("Found {0} loader entries, but {1} SYSLINUX entries\n".format(
+ len(entries), len(syslinux_entries)))
+
+ def assert_key_same_file(a, b, key):
+ aval = a[key]
+ bval = b[key]
+ sys.stderr.write("aval: %r\nbval: %r\n" % (aval, bval))
+
+ # Paths in entries are always relative to /boot
+ entry = os.stat(sysroot + "/boot" + aval)
+
+ # Syslinux entries can be relative to /boot (if it's on another filesystem)
+ # or relative to / if /boot is on /.
+ s1 = os.stat(sysroot + bval)
+ s2 = os.stat(sysroot + "/boot" + bval)
+
+ # A symlink ensures that no matter what they point at the same file
+ assert_eq(entry, s1)
+ assert_eq(entry, s2)
+
+ for i, (entry, syslinuxentry) in enumerate(zip(entries, syslinux_entries)):
+ assert_key_same_file(entry, syslinuxentry, 'linux')
+ assert_key_same_file(entry, syslinuxentry, 'initrd')
+ entry_ostree = get_ostree_option(entry['options'])
+ syslinux_ostree = get_ostree_option(syslinuxentry['options'])
+ if entry_ostree != syslinux_ostree:
+ fatal("Mismatch on ostree option: {0} != {1}".format(
+ entry_ostree, syslinux_ostree))
+
+ sys.stdout.write('SYSLINUX configuration validated\n')
+ return 0
def assert_eq(a, b):
assert a == b, "%r == %r" % (a, b)
-def assert_key_same_file(a, b, key):
- aval = a[key]
- bval = b[key]
- sys.stderr.write("aval: %r\nbval: %r\n" % (aval, bval))
-
- # Paths in entries are always relative to /boot
- entry = os.stat(sysroot + "/boot" + aval)
-
- # Syslinux entries can be relative to /boot (if it's on another filesystem)
- # or relative to / if /boot is on /.
- s1 = os.stat(sysroot + bval)
- s2 = os.stat(sysroot + "/boot" + bval)
-
- # A symlink ensures that no matter what they point at the same file
- assert_eq(entry, s1)
- assert_eq(entry, s2)
-
-
-for i,(entry,syslinuxentry) in enumerate(zip(entries, syslinux_entries)):
- assert_key_same_file(entry, syslinuxentry, 'linux')
- assert_key_same_file(entry, syslinuxentry, 'initrd')
- entry_ostree = get_ostree_option(entry['options'])
- syslinux_ostree = get_ostree_option(syslinuxentry['options'])
- if entry_ostree != syslinux_ostree:
- fatal("Mismatch on ostree option: {0} != {1}".format(entry_ostree, syslinux_ostree))
-
-sys.stdout.write('SYSLINUX configuration validated\n')
-sys.exit(0)
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))