Compare commits

...

50 Commits
v4.2 ... v4.9

Author SHA1 Message Date
Björn Daase
3433754c69 Makefile: Make sure make is invoked with appropriate permissions (#146) 2021-03-01 13:35:44 +01:00
Antynea
db753a9ac8 41_snapshots: update header
* 41_snapshots: update header
  * Update "Automatically update Grub" section.
  * Update "Purpose" section.
  * Update "What this script does" section
2021-02-21 15:37:43 +01:00
Antynea
83bf1da01e Improves systemd.path unit (#139)
* grub-btrfs.path : improves unit

#### Remember to modify your configuration accordingly.  
Allows the unit to start and stop automatically when the mount point is detected.  
If the mount point is already mounted when the unit is activated `systemctl enable grub-btrfs.path`,  
it will be necessary to start the unit for monitoring to begin `systemctl start grub-btrfs.path`.

- `DefaultDependencies=no`
Prevents systemd from automatically generating `Wants= or Requires= or After=`.
- `Requires=\x2esnapshots.mount`
Ensures unit is started if mount point exists.
- `After=\x2esnapshots.mount`
Unit start after the mounting point exists.
- `BindsTo=\x2esnapshots.mount`
If the mount point is removed, the unit will stop.
- `PathModified=\x2esnapshots.mount`
The monitored folder containing the snapshots.
- `WantedBy=\x2esnapshots.mount`
If the mount point exists, unit start automatically. (only if unit is activated before the mount point is mounted)

* Readme: Update "Automatically update grub" section

Update section following the recent change in the `grub-btrfs.path` unit.  
Add information to be able to update the `grub-btrfs` menu every time the system is restart/shutdown.
2021-02-21 05:26:39 +01:00
Kriss
2f22fd8630 [make help] mention INITCPIO switch (#137)
This commit is an expansion to :
87b816345b

Since a new `make` parameter has been introduced, it should be mentioned
in the output of the `help` target.

Also, the table is being expanded by a new column describing the type of
data that each parameter may be assigned, like paths or boolean values.
2021-01-23 20:46:14 +01:00
Antynea
88a0320d62 [Makefile] remove mkinitcpio dependency (#136)
Errata commit:
This commit has no substantive code change.
This commit is provided only to document a correction to a previous commit message.
This pertains to commit object 87b816345b

Due to improper handling, the aforementioned commit message is incorrect.
Correct message is :

[Makefile] remove `mkinitcpio` dependency

The mkinitcpio binary is not available even on Arch,  when building in a
clean environment (e.g. building distro packages in a clean chroot).

This causes the mkinitcpio hook  to not be present in the final package,
which is resolved by this commit, by adding a `make` switch. This switch
allows users to explicitely turn on inclusion of the hook.

[uninstall:] don't remove non-existent folders

This prevents some warnings being output when on a non-Archlinux system,
without a previously installed initcpio hook, a `make uninstall` is per-
formed.

These three folders should _only_ be deleted if they had been mistakenly
created during `make install`.

Co-authored-by: Kriss <kr1ss.x@yandex.com>
2021-01-23 12:02:11 +01:00
Kriss
87b816345b [Makefile] remove mkinitcpio dependency (#136)
[Makefile] remove `mkinitcpio` dependency
2021-01-17 22:25:10 +01:00
Kriss
d68fdf5fff Adds a new config variable "GRUB_BTRFS_ROOTFLAGS" (#133)
Script:

Improves the rootflags option in the kernel command line:
- Remove "rw" flag.
- Parse fstab mountoptions and add them to rootflags:
Adds functionality to read in  snapshot specific mount flags
from the respective fstab and uses them in combination with the new 
config option, while the latter is prioritized.
Both places can, but don't need to define mount flags. If either of them
doesn't, it will simply not be taken into account.

Config file:

Adds a new config variable "GRUB_BTRFS_ROOTFLAGS":
- The new variable is used to include user-defined rootflags in the 
kernel command line of generated snapshot bootmenu entries.
See config file for more infos.
2021-01-11 13:37:40 +01:00
Kriss
87168d2d50 [Makefile] Modifies install/uninstall target. Adds help target (#135)
Makefile:

Install target:
- Added "uninstall" and "help" target to ".phony".
- Hook initcpio will be installed only on Arch Linux like distributions.

Uninstall target:
- All commands are in silent mode.
- "rmdir" command will not interrupt the uninstallation if the folder does not exist.
- Remove "-r" option to "rm" command.
- Fix a mistake in deleting the "readme" file.
- Uninstalling the "grub-btrfs.cfg" file uses the "GRUB_BTRFS_GRUB_DIRNAME" variable.
- Delete initcpio folder if not on Arch.
- Delete "grub-btrfs" docs and licenses folders.

help target:
- Add "help" target.
2021-01-11 13:04:09 +01:00
Antynea
a437b80a35 improves systemd service (#131)
grub-btrfs.service: remove unnecessary path for bash and grub-mkconfig command

readme.md: add warning section to systemd service section

config file: Improves the description of the variable GRUB_BTRFS_MKCONFIG
2021-01-03 14:50:34 +01:00
Antynea
9408231ecc Corrects an erroneous variable (#128)
Fix #127
Replaces "GRUB_BTRFS_DIRNAME" variable to match with new variable "GRUB_BTRFS_GRUB_DIRNAME" in config file.
2020-12-30 15:31:28 +01:00
Antynea
9722f6732c Corrects a mistake
Corrects the duplicate that appeared
Line16 should be :
`@install -Dm644 "initramfs/Arch Linux/overlay_snap_ro-hook" "$(LIB_DIR)/initcpio/hooks/grub-btrfs-overlayfs"		# Arch Linux only`
2020-10-22 21:19:54 +02:00
Antynea
0ed5adaf32 Fix indentation
My IDE was set up incorrectly.
Convert all tab indentation to space.
2020-10-22 07:07:30 +02:00
Antynea
d4b97415b0 Fix #116 (#118)
* Fix #116 (#118)
  * Renames variable GRUB_BTRFS_DIRNAME to GRUB_BTRFS_GRUB_DIRNAME and improves its description

  * Adds variable GRUB_BTRFS_BOOT_DIRNAME, used to detect the boot partition and the location of kernels/initrafms/microcodes
2020-10-21 19:14:05 +02:00
Antynea
da36aa8847 Update header
* Update header about read-only snapshots.
2020-10-15 16:27:32 +02:00
Antynea
d8df766554 Update README.md
* Update link to /initramfs/readme
2020-10-14 15:29:50 +02:00
Antynea
9adce629f7 Boot on read-only snapshot (#115)
* Create a initramfs folder & configuration files
  * create a initramfs folder
  * create Arch Linux folder
  * Add `HOOK/INSTALL` files to generate a custom initrafms for boot on read-only snapshot for Arch Linux.
  * Add readme file to initramfs folder

* Makefile changes
  * Add readme file
  * Add readme file of initramfs-overlayfs
  * Add HOOK/INSTALL files for Arch Linux

* Readme changes
  * Updates the documentation to be able to boot on a read-only snapshot.
  * Redesign readme again.
2020-10-14 15:17:07 +02:00
Antynea
3c5e741641 Modify "grub btrfs dirname" variable. (#113)
* Modify "GRUB_BTRFS_DIRNAME"
  * Full path to Grub folder is now configurable (/boot is no longer hard coded).
  * Detection of the boot partition is now based on the location of the Grub folder.
  * Warning [see](https://github.com/Antynea/grub-btrfs/pull/113#issuecomment-705916729)
2020-10-09 15:50:02 +02:00
Antynea
fa65c3d6d9 move rmdir to end of uninstall section
If rmdir fails, other commands are not executed, so
move rmdir to end of uninstall section
2020-10-09 02:32:25 +02:00
Antynea
4493bdc6e4 Clean code
Remove commented commands that are no longer needed.
2020-10-07 02:00:23 +02:00
Antynea
a7289b182a Remove several variables not necessary
For easier maintenance,
remove several variables already present in the config file.
2020-10-07 00:36:06 +02:00
Antynea
0fe512776a Modify the function which is used to ignore a path. (#112)
Modify the function which is used to ignore a path.
@ shouldn't be hardcoded.
Create 2 separate functions to ignore a specific path or prefix path.
In specific path, only exact paths are ignored.
In prefix path, any path starting with the specified string will be ignored.
e.g :
if specific path = @, only @ snapshot will be ignored.
if prefix path = @, all snapshots beginning with "@/..." will be ignored.
2020-10-06 23:19:41 +02:00
Antynea
6af193c47a Add new path to ignore docker subvolume
Many distributions now use "@" as the default subvolume.
Add the following path "@/var/lib/docker" to ignore the docker subvolume.
Fix: #110
2020-10-03 12:51:51 +02:00
Antynea
9a771d9842 Stop script if root partition isn't btrfs filesystem
Add filesystem check on the root partition.
If the filesystem isn't btrfs, stop execution.
Update error message for btrfs-prog.
2020-10-01 19:37:43 +02:00
Antynea
64c08a0807 Update header
Update header to reflect change on [Automatically update grub](https://github.com/Antynea/grub-btrfs#automatically-update-grub) section
Remove many `#` characters
2020-10-01 19:28:45 +02:00
Antynea
c9b605153b Redesign readme (#109)
* Add more information

Add more information.
Due to the redesign of the "Customization" section of the readme file.

* Redesign  customization section

Move information of customization section to config file
2020-09-29 13:39:20 +02:00
Antynea
7e922abefb Update "Automatically update grub" section
Update "Automatically update grub" section.
Correct a mistake.
2020-09-28 00:58:21 +02:00
Antynea
d20439554e Update "Automatically update grub" section
Update "Automatically update grub" section.
Trying to make it more understandable.
2020-09-28 00:54:45 +02:00
Antynea
ce8261395f Update Automatically update grub section
Timeshift use `/run/timeshift/backup/timeshift-btrfs/snapshots` mountpoint for its snapshots.
Timeshift users must modify the monitoring path:
```
[Path]
PathModified=/.snapshots
```
to
```
[Path]
PathModified=/run/timeshift/backup/timeshift-btrfs/snapshots
```
2020-09-24 02:21:37 +02:00
Antynea
133c8ebfdb Clean code
Clean indentation/leading/trailing space
2020-09-16 21:07:42 +02:00
Antynea
2349282df5 Improved sorting of the subvolumes list (#107)
* Improved sorting of the subvolumes list

Add functionality to sort subvolume list by: rootid,gen,ogen,path
Default: "-rootid" means list snapshot by new ones first
See [Sorting section](https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-subvolume#SUBCOMMAND)
2020-09-16 19:16:18 +02:00
Antynea
041a9c6606 Microcode variable updated (#106)
* Microcode variable updated

* Modifying variable to reflect improved microcode detection

* Update config

Change "GRUB_BTRFS_INTEL_UCODE" to new variable "GRUB_BTRFS_CUSTOM_MICROCODE"

* Update README.md

Change "GRUB_BTRFS_INTEL_UCODE" to new variable "GRUB_BTRFS_CUSTOM_MICROCODE"
2020-09-16 18:25:11 +02:00
Antynea
7e5bfa597f Update header
* Update header
Improve the warning section about "ro snapshots"
2020-09-16 17:05:17 +02:00
Antynea
f0382536fb Update README.md
automatic microcode detection: now detects amd microcode
2020-09-16 16:21:54 +02:00
Antynea
b50ad439d4 clean code
* root_grub="$(make_system_path_relative_to_its_root /boot/$grub_directory)"
no longer used
2020-09-16 16:17:06 +02:00
Antynea
5f40f30985 Remove Internationalization
Internationalization has never been used. (default : english)
2020-09-16 14:02:02 +02:00
Antynea
d2c15acd72 Enhance microcode detection (#105)
Add all default stock images listed by "grub"
See  [GRUB_EARLY_INITRD_LINUX_STOCK](https://www.gnu.org/software/grub/manual/grub/html_node/Simple-configuration.html) for more informations.
2020-09-16 13:54:21 +02:00
Christian Kotte
77d69aaa81 Update script output (#104)
Script output is now the same as other grub-mkconfig output
2020-09-13 09:39:38 +02:00
Antynea
44ee10f5ef Attempt to fix ignore specific path (#102)
* Attempt to fix ignore specific path

Attempt to fix ignore specific path #100

* Update config
2020-09-05 12:24:46 +02:00
Senya
9cb57dab40 Add uninstall to the Makefile (#99) 2020-08-31 12:49:59 +02:00
Antynea
6bfdf07bbf Add password protection support for the submenu (#97)
* Add password protection support for the submenu

Grub2 supports superuser and user access using passwords. #95

-Ability to add authorized users.
-Possibility to disable password protection for the submenu.

* Update config

* Update README.md
2020-08-29 18:55:39 +02:00
Antynea
7f76eec16d Update Name appearing in the Grub menu
Name appearing in the Grub menu :
Use distribution information from /etc/os-release by default
2020-08-28 04:22:13 +02:00
Antynea
a89834248c Update README.md 2020-08-28 04:19:44 +02:00
Maxim Baz
b49e19ce30 Document how to boot on read-only snapshots, fix #92 2020-08-04 19:03:35 +02:00
Maxim Baz
9b863f027b Ignore @ by default as it is never a snapshot, fix #96, fix #90 2020-07-28 19:27:47 +02:00
darkdragon-001
44771d9756 Use distribution information from /etc/os-release by default. (#94)
Fixes #87
2020-07-18 14:06:58 +02:00
Maxim Baz
18c6eebf31 Allow ignoring precise paths or names, fixes #90 2020-07-17 23:19:26 +02:00
Peter Gantner
6ff1fc7127 grub script: improve snapshot listing performance (#93)
Btrfs filesystems may be slow when listing snapshots and calculating
space usage for each.
And that space information is not needed and never used in the scipt.

So, add --disable-ununsed-space to all calls to btrfs.

See: https://github.com/Antynea/grub-btrfs/issues/91

Co-authored-by: Peter G <nephros@pearl.crownest.nephros.org>
2020-07-17 22:43:27 +02:00
Thomas Winant
92eef3079d Don't let the kernel parameters override the subvol for the snapshot (#85)
Previously, the kernel parameters came after the `rootflags=subvol=<snapshot>`
argument. This means that when the user's standard kernel parameters also
contain a `rootflags=subvol=<root>`, it will override the subvol flag of the
snapshot. So put the snapshot's subvol flag last.
2020-03-22 16:33:12 +01:00
Maxim Baz
4e1b628465 Test if snapper is properly configured before using it (#83) 2020-01-17 21:53:24 +01:00
Luflosi
21df698e04 Fix typos (#80) 2019-12-29 14:23:16 +01:00
9 changed files with 657 additions and 526 deletions

View File

@@ -1,22 +1,22 @@
#! /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
# #
# Purpose: # Purpose:
# Improves Grub by adding "btrfs snapshots" to the Grub menu. # Improves Grub by adding "btrfs snapshots" to the Grub menu.
# You can start your system on a "snapshot" from the Grub menu. # You can boot your system on a "snapshot" from the Grub menu.
# Supports manual snapshots, snapper ... # Supports manual snapshots, snapper, timeshift ...
# Warning : it isn't recommended to start on read-only snapshot # Warning : booting on read-only snapshots can be tricky.
# (Read about it, https://github.com/Antynea/grub-btrfs#warning-booting-on-read-only-snapshots-can-be-tricky)
# #
# What this script does: # What this script does:
# - Automatically List snapshots existing on root partition (btrfs). # - Automatically List snapshots existing on root partition (btrfs).
# - Automatically Detect if "/boot" is in separate partition. # - Automatically Detect if "/boot" is in separate partition.
# - Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots. # - Automatically Detect kernel, initramfs and intel/amd microcode in "/boot" directory on snapshots.
# - Automatically Create corresponding "menuentry" in grub.cfg # - Automatically Create corresponding "menuentry" in grub.cfg.
# - Automatically detect snapper and use snapper's snapshot description if available. # - Automatically detect snapper and use snapper's snapshot description if available.
# - Automatically generate grub.cfg if you use the provided systemd service. # - Automatically generate grub.cfg if you use the provided systemd service.
# #
@@ -24,20 +24,16 @@
# - 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.
# #
# Customization: # Customization:
# Refer to config for the list of available options and their default values. # You have the possibility to modify many parameters in /etc/default/grub-btrfs/config.
# Place your configurations to /etc/default/grub-btrfs/config.
# #
# Automatically update Grub # Automatically update Grub
# If you would like Grub to automatically update when a snapshots is made or deleted: # If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted:
# - Mount your subvolume which contains snapshots to /.snapshots # - Refer to https://github.com/Antynea/grub-btrfs#automatically-update-grub.
# - Use systemctl start/enable grub-btrfs.path
# grub-btrfs.path will automatically (re)generate grub.cfg when a modification appear in /.snapshots
# #
# Special thanks for assistance and contributions: # Special thanks for assistance and contributions:
# - My friends # - My friends
# - All contributors on Github # - All contributors on Github
# #
#########################################################################################################################################################################
set -e set -e
@@ -51,63 +47,48 @@ grub_btrfs_config="${sysconfdir}/default/grub-btrfs/config"
. "$datarootdir/grub/grub-mkconfig_lib" . "$datarootdir/grub/grub-mkconfig_lib"
. "${sysconfdir}/default/grub" . "${sysconfdir}/default/grub"
################################################### ### Variables in /etc/default/grub-btrfs/config
### Variables in /etc/default/grub-btrfs/config ###
###################################################
## Disable Grub-btrfs (default=active) ## Disable Grub-btrfs (default=active)
grub_btrfs_disable=${GRUB_BTRFS_DISABLE:-"false"} [[ "${GRUB_BTRFS_DISABLE:-"false"}" == "true" ]] && exit 0
[[ "${grub_btrfs_disable}" == "true" ]] && exit 0
## Submenu name ## Submenu name
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"Arch Linux snapshots"} distro=$(awk -F "=" '/^NAME=/ {gsub(/"/, "", $2); print $2}' /etc/os-release)
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"${distro:-Linux} snapshots"}
## Prefix entry ## Prefix entry
prefixentry=${GRUB_BTRFS_PREFIXENTRY:-"Snapshot:"} prefixentry=${GRUB_BTRFS_PREFIXENTRY:-"Snapshot:"}
## Show full path snapshot or only name
path_snapshot=${GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT:-"true"}
## Title format
title_format=${GRUB_BTRFS_TITLE_FORMAT:-"p/d/n"}
## Kernel(s) name(s)
nkernel=("${GRUB_BTRFS_NKERNEL[@]}")
## Initramfs name(s)
ninit=("${GRUB_BTRFS_NINIT[@]}")
## Microcode(s) name(s)
microcode=("${GRUB_BTRFS_INTEL_UCODE[@]}")
## Limit snapshots to show in the Grub menu ## Limit snapshots to show in the Grub menu
limit_snap_show="${GRUB_BTRFS_LIMIT:-50}" limit_snap_show="${GRUB_BTRFS_LIMIT:-50}"
## How to sort snapshots list ## How to sort snapshots list
snap_list_sort=${GRUB_BTRFS_SUBVOLUME_SORT:-"descending"} btrfssubvolsort=(--sort="${GRUB_BTRFS_SUBVOLUME_SORT:-"-rootid"}")
case "${snap_list_sort}" in
ascending) btrfssubvolsort=("--sort=+rootid");;
*) btrfssubvolsort=("--sort=-rootid")
esac
## Show snapshots found during run "grub-mkconfig"
show_snap_found=${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}
## Show Total of snapshots found during run "grub-mkconfig"
show_total_snap_found=${GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND:-"true"}
## Ignore specific path during run "grub-mkconfig"
ignore_specific_path=("${GRUB_BTRFS_IGNORE_SPECIFIC_PATH[@]}")
## Snapper's config name ## Snapper's config name
snapper_config=${GRUB_BTRFS_SNAPPER_CONFIG:-"root"} snapper_config=${GRUB_BTRFS_SNAPPER_CONFIG:-"root"}
## Override boot partition detection ## Customize GRUB directory, where "grub.cfg" file is saved
override_boot_partition_detection=${GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION:-"false"} grub_directory=${GRUB_BTRFS_GRUB_DIRNAME:-"/boot/grub"}
## Customize GRUB directory ## Customize BOOT directory, where kernels/initrams/microcode is saved.
grub_directory=${GRUB_BTRFS_DIRNAME:-"grub"} 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
true) unrestricted_access_submenu="--unrestricted ";;
*) unrestricted_access_submenu=""
esac
# Authorized users (--users foo,bar)
if [ ! -z "${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS}" ] ; then
protection_authorized_users="--users ${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS} "
fi
######################## ### variables script
### variables script ###
########################
## Internationalization (default : english)
export TEXTDOMAIN=grub-btrfs-git
export TEXTDOMAINDIR="/usr/share/locale"
## Probe info "Boot partition" ## Probe info "Boot partition"
# Boot device # Boot device
boot_device=$(${grub_probe} --target=device /boot) boot_device=$(${grub_probe} --target=device ${boot_directory})
# hints string # hints string
boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null) boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null)
# UUID of the boot partition # UUID of the boot partition
boot_uuid=$(${grub_probe} --device ${boot_device} --target="fs_uuid" 2>/dev/null) boot_uuid=$(${grub_probe} --device ${boot_device} --target="fs_uuid" 2>/dev/null)
# Type filesystem of boot partition # Type filesystem of boot partition
boot_fs=$(${grub_probe} --target="fs" /boot 2>/dev/null) boot_fs=$(${grub_probe} --device ${boot_device} --target="fs" 2>/dev/null)
## Probe info "Root partition" ## Probe info "Root partition"
# Type filesystem of root partition
root_fs=$(${grub_probe} --target="fs" / 2>/dev/null)
# Root device # Root device
root_device=$(${grub_probe} --target=device /) root_device=$(${grub_probe} --target=device /)
# UUID of the root partition # UUID of the root partition
@@ -125,391 +106,405 @@ check_uuid_required() {
if [ "x${root_uuid}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \ if [ "x${root_uuid}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
|| ! test -e "/dev/disk/by-uuid/${root_uuid}" \ || ! test -e "/dev/disk/by-uuid/${root_uuid}" \
|| ( test -e "${root_device}" && uses_abstraction "${root_device}" lvm ); then || ( test -e "${root_device}" && uses_abstraction "${root_device}" lvm ); then
LINUX_ROOT_DEVICE=${root_device} LINUX_ROOT_DEVICE=${root_device}
else else
LINUX_ROOT_DEVICE=UUID=${root_uuid} LINUX_ROOT_DEVICE=UUID=${root_uuid}
fi fi
} }
## Detect rootflags
detect_rootflags()
{
local fstabflags=$(grep -oE '^\s*[^#][[:graph:]]+\s+/\s+btrfs\s+[[:graph:]]+' "${gbgmp}/${snap_dir_name}/etc/fstab" \
| sed -E 's/^.*[[:space:]]([[:graph:]]+)$/\1/;s/,?subvol(id)?=[^,$]+//g;s/^,//')
rootflags="rootflags=${fstabflags:+$fstabflags,}${GRUB_BTRFS_ROOTFLAGS:+$GRUB_BTRFS_ROOTFLAGS,}"
}
### Error Handling
######################
### Error Handling ###
######################
print_error() print_error()
{ {
local arg="$@" local arg="$@"
local nothing_to_do="If you think an error has occurred , please file a bug report at \" https://github.com/Antynea/grub-btrfs \"\n# Nothing to do. Abort.\n###### - Grub-btrfs: Snapshot detection ended - ######\n" 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"
printf "# ${arg}\n# ${nothing_to_do}" >&2 ; printf "${arg}\n${nothing_to_do}" >&2 ;
exit 0 exit 0
} }
test_btrfs() test_btrfs()
{ {
set +e [[ "$root_fs" != "btrfs" ]] && print_error "Root partition isn't a btrfs filesystem.\nThis script only supports snapshots of the btrfs filesystem."
type btrfs >/dev/null 2>&1 set +e
if [[ $? -ne 0 ]]; then type btrfs >/dev/null 2>&1
print_error "This script only supports snapshots of the btrfs filesystem, make sure you have btrfs-progs on your system." if [[ $? -ne 0 ]]; then
fi print_error "Unable to retrieve info from btrfs filesystem, make sure you have btrfs-progs on your system."
set -e fi
set -e
} }
##############
### Script ###
##############
### Script
## Create entry ## Create entry
entry() { entry()
echo "$@" >> "/boot/$grub_directory/grub-btrfs.cfg" {
# local arg="$@" echo "$@" >> "$grub_directory/grub-btrfs.cfg"
# echo "${arg}" >> "/boot/$grub_directory/grub-btrfs.cfg"
# cat << EOF >> "/boot/$grub_directory/grub-btrfs.cfg"
# ${arg}
# EOF
} }
## menu entries ## menu entries
make_menu_entries() make_menu_entries()
{ {
## \" required for snap,kernels,init,microcode with space in their name ## \" required for snap,kernels,init,microcode with space in their name
entry "submenu '$title_menu' { entry "submenu '$title_menu' {
submenu '---> $title_menu <---' { echo }" submenu '---> $title_menu <---' { 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
prefix_i=${i%%"-"*} prefix_i=${i%%"-"*}
suffix_i=${i#*"-"} suffix_i=${i#*"-"}
alt_suffix_i=${i##*"-"} alt_suffix_i=${i##*"-"}
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}";
elif [ "${kversion}.gz" = "${suffix_i}" ]; then i="${i}"; elif [ "${kversion}.gz" = "${suffix_i}" ]; then i="${i}";
else continue ; else continue ;
fi fi
for u in "${name_microcode[@]}"; do for u in "${name_microcode[@]}"; do
if [[ -f "${boot_dir}"/"${u}" && "${i}" != "${prefix_i}-${kversion}-${alt_suffix_i}" ]] ; 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
set gfxpayload=keep set gfxpayload=keep
insmod ${boot_fs} insmod ${boot_fs}
if [ x\$feature_platform_search_hint = xy ]; then if [ x\$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root ${boot_hs} ${boot_uuid} search --no-floppy --fs-uuid --set=root ${boot_hs} ${boot_uuid}
else else
search --no-floppy --fs-uuid --set=root ${boot_uuid} search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi fi
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}" rw rootflags=subvol=\""${snap_dir_name}"\" ${kernel_parameters}" linux \"${boot_dir_root_grub}/"${k}"\" root="${LINUX_ROOT_DEVICE}" ${kernel_parameters} ${rootflags}subvol=\""${snap_dir_name}"\""
if [[ -f "${boot_dir}"/"${u}" && "${i}" != "${prefix_i}-${kversion}-${alt_suffix_i}" ]] ; 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
done done
done done
entry "}" entry "}"
} }
## Trim a string from leading and trailing whitespaces ## Trim a string from leading and trailing whitespaces
trim() { trim() {
local var="$*" local var="$*"
var="${var#"${var%%[![:space:]]*}"}" var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}" var="${var%"${var##*[![:space:]]}"}"
echo -n "$var" echo -n "$var"
} }
## List of snapshots on filesystem ## List of snapshots on filesystem
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 type snapper >/dev/null 2>&1
if [[ $? -eq 0 ]]; then if [ $? -eq 0 ]; then
local snapper_ids=($(snapper --no-dbus -t 0 -c "$snapper_config" list | tail -n +3 | cut -d'|' -f 1)) if [ -s "/etc/snapper/configs/$snapper_config" ]; then
local snapper_types=($(snapper --no-dbus -t 0 -c "$snapper_config" list | tail -n +3 | cut -d'|' -f 2)) printf "Info: snapper detected, using config '$snapper_config'\n" >&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' IFS=$'\n'
local snapper_descriptions=($(snapper --no-dbus -t 0 -c "$snapper_config" list | 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))
fi else
printf "Warning: snapper detected but config '$snapper_config' does not exist\n" >&2
fi
fi
IFS=$'\n' IFS=$'\n'
# Parse btrfs snapshots # Parse btrfs snapshots
local entries=() local entries=()
local ids=() local ids=()
local max_entry_length=0 local max_entry_length=0
for snap in $(btrfs subvolume list -sa "${btrfssubvolsort}" /); do for snap in $(btrfs subvolume list -sa "${btrfssubvolsort}" /); do
IFS=$oldIFS IFS=$oldIFS
snap=($snap) snap=($snap)
local snap_path_name=${snap[@]:13:${#snap[@]}} local snap_path_name=${snap[@]:13:${#snap[@]}}
# Discard deleted snapshots # Discard deleted snapshots
if [ "$snap_path_name" = "DELETED" ]; then continue; fi if [ "$snap_path_name" = "DELETED" ]; then continue; fi
[[ ${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 "${ignore_specific_path}" ] ; then if [ ! -z "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH}" ] ; then
for isp in ${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
for isp in ${GRUB_BTRFS_IGNORE_PREFIX_PATH[@]} ; do
[[ "${snap_path_name}" == "${isp}"/* ]] && continue 2;
done
fi
# detect if /boot directory exists # detect if /boot directory exists
[[ ! -d "$gbgmp/$snap_path_name/boot" ]] && continue; [[ ! -d "$gbgmp/$snap_path_name/boot" ]] && continue;
local id="${snap_path_name//[!0-9]}" # brutal way to get id: remove everything non-numeric local id="${snap_path_name//[!0-9]}" # brutal way to get id: remove everything non-numeric
ids+=("$id") ids+=("$id")
local entry="${snap[@]:10:2} | ${snap_path_name}" local entry="${snap[@]:10:2} | ${snap_path_name}"
entries+=("$entry") entries+=("$entry")
# Find max length of a snapshot entry, needed for pretty formatting # Find max length of a snapshot entry, needed for pretty formatting
local length="${#entry}" local length="${#entry}"
[[ "$length" -gt "$max_entry_length" ]] && max_entry_length=$length [[ "$length" -gt "$max_entry_length" ]] && max_entry_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 id in "${ids[@]}"; do for id in "${ids[@]}"; do
for j in "${!snapper_ids[@]}"; do for j in "${!snapper_ids[@]}"; do
local snapper_id="${snapper_ids[$j]//[[:space:]]/}" local snapper_id="${snapper_ids[$j]//[[:space:]]/}"
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 length="${#snapper_type}" local length="${#snapper_type}"
[[ "$length" -gt "$max_type_length" ]] && max_type_length=$length [[ "$length" -gt "$max_type_length" ]] && max_type_length=$length
fi fi
done done
done done
for i in "${!entries[@]}"; do for i in "${!entries[@]}"; do
local id="${ids[$i]}" local id="${ids[$i]}"
local entry="${entries[$i]}" local entry="${entries[$i]}"
for j in "${!snapper_ids[@]}"; do for j in "${!snapper_ids[@]}"; do
local snapper_id="${snapper_ids[$j]//[[:space:]]/}" local snapper_id="${snapper_ids[$j]//[[:space:]]/}"
# remove other non numeric characters # remove other non numeric characters
snapper_id="${snapper_id//\*/}" snapper_id="${snapper_id//\*/}"
snapper_id="${snapper_id//\+/}" snapper_id="${snapper_id//\+/}"
snapper_id="${snapper_id//-/}" snapper_id="${snapper_id//-/}"
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]}")
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
done done
echo "$entry" echo "$entry"
done done
IFS=$oldIFS IFS=$oldIFS
} }
## Detect kernels in "/boot" ## Detect kernels in "/boot"
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+=("$okernel")
done done
# Custom name kernel in GRUB_BTRFS_NKERNEL # Custom name kernel in GRUB_BTRFS_NKERNEL
if [ ! -z "${nkernel}" ] ; then if [ ! -z "${GRUB_BTRFS_NKERNEL}" ] ; then
for ckernel in "${boot_dir}/${nkernel[@]}" ; do for ckernel in "${boot_dir}/${GRUB_BTRFS_NKERNEL[@]}" ; do
[[ ! -f "${ckernel}" ]] && continue; [[ ! -f "${ckernel}" ]] && continue;
list_kernel+=("$ckernel") list_kernel+=("$ckernel")
done done
fi fi
} }
## Detect initramfs in "/boot" ## Detect initramfs in "/boot"
detect_initramfs() detect_initramfs()
{ {
list_initramfs=() list_initramfs=()
# Original initramfs (auto-detect) # Original initramfs (auto-detect)
for oinitramfs in "${boot_dir}"/initrd.img-* \ for oinitramfs in "${boot_dir}"/initrd.img-* \
"${boot_dir}"/initrd-*.img \ "${boot_dir}"/initrd-*.img \
"${boot_dir}"/initrd-*.gz \ "${boot_dir}"/initrd-*.gz \
"${boot_dir}"/initramfs-*.img \ "${boot_dir}"/initramfs-*.img \
"${boot_dir}"/initramfs-*.gz ; do "${boot_dir}"/initramfs-*.gz ; 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 [ ! -z "$ninit" ] ; then if [ ! -z "${GRUB_BTRFS_NINIT}" ] ; then
for cinitramfs in "${boot_dir}/${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
} }
## Detect microcode in "/boot" ## Detect microcode in "/boot"
detect_microcode() detect_microcode()
{ {
list_ucode=() list_ucode=()
# Original intel microcode # Original intel/amd microcode (auto-detect)
for oiucode in "${boot_dir}"/intel-ucode.img ; do # See "https://www.gnu.org/software/grub/manual/grub/html_node/Simple-configuration.html"
[[ ! -f "${oiucode}" ]] && continue; for oiucode in "${boot_dir}"/intel-uc.img \
list_ucode+=("$oiucode") "${boot_dir}"/intel-ucode.img \
done "${boot_dir}"/amd-uc.img \
"${boot_dir}"/amd-ucode.img \
"${boot_dir}"/early_ucode.cpio \
"${boot_dir}"/microcode.cpio; do
[[ ! -f "${oiucode}" ]] && continue;
list_ucode+=("$oiucode")
done
# Custom name microcode in GRUB_BTRFS_INTEL_UCODE # Custom name microcode in GRUB_BTRFS_CUSTOM_MICROCODE
if [ ! -z "$microcode" ] ; then if [ ! -z "${GRUB_BTRFS_CUSTOM_MICROCODE}" ] ; then
for cucode in "${boot_dir}/${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
if [ -z "${list_ucode}" ]; then list_ucode=(x); fi if [ -z "${list_ucode}" ]; then list_ucode=(x); fi
} }
## Show full path snapshot or only name ## Show full path snapshot or only name
path_snapshot() path_snapshot()
{ {
case "${path_snapshot}" in case "${GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT:-"true"}" in
true) name_snapshot=("${snap_full_name}");; true) name_snapshot=("${snap_full_name}");;
*) name_snapshot=("${snap_full_name#*"/"}") *) name_snapshot=("${snap_full_name#*"/"}")
esac esac
} }
## Title format in grub-menu ## Title format in grub-menu
title_format() title_format()
{ {
case "${title_format}" in case "${GRUB_BTRFS_TITLE_FORMAT:-"p/d/n"}" in
p/n/d) title_menu="${prefixentry} ${name_snapshot} ${snap_date_time}";; p/n/d) title_menu="${prefixentry} ${name_snapshot} ${snap_date_time}";;
p/d) title_menu="${prefixentry} ${snap_date_time}";; p/d) title_menu="${prefixentry} ${snap_date_time}";;
p/n) title_menu="${prefixentry} ${name_snapshot}";; p/n) title_menu="${prefixentry} ${name_snapshot}";;
d/n) title_menu="${snap_date_time} ${name_snapshot}";; d/n) title_menu="${snap_date_time} ${name_snapshot}";;
n/d) title_menu="${name_snapshot} ${snap_date_time}";; n/d) title_menu="${name_snapshot} ${snap_date_time}";;
p) title_menu="${prefixentry}";; p) title_menu="${prefixentry}";;
d) title_menu="${snap_date_time}";; d) title_menu="${snap_date_time}";;
n) title_menu="${name_snapshot}";; n) title_menu="${name_snapshot}";;
*) title_menu="${prefixentry} ${snap_date_time} ${name_snapshot}" *) title_menu="${prefixentry} ${snap_date_time} ${name_snapshot}"
esac esac
} }
## List of kernels, initramfs and microcode in snapshots ## List of kernels, initramfs and microcode in snapshots
boot_bounded() boot_bounded()
{ {
# Initialize menu entries # Initialize menu entries
IFS=$'\n' IFS=$'\n'
for item in $(snapshot_list); do for item in $(snapshot_list); do
# fix: limit_snap_show=0 [[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0
[[ ${limit_snap_show} -le 0 ]] && break; IFS=$oldIFS
IFS=$oldIFS snap_full_name="$(echo "$item" | cut -d'|' -f2-)" # do not trim it to keep nice formatting
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="$(echo "$item" | cut -d'|' -f2)" snap_dir_name="$(trim "$snap_dir_name")"
snap_dir_name="$(trim "$snap_dir_name")" snap_date_time="$(echo "$item" | cut -d' ' -f1-2)"
snap_date_time="$(echo "$item" | cut -d' ' -f1-2)" snap_date_time="$(trim "$snap_date_time")"
snap_date_time="$(trim "$snap_date_time")"
boot_dir="$gbgmp/$snap_dir_name$boot_directory"
boot_dir="$gbgmp/$snap_dir_name/boot" # Kernel (Original + custom kernel)
# Kernel (Original + custom kernel) detect_kernel
detect_kernel if [ -z "${list_kernel}" ]; then continue; fi
if [ -z "${list_kernel}" ]; then continue; fi name_kernel=("${list_kernel[@]##*"/"}")
name_kernel=("${list_kernel[@]##*"/"}") # Detect rootflags
# Initramfs (Original + custom initramfs) detect_rootflags
detect_initramfs # Initramfs (Original + custom initramfs)
if [ -z "${list_initramfs}" ]; then continue; fi detect_initramfs
name_initramfs=("${list_initramfs[@]##*"/"}") if [ -z "${list_initramfs}" ]; then continue; fi
# microcode (intel-ucode + custom microcode) name_initramfs=("${list_initramfs[@]##*"/"}")
detect_microcode # microcode (auto-detect + custom microcode)
name_microcode=("${list_ucode[@]##*"/"}") detect_microcode
# show snapshot found during run "grub-mkconfig" name_microcode=("${list_ucode[@]##*"/"}")
if [[ "${show_snap_found}" = "true" ]]; then # show snapshot found during run "grub-mkconfig"
printf $"# Found snapshot: %s\n" "$item" >&2 ; if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]]; then
fi printf "Found snapshot: %s\n" "$item" >&2 ;
# Show full path snapshot or only name fi
path_snapshot # Show full path snapshot or only name
# Title format in grub-menu path_snapshot
title_format # Title format in grub-menu
# convert /boot directory to root of GRUB (e.g /boot become /) 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 menuentries boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")"
make_menu_entries # Make menuentries
### Limit snapshots found during run "grub-mkconfig" make_menu_entries
count_limit_snap=$((1+$count_limit_snap)) ### Limit snapshots found during run "grub-mkconfig"
[[ $count_limit_snap -ge $limit_snap_show ]] && break; count_limit_snap=$((1+$count_limit_snap))
# Limit generation of menuentries if exceeds 250 [[ $count_limit_snap -ge $limit_snap_show ]] && break;
# [[ $count_warning_menuentries -ge 250 ]] && break; # Limit generation of menuentries if exceeds 250
done # [[ $count_warning_menuentries -ge 250 ]] && break;
IFS=$oldIFS done
IFS=$oldIFS
} }
boot_separate() boot_separate()
{ {
boot_dir="/boot" boot_dir="${boot_directory}"
# convert /boot directory to root of GRUB (e.g /boot become /) # convert /boot directory to root of GRUB (e.g /boot become /)
boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")" boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")"
# Kernel (Original + custom kernel) # Kernel (Original + custom kernel)
detect_kernel detect_kernel
if [ -z "${list_kernel}" ]; then print_error "Kernels not found."; fi if [ -z "${list_kernel}" ]; then print_error "Kernels not found."; fi
name_kernel=("${list_kernel[@]##*"/"}") name_kernel=("${list_kernel[@]##*"/"}")
# Initramfs (Original + custom initramfs)
detect_initramfs
if [ -z "${list_initramfs}" ]; then print_error "Initramfs not found."; fi
name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode)
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
# Initramfs (Original + custom initramfs) # Initialize menu entries
detect_initramfs IFS=$'\n'
if [ -z "${list_initramfs}" ]; then print_error "Initramfs not found."; fi for item in $(snapshot_list); do
name_initramfs=("${list_initramfs[@]##*"/"}") [[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0
IFS=$oldIFS
# microcode (auto-detect + custom microcode) snap_full_name="$(echo "$item" | cut -d'|' -f2-)" # do not trim it to keep nice formatting
detect_microcode snap_dir_name="$(echo "$item" | cut -d'|' -f2)"
name_microcode=("${list_ucode[@]##*"/"}") snap_dir_name="$(trim "$snap_dir_name")"
snap_date_time="$(echo "$item" | cut -d' ' -f1-2)"
# Initialize menu entries snap_date_time="$(trim "$snap_date_time")"
IFS=$'\n' # Detect rootflags
for item in $(snapshot_list); do detect_rootflags
# fix: limit_snap_show=0 # show snapshot found during run "grub-mkconfig"
[[ ${limit_snap_show} -le 0 ]] && break; if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]]; then
IFS=$oldIFS printf "Found snapshot: %s\n" "$item" >&2 ;
snap_full_name="$(echo "$item" | cut -d'|' -f2-)" # do not trim it to keep nice formatting fi
snap_dir_name="$(echo "$item" | cut -d'|' -f2)" # Show full path snapshot or only name
snap_dir_name="$(trim "$snap_dir_name")" path_snapshot
snap_date_time="$(echo "$item" | cut -d' ' -f1-2)" # Title format in grub-menu
snap_date_time="$(trim "$snap_date_time")" title_format
# show snapshot found during run "grub-mkconfig" # Make menuentries
if [[ "${show_snap_found}" = "true" ]]; then make_menu_entries
printf $"# Found snapshot: %s\n" "$item" >&2 ; # Limit snapshots found during run "grub-mkconfig"
fi count_limit_snap=$((1+$count_limit_snap))
# Show full path snapshot or only name [[ $count_limit_snap -ge $limit_snap_show ]] && break;
path_snapshot # Limit generation of menuentries if exceeds 250
# Title format in grub-menu # [[ $count_warning_menuentries -ge 250 ]] && break;
title_format done
# Make menuentries IFS=$oldIFS
make_menu_entries
# Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+$count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break;
# Limit generation of menuentries if exceeds 250
# [[ $count_warning_menuentries -ge 250 ]] && break;
done
IFS=$oldIFS
} }
### Start ### ### Start
printf "###### - Grub-btrfs: Snapshot detection started - ######\n" >&2 ; printf "Detecting snapshots ...\n" >&2 ;
# if btrfs prog isn't installed, exit # Only support btrfs snapshots
test_btrfs test_btrfs
# Delete existing config # Delete existing config
#rm -f --preserve-root "/boot/$grub_directory/grub-btrfs.cfg" #rm -f --preserve-root "$grub_directory/grub-btrfs.cfg"
> "/boot/$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 subvolid=5 /dev/disk/by-uuid/$root_uuid $gbgmp/
@@ -520,37 +515,35 @@ count_limit_snap=0
# detect uuid requirement # detect uuid requirement
check_uuid_required check_uuid_required
# Detects if /boot is a separate partition # Detects if /boot is a separate partition
if [[ "$override_boot_partition_detection" == "true" ]]; then if [[ "${GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION:-"false"}" == "true" ]]; then
printf "# Info: Override boot partition detection : enable \n" >&2 ; printf "Info: Override boot partition detection : enable \n" >&2 ;
boot_separate boot_separate
else else
if [[ "$root_uuid" != "$boot_uuid" ]]; then if [[ "$root_uuid" != "$boot_uuid" ]]; then
printf "# Info: Separate boot partition detected \n" >&2 ; printf "Info: Separate boot partition detected \n" >&2 ;
boot_separate boot_separate
else else
printf "# Info: Separate boot partition not detected \n" >&2 ; printf "Info: Separate boot partition not detected \n" >&2 ;
boot_bounded boot_bounded
fi fi
fi fi
# unmounting mount point # unmounting mount point
umount $gbgmp 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 ${count_warning_menuentries} total GRUB entries. You might experience issues loading snapshots menu in GRUB.\n" >&2 ;
# printf "# menuentries = $count_warning_menuentries \n" >&2 ; # printf "menuentries = $count_warning_menuentries \n" >&2 ;
# Show total found snapshots # Show total found snapshots
if [[ "${show_total_snap_found}" = "true" && ! -z "${count_limit_snap}" && "${count_limit_snap}" != "0" ]]; then if [[ "${GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND:-"true"}" = "true" && ! -z "${count_limit_snap}" && "${count_limit_snap}" != "0" ]]; then
printf "# Found ${count_limit_snap} snapshot(s)\n" >&2 ; printf "Found ${count_limit_snap} snapshot(s)\n" >&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
root_grub="$(make_system_path_relative_to_its_root /boot/$grub_directory)"
# Make a submenu in GRUB (grub.cfg) # Make a submenu in GRUB (grub.cfg)
cat << EOF cat << EOF
submenu '${submenuname}' { submenu '${submenuname}' ${protection_authorized_users}${unrestricted_access_submenu}{
configfile "\${prefix}/grub-btrfs.cfg" configfile "\${prefix}/grub-btrfs.cfg"
} }
EOF EOF
printf "###### - Grub-btrfs: Snapshot detection ended - ######\n" >&2 ; ### End
### End ###

View File

@@ -1,14 +1,71 @@
PKGNAME ?= grub-btrfs PKGNAME ?= grub-btrfs
PREFIX ?= /usr PREFIX ?= /usr
INITCPIO ?= false
SHARE_DIR = $(DESTDIR)$(PREFIX)/share SHARE_DIR = $(DESTDIR)$(PREFIX)/share
LIB_DIR = $(DESTDIR)$(PREFIX)/lib LIB_DIR = $(DESTDIR)$(PREFIX)/lib
.PHONY: install .PHONY: install uninstall help
install: install:
@if test "$(shell id -u)" != 0; then \
echo "You are not root, run this target as root please."; \
exit 1; \
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
@install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.service @install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.service
@install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.path @install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.path
@install -Dm644 -t "$(SHARE_DIR)/licenses/$(PKGNAME)/" LICENSE @install -Dm644 -t "$(SHARE_DIR)/licenses/$(PKGNAME)/" LICENSE
@# 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)/doc/$(PKGNAME)/" README.md
@install -Dm644 "initramfs/readme.md" "$(SHARE_DIR)/doc/$(PKGNAME)/initramfs-overlayfs.md"
uninstall:
@if test "$(shell id -u)" != 0; then \
echo "You are not root, run this target as root please."; \
exit 1; \
fi
@grub_dirname="$$(grep -oP '^[[:space:]]*GRUB_BTRFS_GRUB_DIRNAME=\K.*' "$(DESTDIR)/etc/default/grub-btrfs/config" | sed "s|\s*#.*||;s|(\s*\(.\+\)\s*)|\1|;s|['\"]||g")"; \
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)/initcpio/install/grub-btrfs-overlayfs"
@rm -f "$(LIB_DIR)/initcpio/hooks/grub-btrfs-overlayfs"
@# Arch Linux UNlike distros only :
@if test "$(INITCPIO)" != true && test -d "$(LIB_DIR)/initcpio"; then \
rmdir --ignore-fail-on-non-empty "$(LIB_DIR)/initcpio/install" || :; \
rmdir --ignore-fail-on-non-empty "$(LIB_DIR)/initcpio/hooks" || :; \
rmdir --ignore-fail-on-non-empty "$(LIB_DIR)/initcpio" || :; \
fi
@rm -f "$(SHARE_DIR)/doc/$(PKGNAME)/README.md"
@rm -f "$(SHARE_DIR)/doc/$(PKGNAME)/initramfs-overlayfs.md"
@rm -f "$(SHARE_DIR)/licenses/$(PKGNAME)/LICENSE"
@rmdir --ignore-fail-on-non-empty "$(SHARE_DIR)/doc/$(PKGNAME)/" || :
@rmdir --ignore-fail-on-non-empty "$(SHARE_DIR)/licenses/$(PKGNAME)/" || :
@rmdir --ignore-fail-on-non-empty "$(DESTDIR)/etc/default/grub-btrfs" || :
help:
@echo
@echo "Usage: $(MAKE) [ <parameter>=<value> ... ] [ <action> ]"
@echo
@echo " actions: install"
@echo " uninstall"
@echo " help"
@echo
@echo " parameter | type | description | defaults"
@echo " ----------+------+--------------------------------+----------------------------"
@echo " DESTDIR | path | install destination | <unset>"
@echo " PREFIX | path | system tree prefix | '/usr'"
@echo " SHARE_DIR | path | shared data location | '\$$(DESTDIR)\$$(PREFIX)/share'"
@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

169
README.md
View File

@@ -6,22 +6,30 @@
This is a version 4.xx of grub-btrfs This is a version 4.xx of grub-btrfs
##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt` ##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt`
## ##
### Description ### Description :
Improves Grub by adding "btrfs snapshots" to the Grub menu. Improves Grub by adding "btrfs snapshots" to the Grub menu.
You can start your system on a "snapshot" from the Grub menu. You can boot your system on a "snapshot" from the Grub menu.
Supports manual snapshots, snapper, timeshift ... Supports manual snapshots, snapper, timeshift ...
##### Warning : it isn't recommended to start on read-only snapshot ##### Warning: booting on read-only snapshots can be tricky
If you choose to do it, `/var/log` or even `/var` must be on a separate subvolume.
Otherwise, make sure your snapshots are writeable.
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 : ### What does grub-btrfs v4.xx do :
* Automatically List snapshots existing on root partition (btrfs). * Automatically List snapshots existing on root partition (btrfs).
* Automatically Detect if "/boot" is in separate partition. * Automatically Detect if "/boot" is in separate partition.
* Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots. * Automatically Detect kernel, initramfs and intel/amd microcode in "/boot" directory on snapshots.
* Automatically Create corresponding "menuentry" in `grub.cfg` * Automatically Create corresponding "menuentry" in `grub.cfg`
* Automatically detect snapper and use snapper's snapshot description if available. * Automatically detect snapper and use snapper's snapshot description if available.
* Automatically generate `grub.cfg` if you use the provided systemd service. * Automatically generate `grub.cfg` if you use the provided systemd service.
## ##
### Installation : ### Installation :
#### Arch Linux #### Arch Linux
@@ -30,120 +38,65 @@ Supports manual snapshots, snapper, timeshift ...
pacman -S grub-btrfs 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.
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`.
## ##
### 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`.
See [config file](https://github.com/Antynea/grub-btrfs/blob/master/config) for more information.
* GRUB_BTRFS_SUBMENUNAME="Arch Linux Snapshots"
Name appearing in the Grub menu.
* GRUB_BTRFS_PREFIXENTRY="Snapshot:"
Add a name ahead your snapshots entries in the Grub menu.
* GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="true"
Show full path snapshot or only name in the Grub menu, weird reaction with snapper.
* GRUB_BTRFS_TITLE_FORMAT="p/d/n"
Custom title, shows/hides p"prefix" d"date" n"name" in the Grub menu, separator "/", custom order available.
* GRUB_BTRFS_LIMIT="50"
Limit the number of snapshots populated in the GRUB menu.
* GRUB_BTRFS_SUBVOLUME_SORT="descending"
Sort the found subvolumes by newest first ("descending") or oldest first ("ascending").
If "ascending" is chosen then
the $GRUB_BTRFS_LIMIT oldest subvolumes will populate the menu.
* GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="true"
Show snapshots found during run "grub-mkconfig".
* GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true"
Show Total number of snapshots found during run "grub-mkconfig".
* GRUB_BTRFS_NKERNEL=("kernel-custom")
Use it only if you have a custom kernel name
* GRUB_BTRFS_NINIT=("initramfs-custom.img" "initrd.img-custom")
Use it only if you have a custom initramfs name.
* GRUB_BTRFS_INTEL_UCODE=("intel-ucode.img")
Use it only if you have custom intel-ucode.
* GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker")
Ignore specific path during run "grub-mkconfig".
For example:
If path is a directory `# Found Snapshot: 2016-03-31 10:24:41` **var/lib/docker/btrfs/subvolumes/...**
use : `GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker")`
If path is a subvolume : `# Found Snapshot: 2016-03-31 10:24:41` **@var/lib/docker/btrfs/subvolumes/...**
use : `GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@var/lib/docker")`
You can combine them
use : `GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@var/lib/docker" "var/lib/docker")`
* GRUB_BTRFS_SNAPPER_CONFIG="root"
Snapper's config name to use.
* GRUB_BTRFS_DISABLE="false"
Disable grub-btrfs.
* GRUB_BTRFS_DIRNAME="grub"
Name of the grub folder in `/boot/`, might be grub2 on some distributions.
* GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="false"
Change to "true" if you have a boot partition in a different subvolume.
* GRUB_BTRFS_MKCONFIG=grub-mkconfig
Name or path of the 'grub-mkconfig' executable; might be 'grub2-mkconfig' on some distributions.
## ##
### Automatically update grub ### Automatically update grub
If you would like Grub to automatically update when a snapshots is made or deleted: 1- If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted:
* Mount your subvolume which contains snapshots to `/.snapshots` * Use `systemctl enable grub-btrfs.path`.
* Use `systemctl start/enable grub-btrfs.path` * `grub-btrfs.path` automatically (re)generates `grub-btrfs.cfg` when a modification appears in `/.snapshots` mount point (by default).
* `grub-btrfs.path` automatically (re)generate `grub.cfg` when a modification appear in `/.snapshots` * If the `/.snapshots` mount point is already mounted, then use `systemctl start grub-btrfs.path` to start monitoring.
Otherwise, the unit will automatically start monitoring when the mount point will be available.
* If your snapshots location aren't mounted in `/.snapshots`, you must modify `grub-btrfs.path` unit using
`systemctl edit --full grub-btrfs.path` and run `systemctl reenable grub-btrfs.path` for changes take effect.
To find out the name of the `.mount` unit
use `systemctl list-units -t mount`.
* For example: Timeshift mounts its snapshot folder in `/run/timeshift/backup/timeshift-btrfs/snapshots`.
Use `systemctl edit --full grub-btrfs.path`.
Then replace the whole block by:
```
[Unit]
Description=Monitors for new snapshots
DefaultDependencies=no
Requires=run-timeshift-backup.mount
After=run-timeshift-backup.mount
BindsTo=run-timeshift-backup.mount
[Path]
PathModified=/run/timeshift/backup/timeshift-btrfs/snapshots
[Install]
WantedBy=run-timeshift-backup.mount
```
Then save and finally run `systemctl reenable grub-btrfs.path` for changes take effect.
Optional:
If the `/run/timeshift/backup/timeshift-btrfs/snapshots` mount point is already mounted,
then use `systemctl start grub-btrfs.path` to start monitoring.
Otherwise, the unit will automatically start monitoring when the mount point will be available.
* 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:
[Look at this comment](https://github.com/Antynea/grub-btrfs/issues/138#issuecomment-766918328)
Currently not implemented
##### 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 ### Special thanks for assistance and contributions
* [maximbaz](https://github.com/maximbaz) * [maximbaz](https://github.com/maximbaz)
* [crossroads1112](https://github.com/crossroads1112) * [All contributors](https://github.com/Antynea/grub-btrfs/graphs/contributors)
* [penetal](https://github.com/penetal)
* [wesbarnett](https://github.com/wesbarnett)
* [Psykar](https://github.com/Psykar)
* [anyc](https://github.com/anyc)
* [daftaupe](https://github.com/daftaupe)
* [N-Parsons](https://github.com/N-Parsons)
## ##

132
config
View File

@@ -1,76 +1,122 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Name appearing in the Grub menu # Disable grub-btrfs.
# Default: "Arch Linux snapshots" # Default: "false"
#GRUB_BTRFS_DISABLE="true"
# Name appearing in the Grub menu.
# Default: "Use distribution information from /etc/os-release."
#GRUB_BTRFS_SUBMENUNAME="Arch Linux snapshots" #GRUB_BTRFS_SUBMENUNAME="Arch Linux snapshots"
# Add a name ahead your snapshots entries in the Grub menu # Add a name ahead your snapshots entries in the Grub menu.
# Default: "Snapshot:" # Default: "Snapshot:"
#GRUB_BTRFS_PREFIXENTRY="Snapshot:" #GRUB_BTRFS_PREFIXENTRY="Snapshot:"
# Show full path snapshot or only name in the Grub menu # Show full path snapshot or only name in the Grub menu, weird reaction with snapper.
# Default: "true" # Default: "true"
#GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="true" #GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="false"
# Custom title # Custom title.
# shows/hides p"prefix" d"date" n"name" in the Grub menu, separator "/", custom order available # shows/hides p"prefix" d"date" n"name" in the Grub menu, separator "/", custom order available.
# Default: "p/d/n" # Default: "p/d/n"
#GRUB_BTRFS_TITLE_FORMAT="p/d/n" #GRUB_BTRFS_TITLE_FORMAT="p/d/n"
# Limit the number of snapshots populated in the GRUB menu # Limit the number of snapshots populated in the GRUB menu.
# Default: "50" # Default: "50"
#GRUB_BTRFS_LIMIT="50" #GRUB_BTRFS_LIMIT="50"
# Sort the found subvolumes by newest first ("descending") or oldest first ("ascending") and show $GRUB_BTRFS_LIMIT first entries. # Sort the found subvolumes by "ogeneration" or "generation" or "path" or "rootid".
# Default: "descending" # # See Sorting section to https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-subvolume#SUBCOMMAND
#GRUB_BTRFS_SUBVOLUME_SORT="descending" # "-rootid" means list snapshot by new ones first.
# Default: "-rootid"
#GRUB_BTRFS_SUBVOLUME_SORT="+ogen,-gen,path,rootid"
# Show snapshots found during run "grub-mkconfig" # Show snapshots found during run "grub-mkconfig"
# Default: "true" # Default: "true"
#GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="true" #GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"
# Show Total of snapshots found during run "grub-mkconfig" # Show Total of snapshots found during run "grub-mkconfig"
# Default: "true" # Default: "true"
#GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true" #GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true"
# Use only if you have custom kernel name # By default, "grub-btrfs" automatically detects most existing kernels.
# Default: # If you have one or more custom kernels, you can add them here.
#GRUB_BTRFS_NKERNEL=("vmlinuz-linux") # Default: ("")
#GRUB_BTRFS_NKERNEL=("kernel-custom" "vmlinux-custom")
# Use only if you have custom initramfs name # By default, "grub-btrfs" automatically detects most existing initramfs.
# Default: # If you have one or more custom initramfs, you can add them here.
#GRUB_BTRFS_NINIT=("initramfs-linux.img" "initramfs-linux-fallback.img") # Default: ("")
#GRUB_BTRFS_NINIT=("initramfs-custom.img" "initrd-custom.img" "otherinit-custom.gz")
# Use only if you have custom intel-ucode # By default, "grub-btrfs" automatically detects most existing microcodes.
# Default: # If you have one or more custom microcodes, you can add them here.
#GRUB_BTRFS_INTEL_UCODE=("intel-ucode.img") # Default: ("")
#GRUB_BTRFS_CUSTOM_MICROCODE=("custom-ucode.img" "custom-uc.img "custom_ucode.cpio")
# Comma seperated mount options to be used when booting a snapshot.
# 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
# takes priority over `fstab` entries.
# NB: Do NOT include "subvol=..." or "subvolid=..." here.
# Default: ""
#GRUB_BTRFS_ROOTFLAGS="space_cache,commit=10,norecovery"
# Ignore specific path during run "grub-mkconfig". # Ignore specific path during run "grub-mkconfig".
# If path is a directory, # Found Snapshot: 2016-03-31 10:24:41 var/lib/docker/btrfs/subvolumes/... # Only exact paths are ignored.
# use : GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker"); # e.g : if `specific path` = @, only `@` snapshot will be ignored.
# If path is a subvolume, # Found Snapshot: 2016-03-31 10:24:41 @var/lib/docker/btrfs/subvolumes/... # Default: ("@")
# use : GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@var/lib/docker"); GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@")
# You can combine them
# use : GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@var/lib/docker" "var/lib/docker")
# Default:
GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker" "@var/lib/docker")
# Ignore prefix path during run "grub-mkconfig".
# Any path starting with the specified string will be ignored.
# e.g : if `prefix path` = @, all snapshots beginning with "@/..." will be ignored.
# Default: ("var/lib/docker" "@var/lib/docker" "@/var/lib/docker")
GRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/docker")
# 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.
# Default: "false"
#GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="true"
# Location of the folder containing the "grub.cfg" file.
# Use by grub-btrfs to save the file "grub-btrfs.cfg".
# Might be grub2 on some systems.
# For example, on Fedora with EFI : "/boot/efi/EFI/fedora"
# Default: "/boot/grub"
#GRUB_BTRFS_GRUB_DIRNAME="/boot/grub2"
# Location of kernels/initramfs/microcode.
# Use by "grub-btrfs" to detect the boot partition and the location of kernels/initrafms/microcodes.
# Default: "/boot"
#GRUB_BTRFS_BOOT_DIRNAME="/boot"
# Name/path of grub-mkconfig command, use by "grub-btrfs.service"
# Might be 'grub2-mkconfig' on some systems (Fedora ...)
# Default paths are /sbin:/bin:/usr/sbin:/usr/bin,
# if your path is missing, report it on the upstream project.
# For example, on Fedora : "/sbin/grub2-mkconfig"
# You can use only name or full path.
# Default: grub-mkconfig
#GRUB_BTRFS_MKCONFIG=/usr/bin/grub2-mkconfig
# Snapper
# Snapper's config name to use # Snapper's config name to use
# Default: "root" # Default: "root"
#GRUB_BTRFS_SNAPPER_CONFIG="root" #GRUB_BTRFS_SNAPPER_CONFIG="root"
# Disable Grub-btrfs # Password protection management for submenu,snapshots
# Refer to the Grub documentation https://www.gnu.org/software/grub/manual/grub/grub.html#Authentication-and-authorisation
# and this comment https://github.com/Antynea/grub-btrfs/issues/95#issuecomment-682295660
#
# Add authorized usernames separate by comma (foo,bar)
# When Grub's password protection is enabled, the superuser is authorized by default, it isn't necessary to add it
# Default: ""
#GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS="foo,bar"
#
# Disable authentication support for submenu of Grub-btrfs only (--unrestricted)
# doesn't work if GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS isn't empty
# Default: "false" # Default: "false"
#GRUB_BTRFS_DISABLE="false" #GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU="true"
# Change to "true" if you have a boot partition in a different subvolume
# Default: "false"
#GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="false"
# Might be grub2 on some systems ex. /boot/grub2/...
# Default: "grub"
#GRUB_BTRFS_DIRNAME="grub"
# Might be 'grub2-mkconfig' on some systems
# Default: /usr/bin/grub-mkconfig
#GRUB_BTRFS_MKCONFIG=/usr/bin/grub2-mkconfig

View File

@@ -1,8 +1,12 @@
[Unit] [Unit]
Description=Monitors for new snapshots Description=Monitors for new snapshots
DefaultDependencies=no
Requires=\x2esnapshots.mount
After=\x2esnapshots.mount
BindsTo=\x2esnapshots.mount
[Path] [Path]
PathModified=/.snapshots PathModified=/.snapshots
[Install] [Install]
WantedBy=multi-user.target WantedBy=\x2esnapshots.mount

View File

@@ -8,4 +8,4 @@ Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin"
# Load environment variables from the configuration # Load environment variables from the configuration
EnvironmentFile=/etc/default/grub-btrfs/config EnvironmentFile=/etc/default/grub-btrfs/config
# Regenerate just '/boot/grub/grub-btrfs.cfg' if it exists and is not empty, else regenerate the whole grub menu # Regenerate just '/boot/grub/grub-btrfs.cfg' if it exists and is not empty, else regenerate the whole grub menu
ExecStart=/bin/bash -c 'if [ -s "/boot/${GRUB_BTRFS_DIRNAME:-grub}/grub-btrfs.cfg" ]; then /etc/grub.d/41_snapshots-btrfs; else ${GRUB_BTRFS_MKCONFIG:-/usr/bin/grub-mkconfig} -o /boot/${GRUB_BTRFS_DIRNAME:-grub}/grub.cfg; fi' ExecStart=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'

View File

@@ -0,0 +1,15 @@
#!/usr/bin/ash
run_latehook() {
local root_mnt="/new_root"
local current_dev=$(resolve_device "$root"); # resolve devices for blkid
if [[ $(blkid "${current_dev}" -s TYPE -o value) = "btrfs" ]] && [[ $(btrfs property get ${root_mnt} ro) != "ro=false" ]]; then # run only on a read only snapshot
local lower_dir=$(mktemp -d -p /)
local ram_dir=$(mktemp -d -p /)
mount --move ${root_mnt} ${lower_dir} # move new_root to lower_dir
mount -t tmpfs cowspace ${ram_dir} #meuh!!! space, you can't test !
mkdir -p ${ram_dir}/upper
mkdir -p ${ram_dir}/work
mount -t overlay -o lowerdir=${lower_dir},upperdir=${ram_dir}/upper,workdir=${ram_dir}/work rootfs ${root_mnt}
fi
}

View File

@@ -0,0 +1,18 @@
#!/bin/bash
build() {
add_module btrfs
add_module overlay
add_binary btrfs
add_binary btrfsck
add_binary blkid
add_runscript
}
help() {
cat <<HELPEOF
This hook uses overlayfs to boot on a read only snapshot.
HELPEOF
}
# vim: set ft=sh ts=4 sw=4 et:

45
initramfs/readme.md Normal file
View File

@@ -0,0 +1,45 @@
### Description :
Booting on a snapshot in read-only mode can be tricky.
An elegant way is to boot this snapshot using overlayfs (included in the kernel ≥ 3.18).
Using overlayfs, the booted snapshot will behave like a live-cd in non-persistent mode.
The snapshot will not be modified, the system will be able to boot correctly, because a writeable folder will be included in the ram.
(no more problems due to `/var` not open for writing)
Any changes in this system thus started will be lost when the system is rebooted/shutdown.
To do this, it is necessary to modify the initramfs.
This means that any snapshot that does not include this modified initramfs will not be able to benefit from it.
(except for separate boot partitions)
#
### Installation :
#### Arch Linux
1.
`Pacman -S grub-btrfs`
Or if you use git
copy the `overlay_snap_ro-install` file to `/etc/initcpio/install/grub-btrfs-overlayfs`
copy the `overlay_snap_ro-hook` file to `/etc/initcpio/hooks/grub-btrfs-overlayfs`
You must rename the files. (I did it above)
For example :
`overlay_snap_ro-install` to `grub-btrfs-overlayfs`
`overlay_snap_ro-hook` to `grub-btrfs-overlayfs`
Keep in mind that the files must have exactly the same name to ensure a match.
2.
Edit the file `/etc/mkinitcpio.conf`
Added hook `grub-btrfs-overlayfs` at the end of the line `HOOKS`.
For example :
`HOOKS=(base udev autodetect modconf block filesystems keyboard fsck grub-btrfs-overlayfs)`
You notice that the name of the `hook` must match the name of the 2 installed files. (don't forget it)
3.
Re-generate your initramfs
`mkinitcpio -P` (option -P means, all preset present in `/etc/mkinitcpio.d`)
#### Other distribution
Refer to your distribution's documentation
or contribute to this project to add a paragraph.
#