diff --git a/Makefile-boot.am b/Makefile-boot.am index 49b3c037..0a54da83 100644 --- a/Makefile-boot.am +++ b/Makefile-boot.am @@ -39,6 +39,16 @@ systemdsystemunit_DATA = src/boot/ostree-prepare-root.service \ src/boot/ostree-remount.service endif +pkglibexec_SCRIPTS += src/boot/grub2-15_ostree + +if BUILDOPT_GRUB2 +install-grub2-config-hook: + mkdir -p $(DESTDIR)$(grub2configdir) + ln -sf $(pkglibexecdir)/grub2-15_ostree $(DESTDIR)$(grub2configdir)/15_ostree +grub2configdir = $(sysconfdir)/grub.d +INSTALL_DATA_HOOKS += install-grub2-config-hook +endif + EXTRA_DIST += src/boot/dracut/module-setup.sh \ src/boot/dracut/ostree.conf \ src/boot/mkinitcpio/ostree \ diff --git a/Makefile-decls.am b/Makefile-decls.am index a57466cf..a5c9d503 100644 --- a/Makefile-decls.am +++ b/Makefile-decls.am @@ -30,6 +30,7 @@ sbin_PROGRAMS = bin_SCRIPTS = lib_LTLIBRARIES = libexec_PROGRAMS = +pkglibexec_SCRIPTS = noinst_LTLIBRARIES = noinst_PROGRAMS = privlibdir = $(pkglibdir) diff --git a/Makefile-libostree.am b/Makefile-libostree.am index fbe173dc..4d1f9019 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -35,6 +35,8 @@ libostreeinclude_HEADERS = $(libostree_public_headers) libostree_1_la_SOURCES = \ src/libostree/ostree-async-progress.c \ + src/libostree/ostree-cmdprivate.h \ + src/libostree/ostree-cmdprivate.c \ src/libostree/ostree-core-private.h \ src/libostree/ostree-core.c \ src/libostree/ostree-checksum-input-stream.c \ @@ -74,6 +76,8 @@ libostree_1_la_SOURCES = \ src/libostree/ostree-deployment.c \ src/libostree/ostree-bootloader.h \ src/libostree/ostree-bootloader.c \ + src/libostree/ostree-bootloader-grub2.h \ + src/libostree/ostree-bootloader-grub2.c \ src/libostree/ostree-bootloader-syslinux.h \ src/libostree/ostree-bootloader-syslinux.c \ src/libostree/ostree-bootloader-uboot.h \ diff --git a/Makefile-ostree.am b/Makefile-ostree.am index 47b06f1e..86ee144e 100644 --- a/Makefile-ostree.am +++ b/Makefile-ostree.am @@ -66,6 +66,7 @@ ostree_SOURCES += \ src/ostree/ot-admin-builtins.h \ src/ostree/ot-admin-instutil-builtin-selinux-ensure-labeled.c \ src/ostree/ot-admin-instutil-builtin-set-kargs.c \ + src/ostree/ot-admin-instutil-builtin-grub2-generate.c \ src/ostree/ot-admin-instutil-builtins.h \ src/ostree/ot-admin-functions.h \ src/ostree/ot-admin-functions.c \ diff --git a/configure.ac b/configure.ac index b812c40f..ce2bf025 100644 --- a/configure.ac +++ b/configure.ac @@ -201,6 +201,12 @@ AS_IF([test "x$with_dracut" = "xyes" || test "x$with_mkinitcpio" = "xyes"], [ ]) AM_CONDITIONAL(BUILDOPT_SYSTEMD, test x$with_systemd = xyes) +AC_ARG_WITH(grub2, + AS_HELP_STRING([--with-grub2], + [Install grub2 hook (default: yes)]),, + [with_grub2=yes]) +AM_CONDITIONAL(BUILDOPT_GRUB2, test x$with_grub2 = xyes) + dnl for tests AS_IF([test "x$found_introspection" = xyes], [ AC_PATH_PROG(GJS, [gjs]) diff --git a/packaging/ostree.spec.in b/packaging/ostree.spec.in index 808a2ef3..265f3db4 100644 --- a/packaging/ostree.spec.in +++ b/packaging/ostree.spec.in @@ -46,6 +46,14 @@ Requires: %{name} = %{version}-%{release} %description devel The %{name}-devel package includes the header files for the %{name} library. +%package grub2 +Summary: GRUB2 integration for OSTree +Group: Development/Libraries +Requires: grub2 + +%description grub2 +GRUB2 integration for OSTree + %prep %setup -q -n ostree-%{version} @@ -94,3 +102,7 @@ rm -rf $RPM_BUILD_ROOT %dir %{_datadir}/gtk-doc/html/ostree %{_datadir}/gtk-doc/html/ostree %{_datadir}/gir-1.0/OSTree-1.0.gir + +%files grub2 +%{_sysconfdir}/grub.d/*ostree +%{_libexecdir}/ostree/grub2* diff --git a/src/boot/grub2-15_ostree b/src/boot/grub2-15_ostree new file mode 100644 index 00000000..dfff6e89 --- /dev/null +++ b/src/boot/grub2-15_ostree @@ -0,0 +1,47 @@ +#!/bin/sh +# +# Copyright (C) 2014 Colin Walters +# +# This program 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 licence 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. + +# Gracefully exit if ostree is not installed +if ! which ostree >/dev/null 2>/dev/null; then + exit 0 +fi + +# Make sure we're in the right environment +if ! test -n "${GRUB_DEVICE}"; then + echo "This script must be run as a child of grub2-mkconfig" 1>&2 + exit 1 +fi + +set -e + +# Pick up stuff from grub's helper that we want to inject into our +# generated bootloader configuration. Yes, this is pretty awful, but +# it's a lot better than reimplementing the config-generating bits of +# OSTree in shell script. + +. /usr/share/grub/grub-mkconfig_lib + +DEVICE=${GRUB_DEVICE_BOOT:-${GRUB_DEVICE}} + +GRUB2_BOOT_DEVICE_ID="$(grub_get_device_id ${DEVICE})" +export GRUB2_BOOT_DEVICE_ID +GRUB2_PREPARE_ROOT_CACHE="$(prepare_grub_to_access_device ${DEVICE})" +export GRUB2_PREPARE_ROOT_CACHE + +exec ostree admin instutil grub2-generate diff --git a/src/libostree/ostree-bootloader-grub2.c b/src/libostree/ostree-bootloader-grub2.c new file mode 100644 index 00000000..8f4dcae9 --- /dev/null +++ b/src/libostree/ostree-bootloader-grub2.c @@ -0,0 +1,261 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This program 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 licence 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 "ostree-sysroot-private.h" +#include "ostree-bootloader-grub2.h" +#include "otutil.h" +#include +#include +#include "libgsystem.h" + +#include + +struct _OstreeBootloaderGrub2 +{ + GObject parent_instance; + + OstreeSysroot *sysroot; + GFile *config_path_bios; +}; + +typedef GObjectClass OstreeBootloaderGrub2Class; + +static void _ostree_bootloader_grub2_bootloader_iface_init (OstreeBootloaderInterface *iface); +G_DEFINE_TYPE_WITH_CODE (OstreeBootloaderGrub2, _ostree_bootloader_grub2, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (OSTREE_TYPE_BOOTLOADER, _ostree_bootloader_grub2_bootloader_iface_init)); + +static gboolean +_ostree_bootloader_grub2_query (OstreeBootloader *bootloader) +{ + OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); + + return g_file_query_exists (self->config_path_bios, NULL); +} + +static const char * +_ostree_bootloader_grub2_get_name (OstreeBootloader *bootloader) +{ + return "grub2"; +} + +gboolean +_ostree_bootloader_grub2_generate_config (OstreeBootloaderGrub2 *self, + int bootversion, + int target_fd, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + GString *output = g_string_new (""); + gs_unref_object GOutputStream *out_stream = NULL; + gs_unref_ptrarray GPtrArray *loader_configs = NULL; + guint i; + gsize bytes_written; + /* So... yeah. Just going to hardcode these. */ + static const char hardcoded_video[] = "load_video\n" + "set gfxpayload=keep\n"; + static const char hardcoded_insmods[] = "insmod gzio\n"; + const char *grub2_boot_device_id = + g_getenv ("GRUB2_BOOT_DEVICE_ID"); + const char *grub2_prepare_root_cache = + g_getenv ("GRUB2_PREPARE_ROOT_CACHE"); + + /* We must have been called via the wrapper script */ + g_assert (grub2_boot_device_id != NULL); + g_assert (grub2_prepare_root_cache != NULL); + + out_stream = g_unix_output_stream_new (target_fd, FALSE); + + if (!_ostree_sysroot_read_boot_loader_configs (self->sysroot, bootversion, + &loader_configs, + cancellable, error)) + goto out; + + for (i = 0; i < loader_configs->len; i++) + { + OstreeBootconfigParser *config = loader_configs->pdata[i]; + const char *title; + const char *options; + const char *kernel; + const char *initrd; + char *quoted_title = NULL; + char *uuid = NULL; + char *quoted_uuid = NULL; + + title = ostree_bootconfig_parser_get (config, "title"); + if (!title) + title = "(Untitled)"; + + kernel = ostree_bootconfig_parser_get (config, "linux"); + + quoted_title = g_shell_quote (title); + uuid = g_strdup_printf ("ostree-%u-%s", (guint)i, grub2_boot_device_id); + quoted_uuid = g_shell_quote (uuid); + g_string_append_printf (output, "menuentry %s --class gnu-linux --class gnu --class os --unrestricted %s {\n", quoted_title, quoted_uuid); + g_free (uuid); + g_free (quoted_title); + g_free (quoted_uuid); + + /* Hardcoded sections */ + g_string_append (output, hardcoded_video); + g_string_append (output, hardcoded_insmods); + g_string_append (output, grub2_prepare_root_cache); + g_string_append_c (output, '\n'); + + if (!kernel) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "No \"linux\" key in bootloader config"); + goto out; + } + g_string_append (output, "linux16 "); + g_string_append (output, kernel); + + options = ostree_bootconfig_parser_get (config, "options"); + if (options) + { + g_string_append_c (output, ' '); + g_string_append (output, options); + } + g_string_append_c (output, '\n'); + + initrd = ostree_bootconfig_parser_get (config, "initrd"); + if (initrd) + { + g_string_append (output, "initrd16 "); + g_string_append (output, initrd); + g_string_append_c (output, '\n'); + } + + g_string_append (output, "}\n"); + } + + if (!g_output_stream_write_all (out_stream, output->str, output->len, + &bytes_written, cancellable, error)) + goto out; + + ret = TRUE; + out: + if (output) + g_string_free (output, TRUE); + return ret; +} + +static gboolean +_ostree_bootloader_grub2_write_config (OstreeBootloader *bootloader, + int bootversion, + GCancellable *cancellable, + GError **error) +{ + OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (bootloader); + gboolean ret = FALSE; + gs_unref_object GFile *new_config_path = NULL; + gs_unref_object GSSubprocessContext *procctx = NULL; + gs_unref_object GSSubprocess *proc = NULL; + gs_strfreev char **child_env = g_get_environ (); + gs_free char *bootversion_str = g_strdup_printf ("%u", (guint)bootversion); + + new_config_path = ot_gfile_resolve_path_printf (self->sysroot->path, "boot/loader.%d/grub.cfg", + bootversion); + + procctx = gs_subprocess_context_newv ("grub2-mkconfig", "-o", + gs_file_get_path_cached (new_config_path), + NULL); + child_env = g_environ_setenv (child_env, "_OSTREE_GRUB2_BOOTVERSION", bootversion_str, TRUE); + gs_subprocess_context_set_environment (procctx, child_env); + gs_subprocess_context_set_stdout_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_NULL); + if (g_getenv ("OSTREE_DEBUG_GRUB2")) + gs_subprocess_context_set_stderr_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT); + else + gs_subprocess_context_set_stderr_disposition (procctx, GS_SUBPROCESS_STREAM_DISPOSITION_NULL); + + /* In the current Fedora grub2 package, this script doesn't even try + to be atomic; it just does: + +cat ${grub_cfg}.new > ${grub_cfg} +rm -f ${grub_cfg}.new + + Upstream is fixed though. + */ + proc = gs_subprocess_new (procctx, cancellable, error); + if (!proc) + goto out; + + if (!gs_subprocess_wait_sync_check (proc, cancellable, error)) + goto out; + + /* Now let's fdatasync() for the new file */ + if (!gs_file_sync_data (new_config_path, cancellable, error)) + goto out; + + ret = TRUE; + out: + return ret; +} + +static gboolean +_ostree_bootloader_grub2_is_atomic (OstreeBootloader *bootloader) +{ + return TRUE; +} + +static void +_ostree_bootloader_grub2_finalize (GObject *object) +{ + OstreeBootloaderGrub2 *self = OSTREE_BOOTLOADER_GRUB2 (object); + + g_clear_object (&self->sysroot); + g_clear_object (&self->config_path_bios); + + G_OBJECT_CLASS (_ostree_bootloader_grub2_parent_class)->finalize (object); +} + +void +_ostree_bootloader_grub2_init (OstreeBootloaderGrub2 *self) +{ +} + +static void +_ostree_bootloader_grub2_bootloader_iface_init (OstreeBootloaderInterface *iface) +{ + iface->query = _ostree_bootloader_grub2_query; + iface->get_name = _ostree_bootloader_grub2_get_name; + iface->write_config = _ostree_bootloader_grub2_write_config; + iface->is_atomic = _ostree_bootloader_grub2_is_atomic; +} + +void +_ostree_bootloader_grub2_class_init (OstreeBootloaderGrub2Class *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = _ostree_bootloader_grub2_finalize; +} + +OstreeBootloaderGrub2 * +_ostree_bootloader_grub2_new (OstreeSysroot *sysroot) +{ + OstreeBootloaderGrub2 *self = g_object_new (OSTREE_TYPE_BOOTLOADER_GRUB2, NULL); + self->sysroot = g_object_ref (sysroot); + self->config_path_bios = g_file_resolve_relative_path (self->sysroot->path, "boot/grub2/grub.cfg"); + return self; +} diff --git a/src/libostree/ostree-bootloader-grub2.h b/src/libostree/ostree-bootloader-grub2.h new file mode 100644 index 00000000..334ad49b --- /dev/null +++ b/src/libostree/ostree-bootloader-grub2.h @@ -0,0 +1,40 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This program 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 licence 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 "ostree-bootloader.h" + +G_BEGIN_DECLS + +#define OSTREE_TYPE_BOOTLOADER_GRUB2 (_ostree_bootloader_grub2_get_type ()) +#define OSTREE_BOOTLOADER_GRUB2(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OSTREE_TYPE_BOOTLOADER_GRUB2, OstreeBootloaderGrub2)) +#define OSTREE_IS_BOOTLOADER_GRUB2(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OSTREE_TYPE_BOOTLOADER_GRUB2)) + +typedef struct _OstreeBootloaderGrub2 OstreeBootloaderGrub2; + +GType _ostree_bootloader_grub2_get_type (void) G_GNUC_CONST; + +OstreeBootloaderGrub2 * _ostree_bootloader_grub2_new (OstreeSysroot *sysroot); + +gboolean _ostree_bootloader_grub2_generate_config (OstreeBootloaderGrub2 *self, int bootversion, int target_fd, GCancellable *cancellable, GError **error); + +G_END_DECLS + diff --git a/src/libostree/ostree-bootloader.c b/src/libostree/ostree-bootloader.c index 5cb7c5ea..37219999 100644 --- a/src/libostree/ostree-bootloader.c +++ b/src/libostree/ostree-bootloader.c @@ -61,3 +61,14 @@ _ostree_bootloader_write_config (OstreeBootloader *self, return OSTREE_BOOTLOADER_GET_IFACE (self)->write_config (self, bootversion, cancellable, error); } + +gboolean +_ostree_bootloader_is_atomic (OstreeBootloader *self) +{ + g_return_val_if_fail (OSTREE_IS_BOOTLOADER (self), FALSE); + + if (OSTREE_BOOTLOADER_GET_IFACE (self)->is_atomic) + return OSTREE_BOOTLOADER_GET_IFACE (self)->is_atomic (self); + else + return TRUE; +} diff --git a/src/libostree/ostree-bootloader.h b/src/libostree/ostree-bootloader.h index 0d07fdba..a84ce6ba 100644 --- a/src/libostree/ostree-bootloader.h +++ b/src/libostree/ostree-bootloader.h @@ -43,6 +43,7 @@ struct _OstreeBootloaderInterface int bootversion, GCancellable *cancellable, GError **error); + gboolean (* is_atomic) (OstreeBootloader *self); }; GType _ostree_bootloader_get_type (void) G_GNUC_CONST; @@ -56,5 +57,7 @@ gboolean _ostree_bootloader_write_config (OstreeBootloader *self, GCancellable *cancellable, GError **error); +gboolean _ostree_bootloader_is_atomic (OstreeBootloader *self); + G_END_DECLS diff --git a/src/libostree/ostree-cmdprivate.c b/src/libostree/ostree-cmdprivate.c new file mode 100644 index 00000000..3d6a1941 --- /dev/null +++ b/src/libostree/ostree-cmdprivate.c @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "ostree-cmdprivate.h" +#include "ostree-sysroot.h" +#include "ostree-bootloader-grub2.h" + +#include "otutil.h" + +static gboolean +impl_ostree_generate_grub2_config (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error) +{ + gs_unref_object OstreeBootloaderGrub2 *grub2 = _ostree_bootloader_grub2_new (sysroot); + + return _ostree_bootloader_grub2_generate_config (grub2, bootversion, target_fd, cancellable, error); +} + +/** + * ostree_cmdprivate: (skip) + * + * Do not call this function; it is used to share private API between + * the OSTree commandline and the library. + */ +OstreeCmdPrivateVTable * +ostree_cmd__private__ (void) +{ + static OstreeCmdPrivateVTable table = { + impl_ostree_generate_grub2_config + }; + + return &table; +} + diff --git a/src/libostree/ostree-cmdprivate.h b/src/libostree/ostree-cmdprivate.h new file mode 100644 index 00000000..ac2972a6 --- /dev/null +++ b/src/libostree/ostree-cmdprivate.h @@ -0,0 +1,35 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 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 "ostree-types.h" + +G_BEGIN_DECLS + +typedef struct { + gboolean (* ostree_generate_grub2_config) (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error); +} OstreeCmdPrivateVTable; + +OstreeCmdPrivateVTable * +ostree_cmd__private__ (void); + +G_END_DECLS + diff --git a/src/libostree/ostree-sysroot-deploy.c b/src/libostree/ostree-sysroot-deploy.c index 905854f1..9934e0f8 100644 --- a/src/libostree/ostree-sysroot-deploy.c +++ b/src/libostree/ostree-sysroot-deploy.c @@ -1004,6 +1004,8 @@ get_kernel_from_tree (GFile *deployroot, GError **error) { gboolean ret = FALSE; + gs_unref_object GFile *ostree_bootdir + = g_file_resolve_relative_path (deployroot, "usr/lib/ostree-boot"); gs_unref_object GFile *bootdir = g_file_get_child (deployroot, "boot"); gs_unref_object GFileEnumerator *dir_enum = NULL; gs_unref_object GFile *ret_kernel = NULL; @@ -1011,11 +1013,22 @@ get_kernel_from_tree (GFile *deployroot, gs_free char *kernel_checksum = NULL; gs_free char *initramfs_checksum = NULL; - dir_enum = g_file_enumerate_children (bootdir, OSTREE_GIO_FAST_QUERYINFO, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, error); - if (!dir_enum) - goto out; + if (g_file_query_exists (ostree_bootdir, NULL)) + { + dir_enum = g_file_enumerate_children (ostree_bootdir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, error); + if (!dir_enum) + goto out; + } + else + { + dir_enum = g_file_enumerate_children (bootdir, OSTREE_GIO_FAST_QUERYINFO, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL, error); + if (!dir_enum) + goto out; + } while (TRUE) { @@ -1510,6 +1523,7 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, guint i; gboolean requires_new_bootversion = FALSE; gboolean found_booted_deployment = FALSE; + gboolean bootloader_is_atomic = FALSE; g_assert (self->loaded); @@ -1578,6 +1592,8 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, g_prefix_error (error, "Swapping current bootlinks: "); goto out; } + + bootloader_is_atomic = TRUE; } else { @@ -1615,11 +1631,17 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, g_debug ("Using bootloader: %s", bootloader ? g_type_name (G_TYPE_FROM_INSTANCE (bootloader)) : "(none)"); - if (bootloader && !_ostree_bootloader_write_config (bootloader, new_bootversion, - cancellable, error)) + if (bootloader) + bootloader_is_atomic = _ostree_bootloader_is_atomic (bootloader); + + if (bootloader) { - g_prefix_error (error, "Bootloader write config: "); - goto out; + if (!_ostree_bootloader_write_config (bootloader, new_bootversion, + cancellable, error)) + { + g_prefix_error (error, "Bootloader write config: "); + goto out; + } } if (!full_system_sync (cancellable, error)) @@ -1627,7 +1649,7 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, g_prefix_error (error, "Full sync: "); goto out; } - + if (!swap_bootloader (self, self->bootversion, new_bootversion, cancellable, error)) { @@ -1637,7 +1659,8 @@ ostree_sysroot_write_deployments (OstreeSysroot *self, } gs_log_structured_print_id_v (OSTREE_DEPLOYMENT_COMPLETE_ID, - "Transaction complete; bootconfig swap: %s deployment count change: %i)", + "%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); diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index c88c6d42..160fc078 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -26,6 +26,7 @@ #include "ostree-sysroot-private.h" #include "ostree-bootloader-uboot.h" #include "ostree-bootloader-syslinux.h" +#include "ostree-bootloader-grub2.h" static gboolean find_booted_deployment (OstreeSysroot *self, @@ -853,11 +854,16 @@ _ostree_sysroot_query_bootloader (OstreeSysroot *self) { OstreeBootloaderSyslinux *syslinux; OstreeBootloaderUboot *uboot; + OstreeBootloaderGrub2 *grub2; syslinux = _ostree_bootloader_syslinux_new (self); if (_ostree_bootloader_query ((OstreeBootloader*)syslinux)) return (OstreeBootloader*) (syslinux); + grub2 = _ostree_bootloader_grub2_new (self); + if (_ostree_bootloader_query ((OstreeBootloader*)grub2)) + return (OstreeBootloader*) (grub2); + uboot = _ostree_bootloader_uboot_new (self); if (_ostree_bootloader_query ((OstreeBootloader*)uboot)) return (OstreeBootloader*) (uboot); diff --git a/src/ostree/ot-admin-builtin-instutil.c b/src/ostree/ot-admin-builtin-instutil.c index a0a29d28..7a17dd3b 100644 --- a/src/ostree/ot-admin-builtin-instutil.c +++ b/src/ostree/ot-admin-builtin-instutil.c @@ -40,6 +40,7 @@ static OstreeAdminInstUtilCommand admin_instutil_subcommands[] = { { "selinux-ensure-labeled", ot_admin_instutil_builtin_selinux_ensure_labeled }, #endif { "set-kargs", ot_admin_instutil_builtin_set_kargs }, + { "grub2-generate", ot_admin_instutil_builtin_grub2_generate }, { NULL, NULL } }; diff --git a/src/ostree/ot-admin-instutil-builtin-grub2-generate.c b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c new file mode 100644 index 00000000..0b00cf97 --- /dev/null +++ b/src/ostree/ot-admin-instutil-builtin-grub2-generate.c @@ -0,0 +1,84 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * This program 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 licence 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 "ot-admin-instutil-builtins.h" +#include "ostree-cmdprivate.h" + +#include "otutil.h" + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error) +{ + gboolean ret = FALSE; + guint bootversion; + gs_unref_object GFile *subpath = NULL; + gs_unref_object OstreeSePolicy *sepolicy = NULL; + gs_unref_ptrarray GPtrArray *deployments = NULL; + GOptionContext *context = NULL; + gs_unref_object GFile *deployment_path = NULL; + + context = g_option_context_new ("BOOTVERSION - generate GRUB2 configuration from given BLS entries"); + + g_option_context_add_main_entries (context, options, NULL); + + if (!g_option_context_parse (context, &argc, &argv, error)) + goto out; + + if (argc >= 2) + { + bootversion = (guint) g_ascii_strtoull (argv[1], NULL, 10); + if (!(bootversion == 0 || bootversion == 1)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "Invalid bootversion: %u", bootversion); + goto out; + } + } + else + { + const char *bootversion_env = g_getenv ("_OSTREE_GRUB2_BOOTVERSION"); + if (bootversion_env) + bootversion = g_ascii_strtoull (bootversion_env, NULL, 10); + else + bootversion = ostree_sysroot_get_bootversion (sysroot); + g_assert (bootversion == 0 || bootversion == 1); + } + + if (!ostree_sysroot_load (sysroot, cancellable, error)) + goto out; + + if (!ostree_cmd__private__()->ostree_generate_grub2_config (sysroot, bootversion, 1, cancellable, error)) + goto out; + + ret = TRUE; + out: + if (context) + g_option_context_free (context); + return ret; +} diff --git a/src/ostree/ot-admin-instutil-builtins.h b/src/ostree/ot-admin-instutil-builtins.h index b079ddea..5442eb52 100644 --- a/src/ostree/ot-admin-instutil-builtins.h +++ b/src/ostree/ot-admin-instutil-builtins.h @@ -26,6 +26,7 @@ G_BEGIN_DECLS gboolean ot_admin_instutil_builtin_selinux_ensure_labeled (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error); gboolean ot_admin_instutil_builtin_set_kargs (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error); +gboolean ot_admin_instutil_builtin_grub2_generate (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error); G_END_DECLS diff --git a/tests/test-admin-deploy-grub2.sh b/tests/test-admin-deploy-grub2.sh new file mode 100755 index 00000000..d07a263a --- /dev/null +++ b/tests/test-admin-deploy-grub2.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright (C) 2011,2014 Colin Walters +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -e + +. $(dirname $0)/libtest.sh + +echo "1..1" + +setup_os_repository "archive-z2" "grub2" + +echo "ok setup" + +. $(dirname $0)/admin-test.sh