2014-01-15 11:47:05 +01:00
|
|
|
From: Michael Chang <mchang@suse.com>
|
|
|
|
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.
|
|
|
|
|
2014-01-17 13:38:35 +01:00
|
|
|
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.
|
|
|
|
|
2014-01-15 11:47:05 +01:00
|
|
|
Signed-off-by: Michael Chang <mchang@suse.com>
|
|
|
|
|
|
|
|
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
|
2014-01-17 13:38:35 +01:00
|
|
|
@@ -250,7 +250,10 @@ export GRUB_DEFAULT \
|
2014-01-15 11:47:05 +01:00
|
|
|
GRUB_OS_PROBER_SKIP_LIST \
|
|
|
|
GRUB_DISABLE_SUBMENU \
|
|
|
|
GRUB_CMDLINE_LINUX_RECOVERY \
|
|
|
|
- GRUB_USE_LINUXEFI
|
|
|
|
+ GRUB_USE_LINUXEFI \
|
|
|
|
+ GRUB_DISABLE_BOOTING_SNAPSHOT \
|
2014-01-17 13:38:35 +01:00
|
|
|
+ GRUB_DISABLE_BOOTING_SNAPSHOT_SUBMENU \
|
|
|
|
+ GRUB_ENABLE_CUSTOM_SNAPSHOT_SUBMENU
|
2014-01-15 11:47:05 +01:00
|
|
|
|
|
|
|
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
|
2014-01-17 13:38:35 +01:00
|
|
|
@@ -0,0 +1,174 @@
|
2014-01-15 11:47:05 +01:00
|
|
|
+#! /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 <http://www.gnu.org/licenses/>.
|
|
|
|
+
|
|
|
|
+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
|
2014-01-17 13:38:35 +01:00
|
|
|
+slave_cfg_name="snapshot_menuentry.cfg"
|
|
|
|
+slave_cfg="boot/grub2/${slave_cfg_name}"
|
2014-01-15 11:47:05 +01:00
|
|
|
+
|
|
|
|
+# 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"
|
|
|
|
+
|
2014-01-17 13:38:35 +01:00
|
|
|
+# Stockpile directory for created slave config for snapshots without it
|
|
|
|
+scanned_snapshot_cfg_dir="/boot/grub2/scanned_snapshot_cfg"
|
|
|
|
+
|
2014-01-15 11:47:05 +01:00
|
|
|
+# 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
|
2014-01-17 13:38:35 +01:00
|
|
|
+
|
|
|
|
+# 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
|
|
|
|
+# GRUB_DISABLE_BOOTING_SNAPSHOT suggests. So for new you'll need to explicit
|
|
|
|
+# specify GRUB_DISABLE_BOOTING_SNAPSHOT=false the update the config
|
|
|
|
+if [ "x${GRUB_DISABLE_BOOTING_SNAPSHOT}" != "xfalse" ]; then
|
2014-01-15 11:47:05 +01:00
|
|
|
+ rm -f "/${slave_cfg}"
|
|
|
|
+ rm -f "${master_snapshot_cfg}"
|
2014-01-17 13:38:35 +01:00
|
|
|
+ rm -rf "${scanned_snapshot_cfg_dir}"
|
2014-01-15 11:47:05 +01:00
|
|
|
+ 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
|
2014-01-17 13:38:35 +01:00
|
|
|
+
|
|
|
|
+ # Scan existing snapshots to create their missing slave configs
|
|
|
|
+ # This should only be done once
|
|
|
|
+ if [ ! -d "$scanned_snapshot_cfg_dir" ]; then
|
|
|
|
+
|
|
|
|
+ mkdir -p "$scanned_snapshot_cfg_dir"
|
|
|
|
+
|
|
|
|
+ for snapshot in /.snapshots/*/snapshot; do
|
|
|
|
+ config="${snapshot}/etc/default/grub"
|
|
|
|
+
|
|
|
|
+ bootdir="${snapshot}/boot"
|
|
|
|
+ outdir="${scanned_snapshot_cfg_dir}${snapshot}"
|
|
|
|
+
|
|
|
|
+ # skip if slave config already exists in snapshot
|
|
|
|
+ if [ -f "${snapshot}/${slave_cfg}" ]; 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
|
|
|
|
+ mkdir -p "$outdir"
|
|
|
|
+ mv -f "/${slave_cfg}.new" "${outdir}/${slave_cfg_name}"
|
|
|
|
+ fi
|
|
|
|
+ done
|
|
|
|
+
|
|
|
|
+ fi
|
|
|
|
+
|
2014-01-15 11:47:05 +01:00
|
|
|
+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${GRUB_DISABLE_BOOTING_SNAPSHOT_SUBMENU}" != "xtrue" ]; then
|
|
|
|
+ cat <<EOF
|
|
|
|
+if [ -f \${config_directory}/`basename ${master_snapshot_cfg}` ]; then
|
|
|
|
+ source \${config_directory}/`basename ${master_snapshot_cfg}`
|
|
|
|
+elif [ -z "\${config_directory}" -a -f \$prefix/`basename ${master_snapshot_cfg}` ]; then
|
|
|
|
+ source \$prefix/`basename ${master_snapshot_cfg}`;
|
|
|
|
+fi
|
|
|
|
+EOF
|
|
|
|
+fi
|
|
|
|
+
|
|
|
|
+# Still we create the file regardless GRUB_DISABLE_BOOTING_SNAPSHOT_SUBMENU, as it
|
|
|
|
+# could be source to run as a backup
|
|
|
|
+# Here we search and list snapshots created by snapper by using it's convention on
|
|
|
|
+# naming snapshots
|
2014-01-17 13:38:35 +01:00
|
|
|
+
|
|
|
|
+if [ "x${GRUB_ENABLE_CUSTOM_SNAPSHOT_SUBMENU}" != "xtrue" ]; then
|
|
|
|
+
|
|
|
|
+# Write default config if custom one not in use
|
|
|
|
+ cat <<EOF >"${master_snapshot_cfg}"
|
2014-01-15 11:47:05 +01:00
|
|
|
+insmod regexp
|
|
|
|
+submenu "Bootable snapshots for ${OS}" {
|
|
|
|
+ for x in /.snapshots/*; do
|
|
|
|
+ if [ -f "\$x/snapshot/${slave_cfg}" ]; then
|
|
|
|
+ snapshot_found=true
|
|
|
|
+ submenu "\$x" "\$x" {
|
|
|
|
+ set subvol="\$2/snapshot"
|
|
|
|
+ export subvol
|
|
|
|
+ source "\${subvol}/${slave_cfg}"
|
|
|
|
+ }
|
2014-01-17 13:38:35 +01:00
|
|
|
+ elif [ -f "${scanned_snapshot_cfg_dir}\$x/snapshot/${slave_cfg_name}" ]; then
|
|
|
|
+ snapshot_found=true
|
|
|
|
+ submenu "\$x" "\$x" {
|
|
|
|
+ set subvol="\$2/snapshot"
|
|
|
|
+ export subvol
|
|
|
|
+ source "${scanned_snapshot_cfg_dir}\${subvol}/${slave_cfg_name}"
|
|
|
|
+ }
|
2014-01-15 11:47:05 +01:00
|
|
|
+ fi
|
|
|
|
+ done
|
|
|
|
+ if [ x\$snapshot_found != xtrue ]; then
|
|
|
|
+ submenu "Not Found" {true}
|
|
|
|
+ fi
|
|
|
|
+}
|
|
|
|
+EOF
|
2014-01-17 13:38:35 +01:00
|
|
|
+
|
|
|
|
+fi
|
|
|
|
+
|