Compare commits

...

14 Commits
v4.9 ... v4.10

Author SHA1 Message Date
Antynea
8142691be1 Adds missing newline
* Adds missing newline:
  "\n" was missing.
2021-09-24 15:54:04 +02:00
Antynea
bab78d4ed8 Write-protect user data
* Write-protect user data
  * The script does not need write access to the data.
  Adds "ro" flags to provide protection against accidental writing.
2021-09-24 12:24:15 +02:00
Antynea
544d2e84ac Adds security if a false positive is detected
* Adds security if a false positive is detected:
  * if the command "grep -qs "$gbgmp" /proc/mounts;" returns a false positive.
  "rm -d" will return an error if the directory is not empty.
2021-09-24 12:12:43 +02:00
Antynea
b346727219 Deletes unused code
* Deletes unused code:
  * Limit generation of menuentries if exceeds 250 has never been used.
  Uses "GRUB_BTRFS_LIMIT" (default 50) instead
2021-09-23 15:28:28 +02:00
Antynea
f1ca0db36d Update header installation section
* Update header installation section:
  * Remove instructions
  (Refet to the project website, installation section)
2021-09-23 14:54:59 +02:00
Antynea
c4d0df3a97 Rework the creation of the "grub-btrfs.cfg" file.
* Rework the creation of the "grub-btrfs.cfg" file:
  * Before, the "grub-btrfs.cfg" file was deleted and then the new configuration was written.
  No backup was made.
  * Now, the new configuration will be written in a temporary file "grub-btrfs.new" and then analysed with the "grub_script_check" command before being finally written in the "grub-btrfs.cfg" file.
  If an error is detected, the "grub-btrfs.new" file will coexist with the old "grub-btrfs.cfg" file, if it exists.
2021-09-23 14:49:56 +02:00
Antynea
c1cadccd1f Adds trap command on EXIT signal
* Adds trap command on EXIT signal:
  * Now umount command will launch on EXIT signal. 
  * Adds a function called by the trap on EXIT signal to unmount and delete the temporary folder. 
  (That should be the end of multiple tmp.xxxxxxxxxx in /tmp)
    - If the command fails, retry every 2 seconds. After 10 attempts, it will stop and display a warning.
    - If the command is successful, "Succes" will be displayed.
  * Adds "grub-btrfs" as a prefix to the temporarie mount folder.
  (before = tmp.xxxxxxxxx , now = grub-btrfs.xxxxxxxxxx)
2021-09-23 11:49:21 +02:00
Antynea
8cc214fd0e Corrects printf format string
* Corrects printf format string:
  * printf interprets escape sequences and format specifiers in the format string. If variables are included, any escape sequences or format specifiers in the data will be interpreted too, when you most likely wanted to treat it as data.
2021-09-22 19:08:55 +02:00
Antynea
81bde02b03 Update "Installation section"
* Update "Installation section":
  * Adds required dependencies
  * Indicates that the command "update-grub", is an alias to "grub-mkconfig" on Debian-like distributions.
2021-09-22 17:07:44 +02:00
Antynea
14bf041ba6 Deactivate the script as soon as possible
* With these changes, the script will be disabled as soon as possible, if :
  * "GRUB_BTRFS_DISABLE" If this variable is set to "true"
  * "btrfs-progs isn't installed" This package is required to retrieve information from the btrfs filesystem.
  * "grub-mkconfig_lib couldn't be found" This library is required because the script depends on it.
  * "Root filesystem isn't btrfs" grub-btrfs currently checks only the btrfs snapshots present on the root partition.
2021-09-22 15:49:02 +02:00
Antynea
863107588c Remove redundant check
Running a command and then checking its exit status $? against 0 is redundant.
Instead of just checking the exit code of a command, it checks the exit code of a command that checks the exit code of a command.
2021-09-22 15:40:05 +02:00
Antynea
2851ecd72b Removes double negation in file test operators
* Removes double negation in file test operators:
  * Replaces the "! -z" operator with "-n".
2021-09-22 15:31:03 +02:00
Antynea
679d000446 Add possibility to boot without init (#164)
* Add possibility to boot without init(rd,ramfs):
  - For a snapshot to be valid, it must contain a boot folder and a kernel from the official list (or have been added to the custom kernel list)
  - if a snapshot doesn't contain an init(rd,ramfs), it will be detected as valid.
  - Suppress script stop when an init is not found
  - If init isn't found, add the letter "x" to the init list. (hoping this doesn't break the support for custom init names)
  - The microcode support is still present, despite the absence of init(rd,ramfs), is it really relevant ?
2021-09-17 15:39:23 +02:00
Antynea
981777d745 Add filter snapper's snapshot (#158)
- Add filter to ignore snapper's snapshot "type or description" during run "grub-mkconfig"

- Two new variables available in the config file:
# Ignore specific type of snapper's snapshot during run "grub-mkconfig".
# Type = single, pre or post.
# Default: ("")
GRUB_BTRFS_IGNORE_SNAPPER_TYPE=("")

# Ignore specific description of snapper's snapshot during run "grub-mkconfig".
# Default: ("")
GRUB_BTRFS_IGNORE_SNAPPER_DESCRIPTION=("")
2021-07-14 12:48:20 +02:00
3 changed files with 172 additions and 99 deletions

View File

@@ -1,6 +1,5 @@
#! /usr/bin/env bash #! /usr/bin/env bash
# #
#
# Written by: Antynea # Written by: Antynea
# BTC donation address: 1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt # BTC donation address: 1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt
# Github: https://github.com/Antynea/grub-btrfs # Github: https://github.com/Antynea/grub-btrfs
@@ -21,7 +20,7 @@
# - Automatically generate grub.cfg if you use the provided systemd service. # - Automatically generate grub.cfg if you use the provided systemd service.
# #
# Installation: # Installation:
# - Run `make install` or look into Makefile for instructions on where to put each file. # - Refer to https://github.com/Antynea/grub-btrfs#installation-
# #
# Customization: # Customization:
# You have the possibility to modify many parameters in /etc/default/grub-btrfs/config. # You have the possibility to modify many parameters in /etc/default/grub-btrfs/config.
@@ -37,25 +36,34 @@
set -e set -e
prefix="/usr"
exec_prefix="/usr"
datarootdir="/usr/share" datarootdir="/usr/share"
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" [[ -f "$grub_btrfs_config" ]] && . "$grub_btrfs_config"
. "$datarootdir/grub/grub-mkconfig_lib" [[ -f "${sysconfdir}/default/grub" ]] && . "${sysconfdir}/default/grub"
. "${sysconfdir}/default/grub"
## Exit the script, if:
disable_script() {
# Disable Grub-btrfs is set to true (default=false)
[[ "${GRUB_BTRFS_DISABLE:-"false"}" == "true" ]] && return 1
# btrfs-progs isn't installed
if ! type btrfs >/dev/null 2>&1; then return 1; fi
# grub-mkconfig_lib couldn't be found
[[ -f "$datarootdir/grub/grub-mkconfig_lib" ]] && . "$datarootdir/grub/grub-mkconfig_lib" || return 1
# Root filesystem isn't btrfs
root_fs=$(${grub_probe} --target="fs" / 2>/dev/null)
[[ "$root_fs" != "btrfs" ]] && return 1
return 0
}
disable_script
### Variables in /etc/default/grub-btrfs/config
## Disable Grub-btrfs (default=active)
[[ "${GRUB_BTRFS_DISABLE:-"false"}" == "true" ]] && exit 0
## 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)
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"${distro:-Linux} snapshots"} submenuname=${GRUB_BTRFS_SUBMENUNAME:-"${distro:-Linux} snapshots"}
## Prefix entry ## Prefix entry
prefixentry=${GRUB_BTRFS_PREFIXENTRY:-"Snapshot:"} prefixentry=${GRUB_BTRFS_PREFIXENTRY:-"Snapshot:"}
## Limit snapshots to show in the Grub menu ## Limit snapshots to show in the Grub menu (default=50)
limit_snap_show="${GRUB_BTRFS_LIMIT:-50}" limit_snap_show="${GRUB_BTRFS_LIMIT:-50}"
## How to sort snapshots list ## How to sort snapshots list
btrfssubvolsort=(--sort="${GRUB_BTRFS_SUBVOLUME_SORT:-"-rootid"}") btrfssubvolsort=(--sort="${GRUB_BTRFS_SUBVOLUME_SORT:-"-rootid"}")
@@ -72,31 +80,24 @@ case "${GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU:-"false"}" in
*) unrestricted_access_submenu="" *) unrestricted_access_submenu=""
esac esac
# Authorized users (--users foo,bar) # Authorized users (--users foo,bar)
if [ ! -z "${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS}" ] ; then 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
### variables script ## Probe informations of Root and Boot devices
## Probe info "Boot partition" # Probe info "Root partition"
# Boot device root_device=$(${grub_probe} --target=device /) # Root device
boot_device=$(${grub_probe} --target=device ${boot_directory}) root_uuid=$(${grub_probe} --device ${root_device} --target="fs_uuid" 2>/dev/null) # UUID of the root device
# hints string # Probe info "Boot partition"
boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null) boot_device=$(${grub_probe} --target=device ${boot_directory}) # Boot device
# UUID of the boot partition 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) boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null) # hints string
# Type filesystem of boot partition 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)
## Probe info "Root partition"
# Type filesystem of root partition
root_fs=$(${grub_probe} --target="fs" / 2>/dev/null)
# Root device
root_device=$(${grub_probe} --target=device /)
# UUID of the root partition
root_uuid=$(${grub_probe} --device ${root_device} --target="fs_uuid" 2>/dev/null)
## Parameters passed to the kernel ## Parameters passed to the kernel
kernel_parameters="$GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT" kernel_parameters="$GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT"
## Mount point location ## Mount point location
gbgmp=$(mktemp -d) gbgmp=$(mktemp -dt grub-btrfs.XXXXXXXXXX)
## Class for theme ## Class for theme
CLASS="--class snapshots --class gnu-linux --class gnu --class os" CLASS="--class snapshots --class gnu-linux --class gnu --class os"
## save IFS ## save IFS
@@ -118,32 +119,54 @@ detect_rootflags()
| 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,}"
} }
## Path to grub-script-check
grub_script_check="${bindir}/grub-script-check"
### Error Handling ## Error Handling
print_error() print_error()
{ {
local arg="$@" local err_msg="$*"
local nothing_to_do="If you think an error has occurred , please file a bug report at \" https://github.com/Antynea/grub-btrfs \"\nNothing to do. Abort.\n" local bug_report="If you think an error has occurred , please file a bug report at \" https://github.com/Antynea/grub-btrfs \""
printf "${arg}\n${nothing_to_do}" >&2 ; printf "%s\n" "${err_msg}" "${bug_report}" >&2 ;
exit 0 exit 0
} }
test_btrfs() unmount_gbgmp()
{ {
[[ "$root_fs" != "btrfs" ]] && print_error "Root partition isn't a btrfs filesystem.\nThis script only supports snapshots of the btrfs filesystem." if [[ -d "$gbgmp" ]]; then
set +e local wait=true
type btrfs >/dev/null 2>&1 local wait_max=0
if [[ $? -ne 0 ]]; then printf "Unmount %s .." "$gbgmp" >&2;
print_error "Unable to retrieve info from btrfs filesystem, make sure you have btrfs-progs on your system." while $wait; do
if grep -qs "$gbgmp" /proc/mounts; then
wait_max=$((1+$wait_max))
if umount "$gbgmp" >/dev/null 2>&1; then
wait=false # umount successful
printf " Success\n" >&2;
elif [[ $wait_max = 10 ]]; then
printf "\nWarning: Unable to unmount %s in %s\n" "$root_device" "$gbgmp" >&2;
break;
else
printf "." >&2 ; # output to show that the script is alive
sleep 2 # wait 2 seconds before retry
fi
else
wait=false # not mounted
printf " Success\n" >&2;
fi
done
if [[ "$wait" != true ]]; then
if ! rm -d "$gbgmp" >/dev/null 2>&1; then
printf "Unable to delete %s: Device or ressource is busy\n" "$gbgmp" >&2;
fi
fi fi
set -e fi
} }
### Script
## Create entry ## Create entry
entry() entry()
{ {
echo "$@" >> "$grub_directory/grub-btrfs.cfg" echo "$@" >> "$grub_directory/grub-btrfs.new"
} }
## menu entries ## menu entries
@@ -156,24 +179,24 @@ make_menu_entries()
[[ ! -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
prefix_i=${i%%"-"*} if [[ "${name_initramfs}" != "x" ]] ; then
suffix_i=${i#*"-"} prefix_i=${i%%"-"*}
alt_suffix_i=${i##*"-"} suffix_i=${i#*"-"}
if [ "${kversion}" = "${suffix_i}" ]; then i="${i}"; alt_suffix_i=${i##*"-"}
elif [ "${kversion}.img" = "${suffix_i}" ]; then i="${i}"; if [ "${kversion}" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}-fallback.img" = "${suffix_i}" ]; then i="${i}"; elif [ "${kversion}.img" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}.gz" = "${suffix_i}" ]; then i="${i}"; elif [ "${kversion}-fallback.img" = "${suffix_i}" ]; then i="${i}";
else continue ; elif [ "${kversion}.gz" = "${suffix_i}" ]; then i="${i}";
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
entry " entry "
menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {" menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
fi fi
entry "\ entry "\
if [ x\$feature_all_video_module = xy ]; then if [ x\$feature_all_video_module = xy ]; then
insmod all_video insmod all_video
fi fi
@@ -187,18 +210,50 @@ make_menu_entries()
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"' echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
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}"\"" linux \"${boot_dir_root_grub}/"${k}"\" root="${LINUX_ROOT_DEVICE}" ${kernel_parameters} ${rootflags}subvol=\""${snap_dir_name}"\""
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}"\""
else else
entry "\ entry "\
echo 'Loading Initramfs: "${i}" ...' echo 'Loading Initramfs: "${i}" ...'
initrd \"${boot_dir_root_grub}/"${i}"\"" initrd \"${boot_dir_root_grub}/"${i}"\""
fi fi
entry " }" entry " }"
count_warning_menuentries=$((1+$count_warning_menuentries)) count_warning_menuentries=$((1+$count_warning_menuentries))
done done
else
for u in "${name_microcode[@]}"; do
if [[ "${name_microcode}" != "x" ]] ; then
entry "
menuentry '"${k}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
else
entry "
menuentry '"${k}"' ${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 ${boot_hs} ${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="${LINUX_ROOT_DEVICE}" ${kernel_parameters} ${rootflags}subvol=\""${snap_dir_name}"\""
if [[ "${name_microcode}" != "x" ]] ; then
entry "\
echo 'Loading Microcode: "${u}" ...'
initrd \"${boot_dir_root_grub}/"${u}"\""
fi
entry " }"
count_warning_menuentries=$((1+$count_warning_menuentries))
done
fi
done done
done done
entry "}" entry "}"
@@ -216,17 +271,16 @@ trim() {
snapshot_list() snapshot_list()
{ {
# Query info from snapper if it is installed # Query info from snapper if it is installed
type snapper >/dev/null 2>&1 if type snapper >/dev/null 2>&1; then
if [ $? -eq 0 ]; then
if [ -s "/etc/snapper/configs/$snapper_config" ]; then if [ -s "/etc/snapper/configs/$snapper_config" ]; then
printf "Info: snapper detected, using config '$snapper_config'\n" >&2 printf "Info: snapper detected, using config: %s\n" "$snapper_config" >&2
local snapper_ids=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | cut -d'|' -f 1)) local snapper_ids=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | cut -d'|' -f 1))
local snapper_types=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | cut -d'|' -f 2)) local snapper_types=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | cut -d'|' -f 2))
IFS=$'\n' IFS=$'\n'
local snapper_descriptions=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | rev | cut -d'|' -f 2 | rev)) local snapper_descriptions=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | rev | cut -d'|' -f 2 | rev))
else else
printf "Warning: snapper detected but config '$snapper_config' does not exist\n" >&2 printf "Warning: snapper detected but config: %s does not exist\n" "$snapper_config" >&2
fi fi
fi fi
@@ -246,12 +300,12 @@ snapshot_list()
[[ ${snap_path_name%%"/"*} == "<FS_TREE>" ]] && snap_path_name=${snap_path_name#*"/"} [[ ${snap_path_name%%"/"*} == "<FS_TREE>" ]] && snap_path_name=${snap_path_name#*"/"}
# ignore specific path during run "grub-mkconfig" # ignore specific path during run "grub-mkconfig"
if [ ! -z "${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
[[ "${snap_path_name}" == "${isp}" ]] && continue 2; [[ "${snap_path_name}" == "${isp}" ]] && continue 2;
done done
fi fi
if [ ! -z "${GRUB_BTRFS_IGNORE_PREFIX_PATH}" ] ; then if [ -n "${GRUB_BTRFS_IGNORE_PREFIX_PATH}" ] ; then
for isp in ${GRUB_BTRFS_IGNORE_PREFIX_PATH[@]} ; do for isp in ${GRUB_BTRFS_IGNORE_PREFIX_PATH[@]} ; do
[[ "${snap_path_name}" == "${isp}"/* ]] && continue 2; [[ "${snap_path_name}" == "${isp}"/* ]] && continue 2;
done done
@@ -296,6 +350,18 @@ snapshot_list()
if [[ "$snapper_id" == "$id" ]]; then if [[ "$snapper_id" == "$id" ]]; then
local snapper_type=$(trim "${snapper_types[$j]}") local snapper_type=$(trim "${snapper_types[$j]}")
local snapper_description=$(trim "${snapper_descriptions[$j]}") local snapper_description=$(trim "${snapper_descriptions[$j]}")
# ignore snapper_type or snapper_description during run "grub-mkconfig"
if [ -n "${GRUB_BTRFS_IGNORE_SNAPPER_TYPE}" ] ; then
for ist in ${GRUB_BTRFS_IGNORE_SNAPPER_TYPE[@]} ; do
[[ "${snapper_type}" == "${ist}" ]] && continue 3;
done
fi
if [ -n "${GRUB_BTRFS_IGNORE_SNAPPER_DESCRIPTION}" ] ; then
for isd in ${GRUB_BTRFS_IGNORE_SNAPPER_DESCRIPTION[@]} ; do
[[ "${snapper_description}" == "${isd}" ]] && continue 3;
done
fi
printf -v entry "%-${max_entry_length}s | %-${max_type_length}s | %s" "$entry" "$snapper_type" "$snapper_description" printf -v entry "%-${max_entry_length}s | %-${max_type_length}s | %s" "$entry" "$snapper_type" "$snapper_description"
break break
fi fi
@@ -319,7 +385,7 @@ detect_kernel()
done done
# Custom name kernel in GRUB_BTRFS_NKERNEL # Custom name kernel in GRUB_BTRFS_NKERNEL
if [ ! -z "${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+=("$ckernel")
@@ -342,12 +408,13 @@ detect_initramfs()
done done
# Custom name initramfs in GRUB_BTRFS_NINIT # Custom name initramfs in GRUB_BTRFS_NINIT
if [ ! -z "${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
if [ -z "${list_initramfs}" ]; then list_initramfs=(x); fi
} }
## Detect microcode in "/boot" ## Detect microcode in "/boot"
@@ -367,7 +434,7 @@ detect_microcode()
done done
# Custom name microcode in GRUB_BTRFS_CUSTOM_MICROCODE # Custom name microcode in GRUB_BTRFS_CUSTOM_MICROCODE
if [ ! -z "${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")
@@ -424,7 +491,6 @@ boot_bounded()
detect_rootflags detect_rootflags
# Initramfs (Original + custom initramfs) # Initramfs (Original + custom initramfs)
detect_initramfs detect_initramfs
if [ -z "${list_initramfs}" ]; then continue; fi
name_initramfs=("${list_initramfs[@]##*"/"}") name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode) # microcode (auto-detect + custom microcode)
detect_microcode detect_microcode
@@ -444,11 +510,10 @@ boot_bounded()
### 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;
# Limit generation of menuentries if exceeds 250
# [[ $count_warning_menuentries -ge 250 ]] && break;
done done
IFS=$oldIFS IFS=$oldIFS
} }
boot_separate() boot_separate()
{ {
boot_dir="${boot_directory}" boot_dir="${boot_directory}"
@@ -461,7 +526,6 @@ boot_separate()
name_kernel=("${list_kernel[@]##*"/"}") name_kernel=("${list_kernel[@]##*"/"}")
# Initramfs (Original + custom initramfs) # Initramfs (Original + custom initramfs)
detect_initramfs detect_initramfs
if [ -z "${list_initramfs}" ]; then print_error "Initramfs not found."; fi
name_initramfs=("${list_initramfs[@]##*"/"}") name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode) # microcode (auto-detect + custom microcode)
detect_microcode detect_microcode
@@ -492,22 +556,17 @@ boot_separate()
# 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;
# Limit generation of menuentries if exceeds 250
# [[ $count_warning_menuentries -ge 250 ]] && break;
done done
IFS=$oldIFS IFS=$oldIFS
} }
### Start
printf "Detecting snapshots ...\n" >&2 ; printf "Detecting snapshots ...\n" >&2 ;
# Only support btrfs snapshots rm -f "$grub_directory/grub-btrfs.new"
test_btrfs > "$grub_directory/grub-btrfs.new"
# Delete existing config
#rm -f --preserve-root "$grub_directory/grub-btrfs.cfg"
> "$grub_directory/grub-btrfs.cfg"
# Create mount point then mounting # Create mount point then mounting
[[ ! -d $gbgmp ]] && mkdir -p $gbgmp [[ ! -d $gbgmp ]] && mkdir -p "$gbgmp"
mount -o subvolid=5 /dev/disk/by-uuid/$root_uuid $gbgmp/ mount -o ro,subvolid=5 /dev/disk/by-uuid/"$root_uuid" "$gbgmp/"
trap "unmount_gbgmp" EXIT # unmounting mount point on EXIT signal
# Count menuentries # Count menuentries
count_warning_menuentries=0 count_warning_menuentries=0
# Count snapshots # Count snapshots
@@ -527,23 +586,25 @@ else
boot_bounded boot_bounded
fi fi
fi fi
# unmounting mount point
umount $gbgmp
# Show warn, menuentries exceeds 250 entries # 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 ; [[ $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 ;
# printf "menuentries = $count_warning_menuentries \n" >&2 ;
# Show total found snapshots # Show total found snapshots
if [[ "${GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND:-"true"}" = "true" && ! -z "${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 ${count_limit_snap} snapshot(s)\n" >&2 ; printf "Found %s snapshot(s)\n" "${count_limit_snap}" >&2 ;
fi fi
# if no snapshot found, exit # if no snapshot found, exit
if [[ "${count_limit_snap}" = "0" || -z "${count_limit_snap}" ]]; then if [[ "${count_limit_snap}" = "0" || -z "${count_limit_snap}" ]]; then
print_error "No snapshots found." print_error "No snapshots found."
fi fi
# Make a submenu in GRUB (grub.cfg) # Make a submenu in GRUB (grub.cfg) and move "grub-btrfs.new" to "grub-btrfs.cfg"
cat << EOF if ${grub_script_check} "$grub_directory/grub-btrfs.new"; then
cat "$grub_directory/grub-btrfs.new" > "$grub_directory/grub-btrfs.cfg"
rm -f "$grub_directory/grub-btrfs.new"
cat << EOF
submenu '${submenuname}' ${protection_authorized_users}${unrestricted_access_submenu}{ submenu '${submenuname}' ${protection_authorized_users}${unrestricted_access_submenu}{
configfile "\${prefix}/grub-btrfs.cfg" configfile "\${prefix}/grub-btrfs.cfg"
} }
EOF EOF
### End else
print_error "Syntax errors are detected in generated grub-btrfs.cfg file."
fi

View File

@@ -33,7 +33,7 @@ Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/i
## ##
### Installation : ### Installation :
#### Arch Linux #### Arch Linux
The package is available in the community repository [grub-btrfs](https://archlinux.org/packages/community/any/grub-btrfs/)
``` ```
pacman -S grub-btrfs pacman -S grub-btrfs
``` ```
@@ -41,10 +41,13 @@ pacman -S grub-btrfs
#### Manual #### Manual
* Run `make install` or look into Makefile for instructions on where to put each file. * Run `make install` or look into Makefile for instructions on where to put each file.
* Dependencies:
* [btrfs-progs](https://archlinux.org/packages/core/x86_64/btrfs-progs/)
* [grub](https://archlinux.org/packages/core/x86_64/grub/)
NOTE: Generate your Grub menu after installation for the changes to take effect. NOTE: Generate your Grub menu after installation for the changes to take effect.
On Arch Linux use `grub-mkconfig -o /boot/grub/grub.cfg`. On Arch Linux use `grub-mkconfig -o /boot/grub/grub.cfg`.
On Debian-like distribution `update-grub` is an alias to `grub-mkconfig ...`
## ##
### Customization : ### Customization :

9
config
View File

@@ -74,6 +74,15 @@ GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@")
# Default: ("var/lib/docker" "@var/lib/docker" "@/var/lib/docker") # Default: ("var/lib/docker" "@var/lib/docker" "@/var/lib/docker")
GRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/docker") GRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/docker")
# Ignore specific type of snapper's snapshot during run "grub-mkconfig".
# Type = single, pre, post.
# Default: ("")
GRUB_BTRFS_IGNORE_SNAPPER_TYPE=("")
# Ignore specific description of snapper's snapshot during run "grub-mkconfig".
# Default: ("")
GRUB_BTRFS_IGNORE_SNAPPER_DESCRIPTION=("")
# By default "grub-btrfs" automatically detects your boot partition, # By default "grub-btrfs" automatically detects your boot partition,
# either located at the system root or on a separate partition, # either located at the system root or on a separate partition,
# but cannot detect if it is in a subvolume. # but cannot detect if it is in a subvolume.