From: Michael Chang Subject: create menus for btrfs snapshot References: fate#316522, fate#316232 Patch-Mainline: no This patch adds a new script that will create the menus used for booting btrfs snapshots. v1: * Support existing snapshots by creating their missing slave configs. * Temporarily default to disable this feature until receiving more tests from QA. * Introduce GRUB_ENABLE_CUSTOM_SNAPSHOT_SUBMENU to allow custom submenu for listing snapshots rather than the default one. v2: * Fix bootable snapshots not found while root is on Btrfs subvolume (bnc#859587) * Create missing slave config in /.snapshots// * Prefix with SUSE_ for related options v3: * When booting btrfs snapshots disabled, deleting snapshot master config if it's not customized Signed-off-by: Michael Chang Index: grub-2.02~beta2/Makefile.util.def =================================================================== --- grub-2.02~beta2.orig/Makefile.util.def +++ grub-2.02~beta2/Makefile.util.def @@ -509,6 +509,13 @@ script = { installdir = grubconf; }; +script = { + name = '80_btrfs_snapshot'; + common = util/grub.d/80_btrfs_snapshot.in; + installdir = grubconf; + condition = COND_HOST_LINUX; +}; + program = { mansection = 1; name = grub-mkrescue; Index: grub-2.02~beta2/util/grub-mkconfig.in =================================================================== --- grub-2.02~beta2.orig/util/grub-mkconfig.in +++ grub-2.02~beta2/util/grub-mkconfig.in @@ -250,7 +250,10 @@ export GRUB_DEFAULT \ GRUB_OS_PROBER_SKIP_LIST \ GRUB_DISABLE_SUBMENU \ GRUB_CMDLINE_LINUX_RECOVERY \ - GRUB_USE_LINUXEFI + GRUB_USE_LINUXEFI \ + SUSE_DISABLE_BOOTING_SNAPSHOT \ + SUSE_DISABLE_BOOTING_SNAPSHOT_SUBMENU \ + SUSE_ENABLE_CUSTOM_SNAPSHOT_SUBMENU if test "x${grub_cfg}" != "x"; then rm -f "${grub_cfg}.new" Index: grub-2.02~beta2/util/grub.d/80_btrfs_snapshot.in =================================================================== --- /dev/null +++ grub-2.02~beta2/util/grub.d/80_btrfs_snapshot.in @@ -0,0 +1,174 @@ +#! /bin/sh +set -e + +# grub-mkconfig helper script. +# Copyright (C) 2006,2007,2008,2009,2010 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +prefix="@prefix@" +exec_prefix="@exec_prefix@" +datarootdir="@datarootdir@" + +. "${datarootdir}/grub2/grub-mkconfig_lib" + +# It's pointless to proceed if not using Btrfs +if [ "x${GRUB_FS}" != "xbtrfs" ]; then + exit 0 +fi + +# The default master/main config path looked up by core.img +master_cfg="/boot/grub2/grub.cfg" + +# The config with submenu of bootable btrfs snapshots +master_snapshot_cfg="/boot/grub2/snapshot_submenu.cfg" + +# The slave config path in btrfs snapshot that will be sourced by master config +# The menu entries in slave config will have it's root overridable by specified +# subvolume name +slave_cfg_name="snapshot_menuentry.cfg" +slave_cfg="boot/grub2/${slave_cfg_name}" + +# The current config which is being outputted by grub-mkconfig +output_cfg=`readlink /proc/$PPID/fd/1 | sed s/.new$//` + +grub_mkconfig_dir=`dirname $0` +grub_script_check="${bindir}/grub2-script-check" + + +# The real root (subvolume) where system installed to +rel_root=`make_system_path_relative_to_its_root /` + +# Remove any slave config if booting snapshot gets disabled, in case it will become +# inconsistent on further updates, note this also removes master_snapshot_cfg + +# Temporarily we disable this as it is quite new and still in developing +# It's subjected to be enabled by default in future as the option name +# SUSE_DISABLE_BOOTING_SNAPSHOT suggests. So for new you'll need to explicit +# specify SUSE_DISABLE_BOOTING_SNAPSHOT=false the update the config +if [ "x${SUSE_DISABLE_BOOTING_SNAPSHOT}" != "xfalse" ]; then + rm -f "/${slave_cfg}" +# Delete snapshot master config if not customized + if [ "x${SUSE_ENABLE_CUSTOM_SNAPSHOT_SUBMENU}" != "xtrue" ]; then + rm -f "${master_snapshot_cfg}" + fi + exit 0 +fi + +# Only attempt to update slave config with master +if [ "x$output_cfg" = "x$master_cfg" ]; then + # Create the slave config by redirecting the standard output to it + # Output menu entries with overridable root + overridable_root_by_subvol=true ${grub_mkconfig_dir}/10_linux >"/${slave_cfg}.new" + + # Check if the config is sane to use + if ${grub_script_check} "/${slave_cfg}.new"; then + mv -f "/${slave_cfg}.new" "/${slave_cfg}" + fi + + # Scan existing snapshots to create their missing slave configs + # This should only be done once + + for s_dir in /.snapshots/*; do + + snapshot="${s_dir}/snapshot" + config="${snapshot}/etc/default/grub" + bootdir="${snapshot}/boot" + + if [ ! -d "$snapshot" ]; then + continue + elif [ -f "${snapshot}/${slave_cfg}" ]; then + continue + elif [ -f "${s_dir}/${slave_cfg_name}" ]; then + continue + fi + + ( + # source config for kernel command lines .. etc + if [ -f "$config" ]; then + . "$config" + else + # skip when no config + continue + fi + + overridable_root_by_subvol=true boot_prefix="$bootdir" ${grub_mkconfig_dir}/10_linux > "/${slave_cfg}.new" + ) + + # Check if the config is sane to use + if ${grub_script_check} "/${slave_cfg}.new"; then + mv -f "/${slave_cfg}.new" "${s_dir}/${slave_cfg_name}" + fi + done + +fi + +# Create the bootable snapshots submenus in master config, use the ${OS} to indicate +# distribution that owns these snapshots. +if [ "x${GRUB_DISTRIBUTOR}" = "x" ] ; then + OS=GNU/Linux +else + OS="${GRUB_DISTRIBUTOR}" +fi + +# Offer an option to allow disabling (built-in) snapshot submenu. It's possible to use +# any other submenu with more integrated information retrieved from certain snapshot +# utility's metadata and this option would help to get their boot menu tidy without +# submenu with duplicated purpose. +if [ "x${SUSE_DISABLE_BOOTING_SNAPSHOT_SUBMENU}" != "xtrue" ]; then + cat <"${master_snapshot_cfg}" +insmod regexp +submenu "Bootable snapshots for ${OS}" { + for x in ${rel_root}/.snapshots/*; do + if [ -f "\$x/${slave_cfg_name}" ]; then + snapshot_found=true + submenu "\$x" "\$x/snapshot" "\$x/${slave_cfg_name}" { + set subvol="\$2" + export subvol + source "\$3" + } + elif [ -f "\$x/snapshot/${slave_cfg}" ]; then + snapshot_found=true + submenu "\$x" "\$x/snapshot" "\$x/snapshot/${slave_cfg}" { + set subvol="\$2" + export subvol + source "\$3" + } + fi + done + if [ x\$snapshot_found != xtrue ]; then + submenu "Not Found" {true} + fi +} +EOF + +fi +