From d54f3d7366d188f32863c2800773b82a98657b07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Sat, 20 Aug 2022 00:59:57 +0200 Subject: [PATCH 01/11] grub-btrfsd: Fix #211 for OpenRC-Daemon --- Makefile | 1 + README.md | 23 ++++++++++++++++------- grub-btrfs-openrc | 42 +++++++++++++++++++++++++++++++++++++++--- grub-btrfsd.confd | 13 ++++++++++--- grub-btrfsd.initd | 8 +++----- 5 files changed, 69 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 04b1575..2807af2 100644 --- a/Makefile +++ b/Makefile @@ -69,6 +69,7 @@ uninstall: help: @echo @echo "Usage: $(MAKE) [ = ... ] [ ]" + @echo "Example: $(MAKE) OPENRC=true SYSTEMD=false install" @echo @echo " actions: install" @echo " uninstall" diff --git a/README.md b/README.md index 9550a5d..bf96dd4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,11 @@ ## grub-btrfs -This is a version 4.xx of grub-btrfs +[![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 + ##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt` - - - ### Description: @@ -22,7 +26,7 @@ This project includes its own solution. Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/initramfs/readme.md). - - - -### What features does grub-btrfs v4.xx have? +### What features does grub-btrfs have? * 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. @@ -47,9 +51,13 @@ eselect repository enable guru emerge --sync ``` + Now merge grub-btrfs via `emerge app-backup/grub-btrfs` +If you are using SystemD on Gentoo, make sure the USE-Flag `systemD` is set. (Either globally in make.conf or in package.use for the package app-backup/grub-btrfs) +Without systemD USE-Flag the OpenRC-Daemon of grub-btrfs will be installed. + #### Kali Linux [grub-btrfs](http://pkg.kali.org/pkg/grub-btrfs) is available in the Kali Linux repository and can be installed with: ``` @@ -64,7 +72,7 @@ Booting into read-only snapshots is fully supported when choosing "btrfs" as fil * [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/) + * [gawk](https://archlinux.org/packages/core/x86_64/gawk/) #### NOTE: All distros Generate your grub menu after installation for the changes to take effect. @@ -128,11 +136,12 @@ Currently not implemented ## #### OpenRC 1. If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted: +* If you are using Timeshift, newer versions of it mount their snapshots to `/run/timeshift/$pidofthecurrentlyrunnigtimeshift/backup/timeshift-btrfs`. The OpenRC-Daemon can automatically take care of the detection of the correct PID and directory if you set the variable `timeshift_auto` to `true` in `etc/conf.d/grub-btrfsd`. In this case the variable `snapshots` has no influence. +* If you don't want to use `timeshift_auto`, set the variable `snapshots` in the file `/etc/conf.d/grub-btrfsd` to the path of your snapshot directory. By default this is set to snappers default directory, `./snapper`. +For Timeshift keep in mind, that newer versions of Timeshift will not work with the `/run/timeshift/backup/timeshift-btrfs/snapshots` path. However there is a [workaround](https://www.lorenzobettini.it/2022/07/timeshift-and-grub-btrfs-in-linux-arch/) that works for now. * 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 + * `grub-btrfsd` automatically watches the snapshot directory and updates the grub-menu when a change occurs 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` @@ -150,7 +159,7 @@ Just add the following script as `/etc/local.d/grub-btrfs-update.stop` 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`. + Make your script executable 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` diff --git a/grub-btrfs-openrc b/grub-btrfs-openrc index 988be81..738d590 100755 --- a/grub-btrfs-openrc +++ b/grub-btrfs-openrc @@ -1,7 +1,43 @@ #!/bin/sh -echo $$ > /run/grub-btrfsd.pid -snapshots="${1:-/run/timeshift/backup/timeshift-btrfs/snapshots}" +# Copyright 2022 Pascal Jaeger +# Distributed under the terms of the GNU General Public License v3 +# Update GRUB when new BTRFS snapshots are created. -while true; do sleep 1 && inotifywait -e create -e delete "$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 +timeshift_pid +watchtime=0 +snapshots="${1}" +timeshift_auto="${2}" +if ! [ "${#snapshots}" -gt 0 ] && ! [ ${timeshift_auto} ]; then + echo "Please specify the snapshots directory" >&2 + exit 1 +fi +if [ ${timeshift_auto} ]; then + watchtime=15 +else + watchtime=0 +fi + +while true; do + if [ ${timeshift_auto} == "true" ] && ! [ "${#timeshift_pid}" -gt 0 ] ; then + inotifywait -e create -e delete /run/timeshift && { + sleep 1 + timeshift_pid=$(ps ax | awk '{sub(/.*\//, "", $5)} $5 ~ /timeshift/ {print $1}') + snapshots="/run/timeshift/${timeshift_pid}/backup/timeshift-btrfs/snapshots" + } + else + while [ -d "$snapshots" ]; do + sleep 1 + inotifywait -e create -e delete -e unmount -t "$watchtime" "$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 + timeshift_pid="" + fi +done diff --git a/grub-btrfsd.confd b/grub-btrfsd.confd index 9033c82..adeff11 100644 --- a/grub-btrfsd.confd +++ b/grub-btrfsd.confd @@ -1,3 +1,10 @@ -# Where to locate the root snapshots -#snapshots="/.snapshots" # Snapper in the root directory -snapshots="/run/timeshift/backup/timeshift-btrfs/snapshots" # Timeshift +# Copyright 2022 Pascal Jaeger +# Distributed under the terms of the GNU General Public License v3 + +## Where to locate the root snapshots +snapshots="/.snapshots" # Snapper in the root directory +#snapshots="/run/timeshift/backup/timeshift-btrfs/snapshots" # Timeshift < v22.06 + +## Autodetect timeshift snapshot directory. If this it set to true, variable snapshots is not taken into account. Use this for Timeshift >= v22.06 +timeshift_auto=true # Timeshift >= v22.06 +#timeshift_auto=false # snapper diff --git a/grub-btrfsd.initd b/grub-btrfsd.initd index 3782782..29e4e39 100755 --- a/grub-btrfsd.initd +++ b/grub-btrfsd.initd @@ -1,15 +1,13 @@ #!/sbin/openrc-run -# Copyright 1999-2021 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 +# Copyright 2021 Pascal Jaeger +# Distributed under the terms of the GNU General Public License v3 name="grub-btrfs daemon" command="/usr/bin/grub-btrfs-openrc" -command_args="${snapshots}" +command_args="${snapshots} ${timeshift_auto}" pidfile="/run/{RC_SVCNAME}.pid" command_background=true depend() { use localmount } - - From 6280f95139412b8e00e70767881080f30161a321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Sat, 20 Aug 2022 01:24:25 +0200 Subject: [PATCH 02/11] grub-btrfs: Give messages when the script exits --- 41_snapshots-btrfs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/41_snapshots-btrfs b/41_snapshots-btrfs index befdb31..add2b37 100644 --- a/41_snapshots-btrfs +++ b/41_snapshots-btrfs @@ -42,14 +42,6 @@ grub_btrfs_config="${sysconfdir}/default/grub-btrfs/config" [[ -f "$grub_btrfs_config" ]] && . "$grub_btrfs_config" [[ -f "${sysconfdir}/default/grub" ]] && . "${sysconfdir}/default/grub" -## Exit the script, if: -[[ "${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() { @@ -59,6 +51,14 @@ print_error() exit 0 } +## Exit the script, if: +[[ "${GRUB_BTRFS_DISABLE,,}" == "true" ]] && print_error "GRUB_BTRFS_DISABLE is set to true (default=false)" +if ! type btrfs >/dev/null 2>&1; then print_error "btrfs-progs isn't installed"; fi +[[ -f "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" ]] && . "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" || print_error "grub-mkconfig_lib couldn't be found" +root_fs=$(${grub_probe} --target="fs" / 2>/dev/null) +[[ "$root_fs" != "btrfs" ]] && print_error "Root filesystem isn't btrfs" + + printf "Detecting snapshots ...\n" >&2 ; ## Submenu name From 14c42b82eb9286cd3ff52ef2c519d01250b65dbe Mon Sep 17 00:00:00 2001 From: Pascal J Date: Sat, 20 Aug 2022 11:01:06 +0200 Subject: [PATCH 03/11] grub-btrfsd: Update README.md, Fix #213 Signed-off-by: Jaeger --- README.md | 109 +++++++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index bf96dd4..ef378fa 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,9 @@ ## grub-btrfs -[![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 - -##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt` +* BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt` - - - -### Description: +### Description Improves grub by adding "btrfs snapshots" to the grub menu. You can boot your system on a "snapshot" from the grub menu. @@ -35,7 +30,7 @@ Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/i * Automatically generate `grub.cfg` if you use the provided systemd service. - - - -### Installation: +### Installation #### Arch Linux The package is available in the community repository [grub-btrfs](https://archlinux.org/packages/community/any/grub-btrfs/) ``` @@ -50,14 +45,12 @@ emerge -av app-eselect/eselect-repository eselect repository enable guru emerge --sync ``` - - -Now merge grub-btrfs via -`emerge app-backup/grub-btrfs` - If you are using SystemD on Gentoo, make sure the USE-Flag `systemD` is set. (Either globally in make.conf or in package.use for the package app-backup/grub-btrfs) Without systemD USE-Flag the OpenRC-Daemon of grub-btrfs will be installed. +Emerge grub-btrfs via +`emerge app-backup/grub-btrfs` + #### Kali Linux [grub-btrfs](http://pkg.kali.org/pkg/grub-btrfs) is available in the Kali Linux repository and can be installed with: ``` @@ -81,29 +74,38 @@ 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: - +### 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. +#### 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. - - - -### Automatically update grub upon snapshot: +### SystemD service +#### Automatically update grub upon snapshot To automatically regenerate `grub-btrfs.cfg` when a modification appears in the `/.snapshots` mount point, run -```bash +``` systemctl enable grub-btrfs.path systemctl start grub-btrfs.path # In case the mount point is available already ``` Monitoring starts automatically when the mount point becomes available. -#### Snapshots not in `/.snapshots` +##### Snapshots not in `/.snapshots` To modify `grub-btrfs.path` run -```bash +``` systemctl edit --full grub-btrfs.path systemctl reenable grub-btrfs.path ``` To find out the name of the `.mount` unit use `systemctl list-units -t mount`. +#### Automatically update grub upon restart/ boot: +[Look at this comment](https://github.com/Antynea/grub-btrfs/issues/138#issuecomment-766918328) +Currently not implemented + **Timeshift** + 1. Run `systemctl edit --full grub-btrfs.path` 1. Replace the whole block by: ``` @@ -128,47 +130,52 @@ Note: You can view your change to `systemctl cat grub-btrfs.path`. To revert change use `systemctl revert grub-btrfs.path`. ----- -### Automatically update grub upon restart/boot: -[Look at this comment](https://github.com/Antynea/grub-btrfs/issues/138#issuecomment-766918328) -Currently not implemented +Note: If you are using timeshift version v22.06 or newer, snapshots are now saved in the direcory `/run/timeshift/$PIDofthecurrentlyrunnigtimeshift/backup/timeshift-btrfs` by Timeshift. The PID is changing everytime you open Timeshift. This can not be changed, but when the mount `/run/timeshift/backup/` is created in `/etc/fstab` timeshift will use that. For further information on this workaround see [Lorenzo Bettinis blog](https://www.lorenzobettini.it/2022/07/timeshift-and-grub-btrfs-in-linux-arch/). ## -#### OpenRC -1. If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted: -* If you are using Timeshift, newer versions of it mount their snapshots to `/run/timeshift/$pidofthecurrentlyrunnigtimeshift/backup/timeshift-btrfs`. The OpenRC-Daemon can automatically take care of the detection of the correct PID and directory if you set the variable `timeshift_auto` to `true` in `etc/conf.d/grub-btrfsd`. In this case the variable `snapshots` has no influence. -* If you don't want to use `timeshift_auto`, set the variable `snapshots` in the file `/etc/conf.d/grub-btrfsd` to the path of your snapshot directory. By default this is set to snappers default directory, `./snapper`. -For Timeshift keep in mind, that newer versions of Timeshift will not work with the `/run/timeshift/backup/timeshift-btrfs/snapshots` path. However there is a [workaround](https://www.lorenzobettini.it/2022/07/timeshift-and-grub-btrfs-in-linux-arch/) that works for now. -* 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 and updates the grub-menu when a change occurs +### OpenRC daemon +#### Automatically update grub upon snapshot +If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted, configure `/etc/conf.d/grub-btrfsd` and after that start the daemon. +###### Timeshift versions >= v22.06 (default) +This is the default setting, you don't need to change anything in `/etc/conf.d/grub-btrfsd`, keep on reading at the "How to (auto)start the daemon" heading. +Newer versions of Timeshift mount their snapshots to `/run/timeshift/$PIDofthecurrentlyrunnigtimeshift/backup/timeshift-btrfs`. The PID is changing everytime you close Timeshift and open it again. The OpenRC-Daemon can automatically take care of the detection of the correct PID and directory if you set the variable `timeshift_auto` to `true` in `/etc/conf.d/grub-btrfsd`. In this case the variable `snapshots` has no influence. +###### Timeshift versions < v22.06 +If you don't want to use `timeshift_auto`, set the variable `snapshots` in the file `/etc/conf.d/grub-btrfsd` to the path of your snapshot directory. This is usually `/run/timeshift/backup/timeshift-btrfs/snapshots`. This will not work for newer Timeshift versions, however there is a [workaround](https://www.lorenzobettini.it/2022/07/timeshift-and-grub-btrfs-in-linux-arch/) that works for now. Basically you need to mount the root subvolume to `/run/timeshift/backup` by putting this line into `/etc/fstab`: +``` +UUID= /run/timeshift/backup btrfs defaults,noatime 0 0 +``` +You can get your UUID with the command `blkid`. -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` - ```bash - #!/bin/bash +###### Snapper +For snapper set `timeshift-auto=false` and `snapshots` to Snapper snapshots directory. (usually `/.snapshots`) +##### How to (auto)start the daemon +Use `sudo 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 `sudo rc-service grub-btrfsd start`. +`grub-btrfsd` then automatically watches the snapshot directory and updates the grub-menu when a change occurs. +When you changed a setting in `/etc/conf.d/grub-btrfd`, you have to restart the daemon with `sudo rc-service grub-btrfd restart` to make the change become effective. + +#### Automatically update grub upon restart/boot: +If you would like the grub-btrfs menu to automatically update on system restart/ shutdown, just add the following script as `/etc/local.d/grub-btrfs-update.stop`: +```bash +#!/usr/bin/env bash + +description="Update the grub btrfs snapshots menu" +name="grub-btrfs-update" + +depend() +{ + use localmount +} - 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 executable with `chmod a+x /etc/local.d/grub-btrfs-update.stop`. +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 executable 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 * [Maxim Baz](https://github.com/maximbaz) From 961675ca31a1f18409ada042d1bf3289c18573e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Mon, 29 Aug 2022 22:11:01 +0200 Subject: [PATCH 04/11] grub-btrfsd: Merge openrc and systemd daemon Fix #213, Fix #211, Fix #215 --- Makefile | 47 ++++++-- README.md | 188 +++++++++++++++++------------ grub-btrfs-openrc | 43 ------- grub-btrfs.path | 12 -- grub-btrfs.service | 11 -- grub-btrfsd | 151 +++++++++++++++++++++++ grub-btrfsd.confd | 9 +- grub-btrfsd.initd | 4 +- grub-btrfsd.service | 19 +++ manpages/grub-btrfs.8.man | 240 +++++++++++++++++++++++++++++++++++++ manpages/grub-btrfs.8.org | 180 ++++++++++++++++++++++++++++ manpages/grub-btrfsd.8.man | 63 ++++++++++ manpages/grub-btrfsd.8.org | 57 +++++++++ 13 files changed, 870 insertions(+), 154 deletions(-) delete mode 100755 grub-btrfs-openrc delete mode 100644 grub-btrfs.path delete mode 100644 grub-btrfs.service create mode 100755 grub-btrfsd create mode 100644 grub-btrfsd.service create mode 100644 manpages/grub-btrfs.8.man create mode 100644 manpages/grub-btrfs.8.org create mode 100644 manpages/grub-btrfsd.8.man create mode 100644 manpages/grub-btrfsd.8.org diff --git a/Makefile b/Makefile index 2807af2..93be560 100644 --- a/Makefile +++ b/Makefile @@ -8,37 +8,64 @@ OPENRC ?= false SHARE_DIR = $(DESTDIR)$(PREFIX)/share LIB_DIR = $(DESTDIR)$(PREFIX)/lib BIN_DIR = $(DESTDIR)$(PREFIX)/bin +MAN_DIR = $(SHARE_DIR)/man -.PHONY: install uninstall help +TEMP_DIR = ./temp + +.PHONY: install uninstall clean help install: @if test "$(shell id -u)" != 0; then \ echo "You are not root, run this target as root please."; \ exit 1; \ fi + @echo " Installing " + @echo + @echo " :::::::: ::::::::: ::: ::: ::::::::: ::::::::: ::::::::::: ::::::::: :::::::::: :::::::: " + @echo " :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: :+: " + @echo " +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ +:+ " + @echo " :#: +#++:++#: +#+ +:+ +#++:++#+ +#++:++#++:++ +#++:++#+ +#+ +#++:++#: :#::+::# +#++:++#++ " + @echo " +#+ +#+# +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ +#+ " + @echo " #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# #+# " + @echo " ######## ### ### ######## ######### ######### ### ### ### ### ######## " + @echo + @echo " For further information visit https://github.com/Antynea/grub-btrfs or read the man page: 'man grub-btrfs'" + @echo + @mkdir "${TEMP_DIR}" + @chmod 777 ${TEMP_DIR} + @cp manpages/grub-btrfs.8.man ${TEMP_DIR}/grub-btrfs.8 + @bzip2 ${TEMP_DIR}/grub-btrfs.8 + @install -Dm644 -t "${MAN_DIR}/man8" "${TEMP_DIR}/grub-btrfs.8.bz2" + @cp manpages/grub-btrfsd.8.man ${TEMP_DIR}/grub-btrfsd.8 + @bzip2 ${TEMP_DIR}/grub-btrfsd.8 + @install -Dm644 -t "${MAN_DIR}/man8" "${TEMP_DIR}/grub-btrfsd.8.bz2"; @install -Dm755 -t "$(DESTDIR)/etc/grub.d/" 41_snapshots-btrfs @install -Dm644 -t "$(DESTDIR)/etc/default/grub-btrfs/" config + @install -Dm744 -t "$(BIN_DIR)/" grub-btrfsd; @# 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; \ + echo "Installing systemd .service file"; \ + install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfsd.service; \ fi @# OpenRC init system @if test "$(OPENRC)" = true; then \ - install -Dm744 -t "$(BIN_DIR)/" grub-btrfs-openrc; \ + echo "Installing openRC init.d & conf.d file"; \ install -Dm744 grub-btrfsd.initd "$(DESTDIR)/etc/init.d/grub-btrfsd"; \ install -Dm644 grub-btrfsd.confd "$(DESTDIR)/etc/conf.d/grub-btrfsd"; \ fi @# Arch Linux like distros only : @if test "$(INITCPIO)" = true; then \ + echo "Installing initcpio hook"; \ 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" + @rm -rf "${TEMP_DIR}" uninstall: + @echo "Uninstalling grub-btrfs" @if test "$(shell id -u)" != 0; then \ echo "You are not root, run this target as root please."; \ exit 1; \ @@ -47,12 +74,14 @@ 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.path" - @rm -f "$(LIB_DIR)/systemd/system/grub-btrfs.service" - @rm -f "$(BIN_DIR)/grub-btrfs-openrc;" + @rm -f "$(LIB_DIR)/systemd/system/grub-btrfsd.service" + @rm -f "$(BIN_DIR)/grub-btrfsd;" @rm -f "$(DESTDIR)/etc/init.d/grub-btrfsd;" + @rm -f "$(DESTDIR)/etc/conf.d/grub-btrfsd;" @rm -f "$(LIB_DIR)/initcpio/install/grub-btrfs-overlayfs" @rm -f "$(LIB_DIR)/initcpio/hooks/grub-btrfs-overlayfs" + @rm -f "$(MAN_DIR)/man8/grub-btrfs.8.bz2" + @rm -f "$(MAN_DIR)/man8/grub-btrfsd.8.bz2" @# 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" || :; \ @@ -66,6 +95,10 @@ uninstall: @rmdir --ignore-fail-on-non-empty "$(SHARE_DIR)/licenses/$(PKGNAME)/" || : @rmdir --ignore-fail-on-non-empty "$(DESTDIR)/etc/default/grub-btrfs" || : +clean: + @echo "Deleting ./temp" + @rm -rf "${TEMP_DIR}" + help: @echo @echo "Usage: $(MAKE) [ = ... ] [ ]" diff --git a/README.md b/README.md index ef378fa..700a587 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ ## grub-btrfs -* BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt` +##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt` - - - -### Description +### Description: Improves grub by adding "btrfs snapshots" to the grub menu. You can boot your system on a "snapshot" from the grub menu. @@ -27,10 +27,10 @@ Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/i * Automatically detect kernel, initramfs and intel/amd microcode in `/boot` directory on snapshots. * Automatically create corresponding "menuentry" in `grub.cfg` * Automatically detect the type/tags and descriptions/comments of snapper/timeshift snapshots. -* Automatically generate `grub.cfg` if you use the provided systemd service. +* Automatically generate `grub.cfg` if you use the provided systemd/ openRC service. - - - -### Installation +### Installation: #### Arch Linux The package is available in the community repository [grub-btrfs](https://archlinux.org/packages/community/any/grub-btrfs/) ``` @@ -45,8 +45,8 @@ emerge -av app-eselect/eselect-repository eselect repository enable guru emerge --sync ``` -If you are using SystemD on Gentoo, make sure the USE-Flag `systemD` is set. (Either globally in make.conf or in package.use for the package app-backup/grub-btrfs) -Without systemD USE-Flag the OpenRC-Daemon of grub-btrfs will be installed. +If you are using Systemd on Gentoo, make sure the USE-Flag `systemd` is set. (Either globally in make.conf or in package.use for the package app-backup/grub-btrfs) +Without systemd USE-Flag the OpenRC-daemon of grub-btrfs will be installed. Emerge grub-btrfs via `emerge app-backup/grub-btrfs` @@ -66,6 +66,7 @@ Booting into read-only snapshots is fully supported when choosing "btrfs" as fil * [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/) + * (optional for the daemon)[inotify-tools](https://archlinux.org/packages/community/x86_64/inotify-tools/) #### NOTE: All distros Generate your grub menu after installation for the changes to take effect. @@ -74,87 +75,122 @@ 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 +### 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. +For further information see [config file](https://github.com/Antynea/grub-btrfs/blob/master/config) or `man grub-btrfs` + +#### grub-btrfsd daemon +Grub-btrfs comes with a daemon script that automatically updates the grub menu when it sees a snapshot being created or deleted in a directory it is given via command line. + +The daemon can be configured by passing different command line arguments to it. This can be change by either running +```bash +sudo systemctl edit --full grub-btrfsd +``` +(when using systemd) or by editing `/etc/conf.d/grub-btrfsd` (when using openRC). In either case the daemon must be restarted for the changes to take effect with +```bash +sudo systemctl restart grub-btrfsd # for systemd + +``` +or +``` +sudo rc-service grub-btrfsd restart # for openRC +``` + +It is also possible to start the daemon without systemd or openRC. In this case, the daemon should be stopped with +```bash +sudo systemctl stop grub-btrfsd # for systemd +``` +or +```bash +sudo rc-service grub-btrfsd stop # for openRC +``` +Then the daemon can be manually run and played around with with the command `grub-btrfsd`. +For additional information on daemon script and its arguments, run `grub-btrfsd -h` and see `man grub-btrfsd` #### 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. - - - -### SystemD service -#### Automatically update grub upon snapshot -To automatically regenerate `grub-btrfs.cfg` when a modification appears in the `/.snapshots` mount point, run -``` -systemctl enable grub-btrfs.path -systemctl start grub-btrfs.path # In case the mount point is available already -``` -Monitoring starts automatically when the mount point becomes available. - -##### Snapshots not in `/.snapshots` -To modify `grub-btrfs.path` run -``` -systemctl edit --full grub-btrfs.path -systemctl reenable grub-btrfs.path -``` -To find out the name of the `.mount` unit use `systemctl list-units -t mount`. +### Automatically update grub upon snapshot +Grub-btrfs comes with its own daemon, that watches the snapshot directory for you and updates the grub menu automatically every time a snapshot is created or deleted. -#### Automatically update grub upon restart/ boot: +To start it now, run +```bash +sudo systemctl start grub-btrfsd # for systemd +``` +or +```bash +sudo rc-service grub-btrfsd start # for openRC +``` + +To activate it during system startup, run +```bash +sudo systemctl enable grub-btrfsd # for systemd +``` +or +```bash +sudo rc-config add grub-btrfsd default # for openRC +``` + +#### Snapshots not in `/.snapshots` +NOTE: This works also for Timeshift versions < 22.06, the path to watch would be `/run/timeshift/backup/timeshift-btrfs/snapshots`. +##### Systemd +By default the daemon is watching the directory `/.snapshots`. If the daemon should watch a different directory, it can be edited with +```bash +sudo systemctl edit --full grub-btrfsd +``` +What should be edited is the `/.snapshots`-part in the line that says `ExecStart=/usr/bin/grub-btrfsd /.snapshots` +When done, the service should be restarted with +``` bash +sudo systemctl restart grub-btrfsd +``` + +##### OpenRC +Arguments are passed to grub-btrfsd via the file `/etc/conf.d/grub-btrfsd`. +The variable `snapshots` defines, where the daemon will watch for snapshots. +After that, the daemon should be restarted with +``` bash +sudo rc-service grub-btrfsd restart +``` + +**Timeshift >=22.06** +Newer Timeshift versions create a new directory after their process ID in `/run/timeshift` every time they are started. The PID is going to be different every time. +Therefore the daemon can not simply watch a directory, it watches `/run/timeshift` first, if a directory is created it gets Timeshifts current PID, then watches a directory in that newly created directory from Timeshift. +Anyhow, to activate this mode of the daemon, `--timeshift-auto` must be passed to the daemon as a command line argument. + +#### Systemd +Servicefile of grub-btrfsd can be edited with +```bash +sudo systemctl edit --full grub-btrfsd +``` +The line that says `ExecStart=/usr/bin/grub-btrfsd /.snapshots` should be edited into `ExecStart=/usr/bin/grub-btrfsd --timeshift-auto`. +When done, the service should be restarted with +``` bash +sudo systemctl restart grub-btrfsd +``` + +Note: +You can view your change to `systemctl cat grub-btrfsd`. +To revert change use `systemctl revert grub-btrfsd`. + +#### OpenRC +Arguments are passed to grub-btrfsd via the file `/etc/conf.d/grub-btrfsd`. +The variable `optional_args` defines, which optional arguments get passed to the daemon. +Uncomment `#optional_args+="--timeshift-auto "` to pass the command line option `--timeshift-auto` to it. +After that, the daemon should be restarted with +``` bash +sudo rc-service grub-btrfsd restart +``` + +---- +### Automatically update grub upon restart/boot: +#### Systemd [Look at this comment](https://github.com/Antynea/grub-btrfs/issues/138#issuecomment-766918328) Currently not implemented -**Timeshift** - -1. Run `systemctl edit --full grub-btrfs.path` -1. 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 -``` -1. Run `systemctl reenable grub-btrfs.path` to reload the changes you made - -1. Run `systemctl start grub-btrfs.path` to start monitoring.
Otherwise, the unit will automatically start monitoring when the mount point will be available. - -Note: -You can view your change to `systemctl cat grub-btrfs.path`. -To revert change use `systemctl revert grub-btrfs.path`. - -Note: If you are using timeshift version v22.06 or newer, snapshots are now saved in the direcory `/run/timeshift/$PIDofthecurrentlyrunnigtimeshift/backup/timeshift-btrfs` by Timeshift. The PID is changing everytime you open Timeshift. This can not be changed, but when the mount `/run/timeshift/backup/` is created in `/etc/fstab` timeshift will use that. For further information on this workaround see [Lorenzo Bettinis blog](https://www.lorenzobettini.it/2022/07/timeshift-and-grub-btrfs-in-linux-arch/). - -## -### OpenRC daemon -#### Automatically update grub upon snapshot -If you would like grub-btrfs menu to automatically update when a snapshot is created or deleted, configure `/etc/conf.d/grub-btrfsd` and after that start the daemon. -###### Timeshift versions >= v22.06 (default) -This is the default setting, you don't need to change anything in `/etc/conf.d/grub-btrfsd`, keep on reading at the "How to (auto)start the daemon" heading. -Newer versions of Timeshift mount their snapshots to `/run/timeshift/$PIDofthecurrentlyrunnigtimeshift/backup/timeshift-btrfs`. The PID is changing everytime you close Timeshift and open it again. The OpenRC-Daemon can automatically take care of the detection of the correct PID and directory if you set the variable `timeshift_auto` to `true` in `/etc/conf.d/grub-btrfsd`. In this case the variable `snapshots` has no influence. -###### Timeshift versions < v22.06 -If you don't want to use `timeshift_auto`, set the variable `snapshots` in the file `/etc/conf.d/grub-btrfsd` to the path of your snapshot directory. This is usually `/run/timeshift/backup/timeshift-btrfs/snapshots`. This will not work for newer Timeshift versions, however there is a [workaround](https://www.lorenzobettini.it/2022/07/timeshift-and-grub-btrfs-in-linux-arch/) that works for now. Basically you need to mount the root subvolume to `/run/timeshift/backup` by putting this line into `/etc/fstab`: -``` -UUID= /run/timeshift/backup btrfs defaults,noatime 0 0 -``` -You can get your UUID with the command `blkid`. - -###### Snapper -For snapper set `timeshift-auto=false` and `snapshots` to Snapper snapshots directory. (usually `/.snapshots`) -##### How to (auto)start the daemon -Use `sudo 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 `sudo rc-service grub-btrfsd start`. -`grub-btrfsd` then automatically watches the snapshot directory and updates the grub-menu when a change occurs. -When you changed a setting in `/etc/conf.d/grub-btrfd`, you have to restart the daemon with `sudo rc-service grub-btrfd restart` to make the change become effective. - -#### Automatically update grub upon restart/boot: +#### OpenRC If you would like the grub-btrfs menu to automatically update on system restart/ shutdown, just add the following script as `/etc/local.d/grub-btrfs-update.stop`: ```bash #!/usr/bin/env bash diff --git a/grub-btrfs-openrc b/grub-btrfs-openrc deleted file mode 100755 index 738d590..0000000 --- a/grub-btrfs-openrc +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/sh -# Copyright 2022 Pascal Jaeger -# Distributed under the terms of the GNU General Public License v3 -# Update GRUB when new BTRFS snapshots are created. - -timeshift_pid -watchtime=0 - -snapshots="${1}" -timeshift_auto="${2}" - -if ! [ "${#snapshots}" -gt 0 ] && ! [ ${timeshift_auto} ]; then - echo "Please specify the snapshots directory" >&2 - exit 1 -fi -if [ ${timeshift_auto} ]; then - watchtime=15 -else - watchtime=0 -fi - -while true; do - if [ ${timeshift_auto} == "true" ] && ! [ "${#timeshift_pid}" -gt 0 ] ; then - inotifywait -e create -e delete /run/timeshift && { - sleep 1 - timeshift_pid=$(ps ax | awk '{sub(/.*\//, "", $5)} $5 ~ /timeshift/ {print $1}') - snapshots="/run/timeshift/${timeshift_pid}/backup/timeshift-btrfs/snapshots" - } - else - while [ -d "$snapshots" ]; do - sleep 1 - inotifywait -e create -e delete -e unmount -t "$watchtime" "$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 - timeshift_pid="" - fi -done diff --git a/grub-btrfs.path b/grub-btrfs.path deleted file mode 100644 index b624a95..0000000 --- a/grub-btrfs.path +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Monitors for new snapshots -DefaultDependencies=no -Requires=\x2esnapshots.mount -After=\x2esnapshots.mount -BindsTo=\x2esnapshots.mount - -[Path] -PathModified=/.snapshots - -[Install] -WantedBy=\x2esnapshots.mount diff --git a/grub-btrfs.service b/grub-btrfs.service deleted file mode 100644 index 90d0ef9..0000000 --- a/grub-btrfs.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Regenerate grub-btrfs.cfg - -[Service] -Type=oneshot -# Set the possible paths for `grub-mkconfig` -Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin" -# Load environment variables from the configuration -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 -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' diff --git a/grub-btrfsd b/grub-btrfsd new file mode 100755 index 0000000..abf2b04 --- /dev/null +++ b/grub-btrfsd @@ -0,0 +1,151 @@ +#!/bin/sh +# Copyright 2022 Pascal Jaeger +# Distributed under the terms of the GNU General Public License v3 +# Update GRUB when new BTRFS snapshots are created. + +# init +timeshift_pid=-1 +watchtime=0 +logfile=0 +snapshots=-1 +timeshift_auto=false + +# helper functions +GREEN=$'\033[0;32m' +RED=$'\033[0;31m' +CYAN=$'\033[;36m' +RESET=$'\033[0m' + +print_help() { + echo "${CYAN}[?] Usage:" + echo "${0##*/} [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] SNAPSHOTS_DIR" + echo + echo "SNAPSHOTS_DIR Snapshot directory to watch, without effect when --timeshift-auto" + echo + echo "Optional arguments:" + echo "-t, --timeshift-auto Automatically detect Timeshifts snapshot directory" + echo "-l, --log-file Specify a logfile to write to" + echo "-h, --help Display this message${RESET}" +} + +log() { + if [ ${#logfile} -gt 1 ]; then + echo "$(date) ${1}" | tee -a ${logfile} + else + echo "$(date) ${1}" + fi +} + +# parse arguments +while getopts :l:th-: opt; do + case "$opt" in + -) + case "${OPTARG}" in + log-file) + logfile="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 )) + ;; + timeshift-auto) + timeshift_auto=true + ;; + *) + if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then + echo "${RED}[!] Unknown option --${OPTARG} ${RESET}" >&2 + echo + fi + print_help + exit 1 + ;; + esac;; + l) + logfile="${OPTARG}" + ;; + t) + timeshift_auto=true + ;; + h) + print_help + exit 0 + ;; + *) + if [ "$OPTERR" = 1 ] || [ "${optspec:0:1}" = ":" ]; then + echo "${RED}[!] Non-option argument: '-${OPTARG}'${RESET}" >&2 + echo + fi + print_help + exit 1 + ;; + esac +done +shift $(( OPTIND - 1 )) + +snapshots="${1}" + +if [ ${#logfile} -gt 1 ]; then + echo "${GREEN}$(date) grub-btrfsd starting up...${RESET}" | tee ${logfile} +else + echo "${GREEN}$(date) grub-btrfsd starting up...${RESET}" +fi + +log "Arguments:" +log "Snapshot directory: $snapshots" +log "Timestift autodetection: $timeshift_auto" +log "Logfile: $logfile" + +if ! [ -d "$snapshots" ] && ! [ ${timeshift_auto} = true ]; then + log "${RED}[!] No directory found at ${snapshots} ${RESET}" >&2 + log "${RED}[!] Please specify a valid snapshot directory ${RESET}" >&2 + exit 1 +fi + +if [ ${timeshift_auto} = true ]; then + watchtime=15 +else + watchtime=0 +fi + +# start the actual daemon +log "Snapshot dir watchtimeout: $watchtime" +log "${GREEN}Entering infinite while${RESET}" +while true; do + if [ ${timeshift_auto} = true ] && ! [ "${timeshift_pid}" -gt 0 ] ; then + # watch the timeshift folder for a folder that is created when timeshift starts up + if [ "${timeshift_pid}" -eq -2 ]; then + log "detected timeshift shutdown" + fi + timeshift_pid=$(ps ax | awk '{sub(/.*\//, "", $5)} $5 ~ /timeshift/ {print $1}') + if [ "${#timeshift_pid}" -gt 0 ]; then + snapshots="/run/timeshift/${timeshift_pid}/backup/timeshift-btrfs/snapshots" + log "detected running Timeshift at daemon startup, PID is: $timeshift_pid" + log "new snapshots directory is $snapshots" + else + log "Watching /run/timeshift for timeshift to start" + inotifywait -q -q -e create -e delete /run/timeshift && { + sleep 1 + timeshift_pid=$(ps ax | awk '{sub(/.*\//, "", $5)} $5 ~ /timeshift/ {print $1}') + snapshots="/run/timeshift/${timeshift_pid}/backup/timeshift-btrfs/snapshots" + log "${CYAN}detected Timeshift startup, PID is: $timeshift_pid ${RESET}" + log "${CYAN}new snapshots directory is $snapshots ${RESET}" + } + fi + else + while [ -d "$snapshots" ]; do + # watch the actual snapshots folder for a new snapshot or a deletion of a snapshot + log "Watching $snapshots for new snapshots..." + sleep 1 + inotifywait -q -q -e create -e delete -e unmount -t "$watchtime" "$snapshots" && { + log "${CYAN}Detected snapshot creation/ deletion, (re)creating grub menu${RESET}" + 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 + log "${GREEN}Grub menu created${RESET}" + } + done + timeshift_pid=-2 + fi + sleep 1 # leave this here for safety reasons +done + +exit 0 # tradition is tradition diff --git a/grub-btrfsd.confd b/grub-btrfsd.confd index adeff11..d58ff77 100644 --- a/grub-btrfsd.confd +++ b/grub-btrfsd.confd @@ -5,6 +5,9 @@ snapshots="/.snapshots" # Snapper in the root directory #snapshots="/run/timeshift/backup/timeshift-btrfs/snapshots" # Timeshift < v22.06 -## Autodetect timeshift snapshot directory. If this it set to true, variable snapshots is not taken into account. Use this for Timeshift >= v22.06 -timeshift_auto=true # Timeshift >= v22.06 -#timeshift_auto=false # snapper +## Optional arguments to run with the daemon +# Possible options are: +# -t, --timeshift-auto Automatically detect Timeshifts snapshot directory for timeshift >= 22.06 +# -l, --log-file Specify a logfile to write to +#optional_args+="--timeshift-auto " +#optional_args+="--log-file /var/log/grub-btrfsd.log " diff --git a/grub-btrfsd.initd b/grub-btrfsd.initd index 29e4e39..2ffb8b1 100755 --- a/grub-btrfsd.initd +++ b/grub-btrfsd.initd @@ -3,8 +3,8 @@ # Distributed under the terms of the GNU General Public License v3 name="grub-btrfs daemon" -command="/usr/bin/grub-btrfs-openrc" -command_args="${snapshots} ${timeshift_auto}" +command="/usr/bin/grub-btrfsd" +command_args="$optional_args ${snapshots}" pidfile="/run/{RC_SVCNAME}.pid" command_background=true diff --git a/grub-btrfsd.service b/grub-btrfsd.service new file mode 100644 index 0000000..4fe7ee7 --- /dev/null +++ b/grub-btrfsd.service @@ -0,0 +1,19 @@ +[Unit] +Description=Regenerate grub-btrfs.cfg + +[Service] +Type=simple +# Set the possible paths for `grub-mkconfig` +Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin" +# Load environment variables from the configuration +EnvironmentFile=/etc/default/grub-btrfs/config +# Start the daemon, usage of it is: +# grub-btrfsd [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] SNAPSHOTS_DIR +# SNAPSHOTS_DIR Snapshot directory to watch, without effect when --timeshift-auto +# Optional arguments: +# -t, --timeshift-auto Automatically detect Timeshifts snapshot directory +# -l, --log-file Specify a logfile to write to +ExecStart=/usr/bin/grub-btrfsd /.snapshots + +[Install] +WantedBy=multi-user.target diff --git a/manpages/grub-btrfs.8.man b/manpages/grub-btrfs.8.man new file mode 100644 index 0000000..86b4db4 --- /dev/null +++ b/manpages/grub-btrfs.8.man @@ -0,0 +1,240 @@ +.TH "grub-btrfs" "8" + +.SH "NAME" +.PP +grub-btrfs - Automatically add btrfs-Snapshots as a Grub submenu + +.SH "SYNOPSIS" +.PP +/etc/grub.d/41\d\s-2snapshots\s+2\u-btrfs + +.SH "DESCRIPTION" +.PP +Improves grub by adding “btrfs snapshots” to the grub menu. + +.PP +You can boot your system on a “snapshot” from the grub menu. +Supports manual snapshots, snapper and timeshift. +Features of grub-btrfs: +.IP \(em 4 +Automatically list snapshots existing on root partition (btrfs). +.IP \(em 4 +Automatically detect if /boot is in separate partition. +.IP \(em 4 +Automatically detect kernel, initramfs and intel/amd microcode in /boot directory on snapshots. +.IP \(em 4 +Automatically create corresponding “menuentry” in grub.cfg +.IP \(em 4 +Automatically detect the type/tags and descriptions/comments of snapper/timeshift snapshots. +.IP \(em 4 +Automatically generate grub.cfg if you use the provided systemd service. + +.SH "CONFIGURATION" +.PP +grub-btrfs is configured via the file \fC/etc/default/grub\-btrfs/config\fP. +Possible options are: + +.SS "GENERAL" +.SS "\fCGRUB_BTRFS_DISABLE\fP" +.PP +Disable grub-btrfs if true. +.IP \(em 4 +Default: “false” +.IP \(em 4 +Example: \fCGRUB_BTRFS_DISABLE="true"\fP + +.SS "\fCGRUB_BTRFS_TITLE_FORMAT\fP" +.PP +The snapshot entries submenu in Grub are added according to this line. It is possible to change to order of the fields. +.IP \(em 4 +Default: (“date” “snapshot” “type” “description”) +.PP +-Example: \fCGRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description")\fP + +.SS "\fCGRUB_BTRFS_LIMIT\fP" +.PP +Maximum number of snapshots in the GRUB snapshots sub menu. +.IP \(em 4 +Default: “50” +.PP +-Example: \fCGRUB_BTRFS_LIMIT="50"\fP + +.SS "\fCGRUB_BTRFS_SUBVOLUME_SORT\fP" +.PP +Sort the found subvolumes by “ogeneration” or “generation” or “path” or “rootid”. +.IP \(em 4 +See Sorting section in +.BR btrfs-subvolume (8) +.PP +“-rootid” means list snapshot by new ones first. +.IP \(em 4 +Default: “-rootid” +.PP +-Example: \fCGRUB_BTRFS_SUBVOLUME_SORT="+ogen,\-gen,path,rootid"\fP + +.SS "\fCGRUB_BTRFS_SHOW_SNAPSHOTS_FOUND\fP" +.PP +Show snapshots found during run “grub-mkconfig” +.IP \(em 4 +Default: “true” +.PP +-Example: \fCGRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"\fP + +.SS "\fCGRUB_BTRFS_ROOTFLAGS\fP" +.PP +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. +.IP \(em 4 +Default: “” +.PP +-Example: \fCGRUB_BTRFS_ROOTFLAGS="space_cache,commit=10,norecovery"\fP + +.SS "\fCGRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION\fP" +.PP +By default “grub-btrfs” automatically detects your boot partition, +either located at the system root or on a separate partition or in a subvolume, +Change to “true” if your boot partition is not detected as separate. +.IP \(em 4 +Default: “false” +.PP +-Example: \fCGRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="true"\fP + +.SS "CUSTOM KERNELS" +.SS "\fCGRUB_BTRFS_NKERNEL\fP / \fCGRUB_BTRFS_NINIT\fP / \fCGRUB_BTRFS_CUSTOM_MICROCODE\fP" +.PP +By default, “grub-btrfs” automatically detects most existing kernels, initramfs and microcode. +Customs kernel, initramfs and microcodes that are not detected can be added in these variables. +.IP \(em 4 +Default: (“”) +.PP +-Example: \fCGRUB_BTRFS_NKERNEL=("kernel\-5.19.4\-custom" "vmlinux\-5.19.4\-custom")\fP + \fCGRUB_BTRFS_NINIT=("initramfs\-5.19.4\-custom.img" "initrd\-5.19.4\-custom.img" "otherinit\-5.19.4\-custom.gz")\fP + \fCGRUB_BTRFS_CUSTOM_MICROCODE=("custom\-ucode.img" "custom\-uc.img "custom_ucode.cpio")\fP + +.SS "SNAPSHOT FILTERING" +.SS "\fCGRUB_BTRFS_IGNORE_SPECIFIC_PATH\fP" +.PP +Ignore specific path during run “grub-mkconfig”. +Only exact paths are ignored. +e.g : if `specific path` = @, only `@` snapshot will be ignored. +.IP \(em 4 +Default: (“@”) +.PP +-Example: \fCGRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@home")\fP + +.SS "\fCGRUB_BTRFS_IGNORE_PREFIX_PATH\fP" +.PP +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. +.IP \(em 4 +Default: (“var/lib/docker” “@var/lib/docker” “@/var/lib/docker”) +.PP +-Example: \fCGRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/docker")\fP + +.SS "\fCGRUB_BTRFS_IGNORE_SNAPSHOT_TYPE\fP" +.PP +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. +.IP \(em 4 +Default: (“”) +.PP +-Example: \fCGRUB_BTRFS_IGNORE_SNAPSHOT_TYPE=("ondemand")\fP + +.SS "\fCGRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION\fP" +.PP +Ignore specific description of snapshot during run “grub-mkconfig”. +.IP \(em 4 +Default: (“”) +.PP +-Example: \fCGRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION=("timeline")\fP + +.SS "DISTRIBUTION DEPENDENT SETTINGS" +.SS "\fCGRUB_BTRFS_BOOT_DIRNAME\fP" +.PP +Location of kernels/initramfs/microcode. +Used by “grub-btrfs” to detect the boot partition and the location of kernels, initramfs and microcodes. +.IP \(em 4 +Default: “/boot” +.PP +-Example: \fCGRUB_BTRFS_BOOT_DIRNAME="/"\fP + +.SS "\fCGRUB_BTRFS_GRUB_DIRNAME\fP" +.PP +Location of the folder containing the “grub.cfg” file. +Used 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” +.IP \(em 4 +Default: “/boot/grub” +.PP +-Example: \fCGRUB_BTRFS_GRUB_DIRNAME="/boot/grub2"\fP + +.SS "\fCGRUB_BTRFS_MKCONFIG\fP" +.PP +Name/path of the command to generate the grub menu, used by “grub-btrfs.service” +Might be ’grub2-mkconfig’ on some systems (e.g. Fedora) +Default paths are /sbin:/bin:/usr/sbin:/usr/bin, if your path is missing, report it on the upstream project. +You can use the name of the command only or full the path. +.IP \(em 4 +Default: grub-mkconfig +.PP +-Example: \fCGRUB_BTRFS_MKCONFIG=/sbin/grub2\-mkconfig\fP + +.SS "\fCGRUB_BTRFS_SCRIPT_CHECK\fP" +.PP +Name of grub-script-check command, used by “grub-btrfs” +Might be ’grub2-script-check’ on some systems (e.g. Fedora) +.IP \(em 4 +Default: grub-script-check +.IP \(em 4 +Example: \fCGRUB_BTRFS_SCRIPT_CHECK=grub2\-script\-check\fP + +.SS "\fCGRUB_BTRFS_MKCONFIG_LIB\fP" +.PP +Path of grub-mkconfig\d\s-2lib\s+2\u file, used by “grub-btrfs” +Might be ’/usr/share/grub2/grub-mkconfig\d\s-2lib\s+2\u’ on some systems (e.g. Opensuse) +.IP \(em 4 +Default: /usr/share/grub/grub-mkconfig\d\s-2lib\s+2\u +.IP \(em 4 +Example: \fCGRUB_BTRFS_MKCONFIG_LIB=/usr/share/grub2/grub\-mkconfig_lib\fP + +.SS "SECURITY" +.SS "\fCGRUB_BTRFS_PROTECTION_AUTHORIZED_USERS\fP" +.PP +Password protection management for submenu, snapshots +Refer to the Grub documentation \fIhttps://www.gnu.org/software/grub/manual/grub/grub.html#Authentication-and-authorisation\fP +and this comment \fIhttps://github.com/Antynea/grub-btrfs/issues/95#issuecomment-682295660\fP +Add authorized usernames separate by comma (userfoo,userbar). +When Grub’s password protection is enabled, the superuser is authorized by default, it is not necessary to add it +.IP \(em 4 +Default: “- Example: \fCGRUB_BTRFS_PROTECTION_AUTHORIZED_USERS="userfoo,userbar"\fP + +.SS "\fCGRUB_BTRFS_DISABLE_PROTECTION_SUBMENU\fP" +.PP +Disable authentication support for submenu of Grub-btrfs only (--unrestricted) +does not work if GRUB\d\s-2BTRFS\s+2\u\d\s-2PROTECTION\s+2\u\d\s-2AUTHORIZED\s+2\u\d\s-2USERS\s+2\u is not empty +.IP \(em 4 +Default: “false” +.IP \(em 4 +Example: \fCGRUB_BTRFS_DISABLE_PROTECTION_SUBMENU="true"\fP + +.SH "FILES" +.PP +/etc/default/grub-btrfs/config + +.SH "SEE ALSO" +.IR btrfs (8) +.IR btrfs-subvolume (8) +.IR grub-btrfsd (8) +.IR grub-mkconfig (8) + +.SH "COPYRIGHT" +.PP +Copyright (c) 2022 Pascal Jäger diff --git a/manpages/grub-btrfs.8.org b/manpages/grub-btrfs.8.org new file mode 100644 index 0000000..5e6a225 --- /dev/null +++ b/manpages/grub-btrfs.8.org @@ -0,0 +1,180 @@ +#+title: grub-btrfs +#+author: Pascal Jaeger +#+man_class_option: :sectionid 8 + +* NAME + grub-btrfs - Automatically add btrfs-Snapshots as a Grub submenu + +* SYNOPSIS +/etc/grub.d/41_snapshots-btrfs + +* DESCRIPTION +Improves grub by adding "btrfs snapshots" to the grub menu. + +You can boot your system on a "snapshot" from the grub menu. +Supports manual snapshots, snapper and timeshift. +Features of grub-btrfs: +- 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 the type/tags and descriptions/comments of snapper/timeshift snapshots. +- Automatically generate grub.cfg if you use the provided systemd service. + +* CONFIGURATION +grub-btrfs is configured via the file ~/etc/default/grub-btrfs/config~. +Possible options are: + +** GENERAL + +*** ~GRUB_BTRFS_DISABLE~ +Disable grub-btrfs if true. +- Default: "false" +- Example: ~GRUB_BTRFS_DISABLE="true"~ + +*** ~GRUB_BTRFS_TITLE_FORMAT~ +The snapshot entries submenu in Grub are added according to this line. It is possible to change to order of the fields. +- Default: ("date" "snapshot" "type" "description") +-Example: ~GRUB_BTRFS_TITLE_FORMAT=("date" "snapshot" "type" "description")~ + +*** ~GRUB_BTRFS_LIMIT~ +Maximum number of snapshots in the GRUB snapshots sub menu. +- Default: "50" +-Example: ~GRUB_BTRFS_LIMIT="50"~ + +*** ~GRUB_BTRFS_SUBVOLUME_SORT~ +Sort the found subvolumes by "ogeneration" or "generation" or "path" or "rootid". +- See Sorting section in +#+BEGIN_MAN +.BR btrfs-subvolume (8) +#+END_MAN +"-rootid" means list snapshot by new ones first. +- Default: "-rootid" +-Example: ~GRUB_BTRFS_SUBVOLUME_SORT="+ogen,-gen,path,rootid"~ + +*** ~GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND~ +Show snapshots found during run "grub-mkconfig" +- Default: "true" +-Example: ~GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"~ + +*** ~GRUB_BTRFS_ROOTFLAGS~ +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: "" +-Example: ~GRUB_BTRFS_ROOTFLAGS="space_cache,commit=10,norecovery"~ + +*** ~GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION~ +By default "grub-btrfs" automatically detects your boot partition, +either located at the system root or on a separate partition or in a subvolume, +Change to "true" if your boot partition is not detected as separate. +- Default: "false" +-Example: ~GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="true"~ + +** CUSTOM KERNELS + +*** ~GRUB_BTRFS_NKERNEL~ / ~GRUB_BTRFS_NINIT~ / ~GRUB_BTRFS_CUSTOM_MICROCODE~ +By default, "grub-btrfs" automatically detects most existing kernels, initramfs and microcode. +Customs kernel, initramfs and microcodes that are not detected can be added in these variables. +- Default: ("") +-Example: ~GRUB_BTRFS_NKERNEL=("kernel-5.19.4-custom" "vmlinux-5.19.4-custom")~ + ~GRUB_BTRFS_NINIT=("initramfs-5.19.4-custom.img" "initrd-5.19.4-custom.img" "otherinit-5.19.4-custom.gz")~ + ~GRUB_BTRFS_CUSTOM_MICROCODE=("custom-ucode.img" "custom-uc.img "custom_ucode.cpio")~ + +** SNAPSHOT FILTERING + +*** ~GRUB_BTRFS_IGNORE_SPECIFIC_PATH~ +Ignore specific path during run "grub-mkconfig". +Only exact paths are ignored. +e.g : if `specific path` = @, only `@` snapshot will be ignored. +- Default: ("@") +-Example: ~GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("@home")~ + +*** ~GRUB_BTRFS_IGNORE_PREFIX_PATH~ +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") +-Example: ~GRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/docker")~ + +*** ~GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE~ +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: ("") +-Example: ~GRUB_BTRFS_IGNORE_SNAPSHOT_TYPE=("ondemand")~ + +*** ~GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION~ +Ignore specific description of snapshot during run "grub-mkconfig". +- Default: ("") +-Example: ~GRUB_BTRFS_IGNORE_SNAPSHOT_DESCRIPTION=("timeline")~ + +** DISTRIBUTION DEPENDENT SETTINGS + +*** ~GRUB_BTRFS_BOOT_DIRNAME~ +Location of kernels/initramfs/microcode. +Used by "grub-btrfs" to detect the boot partition and the location of kernels, initramfs and microcodes. +- Default: "/boot" +-Example: ~GRUB_BTRFS_BOOT_DIRNAME="/"~ + +*** ~GRUB_BTRFS_GRUB_DIRNAME~ +Location of the folder containing the "grub.cfg" file. +Used 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" +-Example: ~GRUB_BTRFS_GRUB_DIRNAME="/boot/grub2"~ + +*** ~GRUB_BTRFS_MKCONFIG~ +Name/path of the command to generate the grub menu, used by "grub-btrfs.service" +Might be 'grub2-mkconfig' on some systems (e.g. Fedora) +Default paths are /sbin:/bin:/usr/sbin:/usr/bin, if your path is missing, report it on the upstream project. +You can use the name of the command only or full the path. +- Default: grub-mkconfig +-Example: ~GRUB_BTRFS_MKCONFIG=/sbin/grub2-mkconfig~ + +*** ~GRUB_BTRFS_SCRIPT_CHECK~ +Name of grub-script-check command, used by "grub-btrfs" +Might be 'grub2-script-check' on some systems (e.g. Fedora) +- Default: grub-script-check +- Example: ~GRUB_BTRFS_SCRIPT_CHECK=grub2-script-check~ + +*** ~GRUB_BTRFS_MKCONFIG_LIB~ +Path of grub-mkconfig_lib file, used by "grub-btrfs" +Might be '/usr/share/grub2/grub-mkconfig_lib' on some systems (e.g. Opensuse) +- Default: /usr/share/grub/grub-mkconfig_lib +- Example: ~GRUB_BTRFS_MKCONFIG_LIB=/usr/share/grub2/grub-mkconfig_lib~ + +** SECURITY + +*** ~GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS~ +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 (userfoo,userbar). +When Grub's password protection is enabled, the superuser is authorized by default, it is not necessary to add it +- Default: "- Example: ~GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS="userfoo,userbar"~ + +*** ~GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU~ +Disable authentication support for submenu of Grub-btrfs only (--unrestricted) +does not work if GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS is not empty +- Default: "false" +- Example: ~GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU="true"~ + +* FILES +/etc/default/grub-btrfs/config + +* SEE ALSO +#+BEGIN_MAN +.IR btrfs (8) +.IR btrfs-subvolume (8) +.IR grub-btrfsd (8) +.IR grub-mkconfig (8) +#+END_MAN + +* COPYRIGHT +Copyright (c) 2022 Pascal Jäger diff --git a/manpages/grub-btrfsd.8.man b/manpages/grub-btrfsd.8.man new file mode 100644 index 0000000..d1bf4cf --- /dev/null +++ b/manpages/grub-btrfsd.8.man @@ -0,0 +1,63 @@ +.TH "grub-btrfsd" "8" + +.SH "NAME" +.PP +grub-btrfsd - An OpenRC daemon to automatically update the grub menu with +.BR grub-btrfs (8) +.PP +when a new btrfs snapshot is created. + +.SH "SYNOPSIS" +.PP +\fCgrub\-btrfsd [\-h, \-\-help] [\-t, \-\-timeshift\-auto] [\-l, \-\-log\-file LOG_FILE] SNAPSHOTS_DIR\fP + +.SH "DESCRIPTION" +.PP +Grub-btrfs-openrc is a shell script which is meant to be run as a daemon. +Grub-btrfsd watches a directory where snapshots are created or deleted via inotifywait and runs grub-mkconfig (if grub-mkconfig never ran before since grub-btrfs was installed) or \fC/etc/grub.d/41_snapshots\-btrfs\fP (when grub-mkconfig ran before with grub-btrfs installed) when something in that directory changes. + +.SH "OPTIONS" +.SS "\fCSNAPSHOTS_DIR\fP" +.PP +This argument specifies the path where grub-btrfsd looks for newly created snapshots and snapshot deletions. It is usually defined by the program used to make snapshots. +E.g. for Snapper this would be \fC/.snapshots\fP + +.SS "\fC\-t / \-\-timeshift\-auto\fP" +.PP +This is a flag to activate the auto detection of the path where Timeshift stores snapshots. Newer versions (>=22.06) of Timeshift mount their snapshots to \fC/run/timeshift/$PID/backup/timeshift\-btrfs\fP. Where \fC$PID\fP is the process ID of the currently running Timeshift session. The PID is changing every time Timeshift is opened. grub-btrfsd can automatically take care of the detection of the correct PID and directory if this flag is set. In this case the argument \fCSNAPSHOTS_DIR\fP has no effect. + +.SS "\fC\-l /\-\-log\-file\fP" +.PP +This arguments specifies a file where grub-btrfsd should write log messages. + +.SS "\fC\-h / \-\-help\fP" +.PP +Displays a short help message. + +.SH "CONFIGURATION" +.PP +The daemon is usually configured via the file \fC/etc/conf.d/grub\-btrfsd\fP on openrc-init systems and \fCsudo systemctl edit \-\-full grub\-btrfsd\fP on systemd systems. In this file the arguments (See OPTIONS), that OpenRC passes to the daemon when it is started, can be configured. + +.SS "NOTES" +.PP +A common configuration for Snapper would be to set \fCSNAPSHOTS_DIR\fP to \fC/.snapshots\fP and not to set \fC\-\-timeshift\-auto\fP. +For Timeshift \fC\-\-timeshift\-auto\fP is set to true and \fCSNAPSHOTS_DIR\fP can be left as is. + +.SH "FILES" +.PP +\fC/etc/conf.d/grub\-btrfsd\fP +\fC/usr/lib/systemd/system/grub\-btrfsd.service\fP + +.SH "SEE ALSO" +.IR btrfs (8) +.IR btrfs-subvolume (8) +.IR grub-btrfsd (8) +.IR grub-mkconfig (8) +.IR inotifywait (1) +.IR openrc (8) +.IR rc-service (8) +.IR timeshift (1) + +.SH "COPYRIGHT" +.PP +Copyright (c) 2022 Pascal Jäger diff --git a/manpages/grub-btrfsd.8.org b/manpages/grub-btrfsd.8.org new file mode 100644 index 0000000..94776b2 --- /dev/null +++ b/manpages/grub-btrfsd.8.org @@ -0,0 +1,57 @@ +#+title: grub-btrfsd +#+author: Pascal Jaeger +#+man_class_option: :sectionid 8 + +* NAME +grub-btrfsd - An OpenRC daemon to automatically update the grub menu with +#+BEGIN_MAN +.BR grub-btrfs (8) +#+END_MAN +when a new btrfs snapshot is created. + +* SYNOPSIS +~grub-btrfsd [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] SNAPSHOTS_DIR~ + +* DESCRIPTION +Grub-btrfs-openrc is a shell script which is meant to be run as a daemon. +Grub-btrfsd watches a directory where snapshots are created or deleted via inotifywait and runs grub-mkconfig (if grub-mkconfig never ran before since grub-btrfs was installed) or ~/etc/grub.d/41_snapshots-btrfs~ (when grub-mkconfig ran before with grub-btrfs installed) when something in that directory changes. + +* OPTIONS +** ~SNAPSHOTS_DIR~ +This argument specifies the path where grub-btrfsd looks for newly created snapshots and snapshot deletions. It is usually defined by the program used to make snapshots. +E.g. for Snapper this would be ~/.snapshots~ + +** ~-t / --timeshift-auto~ +This is a flag to activate the auto detection of the path where Timeshift stores snapshots. Newer versions (>=22.06) of Timeshift mount their snapshots to ~/run/timeshift/$PID/backup/timeshift-btrfs~. Where ~$PID~ is the process ID of the currently running Timeshift session. The PID is changing every time Timeshift is opened. grub-btrfsd can automatically take care of the detection of the correct PID and directory if this flag is set. In this case the argument ~SNAPSHOTS_DIR~ has no effect. + +** ~-l /--log-file~ +This arguments specifies a file where grub-btrfsd should write log messages. + +** ~-h / --help~ +Displays a short help message. + +* CONFIGURATION +The daemon is usually configured via the file ~/etc/conf.d/grub-btrfsd~ on openrc-init systems and ~sudo systemctl edit --full grub-btrfsd~ on systemd systems. In this file the arguments (See OPTIONS), that OpenRC passes to the daemon when it is started, can be configured. + +** NOTES +A common configuration for Snapper would be to set ~SNAPSHOTS_DIR~ to ~/.snapshots~ and not to set ~--timeshift-auto~. +For Timeshift ~--timeshift-auto~ is set to true and ~SNAPSHOTS_DIR~ can be left as is. + +* FILES +~/etc/conf.d/grub-btrfsd~ +~/usr/lib/systemd/system/grub-btrfsd.service~ + +* SEE ALSO +#+BEGIN_MAN +.IR btrfs (8) +.IR btrfs-subvolume (8) +.IR grub-btrfsd (8) +.IR grub-mkconfig (8) +.IR inotifywait (1) +.IR openrc (8) +.IR rc-service (8) +.IR timeshift (1) +#+END_MAN + +* COPYRIGHT +Copyright (c) 2022 Pascal Jäger From 8c8ee200fd094bdc924cad328e4b473755ef980f Mon Sep 17 00:00:00 2001 From: Pascal J Date: Thu, 1 Sep 2022 09:54:10 +0200 Subject: [PATCH 05/11] general: Formatted Readme a bit --- README.md | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 700a587..9ef1094 100644 --- a/README.md +++ b/README.md @@ -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 ##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt` - - - -### Description: +### 🔎 Description: Improves grub by adding "btrfs snapshots" to the grub menu. You can boot your system on a "snapshot" from the grub menu. @@ -21,7 +21,7 @@ This project includes its own solution. Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/initramfs/readme.md). - - - -### What features does grub-btrfs have? +### ✨ What features does grub-btrfs have? * 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. @@ -30,7 +30,7 @@ Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/i * Automatically generate `grub.cfg` if you use the provided systemd/ openRC service. - - - -### Installation: +### 🛠️ Installation: #### Arch Linux The package is available in the community repository [grub-btrfs](https://archlinux.org/packages/community/any/grub-btrfs/) ``` @@ -43,7 +43,7 @@ If you have not activated the GURU yet, do so by running: ``` emerge -av app-eselect/eselect-repository eselect repository enable guru -emerge --sync +emaint sync -r guru ``` If you are using Systemd on Gentoo, make sure the USE-Flag `systemd` is set. (Either globally in make.conf or in package.use for the package app-backup/grub-btrfs) Without systemd USE-Flag the OpenRC-daemon of grub-btrfs will be installed. @@ -75,12 +75,17 @@ 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: +### ⚙️ Customization: You have the possibility to modify many parameters in `/etc/default/grub-btrfs/config`. For further information see [config file](https://github.com/Antynea/grub-btrfs/blob/master/config) or `man grub-btrfs` +#### 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. #### grub-btrfsd daemon + Grub-btrfs comes with a daemon script that automatically updates the grub menu when it sees a snapshot being created or deleted in a directory it is given via command line. The daemon can be configured by passing different command line arguments to it. This can be change by either running @@ -108,12 +113,8 @@ sudo rc-service grub-btrfsd stop # for openRC Then the daemon can be manually run and played around with with the command `grub-btrfsd`. For additional information on daemon script and its arguments, run `grub-btrfsd -h` and see `man grub-btrfsd` -#### 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. - - - -### Automatically update grub upon snapshot +### 🪀 Automatically update grub upon snapshot Grub-btrfs comes with its own daemon, that watches the snapshot directory for you and updates the grub menu automatically every time a snapshot is created or deleted. To start it now, run @@ -134,17 +135,17 @@ or sudo rc-config add grub-btrfsd default # for openRC ``` -#### Snapshots not in `/.snapshots` +#### 💼 Snapshots not in `/.snapshots` NOTE: This works also for Timeshift versions < 22.06, the path to watch would be `/run/timeshift/backup/timeshift-btrfs/snapshots`. ##### Systemd By default the daemon is watching the directory `/.snapshots`. If the daemon should watch a different directory, it can be edited with ```bash -sudo systemctl edit --full grub-btrfsd +sudo systemctl edit --full grub-btrfsd # for systemd ``` What should be edited is the `/.snapshots`-part in the line that says `ExecStart=/usr/bin/grub-btrfsd /.snapshots` When done, the service should be restarted with ``` bash -sudo systemctl restart grub-btrfsd +sudo systemctl restart grub-btrfsd # for systemd ``` ##### OpenRC @@ -152,40 +153,40 @@ Arguments are passed to grub-btrfsd via the file `/etc/conf.d/grub-btrfsd`. The variable `snapshots` defines, where the daemon will watch for snapshots. After that, the daemon should be restarted with ``` bash -sudo rc-service grub-btrfsd restart +sudo rc-service grub-btrfsd restart # for openRC ``` -**Timeshift >=22.06** +#### 🌟 Timeshift >= version 22.06 Newer Timeshift versions create a new directory after their process ID in `/run/timeshift` every time they are started. The PID is going to be different every time. Therefore the daemon can not simply watch a directory, it watches `/run/timeshift` first, if a directory is created it gets Timeshifts current PID, then watches a directory in that newly created directory from Timeshift. Anyhow, to activate this mode of the daemon, `--timeshift-auto` must be passed to the daemon as a command line argument. -#### Systemd -Servicefile of grub-btrfsd can be edited with +##### Systemd +To pass `--timeshift-auto` to grub-btrfsd, the servicefile of grub-btrfsd can be edited with ```bash -sudo systemctl edit --full grub-btrfsd +sudo systemctl edit --full grub-btrfsd # for systemd ``` The line that says `ExecStart=/usr/bin/grub-btrfsd /.snapshots` should be edited into `ExecStart=/usr/bin/grub-btrfsd --timeshift-auto`. When done, the service should be restarted with ``` bash -sudo systemctl restart grub-btrfsd +sudo systemctl restart grub-btrfsd # for systemd ``` Note: -You can view your change to `systemctl cat grub-btrfsd`. +You can view your change with `systemctl cat grub-btrfsd`. To revert change use `systemctl revert grub-btrfsd`. -#### OpenRC +##### OpenRC Arguments are passed to grub-btrfsd via the file `/etc/conf.d/grub-btrfsd`. The variable `optional_args` defines, which optional arguments get passed to the daemon. Uncomment `#optional_args+="--timeshift-auto "` to pass the command line option `--timeshift-auto` to it. After that, the daemon should be restarted with ``` bash -sudo rc-service grub-btrfsd restart +sudo rc-service grub-btrfsd restart # for openRC ``` ---- -### Automatically update grub upon restart/boot: +### ❇️ Automatically update grub upon restart/boot: #### Systemd [Look at this comment](https://github.com/Antynea/grub-btrfs/issues/138#issuecomment-766918328) Currently not implemented @@ -208,7 +209,7 @@ bash -c 'if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then Make your script executable 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. +* 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 From 9064d611455625edf6f53e3c997070183bd55b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Thu, 1 Sep 2022 23:26:25 +0200 Subject: [PATCH 06/11] grub-btrfsd: add verbose and syslog options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pascal Jäger --- grub-btrfsd | 111 +++++++++++++++++++++++++++---------- grub-btrfsd.confd | 5 ++ grub-btrfsd.service | 3 + manpages/grub-btrfsd.8.man | 12 +++- manpages/grub-btrfsd.8.org | 10 +++- 5 files changed, 109 insertions(+), 32 deletions(-) diff --git a/grub-btrfsd b/grub-btrfsd index abf2b04..ae471f8 100755 --- a/grub-btrfsd +++ b/grub-btrfsd @@ -9,6 +9,8 @@ watchtime=0 logfile=0 snapshots=-1 timeshift_auto=false +verbose=false +syslog=false # helper functions GREEN=$'\033[0;32m' @@ -18,26 +20,52 @@ RESET=$'\033[0m' print_help() { echo "${CYAN}[?] Usage:" - echo "${0##*/} [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] SNAPSHOTS_DIR" + echo "${0##*/} [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] [-v, --verbose] [-s, --syslog] SNAPSHOTS_DIR" echo echo "SNAPSHOTS_DIR Snapshot directory to watch, without effect when --timeshift-auto" echo echo "Optional arguments:" echo "-t, --timeshift-auto Automatically detect Timeshifts snapshot directory" echo "-l, --log-file Specify a logfile to write to" + echo "-v, --verbose Let the log of the daemon be more verbose" + echo "-s, --syslog Write to syslog" echo "-h, --help Display this message${RESET}" } log() { + echo "${2}"$1"${RESET}" + if [ ${syslog} = true ]; then + logger -p user.notice -t ${0##*/}"["$$"]" "$1" + fi if [ ${#logfile} -gt 1 ]; then - echo "$(date) ${1}" | tee -a ${logfile} - else - echo "$(date) ${1}" + echo "$(date) ${1}" >> ${logfile} fi } +vlog() { + if [ ${verbose} = true ]; then + echo "${2}"$1"${RESET}" + if [ ${syslog} = true ]; then + logger -p user.notice -t ${0##*/} "$1" + fi + if [ ${#logfile} -gt 1 ]; then + echo "$(date) ${1}" >> ${logfile} + fi + fi +} + +err() { + echo "${2}"${1}"${RESET}" >&2 + if [ ${syslog} = true ]; then + logger -p user.error -t ${0##*/} "$1" + fi + if [ ${#logfile} -gt 1 ]; then + echo "$(date) error: ${1}" >> ${logfile} + fi +} + # parse arguments -while getopts :l:th-: opt; do +while getopts :l:tvsh-: opt; do case "$opt" in -) case "${OPTARG}" in @@ -47,9 +75,15 @@ while getopts :l:th-: opt; do timeshift-auto) timeshift_auto=true ;; + verbose) + verbose=true + ;; + syslog) + syslog=true + ;; *) if [ "$OPTERR" = 1 ] && [ "${optspec:0:1}" != ":" ]; then - echo "${RED}[!] Unknown option --${OPTARG} ${RESET}" >&2 + err "[!] Unknown option --${OPTARG}" "${RED}" >&2 echo fi print_help @@ -62,13 +96,19 @@ while getopts :l:th-: opt; do t) timeshift_auto=true ;; + v) + verbose=true + ;; + s) + syslog=true + ;; h) print_help exit 0 ;; *) if [ "$OPTERR" = 1 ] || [ "${optspec:0:1}" = ":" ]; then - echo "${RED}[!] Non-option argument: '-${OPTARG}'${RESET}" >&2 + err "[!] Non-option argument: '-${OPTARG}'" "${RED}" >&2 echo fi print_help @@ -81,19 +121,26 @@ shift $(( OPTIND - 1 )) snapshots="${1}" if [ ${#logfile} -gt 1 ]; then - echo "${GREEN}$(date) grub-btrfsd starting up...${RESET}" | tee ${logfile} -else - echo "${GREEN}$(date) grub-btrfsd starting up...${RESET}" + touch "${logfile}" + echo "GRUB-BTRFSD log $(date)" >> "${logfile}" fi -log "Arguments:" -log "Snapshot directory: $snapshots" -log "Timestift autodetection: $timeshift_auto" -log "Logfile: $logfile" +log "grub-btrfsd starting up..." "${GREEN}" + +if [ ${verbose} = true ]; then + inotify_qiet_flag="" +else + inotify_qiet_flag=" -q -q " +fi + +vlog "Arguments:" +vlog "Snapshot directory: $snapshots" +vlog "Timestift autodetection: $timeshift_auto" +vlog "Logfile: $logfile" if ! [ -d "$snapshots" ] && ! [ ${timeshift_auto} = true ]; then - log "${RED}[!] No directory found at ${snapshots} ${RESET}" >&2 - log "${RED}[!] Please specify a valid snapshot directory ${RESET}" >&2 + err "[!] No directory found at ${snapshots}" "${RED}" >&2 + err "[!] Please specify a valid snapshot directory" "${RED}" >&2 exit 1 fi @@ -104,9 +151,10 @@ else fi # start the actual daemon -log "Snapshot dir watchtimeout: $watchtime" -log "${GREEN}Entering infinite while${RESET}" +vlog "Snapshot dir watchtimeout: $watchtime" +vlog "Entering infinite while" "${GREEN}" while true; do + runs=false if [ ${timeshift_auto} = true ] && ! [ "${timeshift_pid}" -gt 0 ] ; then # watch the timeshift folder for a folder that is created when timeshift starts up if [ "${timeshift_pid}" -eq -2 ]; then @@ -116,32 +164,39 @@ while true; do if [ "${#timeshift_pid}" -gt 0 ]; then snapshots="/run/timeshift/${timeshift_pid}/backup/timeshift-btrfs/snapshots" log "detected running Timeshift at daemon startup, PID is: $timeshift_pid" - log "new snapshots directory is $snapshots" + vlog "new snapshots directory is $snapshots" else log "Watching /run/timeshift for timeshift to start" - inotifywait -q -q -e create -e delete /run/timeshift && { - sleep 1 + inotifywait ${inotify_qiet_flag} -e create -e delete /run/timeshift && { + sleep 3 timeshift_pid=$(ps ax | awk '{sub(/.*\//, "", $5)} $5 ~ /timeshift/ {print $1}') snapshots="/run/timeshift/${timeshift_pid}/backup/timeshift-btrfs/snapshots" - log "${CYAN}detected Timeshift startup, PID is: $timeshift_pid ${RESET}" - log "${CYAN}new snapshots directory is $snapshots ${RESET}" + log "detected Timeshift startup, PID is: $timeshift_pid" "${CYAN}" + vlog "new snapshots directory is $snapshots" "${CYAN}" } fi + runs=false else while [ -d "$snapshots" ]; do # watch the actual snapshots folder for a new snapshot or a deletion of a snapshot - log "Watching $snapshots for new snapshots..." - sleep 1 - inotifywait -q -q -e create -e delete -e unmount -t "$watchtime" "$snapshots" && { - log "${CYAN}Detected snapshot creation/ deletion, (re)creating grub menu${RESET}" + if [ ${runs} = false ] && [ ${verbose} = false ]; then + log "Watching $snapshots for new snapshots..." "${CYAN}" + else + vlog "Watching $snapshots for new snapshots..." "${CYAN}" + fi + runs=true + inotifywait ${inotify_qiet_flag} -e create -e delete -e unmount -t "$watchtime" "$snapshots" && { + log "Detected snapshot creation/ deletion, recreating Grub menu" "${CYAN}" sleep 5 if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then /etc/grub.d/41_snapshots-btrfs + log "Grub submenu recreated" "${GREEN}" else ${GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o ${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg + log "Grub menu recreated" "${GREEN}" fi - log "${GREEN}Grub menu created${RESET}" } + sleep 1 done timeshift_pid=-2 fi diff --git a/grub-btrfsd.confd b/grub-btrfsd.confd index d58ff77..7d12ca1 100644 --- a/grub-btrfsd.confd +++ b/grub-btrfsd.confd @@ -9,5 +9,10 @@ snapshots="/.snapshots" # Snapper in the root directory # Possible options are: # -t, --timeshift-auto Automatically detect Timeshifts snapshot directory for timeshift >= 22.06 # -l, --log-file Specify a logfile to write to +# -v, --verbose Let the log of the daemon be more verbose +# -s, --syslog Write to syslog +# Uncomment the line to activate the option +optional_args+="--syslog " # write to syslog by default #optional_args+="--timeshift-auto " #optional_args+="--log-file /var/log/grub-btrfsd.log " +#optional_args+="--verbose " diff --git a/grub-btrfsd.service b/grub-btrfsd.service index 4fe7ee7..b567c00 100644 --- a/grub-btrfsd.service +++ b/grub-btrfsd.service @@ -13,6 +13,9 @@ EnvironmentFile=/etc/default/grub-btrfs/config # Optional arguments: # -t, --timeshift-auto Automatically detect Timeshifts snapshot directory # -l, --log-file Specify a logfile to write to +# -v, --verbose Let the log of the daemon be more verbose +# -s, --syslog Write to syslog, this usually not needed for systemd systems, because systemd +# is logging service output to the syslog anyway ExecStart=/usr/bin/grub-btrfsd /.snapshots [Install] diff --git a/manpages/grub-btrfsd.8.man b/manpages/grub-btrfsd.8.man index d1bf4cf..9158d62 100644 --- a/manpages/grub-btrfsd.8.man +++ b/manpages/grub-btrfsd.8.man @@ -9,7 +9,7 @@ when a new btrfs snapshot is created. .SH "SYNOPSIS" .PP -\fCgrub\-btrfsd [\-h, \-\-help] [\-t, \-\-timeshift\-auto] [\-l, \-\-log\-file LOG_FILE] SNAPSHOTS_DIR\fP +\fCgrub\-btrfsd [\-h, \-\-help] [\-t, \-\-timeshift\-auto] [\-l, \-\-log\-file LOG_FILE] [\-v, \-\-verbose] [\-s, \-\-syslog] SNAPSHOTS_DIR\fP .SH "DESCRIPTION" .PP @@ -26,7 +26,7 @@ E.g. for Snapper this would be \fC/.snapshots\fP .PP This is a flag to activate the auto detection of the path where Timeshift stores snapshots. Newer versions (>=22.06) of Timeshift mount their snapshots to \fC/run/timeshift/$PID/backup/timeshift\-btrfs\fP. Where \fC$PID\fP is the process ID of the currently running Timeshift session. The PID is changing every time Timeshift is opened. grub-btrfsd can automatically take care of the detection of the correct PID and directory if this flag is set. In this case the argument \fCSNAPSHOTS_DIR\fP has no effect. -.SS "\fC\-l /\-\-log\-file\fP" +.SS "\fC\-l / \-\-log\-file\fP" .PP This arguments specifies a file where grub-btrfsd should write log messages. @@ -34,6 +34,14 @@ This arguments specifies a file where grub-btrfsd should write log messages. .PP Displays a short help message. +.SS "\fC\-v / \-\-verbose\fP" +.PP +Let the log of the daemon be more verbose + +.SS "\fC\-s / \-\-syslog\fP" +.PP +Write to syslog + .SH "CONFIGURATION" .PP The daemon is usually configured via the file \fC/etc/conf.d/grub\-btrfsd\fP on openrc-init systems and \fCsudo systemctl edit \-\-full grub\-btrfsd\fP on systemd systems. In this file the arguments (See OPTIONS), that OpenRC passes to the daemon when it is started, can be configured. diff --git a/manpages/grub-btrfsd.8.org b/manpages/grub-btrfsd.8.org index 94776b2..c6521fa 100644 --- a/manpages/grub-btrfsd.8.org +++ b/manpages/grub-btrfsd.8.org @@ -10,7 +10,7 @@ grub-btrfsd - An OpenRC daemon to automatically update the grub menu with when a new btrfs snapshot is created. * SYNOPSIS -~grub-btrfsd [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] SNAPSHOTS_DIR~ +~grub-btrfsd [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] [-v, --verbose] [-s, --syslog] SNAPSHOTS_DIR~ * DESCRIPTION Grub-btrfs-openrc is a shell script which is meant to be run as a daemon. @@ -24,12 +24,18 @@ E.g. for Snapper this would be ~/.snapshots~ ** ~-t / --timeshift-auto~ This is a flag to activate the auto detection of the path where Timeshift stores snapshots. Newer versions (>=22.06) of Timeshift mount their snapshots to ~/run/timeshift/$PID/backup/timeshift-btrfs~. Where ~$PID~ is the process ID of the currently running Timeshift session. The PID is changing every time Timeshift is opened. grub-btrfsd can automatically take care of the detection of the correct PID and directory if this flag is set. In this case the argument ~SNAPSHOTS_DIR~ has no effect. -** ~-l /--log-file~ +** ~-l / --log-file~ This arguments specifies a file where grub-btrfsd should write log messages. ** ~-h / --help~ Displays a short help message. +** ~-v / --verbose~ +Let the log of the daemon be more verbose + +** ~-s / --syslog~ +Write to syslog + * CONFIGURATION The daemon is usually configured via the file ~/etc/conf.d/grub-btrfsd~ on openrc-init systems and ~sudo systemctl edit --full grub-btrfsd~ on systemd systems. In this file the arguments (See OPTIONS), that OpenRC passes to the daemon when it is started, can be configured. From 5805029c7904196d2f7c91ca89334680d2abad36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Fri, 2 Sep 2022 22:55:01 +0200 Subject: [PATCH 07/11] grub-btrfsd: fix problem missing /run/timeshift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pascal Jäger --- grub-btrfsd | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-btrfsd b/grub-btrfsd index ae471f8..4bdd0a3 100755 --- a/grub-btrfsd +++ b/grub-btrfsd @@ -146,6 +146,7 @@ fi if [ ${timeshift_auto} = true ]; then watchtime=15 + [ -d /run/timeshift ] || mkdir /run/timeshift else watchtime=0 fi From 44573e5282b8fec149b9dd44d73e7ab3f5bddacc Mon Sep 17 00:00:00 2001 From: Pascal J Date: Sat, 3 Sep 2022 08:31:25 +0200 Subject: [PATCH 08/11] grub-btrfsd: Change the LogLevel Against spamming the syslog --- grub-btrfsd.service | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grub-btrfsd.service b/grub-btrfsd.service index b567c00..83e474b 100644 --- a/grub-btrfsd.service +++ b/grub-btrfsd.service @@ -3,6 +3,7 @@ Description=Regenerate grub-btrfs.cfg [Service] Type=simple +LogLevelMax=notice # Set the possible paths for `grub-mkconfig` Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin" # Load environment variables from the configuration @@ -14,9 +15,8 @@ EnvironmentFile=/etc/default/grub-btrfs/config # -t, --timeshift-auto Automatically detect Timeshifts snapshot directory # -l, --log-file Specify a logfile to write to # -v, --verbose Let the log of the daemon be more verbose -# -s, --syslog Write to syslog, this usually not needed for systemd systems, because systemd -# is logging service output to the syslog anyway -ExecStart=/usr/bin/grub-btrfsd /.snapshots +# -s, --syslog Write to syslog +ExecStart=/usr/bin/grub-btrfsd /.snapshots --syslog [Install] WantedBy=multi-user.target From 4580c0fa2cd14a1359bb66799d9892ea257fafc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Sat, 3 Sep 2022 23:29:26 +0200 Subject: [PATCH 09/11] grub-btrfsd: better instructions for daemon config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pascal Jäger --- README.md | 126 +++++++++++++++++++++++++++++++++++++++++--- grub-btrfsd.service | 2 +- 2 files changed, 121 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 9ef1094..bb9db1a 100644 --- a/README.md +++ b/README.md @@ -95,14 +95,13 @@ sudo systemctl edit --full grub-btrfsd (when using systemd) or by editing `/etc/conf.d/grub-btrfsd` (when using openRC). In either case the daemon must be restarted for the changes to take effect with ```bash sudo systemctl restart grub-btrfsd # for systemd - ``` or ``` sudo rc-service grub-btrfsd restart # for openRC ``` -It is also possible to start the daemon without systemd or openRC. In this case, the daemon should be stopped with +It is also possible to start the daemon without systemd or openRC. If you want to do this, the daemon should be stopped with ```bash sudo systemctl stop grub-btrfsd # for systemd ``` @@ -116,6 +115,8 @@ For additional information on daemon script and its arguments, run `grub-btrfsd - - - ### 🪀 Automatically update grub upon snapshot Grub-btrfs comes with its own daemon, that watches the snapshot directory for you and updates the grub menu automatically every time a snapshot is created or deleted. +By default this daemon watches the directory `/.snapshots` for changes (new snapshots or deletion of snapshots) and triggers the grub menu creation if a snapshot is found. +Therefore, if Snapper is used with its default directory, the daemon can just be started and nothing needs to be configured. For configuration like Timeshift, or Snapper with a different directory, see further below. To start it now, run ```bash @@ -137,12 +138,39 @@ sudo rc-config add grub-btrfsd default # for openRC #### 💼 Snapshots not in `/.snapshots` NOTE: This works also for Timeshift versions < 22.06, the path to watch would be `/run/timeshift/backup/timeshift-btrfs/snapshots`. + ##### Systemd By default the daemon is watching the directory `/.snapshots`. If the daemon should watch a different directory, it can be edited with ```bash sudo systemctl edit --full grub-btrfsd # for systemd ``` -What should be edited is the `/.snapshots`-part in the line that says `ExecStart=/usr/bin/grub-btrfsd /.snapshots` +What should be edited is the `/.snapshots`-part in the line that says `ExecStart=/usr/bin/grub-btrfsd --syslog /.snapshots`. +So this is what the file should look afterwards: +``` bash +[Unit] +Description=Regenerate grub-btrfs.cfg + +[Service] +Type=simple +LogLevelMax=notice +# Set the possible paths for `grub-mkconfig` +Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin" +# Load environment variables from the configuration +EnvironmentFile=/etc/default/grub-btrfs/config +# Start the daemon, usage of it is: +# grub-btrfsd [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] SNAPSHOTS_DIR +# SNAPSHOTS_DIR Snapshot directory to watch, without effect when --timeshift-auto +# Optional arguments: +# -t, --timeshift-auto Automatically detect Timeshifts snapshot directory +# -l, --log-file Specify a logfile to write to +# -v, --verbose Let the log of the daemon be more verbose +# -s, --syslog Write to syslog +ExecStart=/usr/bin/grub-btrfsd --syslog /path/to/your/snapshot/directory + +[Install] +WantedBy=multi-user.target +``` + When done, the service should be restarted with ``` bash sudo systemctl restart grub-btrfsd # for systemd @@ -151,13 +179,37 @@ sudo systemctl restart grub-btrfsd # for systemd ##### OpenRC Arguments are passed to grub-btrfsd via the file `/etc/conf.d/grub-btrfsd`. The variable `snapshots` defines, where the daemon will watch for snapshots. + +After editing, the file should looks like this: +``` bash +# Copyright 2022 Pascal Jaeger +# Distributed under the terms of the GNU General Public License v3 + +## Where to locate the root snapshots +#snapshots="/.snapshots" # Snapper in the root directory +#snapshots="/run/timeshift/backup/timeshift-btrfs/snapshots" # Timeshift < v22.06 +snapshots="/path/to/your/snapshot/directory" + +## Optional arguments to run with the daemon +# Possible options are: +# -t, --timeshift-auto Automatically detect Timeshifts snapshot directory for timeshift >= 22.06 +# -l, --log-file Specify a logfile to write to +# -v, --verbose Let the log of the daemon be more verbose +# -s, --syslog Write to syslog +# Uncomment the line to activate the option +optional_args+="--syslog " # write to syslog by default +#optional_args+="--timeshift-auto " +#optional_args+="--log-file /var/log/grub-btrfsd.log " +#optional_args+="--verbose " +``` + After that, the daemon should be restarted with ``` bash sudo rc-service grub-btrfsd restart # for openRC ``` #### 🌟 Timeshift >= version 22.06 -Newer Timeshift versions create a new directory after their process ID in `/run/timeshift` every time they are started. The PID is going to be different every time. +Newer Timeshift versions create a new directory named after their process ID in `/run/timeshift` every time they are started. The PID is going to be different every time. Therefore the daemon can not simply watch a directory, it watches `/run/timeshift` first, if a directory is created it gets Timeshifts current PID, then watches a directory in that newly created directory from Timeshift. Anyhow, to activate this mode of the daemon, `--timeshift-auto` must be passed to the daemon as a command line argument. @@ -166,8 +218,45 @@ To pass `--timeshift-auto` to grub-btrfsd, the servicefile of grub-btrfsd can be ```bash sudo systemctl edit --full grub-btrfsd # for systemd ``` -The line that says `ExecStart=/usr/bin/grub-btrfsd /.snapshots` should be edited into `ExecStart=/usr/bin/grub-btrfsd --timeshift-auto`. -When done, the service should be restarted with + +The line that says +```bash +ExecStart=/usr/bin/grub-btrfsd /.snapshots --syslog + +``` + +should be edited into +``` bash +ExecStart=/usr/bin/grub-btrfsd --syslog --timeshift-auto +``` + +So the file looks like this, afterwards: +``` bash +[Unit] +Description=Regenerate grub-btrfs.cfg + +[Service] +Type=simple +LogLevelMax=notice +# Set the possible paths for `grub-mkconfig` +Environment="PATH=/sbin:/bin:/usr/sbin:/usr/bin" +# Load environment variables from the configuration +EnvironmentFile=/etc/default/grub-btrfs/config +# Start the daemon, usage of it is: +# grub-btrfsd [-h, --help] [-t, --timeshift-auto] [-l, --log-file LOG_FILE] SNAPSHOTS_DIR +# SNAPSHOTS_DIR Snapshot directory to watch, without effect when --timeshift-auto +# Optional arguments: +# -t, --timeshift-auto Automatically detect Timeshifts snapshot directory +# -l, --log-file Specify a logfile to write to +# -v, --verbose Let the log of the daemon be more verbose +# -s, --syslog Write to syslog +ExecStart=/usr/bin/grub-btrfsd --syslog --timeshift-auto + +[Install] +WantedBy=multi-user.target +``` + +When done, the service must be restarted with ``` bash sudo systemctl restart grub-btrfsd # for systemd ``` @@ -180,6 +269,31 @@ To revert change use `systemctl revert grub-btrfsd`. Arguments are passed to grub-btrfsd via the file `/etc/conf.d/grub-btrfsd`. The variable `optional_args` defines, which optional arguments get passed to the daemon. Uncomment `#optional_args+="--timeshift-auto "` to pass the command line option `--timeshift-auto` to it. + +After the change, the file should look like this: +(Note that there is no need to comment out the `snapshots` variable. It is ignored when `--timeshift-auto` is active.) +``` bash +# Copyright 2022 Pascal Jaeger +# Distributed under the terms of the GNU General Public License v3 + +## Where to locate the root snapshots +snapshots="/.snapshots" # Snapper in the root directory +#snapshots="/run/timeshift/backup/timeshift-btrfs/snapshots" # Timeshift < v22.06 + +## Optional arguments to run with the daemon +# Possible options are: +# -t, --timeshift-auto Automatically detect Timeshifts snapshot directory for timeshift >= 22.06 +# -l, --log-file Specify a logfile to write to +# -v, --verbose Let the log of the daemon be more verbose +# -s, --syslog Write to syslog +# Uncomment the line to activate the option +optional_args+="--syslog " # write to syslog by default +optional_args+="--timeshift-auto " +#optional_args+="--log-file /var/log/grub-btrfsd.log " +#optional_args+="--verbose " +``` + + After that, the daemon should be restarted with ``` bash sudo rc-service grub-btrfsd restart # for openRC diff --git a/grub-btrfsd.service b/grub-btrfsd.service index 83e474b..35a9ad9 100644 --- a/grub-btrfsd.service +++ b/grub-btrfsd.service @@ -16,7 +16,7 @@ EnvironmentFile=/etc/default/grub-btrfs/config # -l, --log-file Specify a logfile to write to # -v, --verbose Let the log of the daemon be more verbose # -s, --syslog Write to syslog -ExecStart=/usr/bin/grub-btrfsd /.snapshots --syslog +ExecStart=/usr/bin/grub-btrfsd --syslog /.snapshots [Install] WantedBy=multi-user.target From 4c63b65e9e007ee06c6242923683a389ff65bfac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Mon, 5 Sep 2022 20:21:18 +0200 Subject: [PATCH 10/11] grub-btrfsd: Error message when grub(-btrfs) fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pascal Jäger --- 41_snapshots-btrfs | 4 +--- grub-btrfsd | 14 ++++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/41_snapshots-btrfs b/41_snapshots-btrfs index add2b37..52ae310 100644 --- a/41_snapshots-btrfs +++ b/41_snapshots-btrfs @@ -55,9 +55,7 @@ print_error() [[ "${GRUB_BTRFS_DISABLE,,}" == "true" ]] && print_error "GRUB_BTRFS_DISABLE is set to true (default=false)" if ! type btrfs >/dev/null 2>&1; then print_error "btrfs-progs isn't installed"; fi [[ -f "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" ]] && . "${GRUB_BTRFS_MKCONFIG_LIB:-/usr/share/grub/grub-mkconfig_lib}" || print_error "grub-mkconfig_lib couldn't be found" -root_fs=$(${grub_probe} --target="fs" / 2>/dev/null) -[[ "$root_fs" != "btrfs" ]] && print_error "Root filesystem isn't btrfs" - +[[ "$(${grub_probe} --target="fs" / 2>/dev/null)" != "btrfs" ]] && print_error "Root filesystem isn't btrfs" printf "Detecting snapshots ...\n" >&2 ; diff --git a/grub-btrfsd b/grub-btrfsd index 4bdd0a3..c35b181 100755 --- a/grub-btrfsd +++ b/grub-btrfsd @@ -190,11 +190,17 @@ while true; do log "Detected snapshot creation/ deletion, recreating Grub menu" "${CYAN}" sleep 5 if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then - /etc/grub.d/41_snapshots-btrfs - log "Grub submenu recreated" "${GREEN}" + if /etc/grub.d/41_snapshots-btrfs; then + log "Grub submenu recreated" "${GREEN}" + else + err "[!] Error during grub submenu creation (grub-btrfs error)" "${RED}" + fi else - ${GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o ${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg - log "Grub menu recreated" "${GREEN}" + if ${GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o ${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg; then + log "Grub menu recreated" "${GREEN}" + else + err "[!] Error during grub menu creation (grub/ grub-btrfs error)" "${RED}" + fi fi } sleep 1 From de68795d708a1c2f2b7b254732a278a775d2e4d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pascal=20J=C3=A4ger?= Date: Mon, 5 Sep 2022 22:45:19 +0200 Subject: [PATCH 11/11] grub-btrfsd: better support commandline timeshift MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a snapshot is created with `timeshift --create` an the commandline, sometimes the daemon is not fast enough between the first (/run/timeshift) inotifywait and the second (an the actual snapshot directory) inotifywait. Even without any `sleep` between them. So now the grub (sub)menu is always created once in its own process when the daemon sees a timeshift startup. Signed-off-by: Pascal Jäger --- grub-btrfsd | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/grub-btrfsd b/grub-btrfsd index c35b181..5988059 100755 --- a/grub-btrfsd +++ b/grub-btrfsd @@ -151,6 +151,24 @@ else watchtime=0 fi +create_grub_menu() { + # create the grub submenu of the whole grub menu, depending on wether the submenu already exists + # and gives feedback if it worked + if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then + if /etc/grub.d/41_snapshots-btrfs; then + log "Grub submenu recreated" "${GREEN}" + else + err "[!] Error during grub submenu creation (grub-btrfs error)" "${RED}" + fi + else + if ${GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o ${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg; then + log "Grub menu recreated" "${GREEN}" + else + err "[!] Error during grub menu creation (grub/ grub-btrfs error)" "${RED}" + fi + fi +} + # start the actual daemon vlog "Snapshot dir watchtimeout: $watchtime" vlog "Entering infinite while" "${GREEN}" @@ -158,6 +176,7 @@ while true; do runs=false if [ ${timeshift_auto} = true ] && ! [ "${timeshift_pid}" -gt 0 ] ; then # watch the timeshift folder for a folder that is created when timeshift starts up + sleep 1 # for safety so the outer while is not going crazy if [ "${timeshift_pid}" -eq -2 ]; then log "detected timeshift shutdown" fi @@ -169,11 +188,12 @@ while true; do else log "Watching /run/timeshift for timeshift to start" inotifywait ${inotify_qiet_flag} -e create -e delete /run/timeshift && { - sleep 3 + sleep 1 timeshift_pid=$(ps ax | awk '{sub(/.*\//, "", $5)} $5 ~ /timeshift/ {print $1}') snapshots="/run/timeshift/${timeshift_pid}/backup/timeshift-btrfs/snapshots" log "detected Timeshift startup, PID is: $timeshift_pid" "${CYAN}" vlog "new snapshots directory is $snapshots" "${CYAN}" + (create_grub_menu) # create the grub menu once immidiatly in a forking process. Snapshots from commandline using timeshift --create need this } fi runs=false @@ -189,25 +209,15 @@ while true; do inotifywait ${inotify_qiet_flag} -e create -e delete -e unmount -t "$watchtime" "$snapshots" && { log "Detected snapshot creation/ deletion, recreating Grub menu" "${CYAN}" sleep 5 - if [ -s "${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then - if /etc/grub.d/41_snapshots-btrfs; then - log "Grub submenu recreated" "${GREEN}" - else - err "[!] Error during grub submenu creation (grub-btrfs error)" "${RED}" - fi - else - if ${GRUB_BTRFS_MKCONFIG:-grub-mkconfig} -o ${GRUB_BTRFS_GRUB_DIRNAME:-/boot/grub}/grub.cfg; then - log "Grub menu recreated" "${GREEN}" - else - err "[!] Error during grub menu creation (grub/ grub-btrfs error)" "${RED}" - fi - fi + create_grub_menu } sleep 1 done timeshift_pid=-2 fi - sleep 1 # leave this here for safety reasons + if ! [ ${timeshift_auto} = true ] && ! [ -d "${snapshots}" ] ; then # in case someone deletes the snapshots folder (in snapper mode) to prevent the while loop from going wild + break + fi done exit 0 # tradition is tradition