Compare commits

...

22 Commits
v1.11 ... 3.1

Author SHA1 Message Date
Antynea
b8325cf134 Fix: some functions doesn't work as expected (#48)
* Fix: Title format in grub-menu

function: 
- title_format , doesn't work as expected

replace print message with default parameter (p/d/n)

* Update header

- Add Github link
- Clear up some explanations

* Fix: path to grub-mkconfig_lib

. "$pkgdatadir/grub-mkconfig_lib" doesn't work on some distribution
Replaced by . "$datarootdir/grub/grub-mkconfig_lib"

* Fix: matches kernel & initramfs

matches kernel & initramfs doesn't work as expected
2018-04-19 15:45:59 +02:00
Antynea
c5da4014ae Update readme to v3.xx
Update readme to v3.xx

GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES="true" 
Doesn't exist anymore

GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker" "nosnapshot")
Delete "nosnapshot" it is confusing

New option available :
GRUB_BTRFS_DISABLE="true"
(Disable grub-btrfs)
2018-04-17 12:18:56 +02:00
Antynea
8508cac7d8 GRUB shouldn't break anymore (#46)
* Update 41_snapshots-btrfs

Enhanced error handling :
	- new function available: print_error
	- if btrfs-progs is not present, print a error and exit

New options in etc/default/grub 
	- disable this script
		
Enhanced menuentries:
	- menuentries is now store in new grub configfile (/boot/grub/grub.cfg)
	- use new functions for make a menuentry: make_menu_entries and entry
	- harmonize menuentry with matching version kernel&initramfs # initramfs-linux-fallback is include and not boot with intel-ucode if exist , same as original patch in GRUB for Arch Linux
	- make a menuentry in Grub menu (grub.cfg) to load our configfile

Enhanced /boot detection:
	- create two separate function for make menuentries, if /boot is on a separate partition, use function boot_separate, else, boot_bounded
	- if no kernel found, print a message and exit
	- if no initramfs found, print a message and exit

Delete function: boot_dir
No longer uses gettext_printf function of grub-mkconfig_lib

New function to detect kernel:
	- add all original standard kernel
	- verifying if kernel exist before to continue

New functionto  detect initramfs:
	- add all original standard initramfs
	- verifying if initramfs exist before to continue
	
New function to detect microcode

New counter:
	- add a counter to show a warning if the total menuentries made exceeds 250 entries

Purge some obsolete code

Size tabulation is now 4
2018-04-16 21:43:47 +02:00
Maxim Baz
a5a96fad08 Set default value of GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES to true 2018-04-06 16:28:36 +02:00
Maxim Baz
66a06be198 Set default value of GRUB_BTRFS_LIMIT to 50 2018-04-06 16:28:36 +02:00
Maxim Baz
c44eda0913 Skip ignored snapshots during generating entries, not after 2018-04-06 16:28:36 +02:00
Maxim Baz
f0b5d194c7 Add note about GRUB_BTRFS_SNAPPER_CONFIG to README 2018-04-01 21:50:13 +02:00
Maxim Baz
773a8bfb76 Support selecting snapper's config, default to 'root' (#41) 2018-04-01 21:38:22 +02:00
Antynea
1b40cfee20 Update 41_snapshots-btrfs
Update 41_snapshots-btrfs
2018-02-03 22:59:03 +01:00
Antynea
358dedc392 Update 41_snapshots-btrfs
Update 41_snapshots-btrfs
2018-02-03 22:57:04 +01:00
Antynea
55dc182b34 Update README.md 2018-02-03 22:31:43 +01:00
Nathan Parsons
23ddb063cb Add systemd service configuration for grub updating (#38)
* Add systemd service configuration for grub updating

This configuration file causes `update-grub` to be run after
Snapper's cleanup and timeline services are run by systemd

* Make invoked command more universal

* Note the need to run systemctl daemon-reload
2018-02-03 21:50:40 +01:00
Antynea
ca51d74265 Update README.md 2018-01-26 11:00:55 +01:00
Antynea
f8937a3fc7 Update README.md 2018-01-26 10:58:04 +01:00
Antynea
9265eb96de Update README.md 2018-01-26 10:55:45 +01:00
Antynea
72edee3d1c Update README.md 2018-01-26 10:54:37 +01:00
Antynea
d24ba197a8 Update README.md 2018-01-26 10:53:42 +01:00
Antynea
0e826391f1 Update 41_snapshots-btrfs 2018-01-26 09:19:33 +01:00
Antynea
7166d939fa Update README.md 2018-01-26 09:18:13 +01:00
Antynea
5cfbf46c8c fix Snapper id too long #36
* fix Snapper id too long #36
2018-01-07 00:31:16 +01:00
Antynea
12cb591307 Update README.md 2018-01-04 10:06:41 +01:00
Maxim Baz
49c64425eb Use snapper's snapshot description if available, fixes #34 (#35)
* Use snapper's snapshot description if available, fixes #34

* List snapper's snapshot from all configs

* fix: Title format in grub-menu, that didn't work as expected
2018-01-03 21:15:26 +01:00
3 changed files with 439 additions and 284 deletions

2
10-update_grub.conf Normal file
View File

@@ -0,0 +1,2 @@
[Service]
ExecStartPost=/usr/sbin/grub-mkconfig -o /boot/grub/grub.cfg

View File

@@ -1,76 +1,89 @@
#! /usr/bin/env bash
#
#
#################################################################################################################################################
# Written by: Antynea #
# #
# Purpose: Include btrfs snapshots at boot options (grub-menu). #
# #
# What this script does: #
# - Automatically List snapshots existing on root partition (btrfs). #
# - Automatically Detect if "/boot" is in separate partition. #
# - Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots. (For custon name, see below.) #
# - Automatically Create corresponding "menuentry" in grub.cfg , which ensures a very easy rollback. #
# #
# How to use it: #
# - Add this lines to /etc/default/grub: #
# #
# * GRUB_BTRFS_SUBMENUNAME="ArchLinux Snapshots" #
# (Name appearing in the Grub menu.) #
# * GRUB_BTRFS_PREFIXENTRY="Snapshot:" #
# (Add a name ahead your snapshots entries in the Grub menu.) #
# * GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="true" #
# (Show full path snapshot or only name in the Grub menu) #
# * GRUB_BTRFS_TITLE_FORMAT="p/d/n" #
# (Custom title, shows/hides p"prefix" d"date" n"name" in the Grub menu, separator "/", custom order available) #
# * GRUB_BTRFS_LIMIT="100" #
# (Limit the number of snapshots populated in the GRUB menu.) #
# * GRUB_BTRFS_SUBVOLUME_SORT="descending" #
# (Sort the found subvolumes by newest first ("descending") or oldest first ("ascending"). #
# If "ascending" is chosen then the $GRUB_BTRFS_LIMIT oldest subvolumes will populate the menu.) #
# * GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="true" #
# (Show snapshots found during run "grub-mkconfig") #
# * GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true" #
# (Show Total of snapshots found during run "grub-mkconfig") #
# * GRUB_BTRFS_NKERNEL=("vmlinuz-linux") #
# (Use only if you have custom kernel name or auto-detect failed.) #
# * GRUB_BTRFS_NINIT=("initramfs-linux.img" "initramfs-linux-fallback.img") #
# (Use only if you have custom initramfs name or auto-detect failed.) #
# * GRUB_BTRFS_INTEL_UCODE=("intel-ucode.img") #
# (Use only if you have custom intel-ucode or auto-detect failed.) #
# * GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker" "nosnapshot") #
# (Ignore specific path during run "grub-mkconfig") #
# * GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES="false" #
# (Create entries with matching version number instead of all possible combinations of kernel and initramfs) #
# #
# - Generate grub.cfg (on Archlinux use grub-mkconfig -o /boot/grub/grub.cfg) #
# #
# - grub-btrfs automatically generates snapshots entries. #
# - You will see it appear different entries (e.g : Snapshot: [2014-02-12 11:24:37] my snapshot name overkill) #
# #
# #
# To do: #
# #
# * Snapper support .... #
# #
#################################################################################################################################################
#########################################################################################################################################################################
# Written by: Antynea #
# BTC donation address: 1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt #
# Github: https://github.com/Antynea/grub-btrfs #
# #
# Purpose: Include btrfs snapshots at boot options (grub-menu). #
# #
# What this script does: #
# Simple rollback using snapshots you made previously. #
# - Automatically List snapshots existing on root partition (btrfs). #
# - Automatically Detect if "/boot" is in separate partition. #
# - Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots. #
# - Automatically Create corresponding "menuentry" in grub.cfg , which ensures a very easy rollback. #
# - Automatically detect snapper and use snapper's snapshot description if available. #
# #
# How to customize it: #
# - Add this lines to /etc/default/grub: #
# #
# * GRUB_BTRFS_SUBMENUNAME="Arch Linux snapshots" #
# (Name appearing in the Grub menu.) #
# * GRUB_BTRFS_PREFIXENTRY="Snapshot:" #
# (Add a name ahead your snapshots entries in the Grub menu.) #
# * GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="true" #
# (Show full path snapshot or only name in the Grub menu) #
# * GRUB_BTRFS_TITLE_FORMAT="p/d/n" #
# (Custom title, shows/hides p"prefix" d"date" n"name" in the Grub menu, separator "/", custom order available) #
# * GRUB_BTRFS_LIMIT="50" #
# (Limit the number of snapshots populated in the GRUB menu.) #
# * GRUB_BTRFS_SUBVOLUME_SORT="descending" #
# (Sort the found subvolumes by newest first ("descending") or oldest first ("ascending"). #
# If "ascending" is chosen then the $GRUB_BTRFS_LIMIT oldest subvolumes will populate the menu.) #
# * GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="true" #
# (Show snapshots found during run "grub-mkconfig") #
# * GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true" #
# (Show Total of snapshots found during run "grub-mkconfig") #
# * GRUB_BTRFS_NKERNEL=("vmlinuz-linux") #
# (Use only if you have custom kernel name.) #
# * GRUB_BTRFS_NINIT=("initramfs-linux.img" "initramfs-linux-fallback.img") #
# (Use only if you have custom initramfs name.) #
# * GRUB_BTRFS_INTEL_UCODE=("intel-ucode.img") #
# (Use only if you have custom intel-ucode.) #
# * GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker") #
# (Ignore specific path during run "grub-mkconfig") #
# * GRUB_BTRFS_SNAPPER_CONFIG="root" #
# (Snapper's config name to use) #
# * GRUB_BTRFS_DISABLE="false" #
# Disable Grub-btrfs (default=active) #
# #
# - Generate grub.cfg (on Arch Linux use grub-mkconfig -o /boot/grub/grub.cfg) #
# #
# - grub-btrfs automatically generates snapshots entries. #
# - You will see it appear different entries (e.g : Snapshot: [2014-02-12 11:24:37] my snapshot name overkill) #
# #
# Automatically update grub #
# If you would like grub to automatically update when Snapper timeline snapshots and cleanups occur, simply install 10-update_grub.conf in the following locations: #
# - /etc/systemd/system/snapper-timeline.service.d/ #
# - /etc/systemd/system/snapper-cleanup.service.d/ #
# Once the configuration files are in place, systemctl daemon-reload should be run to reload the units and make the changes active. #
# #
# Special thanks for assistance and contributions: #
# - My friends #
# - All contributors on Github #
# #
#########################################################################################################################################################################
set -e
#prefix="/usr"
#exec_prefix="${prefix}"
prefix="/usr"
exec_prefix="/usr"
datarootdir="/usr/share"
#datadir="${datarootdir}"
sysconfdir="/etc"
. "${datarootdir}/grub/grub-mkconfig_lib"
. "${sysconfdir}/default/grub"
. "$datarootdir/grub/grub-mkconfig_lib"
######################################
### Variables in /etc/default/grub ###
######################################
## Disable Grub-btrfs (default=active)
grub_btrfs_disable=${GRUB_BTRFS_DISABLE:-"false"}
[[ "${grub_btrfs_disable}" == "true" ]] && exit 0
## Submenu name
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"ArchLinux Snapshots"}
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"Arch Linux snapshots"}
## Prefix entry
prefixentry=${GRUB_BTRFS_PREFIXENTRY:-"Snapshot:"}
## Show full path snapshot or only name
@@ -83,8 +96,8 @@ nkernel=("${GRUB_BTRFS_NKERNEL[@]}")
ninit=("${GRUB_BTRFS_NINIT[@]}")
## Microcode(s) name(s)
microcode=("${GRUB_BTRFS_INTEL_UCODE[@]}")
## Limit to show in the Grub menu
limit_snap_show="${GRUB_BTRFS_LIMIT:-100}"
## Limit snapshots to show in the Grub menu
limit_snap_show="${GRUB_BTRFS_LIMIT:-50}"
## How to sort snapshots list
snap_list_sort=${GRUB_BTRFS_SUBVOLUME_SORT:-"descending"}
case "${snap_list_sort}" in
@@ -97,9 +110,8 @@ show_snap_found=${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}
show_total_snap_found=${GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND:-"true"}
## Ignore specific path during run "grub-mkconfig"
ignore_specific_path=("${GRUB_BTRFS_IGNORE_SPECIFIC_PATH[@]}")
## create only entries with harmonized version numbers
harmonized_entries=${GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES:-"false"}
## snapper's config name
snapper_config=${GRUB_BTRFS_SNAPPER_CONFIG:-"root"}
########################
### variables script ###
@@ -123,151 +135,205 @@ gbgmp=$(mktemp -d)
CLASS="--class snapshots --class gnu-linux --class gnu --class os"
## save IFS
oldIFS=$IFS
## boot_dir (auto-detect if /boot is separate partition or not)
boot_dir()
######################
### Error Handling ###
######################
print_error()
{
boot_dir="$gbgmp/$snap_dir_name/boot"
[[ "$root_uuid" != "$boot_uuid" ]] && boot_dir="/boot"
echo "$boot_dir"
local arg="$@"
local nothing_to_do="If you think an error has occurred , please file a bug report at \" https://github.com/Antynea/grub-btrfs \"\n# Nothing to do. Abort.\n###### - Grub-btrfs: Snapshot detection ended - ######\n"
printf "# ${arg}\n# ${nothing_to_do}" >&2 ;
exit 0
}
test_btrfs()
{
set +e
type btrfs >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
print_error "This script only supports snapshots of the btrfs filesystem, make sure you have btrfs-progs on your system."
fi
set -e
}
##############
### Script ###
##############
### BEGIN auto detect ###
## Create entry
entry() {
echo "$@" >> "/boot/grub/grub-btrfs.cfg"
# local arg="$@"
# echo "${arg}" >> "/boot/grub/grub-btrfs.cfg"
# cat << EOF >> "/boot/grub/grub-btrfs.cfg"
# ${arg}
# EOF
}
## menu entries
snapshots_entry()
make_menu_entries()
{
## \" required for snap,kernels,init,microcode with space in their name
echo " submenu '"${title_menu[*]}"' {
submenu '---> "${title_menu[*]}" <---' { echo }
"
entry "submenu '$title_menu' {
submenu '---> $title_menu <---' { echo }"
for k in "${name_kernel[@]}"; do
[[ ! -f "${boot_dir}"/"${k}" ]] && continue;
kversion=${k#*"-"}
for i in "${name_initramfs[@]}"; do
prefix_i=${i%%"-"*}
suffix_i=${i#*"-"}
alt_suffix_i=${i##*"-"}
if [ "${kversion}" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}.img" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}-fallback.img" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}.gz" = "${suffix_i}" ]; then i="${i}";
else continue ;
fi
for u in "${name_microcode[@]}"; do
if [ -f "$(boot_dir)"/"${u}" ] ; then
echo "\
menuentry '"${k}" & "${i}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid'{"
else
echo "\
menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid'{"
fi
echo "\
$(save_default_entry)
if [ x\$feature_all_video_module = xy ]; then
insmod all_video
fi
set gfxpayload=keep
insmod ${boot_fs}
if [ x\$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root ${hs_boot} ${boot_uuid}
else
search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
echo 'Loading Kernel: "${k}" ...'
linux \"${boot_dir_real_path}/"${k}"\" root=UUID=${root_uuid} rw rootflags=subvol=\""${snap_dir_name}"\" ${kernel_parameters}"
if [ -f "$(boot_dir)"/"${u}" ] ; then
echo "\
echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...'
initrd \"${boot_dir_real_path}/"${u}"\" \"${boot_dir_real_path}/"${i}"\""
else
echo "\
echo 'Loading Initramfs: "${i}" ...'
initrd \"${boot_dir_real_path}/"${i}"\""
fi
echo " }"
if [[ -f "${boot_dir}"/"${u}" && "${i}" != "${prefix_i}-${kversion}-${alt_suffix_i}" ]] ; then
entry "
menuentry '"${k}" & "${i}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid'{"
else
entry "
menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid'{"
fi
entry "\
if [ x\$feature_all_video_module = xy ]; then
insmod all_video
fi
set gfxpayload=keep
insmod ${boot_fs}
if [ x\$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root ${hs_boot} ${boot_uuid}
else
search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
echo 'Loading Kernel: "${k}" ...'
linux \"${boot_dir_root_grub}/"${k}"\" root=UUID=${root_uuid} rw rootflags=subvol=\""${snap_dir_name}"\" ${kernel_parameters}"
if [[ -f "${boot_dir}"/"${u}" && "${i}" != "${prefix_i}-${kversion}-${alt_suffix_i}" ]] ; then
entry "\
echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...'
initrd \"${boot_dir_root_grub}/"${u}"\" \"${boot_dir_root_grub}/"${i}"\""
else
entry "\
echo 'Loading Initramfs: "${i}" ...'
initrd \"${boot_dir_root_grub}/"${i}"\""
fi
entry " }"
count_warning_menuentries=$((1+$count_warning_menuentries))
done
done
done
echo " }"
entry "}"
}
harmonized_snapshots_entry()
{
## \" required for snap,kernels,init,microcode with space in their name
echo " submenu '"${title_menu[*]}"' {
submenu '---> "${title_menu[*]}" <---' { echo }
"
for k in "${name_kernel[@]}"; do
version=${k#vmlinuz-}
i=""
if [ -f "$(boot_dir)"/initramfs-"${version}".img ]; then
i=initramfs-${version}.img
else
if [ -f "$(boot_dir)"/initrd.img-"${version}" ]; then
i=initrd.img-${version}
fi
fi
for u in "${name_microcode[@]}"; do
if [ -f "$(boot_dir)"/"${u}" ] ; then
echo "\
menuentry '"${k}" & "${i}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid'{"
else
echo "\
menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid'{"
fi
echo "\
$(save_default_entry)
if [ x\$feature_all_video_module = xy ]; then
insmod all_video
fi
set gfxpayload=keep
insmod ${boot_fs}
if [ x\$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root ${hs_boot} ${boot_uuid}
else
search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
echo 'Loading Kernel: "${k}" ...'
linux \"${boot_dir_real_path}/"${k}"\" root=UUID=${root_uuid} rw rootflags=subvol=\""${snap_dir_name}"\" ${kernel_parameters}"
if [ -f "$(boot_dir)"/"${i}" ] ; then
if [ -f "$(boot_dir)"/"${u}" ] ; then
echo "\
echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...'
initrd \"${boot_dir_real_path}/"${u}"\" \"${boot_dir_real_path}/"${i}"\""
else
echo "\
echo 'Loading Initramfs: "${i}" ...'
initrd \"${boot_dir_real_path}/"${i}"\""
fi
fi
echo " }"
done
done
echo " }"
## Trim a string from leading and trailing whitespaces
trim() {
local var="$*"
var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
}
## List of snapshots on filesystem
snapshot_list()
{
# Query info from snapper if it is installed
type snapper >/dev/null 2>&1
if [[ $? -eq 0 ]]; then
local snapper_ids=($(snapper -t 0 -c "$snapper_config" list | tail -n +3 | cut -d'|' -f 2))
local snapper_types=($(snapper -t 0 -c "$snapper_config" list | tail -n +3 | cut -d'|' -f 1))
IFS=$'\n'
local snapper_descriptions=($(snapper -t 0 -c "$snapper_config" list | tail -n +3 | cut -d'|' -f 7))
fi
IFS=$'\n'
# Parse btrfs snapshots
local entries=()
local ids=()
local max_entry_length=0
for snap in $(btrfs subvolume list -sa "${btrfssubvolsort}" /); do
IFS=$oldIFS
snap=($snap)
local snap_path_name=${snap[@]:13:${#snap[@]}}
# Discard deleted snapshots
if [ "$snap_path_name" = "DELETED" ]; then continue; fi
[[ ${snap_path_name%%"/"*} == "<FS_TREE>" ]] && snap_path_name=${snap_path_name#*"/"}
echo ${snap[@]:10:2} ${snap_path_name}
# ignore specific path during run "grub-mkconfig"
if [ ! -z "${ignore_specific_path}" ] ; then
for isp in ${ignore_specific_path[@]} ; do
[[ "${snap_path_name}" == "${isp}"/* ]] && continue 2;
done
fi
# detect if /boot directory exists
[[ ! -d "$gbgmp/$snap_path_name/boot" ]] && continue;
local id="${snap_path_name//[!0-9]}" # brutal way to get id: remove everything non-numeric
ids+=("$id")
local entry="${snap[@]:10:2} | ${snap_path_name}"
entries+=("$entry")
# Find max length of a snapshot entry, needed for pretty formatting
local length="${#entry}"
[[ "$length" -gt "$max_entry_length" ]] && max_entry_length=$length
done
# Find max length of a snapshot type, needed for pretty formatting
local max_type_length=0
for id in "${ids[@]}"; do
for j in "${!snapper_ids[@]}"; do
local snapper_id="${snapper_ids[$j]//[[:space:]]/}"
if [[ "$snapper_id" == "$id" ]]; then
local snapper_type=$(trim "${snapper_types[$j]}")
local length="${#snapper_type}"
[[ "$length" -gt "$max_type_length" ]] && max_type_length=$length
fi
done
done
for i in "${!entries[@]}"; do
local id="${ids[$i]}"
local entry="${entries[$i]}"
for j in "${!snapper_ids[@]}"; do
local snapper_id="${snapper_ids[$j]//[[:space:]]/}"
if [[ "$snapper_id" == "$id" ]]; then
local snapper_type=$(trim "${snapper_types[$j]}")
local snapper_description=$(trim "${snapper_descriptions[$j]}")
printf -v entry "%-${max_entry_length}s | %-${max_type_length}s | %s" "$entry" "$snapper_type" "$snapper_description"
break
fi
done
echo "$entry"
done
IFS=$oldIFS
}
## Detect kernels in "/boot"
detect_kernel()
{
## Arch original kernel (auto-detect)
for akernel in "$(boot_dir)"/vmlinuz-* ; do
list_kernel+=("$akernel")
list_kernel=()
# Original kernel (auto-detect)
for okernel in "${boot_dir}"/vmlinuz-* \
"${boot_dir}"/vmlinux-* \
"${boot_dir}"/kernel-* ; do
[[ ! -f "${okernel}" ]] && continue;
list_kernel+=("$okernel")
done
## Custom name kernel in GRUB_BTRFS_NKERNEL
# Custom name kernel in GRUB_BTRFS_NKERNEL
if [ ! -z "${nkernel}" ] ; then
for ckernel in "${nkernel[@]}" ; do
[[ ! -f /"$(boot_dir)"/"${ckernel}" ]] && continue;
for ckernel in "${boot_dir}/${nkernel[@]}" ; do
[[ ! -f "${ckernel}" ]] && continue;
list_kernel+=("$ckernel")
done
fi
@@ -276,15 +342,21 @@ detect_kernel()
## Detect initramfs in "/boot"
detect_initramfs()
{
## Arch original initramfs (auto-detect)
for ainitramfs in "$(boot_dir)"/initramfs-* ; do
list_initramfs+=("$ainitramfs")
list_initramfs=()
# Original initramfs (auto-detect)
for oinitramfs in "${boot_dir}"/initrd.img-* \
"${boot_dir}"/initrd-*.img \
"${boot_dir}"/initrd-*.gz \
"${boot_dir}"/initramfs-*.img \
"${boot_dir}"/initramfs-*.gz ; do
[[ ! -f "${oinitramfs}" ]] && continue;
list_initramfs+=("$oinitramfs")
done
## Custom name initramfs in GRUB_BTRFS_NINIT
# Custom name initramfs in GRUB_BTRFS_NINIT
if [ ! -z "$ninit" ] ; then
for cinitramfs in "${ninit[@]}" ; do
[[ ! -f /"$(boot_dir)"/"${cinitramfs}" ]] && continue;
for cinitramfs in "${boot_dir}/${ninit[@]}" ; do
[[ ! -f "${cinitramfs}" ]] && continue;
list_initramfs+=("$cinitramfs")
done
fi
@@ -293,26 +365,29 @@ detect_initramfs()
## Detect microcode in "/boot"
detect_microcode()
{
## Arch original intel microcode
for aucode in "$(boot_dir)"/intel-ucode.img ; do
list_ucode+=("$aucode")
list_ucode=()
# Original intel microcode
for oiucode in "${boot_dir}"/intel-ucode.img ; do
[[ ! -f "${oiucode}" ]] && continue;
list_ucode+=("$oiucode")
done
## Custom name microcode in GRUB_BTRFS_INTEL_UCODE
# Custom name microcode in GRUB_BTRFS_INTEL_UCODE
if [ ! -z "$microcode" ] ; then
for cucode in "${microcode[@]}" ; do
[[ ! -f /"$(boot_dir)"/"${cucode}" ]] && continue
for cucode in "${boot_dir}/${microcode[@]}" ; do
[[ ! -f "${cucode}" ]] && continue
list_ucode+=("$cucode")
done
fi
if [ -z "${list_ucode}" ]; then list_ucode=(x); fi
}
## Show full path snapshot or only name
path_snapshot()
{
case "${path_snapshot}" in
true) name_snapshot=("${snap_dir_name}");;
*) name_snapshot=("${snap_dir_name#*"/"}")
true) name_snapshot=("${snap_full_name}");;
*) name_snapshot=("${snap_full_name#*"/"}")
esac
}
@@ -320,100 +395,156 @@ path_snapshot()
title_format()
{
case "${title_format}" in
p/d/n) title_menu=("${prefixentry}" "${snap_date_time}" "${name_snapshot}");;
p/n/d) title_menu=("${prefixentry}" "${snap_dir_name}" "${snap_date_time}");;
p/d) title_menu=("${prefixentry}" "${snap_date_time}");;
p/n) title_menu=("${prefixentry}" "${snap_dir_name}");;
d/n) title_menu=("${snap_date_time}" "${snap_dir_name}");;
n/d) title_menu=("${snap_dir_name}" "${snap_date_time}");;
p) title_menu=("${prefixentry}");;
d) title_menu=("${snap_date_time}");;
n) title_menu=("${snap_dir_name}");;
*) gettext_printf $"# Warning: GRUB_BTRFS_TITLE_FORMAT=${title_format}, syntax error \n" >&2
p/n/d) title_menu="${prefixentry} ${name_snapshot} ${snap_date_time}";;
p/d) title_menu="${prefixentry} ${snap_date_time}";;
p/n) title_menu="${prefixentry} ${name_snapshot}";;
d/n) title_menu="${snap_date_time} ${name_snapshot}";;
n/d) title_menu="${name_snapshot} ${snap_date_time}";;
p) title_menu="${prefixentry}";;
d) title_menu="${snap_date_time}";;
n) title_menu="${name_snapshot}";;
*) title_menu="${prefixentry} ${snap_date_time} ${name_snapshot}"
esac
}
## List of kernels, initramfs and microcode in snapshots
list_kernels_initramfs()
boot_bounded()
{
# Initialize menu entries
IFS=$'\n'
count_limit_snap=0
for item in $(snapshot_list); do
### fix: limit_snap_show=0
# fix: limit_snap_show=0
[[ ${limit_snap_show} -le 0 ]] && break;
IFS=$oldIFS
item=($item)
snap_dir_name=${item[@]:2:${#item[@]}}
### ignore specific path during run "grub-mkconfig"
if [ ! -z "${ignore_specific_path}" ] ; then
for isp in ${ignore_specific_path[@]} ; do
[[ "${gbgmp}"/"${snap_dir_name}" == "${gbgmp}"/"${isp}"/* ]] && continue 2;
done
fi
### detect if /boot directory exists
[[ ! -d "$gbgmp/$snap_dir_name/boot" ]] && continue;
### show snapshot found during run "grub-mkconfig"
snap_date_time=${item[@]:0:2}
if [[ "${show_snap_found}" = "true" ]]; then
gettext_printf $"# Found Snapshot: %s\n" "${snap_date_time} ${snap_dir_name}" >&2 ;
fi
### Kernel (auto-detect + custom kernel)
unset list_kernel
snap_full_name="$(echo "$item" | cut -d'|' -f2-)" # do not trim it to keep nice formatting
snap_dir_name="$(echo "$item" | cut -d'|' -f2)"
snap_dir_name="$(trim "$snap_dir_name")"
snap_date_time="$(echo "$item" | cut -d' ' -f1-2)"
snap_date_time="$(trim "$snap_date_time")"
boot_dir="$gbgmp/$snap_dir_name/boot"
# Kernel (Original + custom kernel)
detect_kernel
if [ -z "${list_kernel}" ]; then continue; fi
name_kernel=("${list_kernel[@]##*"/"}")
# echo "kernel = ${name_kernel[*]}"
if [[ "${harmonized_entries}" != "true" ]]; then
### Initramfs (autodetect + custom initramfs)
unset list_initramfs
detect_initramfs
name_initramfs=("${list_initramfs[@]##*"/"}")
# echo "initramfs = ${name_initramfs[*]}"
fi
### microcode (auto-detect + custom microcode)
unset list_ucode
# Initramfs (Original + custom initramfs)
detect_initramfs
if [ -z "${list_initramfs}" ]; then continue; fi
name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (intel-ucode + custom microcode)
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
# echo "ucode = ${name_microcode[*]}"
### real path to boot
boot_dir_real_path="$(make_system_path_relative_to_its_root "$(boot_dir)")"
### Create menu entries
## name snapshot
path_snapshot
## title menu custom
title_format
# echo "${title_menu[*]}"
if [[ "${harmonized_entries}" = "false" ]]; then
snapshots_entry
else
harmonized_snapshots_entry
# show snapshot found during run "grub-mkconfig"
if [[ "${show_snap_found}" = "true" ]]; then
printf $"# Found snapshot: %s\n" "$item" >&2 ;
fi
# Show full path snapshot or only name
path_snapshot
# Title format in grub-menu
title_format
# convert /boot directory to root of GRUB (e.g /boot become /)
boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")"
# Make menuentries
make_menu_entries
### Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+$count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break;
# Limit generation of menuentries if exceeds 250
# [[ $count_warning_menuentries -ge 250 ]] && break;
done
IFS=$oldIFS
}
boot_separate()
{
boot_dir="/boot"
# convert /boot directory to root of GRUB (e.g /boot become /)
boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")"
# Kernel (Original + custom kernel)
detect_kernel
if [ -z "${list_kernel}" ]; then print_error "Kernels not found."; fi
name_kernel=("${list_kernel[@]##*"/"}")
# Initramfs (Original + custom initramfs)
detect_initramfs
if [ -z "${list_initramfs}" ]; then print_error "Initramfs not found."; fi
name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode)
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
# Initialize menu entries
IFS=$'\n'
for item in $(snapshot_list); do
# fix: limit_snap_show=0
[[ ${limit_snap_show} -le 0 ]] && break;
IFS=$oldIFS
snap_full_name="$(echo "$item" | cut -d'|' -f2-)" # do not trim it to keep nice formatting
snap_dir_name="$(echo "$item" | cut -d'|' -f2)"
snap_dir_name="$(trim "$snap_dir_name")"
snap_date_time="$(echo "$item" | cut -d' ' -f1-2)"
snap_date_time="$(trim "$snap_date_time")"
# show snapshot found during run "grub-mkconfig"
if [[ "${show_snap_found}" = "true" ]]; then
printf $"# Found snapshot: %s\n" "$item" >&2 ;
fi
# Show full path snapshot or only name
path_snapshot
# Title format in grub-menu
title_format
# Make menuentries
make_menu_entries
# Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+$count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break;
# Limit generation of menuentries if exceeds 250
# [[ $count_warning_menuentries -ge 250 ]] && break;
done
IFS=$oldIFS
}
### END auto detect ###
### Start ###
gettext_printf "###### - Grub-btrfs: Auto-detect Start - ######\n" >&2 ;
### create mount point and mounts
[[ ! -d $gbgmp ]] && mkdir -p $gbgmp
mount -o subvolid=5 /dev/disk/by-uuid/$root_uuid $gbgmp/
### Create a menu in grub
echo "submenu '${submenuname}' {"
list_kernels_initramfs ;
## show total found snapshots
if [[ "${show_total_snap_found}" = "true" ]]; then
gettext_printf "# found ${count_limit_snap} snapshot(s)\n" >&2 ;
fi
## if no snapshot found, show a warning
if [[ "${count_limit_snap}" = "0" ]]; then
echo " submenu '---> "No snapshot found : Press ESC to return previous menu" <---' { echo } ";
gettext_printf "# No snapshot found \n# make sure you have at least one snapshot \n# or please file a bug report at \"https://github.com/Antynea/grub-btrfs\"\n" >&2 ;
fi
echo "}"
## unmount mount point
umount $gbgmp
gettext_printf "###### - Grub-btrfs: Auto-detect End - ######\n" >&2 ;
printf "###### - Grub-btrfs: Snapshot detection started - ######\n" >&2 ;
# if btrfs prog isn't installed, exit
test_btrfs
# Delete existing config
#rm -f --preserve-root "/boot/grub/grub-btrfs.cfg"
> "/boot/grub/grub-btrfs.cfg"
# Create mount point then mounting
[[ ! -d $gbgmp ]] && mkdir -p $gbgmp
mount -o subvolid=5 /dev/disk/by-uuid/$root_uuid $gbgmp/
# Count menuentries
count_warning_menuentries=0
# Count snapshots
count_limit_snap=0
# Detects if /boot is a separate partition
if [[ "$root_uuid" != "$boot_uuid" ]]; then
printf "# Info: Separate boot partition detected \n" >&2 ;
boot_separate
else
printf "# Info: Separate boot partition not detected \n" >&2 ;
boot_bounded
fi
# unmounting mount point
umount $gbgmp
# Show warn, menuentries exceeds 250 entries
[[ $count_warning_menuentries -ge 250 ]] && printf "# Generated ${count_warning_menuentries} total GRUB entries. You might experience issues loading snapshots menu in GRUB.\n" >&2 ;
# printf "# menuentries = $count_warning_menuentries \n" >&2 ;
# Show total found snapshots
if [[ "${show_total_snap_found}" = "true" && ! -z "${count_limit_snap}" && "${count_limit_snap}" != "0" ]]; then
printf "# Found ${count_limit_snap} snapshot(s)\n" >&2 ;
fi
# if no snapshot found, exit
if [[ "${count_limit_snap}" = "0" || -z "${count_limit_snap}" ]]; then
print_error "No snapshots found."
fi
root_grub="$(make_system_path_relative_to_its_root /boot/grub)"
# Make a submenu in GRUB (grub.cfg)
cat << EOF
submenu '${submenuname}' {
configfile "${root_grub}/grub-btrfs.cfg"
}
EOF
printf "###### - Grub-btrfs: Snapshot detection ended - ######\n" >&2 ;
### End ###

View File

@@ -1,14 +1,15 @@
[![GitHub release](https://img.shields.io/github/release/Antynea/grub-btrfs.svg)](https://github.com/Antynea/grub-btrfs)
### grub-btrfs
## grub-btrfs
This is a version 1.xx of grub-btrfs
#### Description
This is a version 3.xx of grub-btrfs
##### BTC donation address: 1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt
##
### Description
grub-btrfs, Include btrfs snapshots at boot options. (grub menu)
#### What does grub-btrfs v1.xx do :
##
### What does grub-btrfs v3.xx do :
Simple rollback using snapshots you made previously.
@@ -16,16 +17,18 @@ Simple rollback using snapshots you made previously.
* Automatically Detect if "/boot" is in separate partition.
* Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots. (For custom name, see below.)
* Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots.
* Automatically Create corresponding "menuentry" in grub.cfg , which ensures a very easy rollback.
* Automatically detect snapper and use snapper's snapshot description if available.
##
### How to customize it:
#### How to use it:
You have the possibility to modify many parameters.
Add this lines to /etc/default/grub:
* GRUB_BTRFS_SUBMENUNAME="ArchLinux Snapshots"
* GRUB_BTRFS_SUBMENUNAME="Arch Linux Snapshots"
(Name menu appearing in grub.)
@@ -35,25 +38,25 @@ Add this lines to /etc/default/grub:
* GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="true"
(Show full path snapshot or only name)
(Show full path snapshot or only name, weird reaction with snapper)
* GRUB_BTRFS_TITLE_FORMAT="p/d/n"
(Custom title, shows/hides p"prefix" d"date" n"name" in grub-menu, separator "/", custom order available)
* GRUB_BTRFS_NKERNEL=("vmlinuz-linux")
* GRUB_BTRFS_NKERNEL=("kernel-custom")
(Use only if you have a custom kernel name or auto-detect failed.)
(Use it only if you have a custom kernel name)
* GRUB_BTRFS_NINIT=("initramfs-linux.img" "initramfs-linux-fallback.img")
* GRUB_BTRFS_NINIT=("initramfs-custom.img" "initrd.img-custom")
(Use only if you have a custom initramfs name or auto-detect failed.)
(Use it only if you have a custom initramfs name)
* GRUB_BTRFS_INTEL_UCODE=("intel-ucode.img")
(Use only if you have custom intel-ucode or auto-detect failed.)
(Use it only if you have custom intel-ucode)
* GRUB_BTRFS_LIMIT="100"
* GRUB_BTRFS_LIMIT="50"
(Limit the number of snapshots populated in the GRUB menu.)
@@ -71,27 +74,46 @@ Add this lines to /etc/default/grub:
(Show Total number of snapshots found during run "grub-mkconfig")
* GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker" "nosnapshot")
* GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker")
(Ignore specific path during run "grub-mkconfig")
* GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES="false"
* GRUB_BTRFS_SNAPPER_CONFIG="root"
(Create entries with matching version number instead of all possible combinations of kernel and initramfs)
(Snapper's config name to use)
* GRUB_BTRFS_DISABLE="true"
(Disable grub-btrfs)
Generate grub.cfg (on Archlinux use grub-mkconfig -o /boot/grub/grub.cfg )
Generate grub.cfg (on Arch linux use grub-mkconfig -o /boot/grub/grub.cfg )
grub-btrfs automatically generates snapshots entries.
You will see it appear differents entries (e.g : Snapshot: [2014-02-12 11:24:37] my snapshot name overkill )
You will see it appear differents entries (e.g : Snapshot: 2018-01-03 15:08:41 @test1 )
##
### Automatically update grub
If you would like grub to automatically update when Snapper timeline snapshots and cleanups occur, simply install `10-update_grub.conf` in the following locations:
#### TO DO
- `/etc/systemd/system/snapper-timeline.service.d/`
- `/etc/systemd/system/snapper-cleanup.service.d/`
* Snapper support
Once the configuration files are in place, `systemctl daemon-reload` should be run to reload the units and make the changes active.
## discussion
##
### Discussion
Pour les francophones : https://forums.archlinux.fr/viewtopic.php?f=18&t=17177
##
### Special thanks for assistance and contributions
* [maximbaz](https://github.com/maximbaz)
* [crossroads1112](https://github.com/crossroads1112)
* [penetal](https://github.com/penetal)
* [wesbarnett](https://github.com/wesbarnett)
* [Psykar](https://github.com/Psykar)
* [anyc](https://github.com/anyc)
* [daftaupe](https://github.com/daftaupe)
* [N-Parsons](https://github.com/N-Parsons)
##