grub2/grub2-snapper-plugin.sh

282 lines
7.4 KiB
Bash

#!/bin/sh
set -e
# 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/>.
grub_mkconfig="/usr/sbin/grub2-mkconfig"
grub_mkrelpath="/usr/bin/grub2-mkrelpath"
grub_script_check="/usr/bin/grub2-script-check"
grub_setting="/etc/default/grub"
grub_cfg="/boot/grub2/grub.cfg"
grub_snapshot_cfg="/boot/grub2/snapshot_submenu.cfg"
snapper_snapshot_path="/.snapshots"
snapshot_submenu_name="grub-snapshot.cfg"
snapper_snapshots_cfg="${snapper_snapshot_path}/${snapshot_submenu_name}"
# add hotkeys for s390. (bnc#885668)
hotkey=
incr_hotkey()
{
[ -n "$hotkey" ] || return
expr $hotkey + 1
}
print_hotkey()
{
keys="123456789abdfgijklmnoprstuvwyz"
if [ -z "$hotkey" ]||[ $hotkey -eq 0 ]||[ $hotkey -gt 30 ]; then
return
fi
echo "--hotkey=$(expr substr $keys $hotkey 1)"
}
snapshot_submenu () {
s_dir="$1"
snapshot="${s_dir}/snapshot"
num="`basename $s_dir`"
# bnc#864842 Important snapshots are not marked as such in grub2 menu
# the format is "important distribution version (kernel_version, timestamp, pre/post)"
date=`xmllint --xpath '/snapshot/date/text()' "${s_dir}/info.xml" || echo ""`
date=`echo $date | sed 's/\(.*\) \(.*\):.*/\1T\2/'`
important=`xmllint --xpath "/snapshot/userdata[key='important']/value/text()" "${s_dir}/info.xml" 2>/dev/null || echo ""`
stype=`xmllint --xpath '/snapshot/type/text()' "${s_dir}/info.xml" || echo ""`
kernel_ver=`readlink ${snapshot}/boot/vmlinuz | sed -e 's/^vmlinuz-//' -e 's/-default$//'`
if [ -z "$kernel_ver" -a -L ${snapshot}/boot/image ]; then
kernel_ver=`readlink ${snapshot}/boot/image | sed -e 's/^image-//' -e 's/-default$//'`
fi
eval `cat ${snapshot}/etc/os-release`
# bsc#934252 - Replace SLES 12.1 with SLES12-SP1 for the list of snapshots
if test "${NAME}" = "SLES" -o "${NAME}" = "SLED"; then
VERSION=`echo ${VERSION} | sed -e 's!^\([0-9]\{1,\}\)\.\([0-9]\{1,\}\)$!\1-SP\2!'`
fi
# FATE#318101
# Show user defined comments in grub2 menu for snapshots
# Use userdata tag "bootloader=[user defined text]"
full_desc=`xmllint --xpath "/snapshot/userdata[key='bootloader']/value/text()" "${s_dir}/info.xml" 2>/dev/null || echo ""`
test -z "$full_desc" && desc=`xmllint --xpath '/snapshot/description/text()' "${s_dir}/info.xml" 2>/dev/null || echo ""`
# FATE#317972
# If we have a post entry and the description field is empty,
# we should use the "Pre" number and add that description to the post entry.
if test -z "$full_desc" -a -z "$desc" -a "$stype" = "post"; then
pre_num=`xmllint --xpath '/snapshot/pre_num/text()' "${s_dir}/info.xml" 2>/dev/null || echo ""`
if test -n "$pre_num"; then
if test -f "${snapper_snapshot_path}/${pre_num}/info.xml" ; then
desc=`xmllint --xpath '/snapshot/description/text()' "${snapper_snapshot_path}/${pre_num}/info.xml" 2>/dev/null || echo ""`
fi
fi
fi
test "$important" = "yes" && important="*" || important=" "
test "$stype" = "single" && stype=""
test -z "$stype" || stype=",$stype"
test -z "$desc" || desc=",$desc"
test -z "$full_desc" && full_desc="$kernel_ver,$date$stype$desc"
if test "${NAME}" = "SLES" -o "${NAME}" = "SLED"; then
title="${important}${NAME}${VERSION} ($full_desc)"
else
title="${important}${NAME} ${VERSION} ($full_desc)"
fi
if test "$s390" = "1"; then
subvol="\$2"
else
subvol="\$3"
fi
cat <<EOF
if [ -f "${snapper_snapshot_path}/$num/snapshot/boot/grub2/grub.cfg" ]; then
snapshot_found=true
saved_subvol=\$btrfs_subvol
menuentry `print_hotkey` "$title" "${snapper_snapshot_path}/$num/snapshot" "`$grub_mkrelpath ${snapper_snapshot_path}/${num}/snapshot`" {
btrfs_subvol="$subvol"
extra_cmdline="rootflags=subvol=\$3"
export extra_cmdline
snapshot_num=$num
export snapshot_num
configfile "\$2/boot/grub2/grub.cfg"
btrfs_subvol=\$saved_subvol
}
fi
EOF
hotkey=`incr_hotkey`
return 0
}
snapper_snapshots_cfg_refresh () {
if [ ! -d "$snapper_snapshot_path" ]; then
return
fi
cs=
for s_dir in ${snapper_snapshot_path}/*; do
snapshot="${s_dir}/snapshot"
# list only read-only snapshot (bnc#878528)
if [ ! -d ${s_dir} -o -w "$snapshot" ]; then
continue
fi
if [ -r "${s_dir}/info.xml" -a -r "${s_dir}/snapshot/boot/grub2/grub.cfg" ]; then
cs="${s_dir}
${cs}"
else
# cleanup any grub-snapshot.cfg without associated snapshot info
snapper_cfg="${s_dir}/${snapshot_submenu_name}"
if [ -f "$snapper_cfg" ]; then
rm -f "$snapper_cfg"
rmdir "$s_dir" 2>/dev/null || true
fi
continue
fi
done
hk=""
[ -z "$hotkey" ] || hk="--hotkey=s"
for c in $(printf '%s' "${cs}" | sort -Vr); do
if ! snapshot_submenu "$c" > "${c}/${snapshot_submenu_name}"; then
rm -f "${c}/${snapshot_submenu_name}"
continue
fi
snapshot_cfg="${snapshot_cfg}
if [ -f \"$c/${snapshot_submenu_name}\" ]; then
source \"$c/${snapshot_submenu_name}\"
fi"
done
cat <<EOF >"${snapper_snapshots_cfg}.new"
if [ -z "\$extra_cmdline" ]; then
submenu $hk "Start bootloader from a read-only snapshot" {${snapshot_cfg}
if [ x\$snapshot_found != xtrue ]; then
submenu "Not Found" { true; }
fi
}
fi
EOF
if ${grub_script_check} "${snapper_snapshots_cfg}.new"; then
mv -f "${snapper_snapshots_cfg}.new" "${snapper_snapshots_cfg}"
fi
}
snapshot_submenu_clean () {
for s_dir in ${snapper_snapshot_path}/*; do
snapper_cfg="${s_dir}/${snapshot_submenu_name}"
if [ -f "$snapper_cfg" ]; then
rm -f "$snapper_cfg"
rmdir "$s_dir" 2>/dev/null || true
fi
done
if [ -f "${snapper_snapshot_path}/${snapshot_submenu_name}" ]; then
rm -f "${snapper_snapshot_path}/${snapshot_submenu_name}"
fi
}
set_grub_setting () {
name=$1
val=$2
if grep -q "$name" "$grub_setting"; then
sed -i -e "s!.*\($name\)=.*!\1=\"$val\"!" "$grub_setting"
else
echo "$name=\"$val\"" >> "$grub_setting"
fi
}
enable_grub_settings () {
set_grub_setting SUSE_BTRFS_SNAPSHOT_BOOTING "true"
}
disable_grub_settings () {
set_grub_setting SUSE_BTRFS_SNAPSHOT_BOOTING "false"
}
update_grub () {
"${grub_mkconfig}" -o "${grub_cfg}"
}
machine=`uname -m`
case "$machine" in
(s390|s390x)
hotkey=1
s390=1
;;
esac
cmdline="$0 $* hotkey='$hotkey'"
# Check the arguments.
while test $# -gt 0
do
option=$1
shift
case "$option" in
-e | --enable)
opt_enable=true
;;
-d | --disable)
opt_enable=false
;;
-r | --refresh)
opt_refresh=true
;;
-c | --clean)
opt_clean=true
;;
-*)
;;
esac
done
if [ "x${opt_enable}" = "xtrue" ]; then
#enable_grub_settings
#update_grub
snapper_snapshots_cfg_refresh
elif [ "x${opt_enable}" = "xfalse" ]; then
#disable_grub_settings
update_grub
snapshot_submenu_clean
fi
if [ x${opt_refresh} = "xtrue" ]; then
snapper_snapshots_cfg_refresh
fi
if [ x${opt_clean} = "xtrue" ]; then
snapshot_submenu_clean
fi