Compare commits

...

24 Commits
v4.10 ... v4.11

Author SHA1 Message Date
Antynea
79ae25ea5d Update installation section
Adds make help
2021-11-29 18:58:09 +01:00
Antynea
ee3c366fa4 Add missing initrd (#184) 2021-11-26 02:49:37 +01:00
Antynea
4f1aa38604 Make path of "grub-mkconfig_lib" configurable (#181)
* Make path of "grub-mkconfig_lib" configurable

  * 41_snapshots-btrfs file:
    - Remove "datarootdir" variable, is no longer used
    - Replace "$datarootdir/grub/grub-mkconfig_lib" with "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}"

  * Config file:
    - Adds new GRUB_BTRFS_MKCONFIG_LIB variable
Might be '/usr/share/grub2/grub-mkconfig_lib' on some systems (Opensuse ...)
2021-11-17 19:30:34 +01:00
Antynea
1accd5e272 Make name of "grub-script-check" configurable (#177)
41_snapshots-btrfs file:
  * Remove "grub_script_check" variable

Config file;
  * Make name of "grub-script-check" configurable
    * Might be 'grub2-script-check' on some systems (Fedora ...)
2021-11-07 14:35:17 +01:00
Antynea
2500ce8d30 Fix broken Makefile:
* Remove empty lines.
  * Adds missing double quote.
  * Deleted files differ from installed files:
    * Installed files:
      - "$(BIN_DIR)/" grub-btrfs-openrc;
      - "$(DESTDIR)/etc/init.d/" grub-btrfsd;

    * Deleted files:
      - "$(BIN_DIR)/grub-btrfs.openrcbin";
      - "$(DESTDIR)/etc/init.d/grub-btrfs.openrc";

    * Replace deleted files with:
      - "$(BIN_DIR)/grub-btrfs-openrc;"
      - "$(DESTDIR)/etc/init.d/grub-btrfsd;"
2021-11-07 13:55:18 +01:00
Antynea
d9f54afcb7 Update Installation section:
Update Dependencies
2021-11-04 12:26:23 +01:00
Antynea
33ad3273d3 * trim trailing whitespace.
* snapshot_list function:
  * Rename some variables for better consistency.
  * Remove unused variables.
  * Ignore snapper/timeshift snapshot as soon as possible.
2021-11-02 17:42:28 +01:00
Pascal Jäger
3b0d0c4ff7 changed makefile so it doesnt intefere with arch package build process 2021-11-02 16:18:04 +01:00
Pascal Jäger
66a218356a changed instruction for openrc local service 2021-11-02 16:18:04 +01:00
Pascal Jäger
7dc240faa7 Updated readme to take openRC daemon into consideration 2021-11-02 16:18:04 +01:00
Pascal Jäger
75e6408510 Added openRC daemon 2021-11-02 16:18:04 +01:00
Pascal Jäger
fbc33391cb Added openRC daemon 2021-11-02 16:18:04 +01:00
Pascal Jäger
63c3493504 Added a openRC daemon 2021-11-02 16:18:04 +01:00
Pascal Jäger
02b925e4b5 Added an openRC daemon 2021-11-02 16:18:04 +01:00
Antynea
9d436adf95 Reworks many things (#174)
#### Script:
* Snapper:
  - Now, the information is retrieved from the info.xml file.

* Timeshift:
  * Now, the information is retrieved from the info.json file.

* Probe informations from device:
  * Add the UUID of the root and boot subvolumes

* Show full path snapshot or only name:
  * Remove, this feature never worked correctly

* Grub-menu:
  * Now displays the following information in separate columns:
    - Date of snapshot
    - Path of snapshot
    - Type/Tags of snapshot if available (snapper/timeshift)
    - Description/Comments of snapshot if available (snapper/timeshift)
  * Possibility to display only the desired information(s) (see config file)
  *  Adds a header for the column title
  * GRUB_BTRFS_PREFIXENTRY is remove

  * Boot partition detection:
    * grub-btrfs is now able to detect if the boot folder/partition is a subvolume
    * GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION should no longer be needed for this case

  * Variables:
    * Rename some variables

  * Header:
    * Update the header to reflect the changes.

#### Config:
* GRUB_BTRFS_PREFIXENTRY:
  * Remove, no longer use

* GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT:
  * Remove, no longer use

* GRUB_BTRFS_TITLE_FORMAT:
  * Shows/Hides "date" "snapshot" "type" "description" in the Grub menu, custom order available.
    Default: ("date" "snapshot" "type" "description")

* GRUB_BTRFS_IGNORE_SNAPPER_TYPE:
  * Rename to GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE
    - Supports both timeshift and snapper tags/type

* GRUB_BTRFS_IGNORE_SNAPPER_DESCRIPTION:
  * Rename to GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION
    - Supports both snapper and timeshift description/comments

* GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION:
  * grub-btrfs is now able to detect if the boot folder/partition is a subvolume.
  Activating this parameter should no longer be necessary for this case.

* GRUB_BTRFS_SNAPPER_CONFIG:
  * Remove, no longer use

#### Readme:
* Update "What does grub-btrfs v4.xx do" section
  * Adds support for timeshift
2021-10-25 15:47:26 +02:00
Antynea
301752f300 Update count_limit_snap arithmetic
* Update count_limit_snap arithmetic:
  * "$" isn't required in an arithmetic function
2021-10-21 16:59:08 +02:00
Antynea
3b857348cb Update wait_max arithmetic
* Update wait_max arithmetic:
  * "$" isn't required in an arithmetic function
2021-10-21 16:54:11 +02:00
Antynea
f3d8e99cb8 Update count_warning_menuentries arithmetic
* Update count_warning_menuentries arithmetic:
  * "$" isn't required in an arithmetic function
2021-10-21 16:50:51 +02:00
Antynea
af80fe7993 Comments unused variables
* Comments unused variables:
  * This "$prefix_i" and "$suffix_i" are for information purposes only, and aren't used.
2021-10-21 16:44:59 +02:00
Antynea
c7f403d2a2 Update "GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU"
* Update "GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU":
  * Remove default parameter (false), not needed
  * adds automatic conversion of the value to lower case
2021-10-21 16:39:17 +02:00
Antynea
e6898c0de8 Update disable_script function
* Update disable_script function:
  * A function is no longer required since the commands have been moved to the beginning of the script.
2021-10-21 16:36:12 +02:00
Antynea
a790ff054e "disable_script" function breaks "grub-mkconfig"
* "disable_script" function breaks "grub-mkconfig":
  * Replace "return 1" by "exit 0".
2021-10-07 17:31:45 +02:00
Antynea
df643361cc Add Gentoo and OpenRC instructions
* Add Gentoo instructions in "Installation :" section.
* Add OpenRC instructions in "Automatically update grub :" section
2021-10-07 16:52:44 +02:00
Antynea
b0408225c1 Fix bug Create entries with matching version (#170)
* Fix #169 
  * Create entries with matching version doesn't work properly:
  Adds missing "else continue;"
2021-09-26 19:05:02 +02:00
6 changed files with 328 additions and 274 deletions

426
41_snapshots-btrfs Executable file → Normal file
View File

@@ -16,7 +16,7 @@
# - Automatically Detect if "/boot" is in separate partition.
# - Automatically Detect kernel, initramfs and intel/amd microcode in "/boot" directory on snapshots.
# - Automatically Create corresponding "menuentry" in grub.cfg.
# - Automatically detect snapper and use snapper's snapshot description if available.
# - Automatically detect the type/tags and descriptions/comments of snapper/timeshift snapshots.
# - Automatically generate grub.cfg if you use the provided systemd service.
#
# Installation:
@@ -36,7 +36,6 @@
set -e
datarootdir="/usr/share"
sysconfdir="/etc"
grub_btrfs_config="${sysconfdir}/default/grub-btrfs/config"
@@ -44,38 +43,38 @@ grub_btrfs_config="${sysconfdir}/default/grub-btrfs/config"
[[ -f "${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
[[ "${GRUB_BTRFS_DISABLE,,}" == "true" ]] && exit 0 # Disable Grub-btrfs is set to true (default=false)
if ! type btrfs >/dev/null 2>&1; then exit 0; fi # btrfs-progs isn't installed
[[ -f "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" ]] && . "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" || exit 0 # grub-mkconfig_lib couldn't be found
# Root filesystem isn't btrfs
root_fs=$(${grub_probe} --target="fs" / 2>/dev/null)
[[ "$root_fs" != "btrfs" ]] && exit 0
## Error Handling
print_error()
{
local err_msg="$*"
local 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 ;
exit 0
}
disable_script
printf "Detecting snapshots ...\n" >&2 ;
## Submenu name
distro=$(awk -F "=" '/^NAME=/ {gsub(/"/, "", $2); print $2}' /etc/os-release)
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"${distro:-Linux} snapshots"}
## Prefix entry
prefixentry=${GRUB_BTRFS_PREFIXENTRY:-"Snapshot:"}
## Limit snapshots to show in the Grub menu (default=50)
limit_snap_show="${GRUB_BTRFS_LIMIT:-50}"
## How to sort snapshots list
btrfssubvolsort=(--sort="${GRUB_BTRFS_SUBVOLUME_SORT:-"-rootid"}")
## Snapper's config name
snapper_config=${GRUB_BTRFS_SNAPPER_CONFIG:-"root"}
btrfs_subvolume_sort="--sort=${GRUB_BTRFS_SUBVOLUME_SORT:-"-rootid"}"
## Customize GRUB directory, where "grub.cfg" file is saved
grub_directory=${GRUB_BTRFS_GRUB_DIRNAME:-"/boot/grub"}
## Customize BOOT directory, where kernels/initrams/microcode is saved.
boot_directory=${GRUB_BTRFS_BOOT_DIRNAME:-"/boot"}
## Password protection management for submenu
# Protection support for submenu (--unrestricted)
case "${GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU:-"false"}" in
case "${GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU,,}" in
true) unrestricted_access_submenu="--unrestricted ";;
*) unrestricted_access_submenu=""
esac
@@ -88,16 +87,20 @@ fi
# Probe info "Root partition"
root_device=$(${grub_probe} --target=device /) # 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=$(awk -F":" 'match($1, /(^[ \t]+UUID)/) {sub(/^[ \t]+/, "", $2); print $2}' <<< "$root_uuid_subvolume") # UUID of the root subvolume
# Probe info "Boot partition"
boot_device=$(${grub_probe} --target=device ${boot_directory}) # 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=$(awk -F":" 'match($1, /(^[ \t]+UUID)/) {sub(/^[ \t]+/, "", $2); print $2}' <<< "$boot_uuid_subvolume") # UUID of the boot subvolume
boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null) # hints string
boot_fs=$(${grub_probe} --device ${boot_device} --target="fs" 2>/dev/null) # Type filesystem of boot device
## Parameters passed to the kernel
kernel_parameters="$GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT"
## Mount point location
gbgmp=$(mktemp -dt grub-btrfs.XXXXXXXXXX)
grub_btrfs_mount_point=$(mktemp -dt grub-btrfs.XXXXXXXXXX)
## Class for theme
CLASS="--class snapshots --class gnu-linux --class gnu --class os"
## save IFS
@@ -115,36 +118,25 @@ fi
## Detect rootflags
detect_rootflags()
{
local fstabflags=$(grep -oE '^\s*[^#][[:graph:]]+\s+/\s+btrfs\s+[[:graph:]]+' "${gbgmp}/${snap_dir_name}/etc/fstab" \
local 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/^,//')
rootflags="rootflags=${fstabflags:+$fstabflags,}${GRUB_BTRFS_ROOTFLAGS:+$GRUB_BTRFS_ROOTFLAGS,}"
}
## Path to grub-script-check
grub_script_check="${bindir}/grub-script-check"
## Error Handling
print_error()
unmount_grub_btrfs_mount_point()
{
local err_msg="$*"
local 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 ;
exit 0
}
unmount_gbgmp()
{
if [[ -d "$gbgmp" ]]; then
if [[ -d "$grub_btrfs_mount_point" ]]; then
local wait=true
local wait_max=0
printf "Unmount %s .." "$gbgmp" >&2;
printf "Unmount %s .." "$grub_btrfs_mount_point" >&2;
while $wait; do
if grep -qs "$gbgmp" /proc/mounts; then
wait_max=$((1+$wait_max))
if umount "$gbgmp" >/dev/null 2>&1; then
if grep -qs "$grub_btrfs_mount_point" /proc/mounts; then
wait_max=$((1+wait_max))
if umount "$grub_btrfs_mount_point" >/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;
elif [[ $wait_max = 10 ]]; then
printf "\nWarning: Unable to unmount %s in %s\n" "$root_device" "$grub_btrfs_mount_point" >&2;
break;
else
printf "." >&2 ; # output to show that the script is alive
@@ -156,8 +148,8 @@ if [[ -d "$gbgmp" ]]; then
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;
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;
fi
fi
fi
@@ -173,28 +165,29 @@ echo "$@" >> "$grub_directory/grub-btrfs.new"
make_menu_entries()
{
## \" required for snap,kernels,init,microcode with space in their name
entry "submenu '$title_menu' {
submenu '---> $title_menu <---' { echo }"
entry "submenu '${title_menu}' {
submenu '${title_submenu}' { echo }"
for k in "${name_kernel[@]}"; do
[[ ! -f "${boot_dir}"/"${k}" ]] && continue;
kversion=${k#*"-"}
for i in "${name_initramfs[@]}"; do
if [[ "${name_initramfs}" != "x" ]] ; then
prefix_i=${i%%"-"*}
# prefix_i=${i%%"-"*}
suffix_i=${i#*"-"}
alt_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 [[ "${name_microcode}" != "x" ]] ; then
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
entry "
menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
menuentry ' "${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
fi
entry "\
if [ x\$feature_all_video_module = xy ]; then
@@ -207,9 +200,9 @@ make_menu_entries()
else
search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
echo 'Loading Snapshot: "${snap_date_trim}" "${snap_dir_name_trim}"'
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_trim}"\""
if [[ "${name_microcode}" != "x" ]] ; then
entry "\
echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...'
@@ -220,16 +213,16 @@ make_menu_entries()
initrd \"${boot_dir_root_grub}/"${i}"\""
fi
entry " }"
count_warning_menuentries=$((1+$count_warning_menuentries))
count_warning_menuentries=$((1+count_warning_menuentries))
done
else
else
for u in "${name_microcode[@]}"; do
if [[ "${name_microcode}" != "x" ]] ; then
entry "
menuentry '"${k}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
menuentry ' "${k}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
else
entry "
menuentry '"${k}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
menuentry ' "${k}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
fi
entry "\
if [ x\$feature_all_video_module = xy ]; then
@@ -242,16 +235,16 @@ make_menu_entries()
else
search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
echo 'Loading Snapshot: "${snap_date_trim}" "${snap_dir_name_trim}"'
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_trim}"\""
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))
count_warning_menuentries=$((1+count_warning_menuentries))
done
fi
done
@@ -270,109 +263,117 @@ trim() {
## List of snapshots on filesystem
snapshot_list()
{
# Query info from snapper if it is installed
if type snapper >/dev/null 2>&1; then
if [ -s "/etc/snapper/configs/$snapper_config" ]; then
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_types=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | cut -d'|' -f 2))
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))
else
printf "Warning: snapper detected but config: %s does not exist\n" "$snapper_config" >&2
fi
fi
local snapper_info="info.xml"
local timeshift_info="info.json"
local date_snapshots=()
local path_snapshots=()
local type_snapshots=()
local description_snapshots=()
IFS=$'\n'
# Parse btrfs snapshots
local entries=()
local ids=()
local max_entry_length=0
for snap in $(btrfs subvolume list -sa "${btrfssubvolsort}" /); do
for snap in $(btrfs subvolume list -sa "${btrfs_subvolume_sort}" /); do # Parse btrfs snapshots
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#*"/"}
local path_snapshot=${snap[@]:13:${#snap[@]}}
if [ "$path_snapshot" = "DELETED" ]; then continue; fi # Discard deleted snapshots
[[ ${path_snapshot%%"/"*} == "<FS_TREE>" ]] && path_snapshot=${path_snapshot#*"/"} # Remove the "<FS_TREE>" string at the beginning of the path
# ignore specific path during run "grub-mkconfig"
if [ -n "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH}" ] ; then
for isp in ${GRUB_BTRFS_IGNORE_SPECIFIC_PATH[@]} ; do
[[ "${snap_path_name}" == "${isp}" ]] && continue 2;
for isp in "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH[@]}" ; do
[[ "${path_snapshot}" == "${isp}" ]] && continue 2;
done
fi
if [ -n "${GRUB_BTRFS_IGNORE_PREFIX_PATH}" ] ; then
for isp in ${GRUB_BTRFS_IGNORE_PREFIX_PATH[@]} ; do
[[ "${snap_path_name}" == "${isp}"/* ]] && continue 2;
for isp in "${GRUB_BTRFS_IGNORE_PREFIX_PATH[@]}" ; do
[[ "${path_snapshot}" == "${isp}"/* ]] && continue 2;
done
fi
[[ ! -d "$grub_btrfs_mount_point/$path_snapshot/boot" ]] && continue; # Discard snapshots without /boot folder
# Parse Snapper & timeshift informations
local type_snapshot="N/A"
local description_snapshot="N/A"
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"
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
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"
fi
[[ -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"
if [ -n "${GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE}" ] ; then
for ist in "${GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE[@]}" ; do
[[ "${type_snapshot}" == "${ist}" ]] && continue 2;
done
fi
if [ -n "${GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION}" ] ; then
for isd in "${GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION[@]}" ; do
[[ "${description_snapshot}" == "${isd}" ]] && continue 2;
done
fi
# detect if /boot directory exists
[[ ! -d "$gbgmp/$snap_path_name/boot" ]] && continue;
local date_snapshot="${snap[@]:10:2}"
date_snapshots+=("$date_snapshot")
path_snapshots+=("$path_snapshot")
type_snapshots+=("$type_snapshot")
description_snapshots+=("$description_snapshot")
done
local id="${snap_path_name//[!0-9]}" # brutal way to get id: remove everything non-numeric
ids+=("$id")
# Find max length of a snapshot date, needed for pretty formatting
local max_date_length=0
for i in "${date_snapshots[@]}"; do
local length="${#i}"
[[ "$length" -gt "$max_date_length" ]] && max_date_length=$length
done
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
# Find max length of a snapshot name, needed for pretty formatting
local max_path_length=0
for i in "${path_snapshots[@]}"; do
local length="${#i}"
[[ "$length" -gt "$max_path_length" ]] && max_path_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
for i in "${type_snapshots[@]}"; do
local length="${#i}"
[[ "$length" -gt "$max_type_length" ]] && max_type_length=$length
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:]]/}"
# remove other non numeric characters
snapper_id="${snapper_id//\*/}"
snapper_id="${snapper_id//\+/}"
snapper_id="${snapper_id//-/}"
if [[ "$snapper_id" == "$id" ]]; then
local snapper_type=$(trim "${snapper_types[$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"
break
fi
done
# Find max length of a snapshot description, needed for pretty formatting
local max_description_length=0
for i in "${description_snapshots[@]}"; do
local length="${#i}"
[[ "$length" -gt "$max_description_length" ]] && max_description_length=$length
done
for i in "${!path_snapshots[@]}"; do
printf -v entry "%-${max_date_length}s | %-${max_path_length}s | %-${max_type_length}s | %-${max_description_length}s |" "${date_snapshots[$i]}" "${path_snapshots[$i]}" "${type_snapshots[$i]}" "${description_snapshots[$i]}"
echo "$entry"
done
IFS=$oldIFS
}
## Detect kernels in "/boot"
## Parse snapshots in snapshot_list
parse_snapshot_list()
{
snap_date=" $(echo "$item" | cut -d'|' -f1)" # column_1, first space is necessary for pretty formatting
snap_date_trim="$(trim "$snap_date")"
snap_dir_name="$(echo "$item" | cut -d'|' -f2)" # column_2
snap_dir_name_trim="$(trim "$snap_dir_name")"
snap_snapshot="$snap_dir_name" # Used by "title_format" function
snap_type="$(echo "$item" | cut -d'|' -f3)" # column_3
snap_description="$(echo "$item" | cut -d'|' -f4)" # column_4
}
## Detect kernels in "boot_directory"
detect_kernel()
{
list_kernel=()
@@ -384,7 +385,7 @@ detect_kernel()
list_kernel+=("$okernel")
done
# Custom name kernel in GRUB_BTRFS_NKERNEL
# Custom name kernel in "GRUB_BTRFS_NKERNEL"
if [ -n "${GRUB_BTRFS_NKERNEL}" ] ; then
for ckernel in "${boot_dir}/${GRUB_BTRFS_NKERNEL[@]}" ; do
[[ ! -f "${ckernel}" ]] && continue;
@@ -393,21 +394,19 @@ detect_kernel()
fi
}
## Detect initramfs in "/boot"
## Detect initramfs in "boot_directory"
detect_initramfs()
{
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
"${boot_dir}"/initramfs-* \
"${boot_dir}"/initrd-* ; do
[[ ! -f "${oinitramfs}" ]] && continue;
list_initramfs+=("$oinitramfs")
done
# Custom name initramfs in GRUB_BTRFS_NINIT
# Custom name initramfs in "GRUB_BTRFS_NINIT"
if [ -n "${GRUB_BTRFS_NINIT}" ] ; then
for cinitramfs in "${boot_dir}/${GRUB_BTRFS_NINIT[@]}" ; do
[[ ! -f "${cinitramfs}" ]] && continue;
@@ -417,7 +416,7 @@ detect_initramfs()
if [ -z "${list_initramfs}" ]; then list_initramfs=(x); fi
}
## Detect microcode in "/boot"
## Detect microcode in "boot_directory"
detect_microcode()
{
list_ucode=()
@@ -433,7 +432,7 @@ detect_microcode()
list_ucode+=("$oiucode")
done
# Custom name microcode in GRUB_BTRFS_CUSTOM_MICROCODE
# Custom name microcode in "GRUB_BTRFS_CUSTOM_MICROCODE"
if [ -n "${GRUB_BTRFS_CUSTOM_MICROCODE}" ] ; then
for cucode in "${boot_dir}/${GRUB_BTRFS_CUSTOM_MICROCODE[@]}" ; do
[[ ! -f "${cucode}" ]] && continue
@@ -443,29 +442,39 @@ detect_microcode()
if [ -z "${list_ucode}" ]; then list_ucode=(x); fi
}
## Show full path snapshot or only name
path_snapshot()
{
case "${GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT:-"true"}" in
true) name_snapshot=("${snap_full_name}");;
*) name_snapshot=("${snap_full_name#*"/"}")
esac
}
## Title format in grub-menu
## Title format in Grub-menu
declare -A title_column=( [date]=Date [snapshot]=Snapshot [type]=Type [description]=Description ) # Column title that appears in the header
title_format()
{
case "${GRUB_BTRFS_TITLE_FORMAT:-"p/d/n"}" in
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
title_menu="|" # "|" 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
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
declare -n var="snap_${GRUB_BTRFS_TITLE_FORMAT[$key],,}" # $var is a indirect variable
if [[ "${#var}" -lt "${#title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]}" ]]; then # Add extra spaces if length of $var is smaller than the length of column, needed for pretty formatting
printf -v var "%-$(((${#title_column[${GRUB_BTRFS_TITLE_FORMAT[$key],,}]}-${#var})+${#var}))s" "${var}";
fi
title_menu+="${var}|"
title_submenu+=" $(trim "${var}") |"
done
}
# Adds a header to the grub-btrfs.cfg file
header_menu()
{
local header_entry=""
[[ -z "${GRUB_BTRFS_TITLE_FORMAT}" ]] && GRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description"); # Default parameters
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
declare -n var="snap_${GRUB_BTRFS_TITLE_FORMAT[$key],,}" # $var is a indirect variable
# Center alignment, needed for pretty formatting
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=$((((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
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
sed -i "1imenuentry '|${header_entry}' { echo }" "$grub_directory/grub-btrfs.new" # First "|" is for visuals only
}
## List of kernels, initramfs and microcode in snapshots
@@ -476,39 +485,25 @@ boot_bounded()
for item in $(snapshot_list); do
[[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0
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")"
boot_dir="$gbgmp/$snap_dir_name$boot_directory"
# Kernel (Original + custom kernel)
parse_snapshot_list
boot_dir="$grub_btrfs_mount_point/$snap_dir_name_trim$boot_directory"
detect_kernel
if [ -z "${list_kernel}" ]; then continue; fi
name_kernel=("${list_kernel[@]##*"/"}")
# Detect rootflags
detect_rootflags
# Initramfs (Original + custom initramfs)
detect_initramfs
name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode)
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
detect_rootflags
title_format
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
# show snapshot found during run "grub-mkconfig"
if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "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))
# Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break;
done
IFS=$oldIFS
@@ -517,17 +512,12 @@ boot_bounded()
boot_separate()
{
boot_dir="${boot_directory}"
# 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)
boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")" # convert "boot_directory" to root of GRUB (e.g /boot become /)
detect_kernel
if [ -z "${list_kernel}" ]; then print_error "Kernels not found."; fi
name_kernel=("${list_kernel[@]##*"/"}")
# Initramfs (Original + custom initramfs)
detect_initramfs
name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode)
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
@@ -536,56 +526,33 @@ boot_separate()
for item in $(snapshot_list); do
[[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0
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")"
# Detect rootflags
parse_snapshot_list
detect_rootflags
title_format
make_menu_entries
# show snapshot found during run "grub-mkconfig"
if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "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=$((1+count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break;
done
IFS=$oldIFS
}
printf "Detecting snapshots ...\n" >&2 ;
rm -f "$grub_directory/grub-btrfs.new"
> "$grub_directory/grub-btrfs.new"
> "$grub_directory/grub-btrfs.new" # Create a "grub-btrfs.new" file in "grub_directory"
# Create mount point then mounting
[[ ! -d $gbgmp ]] && mkdir -p "$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_warning_menuentries=0
# Count snapshots
count_limit_snap=0
# detect uuid requirement
[[ ! -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/"
trap "unmount_grub_btrfs_mount_point" EXIT # unmounting mount point on EXIT signal
count_warning_menuentries=0 # Count menuentries
count_limit_snap=0 # Count snapshots
check_uuid_required
# Detects if /boot is a separate partition
if [[ "${GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION:-"false"}" == "true" ]]; then
printf "Info: Override boot partition detection : enable \n" >&2 ;
boot_separate
else
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
fi
[[ "${GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION,,}" == "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
# 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 ;
# Show total found snapshots
@@ -597,7 +564,8 @@ if [[ "${count_limit_snap}" = "0" || -z "${count_limit_snap}" ]]; then
print_error "No snapshots found."
fi
# Make a submenu in GRUB (grub.cfg) and move "grub-btrfs.new" to "grub-btrfs.cfg"
if ${grub_script_check} "$grub_directory/grub-btrfs.new"; then
header_menu
if "${bindir}/${GRUB_BTRFS_SCRIPT_CHECK:-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

View File

@@ -2,9 +2,12 @@ PKGNAME ?= grub-btrfs
PREFIX ?= /usr
INITCPIO ?= false
SYSTEMD ?= true
OPENRC ?= false
SHARE_DIR = $(DESTDIR)$(PREFIX)/share
LIB_DIR = $(DESTDIR)$(PREFIX)/lib
BIN_DIR = $(DESTDIR)$(PREFIX)/bin
.PHONY: install uninstall help
@@ -15,14 +18,22 @@ install:
fi
@install -Dm755 -t "$(DESTDIR)/etc/grub.d/" 41_snapshots-btrfs
@install -Dm644 -t "$(DESTDIR)/etc/default/grub-btrfs/" config
@install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.service
@install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.path
@install -Dm644 -t "$(SHARE_DIR)/licenses/$(PKGNAME)/" LICENSE
@# Systemd init system
@if test "$(SYSTEMD)" = true; then \
install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.path; \
install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.service; \
fi
@# OpenRC init system
@if test "$(OPENRC)" = true; then \
install -Dm744 -t "$(BIN_DIR)/" grub-btrfs-openrc; \
install -Dm744 -t "$(DESTDIR)/etc/init.d/" grub-btrfsd; \
fi
@# Arch Linux like distros only :
@if test "$(INITCPIO)" = true; then \
install -Dm644 "initramfs/Arch Linux/overlay_snap_ro-install" "$(LIB_DIR)/initcpio/install/grub-btrfs-overlayfs"; \
install -Dm644 "initramfs/Arch Linux/overlay_snap_ro-hook" "$(LIB_DIR)/initcpio/hooks/grub-btrfs-overlayfs"; \
fi
@install -Dm644 -t "$(SHARE_DIR)/licenses/$(PKGNAME)/" LICENSE
@install -Dm644 -t "$(SHARE_DIR)/doc/$(PKGNAME)/" README.md
@install -Dm644 "initramfs/readme.md" "$(SHARE_DIR)/doc/$(PKGNAME)/initramfs-overlayfs.md"
@@ -35,8 +46,10 @@ uninstall:
rm -f "$${grub_dirname:-/boot/grub}/grub-btrfs.cfg"
@rm -f "$(DESTDIR)/etc/default/grub-btrfs/config"
@rm -f "$(DESTDIR)/etc/grub.d/41_snapshots-btrfs"
@rm -f "$(LIB_DIR)/systemd/system/grub-btrfs.service"
@rm -f "$(LIB_DIR)/systemd/system/grub-btrfs.path"
@rm -f "$(LIB_DIR)/systemd/system/grub-btrfs.service"
@rm -f "$(BIN_DIR)/grub-btrfs-openrc;"
@rm -f "$(DESTDIR)/etc/init.d/grub-btrfsd;"
@rm -f "$(LIB_DIR)/initcpio/install/grub-btrfs-overlayfs"
@rm -f "$(LIB_DIR)/initcpio/hooks/grub-btrfs-overlayfs"
@# Arch Linux UNlike distros only :
@@ -68,4 +81,6 @@ help:
@echo " LIB_DIR | path | system libraries location | '\$$(DESTDIR)\$$(PREFIX)/lib'"
@echo " PKGNAME | name | name of the ditributed package | 'grub-btrfs'"
@echo " INITCPIO | bool | include mkinitcpio hook | false"
@echo
@echo " SYSTEMD | bool | include unit files | true"
@echo " OPENRC | bool | include OpenRc daemon | false"
@echo

View File

@@ -1,11 +1,11 @@
[![GitHub release](https://img.shields.io/github/release/Antynea/grub-btrfs.svg)](https://github.com/Antynea/grub-btrfs/releases)
![](https://img.shields.io/github/license/Antynea/grub-btrfs.svg)
## grub-btrfs
## grub-btrfs
This is a version 4.xx of grub-btrfs
##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt`
##
- - -
### Description :
Improves Grub by adding "btrfs snapshots" to the Grub menu.
@@ -21,16 +21,16 @@ See [this ticket](https://github.com/Antynea/grub-btrfs/issues/92) for more info
This project includes its own solution.
Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/initramfs/readme.md).
##
- - -
### What does grub-btrfs v4.xx do :
* Automatically List snapshots existing on root partition (btrfs).
* Automatically Detect if "/boot" is in separate partition.
* Automatically Detect kernel, initramfs and intel/amd microcode in "/boot" directory on snapshots.
* Automatically Create corresponding "menuentry" in `grub.cfg`
* Automatically detect snapper and use snapper's snapshot description if available.
* Automatically detect the type/tags and descriptions/comments of snapper/timeshift snapshots.
* Automatically generate `grub.cfg` if you use the provided systemd service.
##
- - -
### Installation :
#### Arch Linux
The package is available in the community repository [grub-btrfs](https://archlinux.org/packages/community/any/grub-btrfs/)
@@ -38,25 +38,43 @@ The package is available in the community repository [grub-btrfs](https://archli
pacman -S grub-btrfs
```
#### Manual
#### Gentoo
grub-btrfs is only available in the Gentoo User Repository (GURU) and not in the official Gentoo repository.
If you have not activated the GURU yet, do so by running:
```
emerge -av app-eselect/eselect-repository
eselect repository enable guru
emerge --sync
```
Now merge grub-btrfs via
`emerge app-backup/grub-btrfs`
#### Manual
* Run `make install` or look into Makefile for instructions on where to put each file.
* Run `make help` to check what options are available.
* Dependencies:
* [btrfs-progs](https://archlinux.org/packages/core/x86_64/btrfs-progs/)
* [grub](https://archlinux.org/packages/core/x86_64/grub/)
* [bash >4](https://archlinux.org/packages/core/x86_64/bash/)
* [gawk ](https://archlinux.org/packages/core/x86_64/gawk/)
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 Debian-like distribution `update-grub` is an alias to `grub-mkconfig ...`
##
#### NOTE: All distros
Generate your Grub menu after installation for the changes to take effect.
For example:
On **Arch Linux** or **Gentoo** use `grub-mkconfig -o /boot/grub/grub.cfg`.
On **Fedora** use `grub2-mkconfig -o /boot/grub2/grub.cfg`
On **Debian-like** distribution `update-grub` is an alias to `grub-mkconfig ...`
- - -
### Customization :
You have the possibility to modify many parameters in `/etc/default/grub-btrfs/config`.
See [config file](https://github.com/Antynea/grub-btrfs/blob/master/config) for more information.
##
### Automatically update grub
1- If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted:
- - -
### Automatically update grub :
#### Systemd
1. If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted:
* Use `systemctl enable grub-btrfs.path`.
* `grub-btrfs.path` automatically (re)generates `grub-btrfs.cfg` when a modification appears in `/.snapshots` mount point (by default).
* If the `/.snapshots` mount point is already mounted, then use `systemctl start grub-btrfs.path` to start monitoring.
@@ -91,15 +109,47 @@ use `systemctl list-units -t mount`.
* You can view your change to `systemctl cat grub-btrfs.path`.
* To revert change use `systemctl revert grub-btrfs.path`.
2- If you would like grub-btrfs menu to automatically update on system restart/shutdown:
2. If you would like grub-btrfs menu to automatically update on system restart/ shutdown:
[Look at this comment](https://github.com/Antynea/grub-btrfs/issues/138#issuecomment-766918328)
Currently not implemented
Currently not implemented
##
#### OpenRC
1. If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted:
* Use `rc-config add grub-btrfsd default`, to start the grub-btrfsd daemon the next time the system boots.
* To start `grub-btrfsd` right now, run `rc-service grub-btrfsd start`
* `grub-btrfsd` automatically watches the snapshot directory of timeshift (/run/timeshift/backup/timeshift-btrfs/snapshots)
and updates the grub-menu when a change occurs.
* Currently untested for snapper
2. If you would like grub-btrfs menu to automatically update on system restart/ shutdown:
Just add the following script as `/etc/local.d/grub-btrfs-update.stop`
```
#!/bin/bash
description="Update the grub btrfs snapshots menu"
name="grub-btrfs-update"
depend()
{
use localmount
}
bash -c 'if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then /etc/grub.d/41_snapshots-btrfs; else {GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o {GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg; fi'
```
Make your script executeable with `chmod a+x /etc/local.d/grub-btrfs-update.stop`.
* The extension ".stop" at the end of the filename indicates to locald that this script should be run at shutdown.
If you want to run the menu update on startup instead, rename the file to `grub-btrfs-update.start`
* Works for snapper and timeshift
##### Warning :
by default, `grub-mkconfig` command is used.
Might be `grub2-mkconfig` on some systems (Fedora ...).
Edit `GRUB_BTRFS_MKCONFIG` variable in `/etc/default/grub-btrfs/config` file to reflect this.
##
- - -
### Special thanks for assistance and contributions
* [maximbaz](https://github.com/maximbaz)
* [Maxim Baz](https://github.com/maximbaz)
* [Schievel1](https://github.com/Antynea/grub-btrfs/discussions/173#discussioncomment-1438790)
* [All contributors](https://github.com/Antynea/grub-btrfs/graphs/contributors)
##
- - -

45
config
View File

@@ -8,18 +8,10 @@
# Default: "Use distribution information from /etc/os-release."
#GRUB_BTRFS_SUBMENUNAME="Arch Linux snapshots"
# Add a name ahead your snapshots entries in the Grub menu.
# Default: "Snapshot:"
#GRUB_BTRFS_PREFIXENTRY="Snapshot:"
# Show full path snapshot or only name in the Grub menu, weird reaction with snapper.
# Default: "true"
#GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="false"
# Custom title.
# shows/hides p"prefix" d"date" n"name" in the Grub menu, separator "/", custom order available.
# Default: "p/d/n"
#GRUB_BTRFS_TITLE_FORMAT="p/d/n"
# Shows/Hides "date" "snapshot" "type" "description" in the Grub menu, custom order available.
# Default: ("date" "snapshot" "type" "description")
#GRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description")
# Limit the number of snapshots populated in the GRUB menu.
# Default: "50"
@@ -74,19 +66,22 @@ GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@")
# Default: ("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".
# Ignore specific type/tag of snapshot during run "grub-mkconfig".
# For snapper:
# Type = single, pre, post.
# For Timeshift:
# Tag = boot, ondemand, hourly, daily, weekly, monthly.
# Default: ("")
GRUB_BTRFS_IGNORE_SNAPPER_TYPE=("")
#GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE=("")
# Ignore specific description of snapper's snapshot during run "grub-mkconfig".
# Ignore specific description of snapshot during run "grub-mkconfig".
# e.g: timeline
# Default: ("")
GRUB_BTRFS_IGNORE_SNAPPER_DESCRIPTION=("")
#GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION=("")
# By default "grub-btrfs" automatically detects your boot partition,
# either located at the system root or on a separate partition,
# but cannot detect if it is in a subvolume.
# Change to "true" if you have a boot partition in a different subvolume.
# either located at the system root or on a separate partition or in a subvolume,
# Change to "true" if your boot partition isn't detected as separate.
# Default: "false"
#GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="true"
@@ -111,10 +106,16 @@ GRUB_BTRFS_IGNORE_SNAPPER_DESCRIPTION=("")
# Default: grub-mkconfig
#GRUB_BTRFS_MKCONFIG=/usr/bin/grub2-mkconfig
# Snapper
# Snapper's config name to use
# Default: "root"
#GRUB_BTRFS_SNAPPER_CONFIG="root"
# Name of grub-script-check command, use by "grub-btrfs"
# Might be 'grub2-script-check' on some systems (Fedora ...)
# For example, on Fedora : "grub2-script-check"
# Default: grub-script-check
#GRUB_BTRFS_SCRIPT_CHECK=grub2-script-check
# Path of grub-mkconfig_lib file, use by "grub-btrfs"
# Might be '/usr/share/grub2/grub-mkconfig_lib' on some systems (Opensuse ...)
# Default: /usr/share/grub/grub-mkconfig_lib
#GRUB_BTRFS_MKCONFIG_LIB=/usr/share/grub2/grub-mkconfig_lib
# Password protection management for submenu,snapshots
# Refer to the Grub documentation https://www.gnu.org/software/grub/manual/grub/grub.html#Authentication-and-authorisation

6
grub-btrfs-openrc Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/sh
echo $$ > /run/grub-btrfsd.pid
while true; do sleep 1 && inotifywait -e create -e delete /run/timeshift/backup/timeshift-btrfs/snapshots && sleep 5 && if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then /etc/grub.d/41_snapshots-btrfs; else ${GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o ${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg; fi ; done

14
grub-btrfsd Executable file
View File

@@ -0,0 +1,14 @@
#!/sbin/openrc-run
# Copyright 1999-2021 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
name="grub-btrfs daemon"
command="/usr/bin/grub-btrfs-openrc"
pidfile="/run/{RC_SVCNAME}.pid"
command_background=true
depend() {
use localmount
}