Compare commits

..

24 Commits

Author SHA1 Message Date
Pascal Jäger
2886ad7b3c fix bashisms
Signed-off-by: Pascal Jäger <pascal.jaeger@leimstift.de>
2024-03-28 10:00:33 +01:00
Pascal J
72a3dc092b Merge pull request #325 from aidan-gibson/master
Fix RAID
2024-03-27 18:16:20 +01:00
Aidan Gibson
6cb200a50b Fix RAID 2024-03-24 19:11:54 -07:00
Pascal J
346a9868b8 Merge pull request #318 from expoodo/yabsnap_info_support
add support for yabsnap snapshot information
2024-03-06 14:48:24 +01:00
Pascal Jäger
b8465d14db fix spelling 2024-03-06 14:43:57 +01:00
Pascal J
0bc09317d8 Merge branch 'master' into yabsnap_info_support 2024-03-06 14:41:49 +01:00
Pascal J
94d742d1d4 Merge pull request #311 from bastien-roucaries/fix_bashism
Fix bashism
2024-03-06 14:24:44 +01:00
Pascal Jäger
363d7da3a7 fix typo uper -> upper 2024-03-06 14:23:26 +01:00
expoodo
585268dad7 Merge branch 'Antynea:master' into yabsnap_info_support 2024-02-19 15:18:18 -05:00
expoodo
34b54de71c removed redundant array slice 2024-02-19 15:16:26 -05:00
expoodo
a8713bbd0b mention yabsnap 2024-02-19 15:12:38 -05:00
Pascal Jäger
ac45f09af3 do not install compressed manpages
Fix #317

Signed-off-by: Pascal Jäger <pascal.jaeger@leimstift.de>
2024-02-19 14:59:57 +01:00
expoodo
d41991979e add support for yabsnap snapshots info 2024-02-18 20:24:13 -05:00
Pascal J
99fc835e9c Merge pull request #305 from felixonmars/patch-1
Update Arch Linux package URL in README.md
2024-01-29 10:45:04 +01:00
Pascal J
5e608f8d96 Merge pull request #309 from yarikoptic/enh-codespell
Add codespell support (config, workflow to alert on new typos) + make it fix typos
2024-01-29 10:44:42 +01:00
Bastien Roucariès
465b56107f Add double quote if needed 2024-01-27 17:42:06 +00:00
Bastien Roucariès
7aa227b378 Fix 41_snapshots-btrs bashish [[ ]] 2024-01-27 17:38:55 +00:00
Yaroslav Halchenko
4ff82352bb Fix indentation after codespell 2023-12-21 19:25:54 -05:00
Yaroslav Halchenko
98a5bbe8c5 [DATALAD RUNCMD] run codespell throughout fixing typo automagically
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "codespell -w",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^
2023-12-21 19:25:13 -05:00
Yaroslav Halchenko
abd2889464 [DATALAD RUNCMD] Do interactive fixing of some ambigous typos
=== Do not change lines below ===
{
 "chain": [],
 "cmd": "codespell -w -i 3 -C 2 ./grub-btrfsd",
 "exit": 0,
 "extra_inputs": [],
 "inputs": [],
 "outputs": [],
 "pwd": "."
}
^^^ Do not change lines above ^^^
2023-12-21 19:25:10 -05:00
Yaroslav Halchenko
25a9876ad4 Add rudimentary codespell config 2023-12-21 19:24:42 -05:00
Yaroslav Halchenko
d82ee289c3 Add github action to codespell master on push and PRs 2023-12-21 19:24:13 -05:00
Felix Yan
ef150c17bb Update Arch Linux package URL in README.md
The old URL returns 404 now.
2023-11-21 16:42:56 +02:00
Brian Morison
490720a13c Update grub-btrfsd (#289)
fix grub.cfg path in grub submenu creation
2023-07-26 21:18:10 +02:00
10 changed files with 164 additions and 107 deletions

6
.codespellrc Normal file
View File

@@ -0,0 +1,6 @@
[codespell]
skip = .git,*.pdf,*.svg,go.sum,.codespellrc
check-hidden = true
# ignore-regex =
# ist -- unfortunate variable
ignore-words-list = ist

22
.github/workflows/codespell.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
---
name: Codespell
on:
push:
branches: [master]
pull_request:
branches: [master]
permissions:
contents: read
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Codespell
uses: codespell-project/actions-codespell@v2

View File

@@ -1,4 +1,4 @@
#! /usr/bin/env bash #! /usr/bin/env sh
# #
# Written by: Antynea # Written by: Antynea
# BTC donation address: 1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt # BTC donation address: 1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt
@@ -41,14 +41,16 @@ set -e
sysconfdir="/etc" sysconfdir="/etc"
grub_btrfs_config="${sysconfdir}/default/grub-btrfs/config" grub_btrfs_config="${sysconfdir}/default/grub-btrfs/config"
[[ -f "$grub_btrfs_config" ]] && . "$grub_btrfs_config" # shellcheck disable=SC1090
[[ -f "${sysconfdir}/default/grub" ]] && . "${sysconfdir}/default/grub" [ -f "$grub_btrfs_config" ] && . "$grub_btrfs_config"
# shellcheck disable=SC1091
[ -f "${sysconfdir}/default/grub" ] && . "${sysconfdir}/default/grub"
## Error Handling ## Error Handling
print_error() print_error()
{ {
local err_msg="$*" err_msg="$*"
local bug_report="If you think an error has occurred, please file a bug report at \"https://github.com/Antynea/grub-btrfs\"" bug_report="If you think an error has occurred, please file a bug report at \"https://github.com/Antynea/grub-btrfs\""
printf "%s\n" "${err_msg}" "${bug_report}" >&2 ; printf "%s\n" "${err_msg}" "${bug_report}" >&2 ;
exit 0 exit 0
} }
@@ -75,15 +77,17 @@ while getopts :V-: opt; do
done done
## Exit the script, if: ## Exit the script, if:
[[ "${GRUB_BTRFS_DISABLE,,}" == "true" ]] && print_error "GRUB_BTRFS_DISABLE is set to true (default=false)" [ "$(echo "$GRUB_BTRFS_DISABLE" | tr '[:upper:]' '[:lower:]')" = 'true' ] && print_error "GRUB_BTRFS_DISABLE is set to true (default=false)"
if ! type btrfs >/dev/null 2>&1; then print_error "btrfs-progs isn't installed"; fi if ! type btrfs >/dev/null 2>&1; then print_error "btrfs-progs isn't installed"; fi
[[ -f "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" ]] && . "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" || print_error "grub-mkconfig_lib couldn't be found" # shellcheck disable=SC1090,SC2015
[[ "$(btrfs filesystem df / 2>&1)" == *"not a btrfs filesystem"* ]] && print_error "Root filesystem isn't btrfs" [ -f "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" ] && . "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" || print_error "grub-mkconfig_lib couldn't be found"
# shellcheck disable=SC2005
if echo "$(btrfs filesystem df / 2>&1)" | grep "not a btrfs filesystem" >/dev/null 2>&1; then print_error "Root filesystem isn't btrfs"; fi
printf "Detecting snapshots ...\n" >&2 ; printf "Detecting snapshots ...\n" >&2 ;
## Submenu name ## Submenu name
distro=$(awk -F "=" '/^NAME=/ {gsub(/"/, "", $2); print $2}' /etc/os-release) distro=$(awk -F "=" '/^NAME=/ {gsub(/"/, "", $2); print $2}' /etc/os-release) # escape '
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"${distro:-Linux} snapshots"} submenuname=${GRUB_BTRFS_SUBMENUNAME:-"${distro:-Linux} snapshots"}
## Limit snapshots to show in the Grub menu (default=50) ## Limit snapshots to show in the Grub menu (default=50)
limit_snap_show="${GRUB_BTRFS_LIMIT:-50}" limit_snap_show="${GRUB_BTRFS_LIMIT:-50}"
@@ -99,7 +103,7 @@ grub_btrfs_directory=${GRUB_BTRFS_GBTRFS_DIRNAME:-${grub_directory}}
grub_btrfs_search_directory=${GRUB_BTRFS_GBTRFS_SEARCH_DIRNAME:-"\${prefix}"} grub_btrfs_search_directory=${GRUB_BTRFS_GBTRFS_SEARCH_DIRNAME:-"\${prefix}"}
## Password protection management for submenu ## Password protection management for submenu
# Protection support for submenu (--unrestricted) # Protection support for submenu (--unrestricted)
case "${GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU,,}" in case "$(echo "$GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU" | tr '[:upper:]' '[:lower:]')" in
true) unrestricted_access_submenu="--unrestricted ";; true) unrestricted_access_submenu="--unrestricted ";;
*) unrestricted_access_submenu="" *) unrestricted_access_submenu=""
esac esac
@@ -108,18 +112,30 @@ if [ -n "${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS}" ] ; then
protection_authorized_users="--users ${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS} " protection_authorized_users="--users ${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS} "
fi fi
## Probe informations of Root and Boot devices ## Probe information of Root and Boot devices
# Probe info "Root partition" # Probe info "Root partition"
# shellcheck disable=SC2154 # grub_probe is provided by grub environment
root_device=$(${grub_probe} --target=device /) # Root device root_device=$(${grub_probe} --target=device /) # Root device
# shellcheck disable=SC2086 # we actually need word splitting here if we have several root devices (e.g. RAID)
root_uuid=$(${grub_probe} --device ${root_device} --target="fs_uuid" 2>/dev/null) # UUID of the root device root_uuid=$(${grub_probe} --device ${root_device} --target="fs_uuid" 2>/dev/null) # UUID of the root device
root_uuid_subvolume=$(btrfs subvolume show / 2>/dev/null) || print_error "UUID of the root subvolume is not available"; # If UUID of root subvolume is not available, then exit root_uuid_subvolume=$(btrfs subvolume show / 2>/dev/null) || print_error "UUID of the root subvolume is not available"; # If UUID of root subvolume is not available, then exit
root_uuid_subvolume=$(awk -F":" 'match($1, /(^[ \t]+UUID)/) {sub(/^[ \t]+/, "", $2); print $2}' <<< "$root_uuid_subvolume") # UUID of the root subvolume root_uuid_subvolume=$(awk -F":" 'match($1, /(^[ \t]+UUID)/) {sub(/^[ \t]+/, "", $2); print $2}' <<EOF
"$root_uuid_subvolume"
EOF
) # UUID of the root subvolume '
# Probe info "Boot partition" # Probe info "Boot partition"
# shellcheck disable=SC2086 # we actually need word splitting here if we have several devices
boot_device=$(${grub_probe} --target=device ${boot_directory}) # Boot device boot_device=$(${grub_probe} --target=device ${boot_directory}) # Boot device
# shellcheck disable=SC2086 # we actually need word splitting here if we have several devices
boot_uuid=$(${grub_probe} --device ${boot_device} --target="fs_uuid" 2>/dev/null) # UUID of the boot device boot_uuid=$(${grub_probe} --device ${boot_device} --target="fs_uuid" 2>/dev/null) # UUID of the boot device
boot_uuid_subvolume=$(btrfs subvolume show "$boot_directory" 2>/dev/null) || boot_uuid_subvolume=" UUID: $root_uuid_subvolume"; # If boot folder isn't a subvolume, then UUID=root_uuid_subvolume boot_uuid_subvolume=$(btrfs subvolume show "$boot_directory" 2>/dev/null) || boot_uuid_subvolume=" UUID: $root_uuid_subvolume"; # If boot folder isn't a subvolume, then UUID=root_uuid_subvolume
boot_uuid_subvolume=$(awk -F":" 'match($1, /(^[ \t]+UUID)/) {sub(/^[ \t]+/, "", $2); print $2}' <<< "$boot_uuid_subvolume") # UUID of the boot subvolume boot_uuid_subvolume=$(awk -F":" 'match($1, /(^[ \t]+UUID)/) {sub(/^[ \t]+/, "", $2); print $2}' <<EOF
"$boot_uuid_subvolume"
EOF
) # UUID of the boot subvolume '
# shellcheck disable=SC2086 # we actually need word splitting here if we have several devices
boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null) # hints string boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null) # hints string
# shellcheck disable=SC2086 # we actually need word splitting here if we have several devices
boot_fs=$(${grub_probe} --device ${boot_device} --target="fs" 2>/dev/null) # Type filesystem of boot device boot_fs=$(${grub_probe} --device ${boot_device} --target="fs" 2>/dev/null) # Type filesystem of boot device
## Parameters passed to the kernel ## Parameters passed to the kernel
@@ -143,16 +159,16 @@ fi
## Detect rootflags ## Detect rootflags
detect_rootflags() detect_rootflags()
{ {
local fstabflags=$(grep -oE '^\s*[^#][[:graph:]]+\s+/\s+btrfs\s+[[:graph:]]+' "${grub_btrfs_mount_point}/${snap_dir_name_trim}/etc/fstab" \ fstabflags=$(grep -oE '^\s*[^#][[:graph:]]+\s+/\s+btrfs\s+[[:graph:]]+' "${grub_btrfs_mount_point}/${snap_dir_name_trim}/etc/fstab" \
| sed -E 's/^.*[[:space:]]([[:graph:]]+)$/\1/;s/,?subvol(id)?=[^,$]+//g;s/^,//') | sed -E 's/^.*[[:space:]]([[:graph:]]+)$/\1/;s/,?subvol(id)?=[^,$]+//g;s/^,//')
rootflags="rootflags=${fstabflags:+$fstabflags,}${GRUB_BTRFS_ROOTFLAGS:+$GRUB_BTRFS_ROOTFLAGS,}" rootflags="rootflags=${fstabflags:+$fstabflags,}${GRUB_BTRFS_ROOTFLAGS:+$GRUB_BTRFS_ROOTFLAGS,}"
} }
unmount_grub_btrfs_mount_point() unmount_grub_btrfs_mount_point()
{ {
if [[ -d "$grub_btrfs_mount_point" ]]; then if [ -d "$grub_btrfs_mount_point" ]; then
local wait=true wait=true
local wait_max=0 wait_max=0
printf "Unmount %s .." "$grub_btrfs_mount_point" >&2; printf "Unmount %s .." "$grub_btrfs_mount_point" >&2;
while $wait; do while $wait; do
if grep -qs "$grub_btrfs_mount_point" /proc/mounts; then if grep -qs "$grub_btrfs_mount_point" /proc/mounts; then
@@ -160,7 +176,7 @@ if [[ -d "$grub_btrfs_mount_point" ]]; then
if umount "$grub_btrfs_mount_point" >/dev/null 2>&1; then if umount "$grub_btrfs_mount_point" >/dev/null 2>&1; then
wait=false # umount successful wait=false # umount successful
printf " Success\n" >&2; printf " Success\n" >&2;
elif [[ $wait_max = 10 ]]; then elif [ $wait_max -eq 10 ]; then
printf "\nWarning: Unable to unmount %s in %s\n" "$root_device" "$grub_btrfs_mount_point" >&2; printf "\nWarning: Unable to unmount %s in %s\n" "$root_device" "$grub_btrfs_mount_point" >&2;
break; break;
else else
@@ -172,9 +188,9 @@ if [[ -d "$grub_btrfs_mount_point" ]]; then
printf " Success\n" >&2; printf " Success\n" >&2;
fi fi
done done
if [[ "$wait" != true ]]; then if [ "$wait" != true ]; then
if ! rm -d "$grub_btrfs_mount_point" >/dev/null 2>&1; then if ! rm -d "$grub_btrfs_mount_point" >/dev/null 2>&1; then
printf "Unable to delete %s: Device or ressource is busy\n" "$grub_btrfs_mount_point" >&2; printf "Unable to delete %s: Device or resource is busy\n" "$grub_btrfs_mount_point" >&2;
fi fi
fi fi
fi fi
@@ -193,13 +209,14 @@ make_menu_entries()
entry "submenu '${title_menu}' { entry "submenu '${title_menu}' {
submenu '${title_submenu}' { echo }" submenu '${title_submenu}' { echo }"
for k in "${name_kernel[@]}"; do for k in "${name_kernel[@]}"; do
[[ ! -f "${boot_dir}"/"${k}" ]] && continue; [ ! -f "${boot_dir}"/"${k}" ] && continue;
kversion=${k#*"-"} kversion=${k#*"-"}
for i in "${name_initramfs[@]}"; do for i in "${name_initramfs[@]}"; do
if [[ "${name_initramfs}" != "x" ]] ; then if [ "${name_initramfs}" != "x" ] ; then
# prefix_i=${i%%"-"*} # prefix_i=${i%%"-"*}
suffix_i=${i#*"-"} suffix_i=${i#*"-"}
# alt_suffix_i=${i##*"-"} # alt_suffix_i=${i##*"-"}
# shellcheck disable=SC2269 # this is a way to exit the if..elif..
if [ "${kversion}" = "${suffix_i}" ]; then i="${i}"; if [ "${kversion}" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}.img" = "${suffix_i}" ]; then i="${i}"; elif [ "${kversion}.img" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}-fallback.img" = "${suffix_i}" ]; then i="${i}"; elif [ "${kversion}-fallback.img" = "${suffix_i}" ]; then i="${i}";
@@ -207,7 +224,7 @@ make_menu_entries()
else continue; else continue;
fi fi
for u in "${name_microcode[@]}"; do for u in "${name_microcode[@]}"; do
if [[ "${name_microcode}" != "x" ]] ; then if [ "${name_microcode}" != "x" ] ; then
entry " entry "
menuentry ' "${k}" & "${i}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {" menuentry ' "${k}" & "${i}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
else else
@@ -228,7 +245,7 @@ make_menu_entries()
echo 'Loading Snapshot: "${snap_date_trim}" "${snap_dir_name_trim}"' echo 'Loading Snapshot: "${snap_date_trim}" "${snap_dir_name_trim}"'
echo 'Loading Kernel: "${k}" ...' echo 'Loading Kernel: "${k}" ...'
linux \"${boot_dir_root_grub}/"${k}"\" root="${LINUX_ROOT_DEVICE}" ${kernel_parameters} ${rootflags}subvol=\""${snap_dir_name_trim}"\"" linux \"${boot_dir_root_grub}/"${k}"\" root="${LINUX_ROOT_DEVICE}" ${kernel_parameters} ${rootflags}subvol=\""${snap_dir_name_trim}"\""
if [[ "${name_microcode}" != "x" ]] ; then if [ "${name_microcode}" != "x" ] ; then
entry "\ entry "\
echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...' echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...'
initrd \"${boot_dir_root_grub}/"${u}"\" \"${boot_dir_root_grub}/"${i}"\"" initrd \"${boot_dir_root_grub}/"${u}"\" \"${boot_dir_root_grub}/"${i}"\""
@@ -242,7 +259,7 @@ make_menu_entries()
done done
else else
for u in "${name_microcode[@]}"; do for u in "${name_microcode[@]}"; do
if [[ "${name_microcode}" != "x" ]] ; then if [ "${name_microcode}" != "x" ] ; then
entry " entry "
menuentry ' "${k}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {" menuentry ' "${k}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
else else
@@ -263,7 +280,7 @@ make_menu_entries()
echo 'Loading Snapshot: "${snap_date_trim}" "${snap_dir_name_trim}"' echo 'Loading Snapshot: "${snap_date_trim}" "${snap_dir_name_trim}"'
echo 'Loading Kernel: "${k}" ...' echo 'Loading Kernel: "${k}" ...'
linux \"${boot_dir_root_grub}/"${k}"\" root="${LINUX_ROOT_DEVICE}" ${kernel_parameters} ${rootflags}subvol=\""${snap_dir_name_trim}"\"" linux \"${boot_dir_root_grub}/"${k}"\" root="${LINUX_ROOT_DEVICE}" ${kernel_parameters} ${rootflags}subvol=\""${snap_dir_name_trim}"\""
if [[ "${name_microcode}" != "x" ]] ; then if [ "${name_microcode}" != "x" ] ; then
entry "\ entry "\
echo 'Loading Microcode: "${u}" ...' echo 'Loading Microcode: "${u}" ...'
initrd \"${boot_dir_root_grub}/"${u}"\"" initrd \"${boot_dir_root_grub}/"${u}"\""
@@ -279,21 +296,21 @@ make_menu_entries()
## Trim a string from leading and trailing whitespaces ## Trim a string from leading and trailing whitespaces
trim() { trim() {
local var="$*" var="$*"
var="${var#"${var%%[![:space:]]*}"}" var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}" var="${var%"${var##*[![:space:]]}"}"
echo -n "$var" printf '%s' "$var"
} }
## List of snapshots on filesystem ## List of snapshots on filesystem
snapshot_list() snapshot_list()
{ {
local snapper_info="info.xml" snapper_info="info.xml"
local timeshift_info="info.json" timeshift_info="info.json"
local date_snapshots=() date_snapshots=()
local path_snapshots=() path_snapshots=()
local type_snapshots=() type_snapshots=()
local description_snapshots=() description_snapshots=()
IFS=$'\n' IFS=$'\n'
for snap in $(btrfs subvolume list -sa "${btrfs_subvolume_sort}" /); do # Parse btrfs snapshots for snap in $(btrfs subvolume list -sa "${btrfs_subvolume_sort}" /); do # Parse btrfs snapshots
IFS=$oldIFS IFS=$oldIFS
@@ -305,7 +322,7 @@ snapshot_list()
# ignore specific path during run "grub-mkconfig" # ignore specific path during run "grub-mkconfig"
if [ -n "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH}" ] ; then if [ -n "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH}" ] ; then
for isp in "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH[@]}" ; do for isp in "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH[@]}" ; do
[[ "${path_snapshot}" == "${isp}" ]] && continue 2; [ "${path_snapshot}" = "${isp}" ] && continue 2;
done done
fi fi
if [ -n "${GRUB_BTRFS_IGNORE_PREFIX_PATH}" ] ; then if [ -n "${GRUB_BTRFS_IGNORE_PREFIX_PATH}" ] ; then
@@ -313,30 +330,39 @@ snapshot_list()
[[ "${path_snapshot}" == "${isp}"/* ]] && continue 2; [[ "${path_snapshot}" == "${isp}"/* ]] && continue 2;
done done
fi fi
[[ ! -d "$grub_btrfs_mount_point/$path_snapshot/boot" ]] && continue; # Discard snapshots without /boot folder [ ! -d "$grub_btrfs_mount_point/$path_snapshot/boot" ] && continue; # Discard snapshots without /boot folder
# Parse Snapper & timeshift informations # Parse Snapper & timeshift & yabsnap information
local type_snapshot="N/A" local type_snapshot="N/A"
local description_snapshot="N/A" local description_snapshot="N/A"
# path to yabsnap snapshot meta data
local yabsnap_info
yabsnap_info="$grub_btrfs_mount_point/${path_snapshot%"/"*}/$(echo "${snap[13]}" | awk -F'/' '{print $3 "-meta.json"}')"
if [[ -s "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$snapper_info" ]] ; then if [[ -s "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$snapper_info" ]] ; then
type_snapshot=$(awk -F"<|>" 'match($2, /^type/) {print $3}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$snapper_info") # search matching string beginning "type" type_snapshot=$(awk -F"<|>" 'match($2, /^type/) {print $3}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$snapper_info") # search matching string beginning "type"
description_snapshot=$(awk -F"<|>" 'match($2, /^description/) {print $3}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$snapper_info") # search matching string beginning "description" description_snapshot=$(awk -F"<|>" 'match($2, /^description/) {print $3}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$snapper_info") # search matching string beginning "description"
elif [[ -s "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$timeshift_info" ]] ; then elif [[ -s "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$timeshift_info" ]] ; then
type_snapshot=$(awk -F" : " 'match($1, /^[ \t]+"tags"/) {gsub(/"|,/,"");print $2}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$timeshift_info") # search matching string beginning "tags" type_snapshot=$(awk -F" : " 'match($1, /^[ \t]+"tags"/) {gsub(/"|,/,"");print $2}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$timeshift_info") # search matching string beginning "tags"
description_snapshot=$(awk -F" : " 'match($1, /^[ \t]+"comments"/) {gsub(/"|,/,"");print $2}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$timeshift_info") # search matching string beginning "comments" description_snapshot=$(awk -F" : " 'match($1, /^[ \t]+"comments"/) {gsub(/"|,/,"");print $2}' "$grub_btrfs_mount_point/${path_snapshot%"/"*}/$timeshift_info") # search matching string beginning "comments" fix '
elif [[ -s $yabsnap_info ]] ; then
type_snapshot=$(grep -P '^\s*"trigger"' $yabsnap_info | awk -F'"' '{print $4}') # search matching string beginning "trigger"
description_snapshot=$(grep -P '^\s*"comment"' $yabsnap_info | awk -F'"' '{print $4}') # search matching string beginning "comment"
fi fi
[[ -z "$type_snapshot" ]] && type_snapshot=("N/A")
[[ -z "$description_snapshot" ]] && description_snapshot=("N/A") [ -z "$type_snapshot" ] && type_snapshot=("N/A")
[ -z "$description_snapshot" ] && description_snapshot=("N/A")
# ignore specific {type,tag,description} of snapshot during run "grub-mkconfig" # ignore specific {type,tag,description} of snapshot during run "grub-mkconfig"
if [ -n "${GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE}" ] ; then if [ -n "${GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE}" ] ; then
for ist in "${GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE[@]}" ; do for ist in "${GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE[@]}" ; do
[[ "${type_snapshot}" == "${ist}" ]] && continue 2; [ "${type_snapshot}" = "${ist}" ] && continue 2;
done done
fi fi
if [ -n "${GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION}" ] ; then if [ -n "${GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION}" ] ; then
for isd in "${GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION[@]}" ; do for isd in "${GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION[@]}" ; do
[[ "${description_snapshot}" == "${isd}" ]] && continue 2; [ "${description_snapshot}" = "${isd}" ] && continue 2;
done done
fi fi
@@ -351,21 +377,21 @@ snapshot_list()
local max_date_length=0 local max_date_length=0
for i in "${date_snapshots[@]}"; do for i in "${date_snapshots[@]}"; do
local length="${#i}" local length="${#i}"
[[ "$length" -gt "$max_date_length" ]] && max_date_length=$length [ "$length" -gt "$max_date_length" ] && max_date_length=$length
done done
# Find max length of a snapshot name, needed for pretty formatting # Find max length of a snapshot name, needed for pretty formatting
local max_path_length=0 local max_path_length=0
for i in "${path_snapshots[@]}"; do for i in "${path_snapshots[@]}"; do
local length="${#i}" local length="${#i}"
[[ "$length" -gt "$max_path_length" ]] && max_path_length=$length [ "$length" -gt "$max_path_length" ] && max_path_length=$length
done done
# Find max length of a snapshot type, needed for pretty formatting # Find max length of a snapshot type, needed for pretty formatting
local max_type_length=0 local max_type_length=0
for i in "${type_snapshots[@]}"; do for i in "${type_snapshots[@]}"; do
local length="${#i}" local length="${#i}"
[[ "$length" -gt "$max_type_length" ]] && max_type_length=$length [ "$length" -gt "$max_type_length" ] && max_type_length=$length
done done
# Find max length of a snapshot description, needed for pretty formatting # Find max length of a snapshot description, needed for pretty formatting
@@ -391,30 +417,31 @@ parse_snapshot_list()
snap_dir_name="$(echo "$item" | cut -d'|' -f2)" # column_2 snap_dir_name="$(echo "$item" | cut -d'|' -f2)" # column_2
snap_dir_name_trim="$(trim "$snap_dir_name")" snap_dir_name_trim="$(trim "$snap_dir_name")"
snap_snapshot="$snap_dir_name" # Used by "title_format" function # shellcheck disable=SC2034 # Used by "title_format" function
snap_snapshot="$snap_dir_name"
# shellcheck disable=SC2034 # Used by "title_format" function
snap_type="$(echo "$item" | cut -d'|' -f3)" # column_3 snap_type="$(echo "$item" | cut -d'|' -f3)" # column_3
# shellcheck disable=SC2034 # Used by "title_format" function
snap_description="$(echo "$item" | cut -d'|' -f4)" # column_4 snap_description="$(echo "$item" | cut -d'|' -f4)" # column_4
} }
## Detect kernels in "boot_directory" ## Detect kernels in "boot_directory"
detect_kernel() detect_kernel()
{ {
list_kernel=() list_kernel=""
# Original kernel (auto-detect) # Original kernel (auto-detect)
for okernel in "${boot_dir}"/vmlinuz-* \ for okernel in "${boot_dir}"/vmlinuz-* \
"${boot_dir}"/vmlinux-* \ "${boot_dir}"/vmlinux-* \
"${boot_dir}"/kernel-* ; do "${boot_dir}"/kernel-* ; do
[[ ! -f "${okernel}" ]] && continue; [ ! -f "${okernel}" ] && continue;
list_kernel+=("$okernel") list_kernel="${list_kernel} $okernel"
done done
# Custom name kernel in "GRUB_BTRFS_NKERNEL" # Custom name kernel in "GRUB_BTRFS_NKERNEL"
if [ -n "${GRUB_BTRFS_NKERNEL}" ] ; then if [ -n "${GRUB_BTRFS_NKERNEL}" ] ; then
for ckernel in "${boot_dir}/${GRUB_BTRFS_NKERNEL[@]}" ; do for ckernel in "${boot_dir}"/${GRUB_BTRFS_NKERNEL} ; do
[[ ! -f "${ckernel}" ]] && continue; [ ! -f "${ckernel}" ] && continue;
list_kernel+=("$ckernel") list_kernel="${list_kernel} $okernel"
done done
fi fi
} }
@@ -427,14 +454,14 @@ detect_initramfs()
for oinitramfs in "${boot_dir}"/initrd.img-* \ for oinitramfs in "${boot_dir}"/initrd.img-* \
"${boot_dir}"/initramfs-* \ "${boot_dir}"/initramfs-* \
"${boot_dir}"/initrd-* ; do "${boot_dir}"/initrd-* ; do
[[ ! -f "${oinitramfs}" ]] && continue; [ ! -f "${oinitramfs}" ] && continue;
list_initramfs+=("$oinitramfs") list_initramfs+=("$oinitramfs")
done done
# Custom name initramfs in "GRUB_BTRFS_NINIT" # Custom name initramfs in "GRUB_BTRFS_NINIT"
if [ -n "${GRUB_BTRFS_NINIT}" ] ; then if [ -n "${GRUB_BTRFS_NINIT}" ] ; then
for cinitramfs in "${boot_dir}/${GRUB_BTRFS_NINIT[@]}" ; do for cinitramfs in "${boot_dir}/${GRUB_BTRFS_NINIT[@]}" ; do
[[ ! -f "${cinitramfs}" ]] && continue; [ ! -f "${cinitramfs}" ] && continue;
list_initramfs+=("$cinitramfs") list_initramfs+=("$cinitramfs")
done done
fi fi
@@ -453,14 +480,14 @@ detect_microcode()
"${boot_dir}"/amd-ucode.img \ "${boot_dir}"/amd-ucode.img \
"${boot_dir}"/early_ucode.cpio \ "${boot_dir}"/early_ucode.cpio \
"${boot_dir}"/microcode.cpio; do "${boot_dir}"/microcode.cpio; do
[[ ! -f "${oiucode}" ]] && continue; [ ! -f "${oiucode}" ] && continue;
list_ucode+=("$oiucode") list_ucode+=("$oiucode")
done done
# Custom name microcode in "GRUB_BTRFS_CUSTOM_MICROCODE" # Custom name microcode in "GRUB_BTRFS_CUSTOM_MICROCODE"
if [ -n "${GRUB_BTRFS_CUSTOM_MICROCODE}" ] ; then if [ -n "${GRUB_BTRFS_CUSTOM_MICROCODE}" ] ; then
for cucode in "${boot_dir}/${GRUB_BTRFS_CUSTOM_MICROCODE[@]}" ; do for cucode in "${boot_dir}/${GRUB_BTRFS_CUSTOM_MICROCODE[@]}" ; do
[[ ! -f "${cucode}" ]] && continue [ ! -f "${cucode}" ] && continue
list_ucode+=("$cucode") list_ucode+=("$cucode")
done done
fi fi
@@ -473,7 +500,7 @@ title_format()
{ {
title_menu="|" # "|" is for visuals only title_menu="|" # "|" is for visuals only
title_submenu="|" # "|" is for visuals only title_submenu="|" # "|" is for visuals only
[[ -z "${GRUB_BTRFS_TITLE_FORMAT}" ]] && GRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description"); # Default parameters [ -z "${GRUB_BTRFS_TITLE_FORMAT}" ] && GRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description"); # Default parameters
for key in "${!GRUB_BTRFS_TITLE_FORMAT[@]}"; do for key in "${!GRUB_BTRFS_TITLE_FORMAT[@]}"; do
[[ ${GRUB_BTRFS_TITLE_FORMAT[$key],,} != "${title_column[${GRUB_BTRFS_TITLE_FORMAT[$key]}],,}" ]] && continue; # User used wrong parameter [[ ${GRUB_BTRFS_TITLE_FORMAT[$key],,} != "${title_column[${GRUB_BTRFS_TITLE_FORMAT[$key]}],,}" ]] && continue; # User used wrong parameter
declare -n var="snap_${GRUB_BTRFS_TITLE_FORMAT[$key],,}" # $var is a indirect variable declare -n var="snap_${GRUB_BTRFS_TITLE_FORMAT[$key],,}" # $var is a indirect variable
@@ -488,15 +515,15 @@ title_format()
# Adds a header to the grub-btrfs.cfg file # Adds a header to the grub-btrfs.cfg file
header_menu() header_menu()
{ {
local header_entry="" header_entry=""
[[ -z "${GRUB_BTRFS_TITLE_FORMAT}" ]] && GRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description"); # Default parameters [ -z "${GRUB_BTRFS_TITLE_FORMAT}" ] && GRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description"); # Default parameters
for key in "${!GRUB_BTRFS_TITLE_FORMAT[@]}"; do for key in "${!GRUB_BTRFS_TITLE_FORMAT[@]}"; do
[[ ${GRUB_BTRFS_TITLE_FORMAT[$key],,} != "${title_column[${GRUB_BTRFS_TITLE_FORMAT[$key]}],,}" ]] && continue; # User used wrong parameter [[ ${GRUB_BTRFS_TITLE_FORMAT[$key],,} != "${title_column[${GRUB_BTRFS_TITLE_FORMAT[$key]}],,}" ]] && continue; # User used wrong parameter
declare -n var="snap_${GRUB_BTRFS_TITLE_FORMAT[$key],,}" # $var is a indirect variable declare -n var="snap_${GRUB_BTRFS_TITLE_FORMAT[$key],,}" # $var is a indirect variable
# Center alignment, needed for pretty formatting # Center alignment, needed for pretty formatting
local lenght_title_column_left=$((${#var}-${#title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]})) local lenght_title_column_left=$((${#var}-${#title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]}))
((lenght_title_column_left%2)) && lenght_title_column_left=$((lenght_title_column_left+1)); # If the difference is an odd number, add an extra space ((lenght_title_column_left%2)) && lenght_title_column_left=$((lenght_title_column_left+1)); # If the difference is an odd number, add an extra space
lenght_title_column_left=$((((lenght_title_column_left/2)+${#title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]}))); lenght_title_column_left=$(((lenght_title_column_left/2)+${#title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]}));
local lenght_title_column_right=$(((${#var}-lenght_title_column_left)+1)) #+1 is necessary for extra "|" character local lenght_title_column_right=$(((${#var}-lenght_title_column_left)+1)) #+1 is necessary for extra "|" character
header_entry+=$(printf "%${lenght_title_column_left}s%${lenght_title_column_right}s" "${title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]}" "|") # Final "|" is for visuals only header_entry+=$(printf "%${lenght_title_column_left}s%${lenght_title_column_right}s" "${title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]}" "|") # Final "|" is for visuals only
done done
@@ -509,12 +536,13 @@ boot_bounded()
# Initialize menu entries # Initialize menu entries
IFS=$'\n' IFS=$'\n'
for item in $(snapshot_list); do for item in $(snapshot_list); do
[[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0 [ "${limit_snap_show}" -le 0 ] && break; # fix: limit_snap_show=0
IFS=$oldIFS IFS=$oldIFS
parse_snapshot_list parse_snapshot_list
boot_dir="$grub_btrfs_mount_point/$snap_dir_name_trim$boot_directory" boot_dir="$grub_btrfs_mount_point/$snap_dir_name_trim$boot_directory"
detect_kernel detect_kernel
if [ -z "${list_kernel}" ]; then continue; fi if [ -z "${list_kernel}" ]; then continue; fi
# TODO
name_kernel=("${list_kernel[@]##*"/"}") name_kernel=("${list_kernel[@]##*"/"}")
detect_initramfs detect_initramfs
name_initramfs=("${list_initramfs[@]##*"/"}") name_initramfs=("${list_initramfs[@]##*"/"}")
@@ -525,12 +553,12 @@ boot_bounded()
boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")" # convert "boot_directory" to root of GRUB (e.g /boot become /) boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")" # convert "boot_directory" to root of GRUB (e.g /boot become /)
make_menu_entries make_menu_entries
# show snapshot found during run "grub-mkconfig" # show snapshot found during run "grub-mkconfig"
if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]]; then if [ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]; then
printf "Found snapshot: %s\n" "$item" >&2 ; printf "Found snapshot: %s\n" "$item" >&2 ;
fi fi
# Limit snapshots found during run "grub-mkconfig" # Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+count_limit_snap)) count_limit_snap=$((1+count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break; [ "$count_limit_snap" -ge "$limit_snap_show" ] && break;
done done
IFS=$oldIFS IFS=$oldIFS
} }
@@ -550,19 +578,19 @@ boot_separate()
# Initialize menu entries # Initialize menu entries
IFS=$'\n' IFS=$'\n'
for item in $(snapshot_list); do for item in $(snapshot_list); do
[[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0 [ "${limit_snap_show}" -le 0 ] && break; # fix: limit_snap_show=0
IFS=$oldIFS IFS=$oldIFS
parse_snapshot_list parse_snapshot_list
detect_rootflags detect_rootflags
title_format title_format
make_menu_entries make_menu_entries
# show snapshot found during run "grub-mkconfig" # show snapshot found during run "grub-mkconfig"
if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]]; then if [ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]; then
printf "Found snapshot: %s\n" "$item" >&2 ; printf "Found snapshot: %s\n" "$item" >&2 ;
fi fi
# Limit snapshots found during run "grub-mkconfig" # Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+count_limit_snap)) count_limit_snap=$((1+count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break; [ "$count_limit_snap" -ge "$limit_snap_show" ] && break;
done done
IFS=$oldIFS IFS=$oldIFS
} }
@@ -574,15 +602,15 @@ if [ -e "$grub_btrfs_directory/grub-btrfs.cfg" ]; then
mv -f "$grub_btrfs_directory/grub-btrfs.cfg" "$grub_btrfs_directory/grub-btrfs.cfg.bkp" mv -f "$grub_btrfs_directory/grub-btrfs.cfg" "$grub_btrfs_directory/grub-btrfs.cfg.bkp"
fi fi
# Create mount point then mounting # Create mount point then mounting
[[ ! -d $grub_btrfs_mount_point ]] && mkdir -p "$grub_btrfs_mount_point" [ ! -d "$grub_btrfs_mount_point" ] && mkdir -p "$grub_btrfs_mount_point"
mount -o ro,subvolid=5 /dev/disk/by-uuid/"$root_uuid" "$grub_btrfs_mount_point/" > /dev/null mount -o ro,subvolid=5 /dev/disk/by-uuid/"$root_uuid" "$grub_btrfs_mount_point/" > /dev/null
trap "unmount_grub_btrfs_mount_point" EXIT # unmounting mount point on EXIT signal trap "unmount_grub_btrfs_mount_point" EXIT # unmounting mount point on EXIT signal
count_warning_menuentries=0 # Count menuentries count_warning_menuentries=0 # Count menuentries
count_limit_snap=0 # Count snapshots count_limit_snap=0 # Count snapshots
check_uuid_required check_uuid_required
# Detects if /boot is a separate partition # Detects if /boot is a separate partition
[[ "${GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION,,}" == "true" ]] && printf "Override boot partition detection : enable \n" >&2 && boot_separate; [ "$(echo "$GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION}" | tr '[:upper:]' '[:lower:]')" = "true" ] && printf "Override boot partition detection : enable \n" >&2 && boot_separate;
if [[ "$root_uuid" != "$boot_uuid" ]] || [[ "$root_uuid_subvolume" != "$boot_uuid_subvolume" ]]; then boot_separate ; else boot_bounded ; fi if [ "$root_uuid" != "$boot_uuid" ] || [ "$root_uuid_subvolume" != "$boot_uuid_subvolume" ]; then boot_separate ; else boot_bounded ; fi
# Make a submenu in GRUB (grub.cfg) # Make a submenu in GRUB (grub.cfg)
cat << EOF cat << EOF
if [ ! -e "${grub_btrfs_search_directory}/grub-btrfs.cfg" ]; then if [ ! -e "${grub_btrfs_search_directory}/grub-btrfs.cfg" ]; then
@@ -594,18 +622,19 @@ submenu '${submenuname}' ${protection_authorized_users}${unrestricted_access_sub
fi fi
EOF EOF
# Show warn, menuentries exceeds 250 entries # Show warn, menuentries exceeds 250 entries
[[ $count_warning_menuentries -ge 250 ]] && printf "Generated %s total GRUB entries. You might experience issues loading snapshots menu in GRUB.\n" "${count_warning_menuentries}" >&2 ; [ $count_warning_menuentries -ge 250 ] && printf "Generated %s total GRUB entries. You might experience issues loading snapshots menu in GRUB.\n" "${count_warning_menuentries}" >&2 ;
# Show total found snapshots # Show total found snapshots
if [[ "${GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND:-"true"}" = "true" && -n "${count_limit_snap}" && "${count_limit_snap}" != "0" ]]; then if [ "${GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND:-"true"}" = "true" ] && [ -n "${count_limit_snap}" ] && [ "${count_limit_snap}" != "0" ]; then
printf "Found %s snapshot(s)\n" "${count_limit_snap}" >&2 ; printf "Found %s snapshot(s)\n" "${count_limit_snap}" >&2 ;
fi fi
# if no snapshot found, delete the "$grub_btrfs_directory/grub-btrfs.new" file and the "$grub_btrfs_directory/grub-btrfs.cfg.bkp" file and exit # if no snapshot found, delete the "$grub_btrfs_directory/grub-btrfs.new" file and the "$grub_btrfs_directory/grub-btrfs.cfg.bkp" file and exit
if [[ "${count_limit_snap}" = "0" || -z "${count_limit_snap}" ]]; then if [ "${count_limit_snap}" = "0" ] || [ -z "${count_limit_snap}" ]; then
rm -f "$grub_btrfs_directory/grub-btrfs.new" "$grub_btrfs_directory/grub-btrfs.cfg.bkp" rm -f "$grub_btrfs_directory/grub-btrfs.new" "$grub_btrfs_directory/grub-btrfs.cfg.bkp"
print_error "No snapshots found." print_error "No snapshots found."
fi fi
# Move "grub-btrfs.new" to "grub-btrfs.cfg" # Move "grub-btrfs.new" to "grub-btrfs.cfg"
header_menu header_menu
# shellcheck disable=SC2154 # bindir is provided by grub environment
if "${bindir}/${GRUB_BTRFS_SCRIPT_CHECK:-grub-script-check}" "$grub_btrfs_directory/grub-btrfs.new"; then if "${bindir}/${GRUB_BTRFS_SCRIPT_CHECK:-grub-script-check}" "$grub_btrfs_directory/grub-btrfs.new"; then
cat "$grub_btrfs_directory/grub-btrfs.new" > "$grub_btrfs_directory/grub-btrfs.cfg" cat "$grub_btrfs_directory/grub-btrfs.new" > "$grub_btrfs_directory/grub-btrfs.cfg"
rm -f "$grub_btrfs_directory/grub-btrfs.new" "$grub_btrfs_directory/grub-btrfs.cfg.bkp" rm -f "$grub_btrfs_directory/grub-btrfs.new" "$grub_btrfs_directory/grub-btrfs.cfg.bkp"

View File

@@ -44,13 +44,11 @@ install:
@cp manpages/grub-btrfs.8.man ${TEMP_DIR}/grub-btrfs.8 @cp manpages/grub-btrfs.8.man ${TEMP_DIR}/grub-btrfs.8
@if test "$(INSTALL_DOCS)" = true; then \ @if test "$(INSTALL_DOCS)" = true; then \
echo "Installing manpages..."; \ echo "Installing manpages..."; \
bzip2 ${TEMP_DIR}/grub-btrfs.8; \ install -Dm644 -t "${MAN_DIR}/man8" "${TEMP_DIR}/grub-btrfs.8"; \
install -Dm644 -t "${MAN_DIR}/man8" "${TEMP_DIR}/grub-btrfs.8.bz2"; \
fi fi
@cp manpages/grub-btrfsd.8.man ${TEMP_DIR}/grub-btrfsd.8 @cp manpages/grub-btrfsd.8.man ${TEMP_DIR}/grub-btrfsd.8
@if test "$(INSTALL_DOCS)" = true; then \ @if test "$(INSTALL_DOCS)" = true; then \
bzip2 ${TEMP_DIR}/grub-btrfsd.8; \ install -Dm644 -t "${MAN_DIR}/man8" "${TEMP_DIR}/grub-btrfsd.8"; \
install -Dm644 -t "${MAN_DIR}/man8" "${TEMP_DIR}/grub-btrfsd.8.bz2"; \
fi fi
@install -Dm755 -t "$(DESTDIR)/etc/grub.d/" 41_snapshots-btrfs @install -Dm755 -t "$(DESTDIR)/etc/grub.d/" 41_snapshots-btrfs
@install -Dm644 -t "$(DESTDIR)/etc/default/grub-btrfs/" config @install -Dm644 -t "$(DESTDIR)/etc/default/grub-btrfs/" config
@@ -147,7 +145,7 @@ help:
@echo " BOOT_DIR_FEDORA | path | boot data location (Fedora, RHEL, CentOS, Rocky...) | '/boot/grub2'" @echo " BOOT_DIR_FEDORA | path | boot data location (Fedora, RHEL, CentOS, Rocky...) | '/boot/grub2'"
@echo " SHARE_DIR | path | shared data location | '\$$(DESTDIR)\$$(PREFIX)/share'" @echo " SHARE_DIR | path | shared data location | '\$$(DESTDIR)\$$(PREFIX)/share'"
@echo " LIB_DIR | path | system libraries location | '\$$(DESTDIR)\$$(PREFIX)/lib'" @echo " LIB_DIR | path | system libraries location | '\$$(DESTDIR)\$$(PREFIX)/lib'"
@echo " PKGNAME | name | name of the ditributed package | 'grub-btrfs'" @echo " PKGNAME | name | name of the distributed package | 'grub-btrfs'"
@echo " INITCPIO | bool | include mkinitcpio hook | false" @echo " INITCPIO | bool | include mkinitcpio hook | false"
@echo " SYSTEMD | bool | include unit files | true" @echo " SYSTEMD | bool | include unit files | true"
@echo " OPENRC | bool | include OpenRc daemon | false" @echo " OPENRC | bool | include OpenRc daemon | false"

View File

@@ -8,7 +8,7 @@
### 🔎 Description: ### 🔎 Description:
grub-btrfs improves the grub bootloader by adding a btrfs snapshots sub-menu, allowing the user to boot into snapshots. grub-btrfs improves the grub bootloader by adding a btrfs snapshots sub-menu, allowing the user to boot into snapshots.
grub-btrfs supports manual snapshots as well as snapper and timeshift created snapshots. grub-btrfs supports manual snapshots as well as snapper, timeshift, and yabsnap created snapshots.
##### Warning: booting read-only snapshots can be tricky ##### Warning: booting read-only snapshots can be tricky
@@ -25,13 +25,13 @@ Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/i
* Automatically detect if `/boot` is in a separate partition. * Automatically detect if `/boot` is in a separate partition.
* Automatically detect kernel, initramfs and Intel/AMD microcode in `/boot` directory within snapshots. * Automatically detect kernel, initramfs and Intel/AMD microcode in `/boot` directory within snapshots.
* Automatically create corresponding menu entries in `grub.cfg` * Automatically create corresponding menu entries in `grub.cfg`
* Automatically detect the type/tags and descriptions/comments of Snapper/Timeshift snapshots. * Automatically detect the type/tags/triggers and descriptions/comments of Snapper/Timeshift/Yabsnap snapshots.
* Automatically generate `grub.cfg` if you use the provided Systemd/ OpenRC service. * Automatically generate `grub.cfg` if you use the provided Systemd/ OpenRC service.
- - - - - -
### 🛠️ Installation: ### 🛠️ Installation:
#### Arch Linux #### Arch Linux
The package is available in the community repository [grub-btrfs](https://archlinux.org/packages/community/any/grub-btrfs/) The package is available in the extra repository [grub-btrfs](https://archlinux.org/packages/extra/any/grub-btrfs/)
``` ```
pacman -S grub-btrfs pacman -S grub-btrfs
``` ```
@@ -65,7 +65,7 @@ Booting into read-only snapshots is fully supported when choosing btrfs as the f
* [grub](https://archlinux.org/packages/core/x86_64/grub/) * [grub](https://archlinux.org/packages/core/x86_64/grub/)
* [bash >4](https://archlinux.org/packages/core/x86_64/bash/) * [bash >4](https://archlinux.org/packages/core/x86_64/bash/)
* [gawk](https://archlinux.org/packages/core/x86_64/gawk/) * [gawk](https://archlinux.org/packages/core/x86_64/gawk/)
* (only when using the grub-btrfsd daemon)[inotify-tools](https://archlinux.org/packages/community/x86_64/inotify-tools/) * (only when using the grub-btrfsd daemon)[inotify-tools](https://archlinux.org/packages/extra/x86_64/inotify-tools/)
- - - - - -
### 📚 Manual usage of grub-btrfs ### 📚 Manual usage of grub-btrfs
@@ -75,7 +75,7 @@ To manually generate grub snapshot entries you can run `sudo /etc/grub.d/41_snap
* On **Fedora** use `grub2-mkconfig -o /boot/grub2/grub.cfg` * On **Fedora** use `grub2-mkconfig -o /boot/grub2/grub.cfg`
* On **Debian and Ubuntu based** distributions `update-grub` is a script that runs `grub-mkconfig ...` * On **Debian and Ubuntu based** distributions `update-grub` is a script that runs `grub-mkconfig ...`
This process can be automated to occur whenever you create or delete snaphots but this process is slightly different depending upon your distributions choice on init system. See the relevant instructions for your init system below. This process can be automated to occur whenever you create or delete snapshots but this process is slightly different depending upon your distributions choice on init system. See the relevant instructions for your init system below.
### ⚙️ Customization: ### ⚙️ Customization:
@@ -97,7 +97,7 @@ The daemon can be configured by passing different command line arguments to it.
The available arguments are: The available arguments are:
* `SNAPSHOTS_DIRS` * `SNAPSHOTS_DIRS`
This argument specifies the (space separated) paths where grub-btrfsd looks for newly created snapshots and snapshot deletions. It is usually defined by the program used to make snapshots. This argument specifies the (space separated) paths where grub-btrfsd looks for newly created snapshots and snapshot deletions. It is usually defined by the program used to make snapshots.
E.g. for Snapper this would be `/.snapshots`. It is possible to define more than one directory here, all directories will inherit the same settings (recursive etc.). E.g. for Snapper or Yabsnap this would be `/.snapshots`. It is possible to define more than one directory here, all directories will inherit the same settings (recursive etc.).
This argument is not necessary to provide if `--timeshift-auto` is set. This argument is not necessary to provide if `--timeshift-auto` is set.
* `-c / --no-color` * `-c / --no-color`
Disable colors in output. Disable colors in output.
@@ -118,7 +118,7 @@ Displays a short help message.
### 🪀 Automatically update grub upon snapshot creation or deletion ### 🪀 Automatically update grub upon snapshot creation or deletion
Grub-btrfsd is a daemon that watches the snapshot directory for you and updates the grub menu automatically every time a snapshot is created or deleted. Grub-btrfsd is a daemon that watches the snapshot directory for you and updates the grub menu automatically every time a snapshot is created or deleted.
By default this daemon watches the directory `/.snapshots` for changes (creation or deletion of snapshots) and triggers the grub menu creation and re-installation of grub if any changes are noticed. By default this daemon watches the directory `/.snapshots` for changes (creation or deletion of snapshots) and triggers the grub menu creation and re-installation of grub if any changes are noticed.
Therefore, if Snapper is used with its default directory, the daemon can just be started and nothing needs to be configured. See the instructions below to configure grub-btrfsd for use with Timeshift or when using an alternative snapshots directory with Snapper. Therefore, if Snapper or Yabsnap is used with its default directory, the daemon can just be started and nothing needs to be configured. See the instructions below to configure grub-btrfsd for use with Timeshift or when using an alternative snapshots directory with Snapper/Yabsnap.
- - - - - -
#### grub-btrfsd systemd instructions #### grub-btrfsd systemd instructions
To start the daemon run: To start the daemon run:
@@ -294,7 +294,7 @@ If you have problems with the daemon, you can run it with the `--verbose`-flag.
``` bash ``` bash
sudo /usr/bin/grub-btrfsd --verbose --timeshift-auto` (for timeshift) sudo /usr/bin/grub-btrfsd --verbose --timeshift-auto` (for timeshift)
# or # or
sudo /usr/bin/grub-btrfsd /.snapshots --verbose` (for snapper) sudo /usr/bin/grub-btrfsd /.snapshots --verbose` (for snapper/yabsnap)
``` ```
Or pass `--verbose` to the daemon using the Systemd .service file or the OpenRC conf.d file respectively. Or pass `--verbose` to the daemon using the Systemd .service file or the OpenRC conf.d file respectively.

12
config
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
GRUB_BTRFS_VERSION=4.12-master-2023-04-28T16:26:00+00:00 GRUB_BTRFS_VERSION=4.13-fix-bashisms-2024-03-27T20:48:48+00:00
# Disable grub-btrfs. # Disable grub-btrfs.
# Default: "false" # Default: "false"
@@ -49,14 +49,14 @@ GRUB_BTRFS_VERSION=4.12-master-2023-04-28T16:26:00+00:00
# Default: ("") # Default: ("")
#GRUB_BTRFS_CUSTOM_MICROCODE=("custom-ucode.img" "custom-uc.img "custom_ucode.cpio") #GRUB_BTRFS_CUSTOM_MICROCODE=("custom-ucode.img" "custom-uc.img "custom_ucode.cpio")
# Additonal kernel command line parameters that should be passed to the kernel # Additional kernel command line parameters that should be passed to the kernel
# when booting a snapshot. # when booting a snapshot.
# For dracut based distros this could be useful to pass "rd.live.overlay.overlayfs=1" # For dracut based distros this could be useful to pass "rd.live.overlay.overlayfs=1"
# or "rd.live.overlay.readonly=1" to the Kernel for booting snapshots read only. # or "rd.live.overlay.readonly=1" to the Kernel for booting snapshots read only.
# Default: "" # Default: ""
#GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS="rd.live.overlay.overlayfs=1" #GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS="rd.live.overlay.overlayfs=1"
# Comma seperated mount options to be used when booting a snapshot. # Comma separated mount options to be used when booting a snapshot.
# They can be defined here as well as in the "/" line inside the respective snapshots' # They can be defined here as well as in the "/" line inside the respective snapshots'
# "/etc/fstab" files. Mount options found in both places are combined, and this variable # "/etc/fstab" files. Mount options found in both places are combined, and this variable
# takes priority over `fstab` entries. # takes priority over `fstab` entries.
@@ -81,6 +81,8 @@ GRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/doc
# Type = single, pre, post. # Type = single, pre, post.
# For Timeshift: # For Timeshift:
# Tag = boot, ondemand, hourly, daily, weekly, monthly. # Tag = boot, ondemand, hourly, daily, weekly, monthly.
# For yabsnap:
# Trigger = S, I, U.
# Default: ("") # Default: ("")
#GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE=("") #GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE=("")
@@ -107,14 +109,14 @@ GRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/doc
# Location where grub-btrfs.cfg should be saved. # Location where grub-btrfs.cfg should be saved.
# Some distributions (like OpenSuSE) store those files at the snapshot directory # Some distributions (like OpenSuSE) store those files at the snapshot directory
# instead of boot. Be aware that this direcory must be available for grub during # instead of boot. Be aware that this directory must be available for grub during
# startup of the system. # startup of the system.
# Default: $GRUB_BTRFS_GRUB_DIRNAME # Default: $GRUB_BTRFS_GRUB_DIRNAME
#GRUB_BTRFS_GBTRFS_DIRNAME="/boot/grub" #GRUB_BTRFS_GBTRFS_DIRNAME="/boot/grub"
# Location of the directory where Grub searches for the grub-btrfs.cfg file. # Location of the directory where Grub searches for the grub-btrfs.cfg file.
# Some distributions (like OpenSuSE) store those file at the snapshot directory # Some distributions (like OpenSuSE) store those file at the snapshot directory
# instead of boot. Be aware that this direcory must be available for grub during # instead of boot. Be aware that this directory must be available for grub during
# startup of the system. # startup of the system.
# Default: "\${prefix}" # This is a grub variable that resolves to where grub is # Default: "\${prefix}" # This is a grub variable that resolves to where grub is
# installed. (like /boot/grub, /boot/efi/grub) # installed. (like /boot/grub, /boot/efi/grub)

View File

@@ -204,9 +204,9 @@ setup() {
} }
create_grub_menu() { create_grub_menu() {
# create the grub submenu of the whole grub menu, depending on wether the submenu already exists # create the grub submenu of the whole grub menu, depending on whether the submenu already exists
# and gives feedback if it worked # and gives feedback if it worked
if grep "snapshots-btrfs" "{grub_directory}/grub.cfg"; then if grep "snapshots-btrfs" "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}"/grub.cfg; then
if /etc/grub.d/41_snapshots-btrfs; then if /etc/grub.d/41_snapshots-btrfs; then
log "Grub submenu recreated" "${GREEN}" log "Grub submenu recreated" "${GREEN}"
else else
@@ -258,7 +258,7 @@ daemon_function() {
set_snapshot_dir set_snapshot_dir
log "${BASHPID}: detected Timeshift startup, PID is: $timeshift_pid" "${CYAN}" log "${BASHPID}: detected Timeshift startup, PID is: $timeshift_pid" "${CYAN}"
vlog "${BASHPID}: new snapshots directory is $snapdir" "${CYAN}" vlog "${BASHPID}: new snapshots directory is $snapdir" "${CYAN}"
(create_grub_menu) # create the grub menu once immidiatly in a forking process. Snapshots from commandline using timeshift --create need this (create_grub_menu) # create the grub menu once immediately in a forking process. Snapshots from commandline using timeshift --create need this
} }
fi fi
runs=false runs=false

View File

@@ -82,7 +82,7 @@ Example: \fCGRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"\fP
.SS "\fCGRUB_BTRFS_ROOTFLAGS\fP" .SS "\fCGRUB_BTRFS_ROOTFLAGS\fP"
.PP .PP
Comma seperated mount options to be used when booting a snapshot. Comma separated mount options to be used when booting a snapshot.
They can be defined here as well as in the “/” line inside the respective snapshots They can be defined here as well as in the “/” line inside the respective snapshots
“/etc/fstab” files. Mount options found in both places are combined, and this variable “/etc/fstab” files. Mount options found in both places are combined, and this variable
takes priority over `fstab` entries. takes priority over `fstab` entries.
@@ -116,7 +116,7 @@ Example: \fCGRUB_BTRFS_NKERNEL=("kernel\-5.19.4\-custom" "vmlinux\-5.19.4\-custo
.SS "\fCGRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS\fP" .SS "\fCGRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS\fP"
.PP .PP
Additonal kernel command line parameters that should be passed to the kernelwhen Additional kernel command line parameters that should be passed to the kernelwhen
booting a snapshot. booting a snapshot.
For dracut based distros this could be useful to pass “rd.live.overlay.overlayfs=1” For dracut based distros this could be useful to pass “rd.live.overlay.overlayfs=1”
or “rd.live.overlay.readonly=1” to the Kernel for booting read only snapshots. or “rd.live.overlay.readonly=1” to the Kernel for booting read only snapshots.
@@ -190,7 +190,7 @@ Example: \fCGRUB_BTRFS_GRUB_DIRNAME="/boot/grub2"\fP
.PP .PP
Location where grub-btrfs.cfg should be saved. Location where grub-btrfs.cfg should be saved.
Some distributions (like OpenSuSE) store those file at the snapshot directory Some distributions (like OpenSuSE) store those file at the snapshot directory
instead of boot. Be aware that this direcory must be available for grub during instead of boot. Be aware that this directory must be available for grub during
startup of the system. startup of the system.
.IP \(em 4 .IP \(em 4
Default: \fC$GRUB_BTRFS_GRUB_DIRNAME\fP Default: \fC$GRUB_BTRFS_GRUB_DIRNAME\fP
@@ -201,7 +201,7 @@ Example: \fCGRUB_BTRFS_GBTRFS_DIRNAME="/.snapshots"\fP
.PP .PP
Location of the directory where Grub searches for the grub-btrfs.cfg file. Location of the directory where Grub searches for the grub-btrfs.cfg file.
Some distributions (like OpenSuSE) store those file at the snapshot directory Some distributions (like OpenSuSE) store those file at the snapshot directory
instead of boot. Be aware that this direcory must be available for grub during instead of boot. Be aware that this directory must be available for grub during
startup of the system. startup of the system.
.IP \(em 4 .IP \(em 4
Default: “\${prefix}” (This is a grub variable that resolves to where grub is Default: “\${prefix}” (This is a grub variable that resolves to where grub is

View File

@@ -58,7 +58,7 @@ Show snapshots found during run "grub-mkconfig"
- Example: ~GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"~ - Example: ~GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"~
*** ~GRUB_BTRFS_ROOTFLAGS~ *** ~GRUB_BTRFS_ROOTFLAGS~
Comma seperated mount options to be used when booting a snapshot. Comma separated mount options to be used when booting a snapshot.
They can be defined here as well as in the "/" line inside the respective snapshots' They can be defined here as well as in the "/" line inside the respective snapshots'
"/etc/fstab" files. Mount options found in both places are combined, and this variable "/etc/fstab" files. Mount options found in both places are combined, and this variable
takes priority over `fstab` entries. takes priority over `fstab` entries.
@@ -84,7 +84,7 @@ Customs kernel, initramfs and microcodes that are not detected can be added in t
~GRUB_BTRFS_CUSTOM_MICROCODE=("custom-ucode.img" "custom-uc.img "custom_ucode.cpio")~ ~GRUB_BTRFS_CUSTOM_MICROCODE=("custom-ucode.img" "custom-uc.img "custom_ucode.cpio")~
*** ~GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS~ *** ~GRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS~
Additonal kernel command line parameters that should be passed to the kernelwhen Additional kernel command line parameters that should be passed to the kernelwhen
booting a snapshot. booting a snapshot.
For dracut based distros this could be useful to pass "rd.live.overlay.overlayfs=1" For dracut based distros this could be useful to pass "rd.live.overlay.overlayfs=1"
or "rd.live.overlay.readonly=1" to the Kernel for booting read only snapshots. or "rd.live.overlay.readonly=1" to the Kernel for booting read only snapshots.
@@ -139,7 +139,7 @@ For example, on Fedora with EFI : "/boot/efi/EFI/fedora"
*** ~GRUB_BTRFS_GBTRFS_DIRNAME~ *** ~GRUB_BTRFS_GBTRFS_DIRNAME~
Location where grub-btrfs.cfg should be saved. Location where grub-btrfs.cfg should be saved.
Some distributions (like OpenSuSE) store those file at the snapshot directory Some distributions (like OpenSuSE) store those file at the snapshot directory
instead of boot. Be aware that this direcory must be available for grub during instead of boot. Be aware that this directory must be available for grub during
startup of the system. startup of the system.
- Default: ~$GRUB_BTRFS_GRUB_DIRNAME~ - Default: ~$GRUB_BTRFS_GRUB_DIRNAME~
- Example: ~GRUB_BTRFS_GBTRFS_DIRNAME="/.snapshots"~ - Example: ~GRUB_BTRFS_GBTRFS_DIRNAME="/.snapshots"~
@@ -147,7 +147,7 @@ For example, on Fedora with EFI : "/boot/efi/EFI/fedora"
*** ~GRUB_BTRFS_GBTRFS_SEARCH_DIRNAME~ *** ~GRUB_BTRFS_GBTRFS_SEARCH_DIRNAME~
Location of the directory where Grub searches for the grub-btrfs.cfg file. Location of the directory where Grub searches for the grub-btrfs.cfg file.
Some distributions (like OpenSuSE) store those file at the snapshot directory Some distributions (like OpenSuSE) store those file at the snapshot directory
instead of boot. Be aware that this direcory must be available for grub during instead of boot. Be aware that this directory must be available for grub during
startup of the system. startup of the system.
- Default: "\${prefix}" (This is a grub variable that resolves to where grub is - Default: "\${prefix}" (This is a grub variable that resolves to where grub is
installed. (like /boot/grub, /boot/efi/grub)) installed. (like /boot/grub, /boot/efi/grub))

View File

@@ -82,7 +82,7 @@ Example: \fCGRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"\fP
.SS "\fCGRUB_BTRFS_ROOTFLAGS\fP" .SS "\fCGRUB_BTRFS_ROOTFLAGS\fP"
.PP .PP
Comma seperated mount options to be used when booting a snapshot. Comma separated mount options to be used when booting a snapshot.
They can be defined here as well as in the “/” line inside the respective snapshots They can be defined here as well as in the “/” line inside the respective snapshots
“/etc/fstab” files. Mount options found in both places are combined, and this variable “/etc/fstab” files. Mount options found in both places are combined, and this variable
takes priority over `fstab` entries. takes priority over `fstab` entries.
@@ -116,7 +116,7 @@ Example: \fCGRUB_BTRFS_NKERNEL=("kernel\-5.19.4\-custom" "vmlinux\-5.19.4\-custo
.SS "\fCGRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS\fP" .SS "\fCGRUB_BTRFS_SNAPSHOT_KERNEL_PARAMETERS\fP"
.PP .PP
Additonal kernel command line parameters that should be passed to the kernelwhen Additional kernel command line parameters that should be passed to the kernelwhen
booting a snapshot. booting a snapshot.
For dracut based distros this could be useful to pass “rd.live.overlay.overlayfs=1” For dracut based distros this could be useful to pass “rd.live.overlay.overlayfs=1”
or “rd.live.overlay.readonly=1” to the Kernel for booting read only snapshots. or “rd.live.overlay.readonly=1” to the Kernel for booting read only snapshots.
@@ -190,7 +190,7 @@ Example: \fCGRUB_BTRFS_GRUB_DIRNAME="/boot/grub2"\fP
.PP .PP
Location where grub-btrfs.cfg should be saved. Location where grub-btrfs.cfg should be saved.
Some distributions (like OpenSuSE) store those file at the snapshot directory Some distributions (like OpenSuSE) store those file at the snapshot directory
instead of boot. Be aware that this direcory must be available for grub during instead of boot. Be aware that this directory must be available for grub during
startup of the system. startup of the system.
.IP \(em 4 .IP \(em 4
Default: \fC$GRUB_BTRFS_GRUB_DIRNAME\fP Default: \fC$GRUB_BTRFS_GRUB_DIRNAME\fP
@@ -201,7 +201,7 @@ Example: \fCGRUB_BTRFS_GBTRFS_DIRNAME="/.snapshots"\fP
.PP .PP
Location of the directory where Grub searches for the grub-btrfs.cfg file. Location of the directory where Grub searches for the grub-btrfs.cfg file.
Some distributions (like OpenSuSE) store those file at the snapshot directory Some distributions (like OpenSuSE) store those file at the snapshot directory
instead of boot. Be aware that this direcory must be available for grub during instead of boot. Be aware that this directory must be available for grub during
startup of the system. startup of the system.
.IP \(em 4 .IP \(em 4
Default: “\${prefix}” (This is a grub variable that resolves to where grub is Default: “\${prefix}” (This is a grub variable that resolves to where grub is