Compare commits

...

104 Commits
1.7.1 ... v4.7

Author SHA1 Message Date
Antynea
0ed5adaf32 Fix indentation
My IDE was set up incorrectly.
Convert all tab indentation to space.
2020-10-22 07:07:30 +02:00
Antynea
d4b97415b0 Fix #116 (#118)
* Fix #116 (#118)
  * Renames variable GRUB_BTRFS_DIRNAME to GRUB_BTRFS_GRUB_DIRNAME and improves its description

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

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

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

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

* Redesign  customization section

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

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

* Modifying variable to reflect improved microcode detection

* Update config

Change "GRUB_BTRFS_INTEL_UCODE" to new variable "GRUB_BTRFS_CUSTOM_MICROCODE"

* Update README.md

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

Attempt to fix ignore specific path #100

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

Grub2 supports superuser and user access using passwords. #95

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

* Update config

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

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

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

Co-authored-by: Peter G <nephros@pearl.crownest.nephros.org>
2020-07-17 22:43:27 +02:00
Thomas Winant
92eef3079d Don't let the kernel parameters override the subvol for the snapshot (#85)
Previously, the kernel parameters came after the `rootflags=subvol=<snapshot>`
argument. This means that when the user's standard kernel parameters also
contain a `rootflags=subvol=<root>`, it will override the subvol flag of the
snapshot. So put the snapshot's subvol flag last.
2020-03-22 16:33:12 +01:00
Maxim Baz
4e1b628465 Test if snapper is properly configured before using it (#83) 2020-01-17 21:53:24 +01:00
Luflosi
21df698e04 Fix typos (#80) 2019-12-29 14:23:16 +01:00
Antynea
27335ffbaf Fixed incorrect path to the grub-btrfs.cfg file in Grub menu (#79)
Fix #72
The submenu generated by "grub-btrfs" doesn't load in the "GRUB menu."
Sometimes the Grub prefix and root variable don't match.
This ensures that the prefix variable is used to load the grub-btrfs.cfg file.
See
How to specify files
and
Special environment variables : root
and
Special environment variables : prefix
2019-12-09 22:40:33 +01:00
Antynea
6cd13037ce Fix #74 (#77)
Improving the readme and config files.
2019-12-08 18:02:05 +01:00
Hrotkó Gábor
4a882e77dc remove non numeric characters from snapshot id (#76)
Snapper support enhanced
2019-12-07 14:14:11 +01:00
Hrotkó Gábor
cb0b55a6bb add --no-dbus option to snapper list (#75)
In a chroot-ed environment, it is necessary to run snapper without dbus.
2019-12-07 12:50:57 +01:00
Antynea
2c03d5f9e2 fix #69 (#70)
Add a search command line to `grub.cfg` for find `grub-btrfs.cfg`
`search -f --set=root --no-floppy /grub/grub-btrfs.cfg`
2019-09-12 13:45:08 +02:00
Hrotkó Gábor
e286bf1a0d fix get description when quota enabled (#68) 2019-08-13 12:43:02 +02:00
Antynea
091ffc0ae9 Update EnvironmentFile (#65)
* Change `EnvironmentFile` to match the new design of the configuration file. (#64)
2018-12-15 03:35:40 +01:00
Maxim Baz
28990c45bb Update Arch Linux install instructions (#63)
added grub-btrfs to the official Arch Linux repos
2018-12-13 20:33:05 +01:00
Antynea
4c57fcbbf4 v4 (#62)
* Readme updated
* localization no longer supported
* New systemd service.
* 41_snapshots-btrfs, ahead updated
* Makefile added
2018-12-13 16:39:16 +01:00
Maxim Baz
e1532c0515 Add Makefile (#60) 2018-12-07 22:09:34 +01:00
Antynea
73a2bd3d32 Enhanced btrfs raid 0 detection (#59)
Fix #58 
- grub-probe should work properly with btrfs raid 0
2018-11-22 08:39:08 +01:00
Maxim Baz
3eb7eb7861 Support snapper 0.7.0 (#57)
Snapper changed the order of columns, ID now comes before type.
2018-10-24 00:29:06 +02:00
Nathan Parsons
35703e71c1 Make 'grub-mkconfig' command name configurable (#56)
* Make 'grub-mkconfig' command name configurable

- Use 'grub-mkconfig' as the default
- Note that some systems use 'grub2-mkconfig'
- Update 10-update_grub.conf to use the configurable grub directory name
- Refactor the systemd commands for clarity and to avoid duplicate regeneration on first run

* Update check_uuid_required() to work for partial regeneration of the GRUB menu
2018-08-15 14:02:13 +02:00
Antynea
a1a48d26b7 Override boot partition detection (#55)
* Override boot partition detection

refer to #54

* Add new option

# GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="false"  
# Change to "true" if you have a boot partition in a different subvolume

* Corrects indentation

* Update readme
GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="false"
(Change to "true" if you have a boot partition in a different subvolume)
2018-07-09 18:55:09 +02:00
Crafter6432
13a7186aaf Add systemd.path as option to monitor for new Snapshots (#53)
* Use systemd.path to regenerate grub-btrfs.cfg

* Added option GRUB_BTRFS_DIRNAME

* Updated README
2018-06-30 14:46:30 +02:00
Antynea
9b73e0ac62 Check uuid requirement. (#52)
* detect uuid requirement

add new function to detect uuid requirement

* Reduce generation time

New function doesn't need to be called at each generation of a menu entry
2018-06-11 15:52:00 +02:00
Maxim Baz
b17e7bd6a1 Add a dedicated config file (#49) 2018-04-20 18:08:37 +02:00
Antynea
b8325cf134 Fix: some functions doesn't work as expected (#48)
* Fix: Title format in grub-menu

function: 
- title_format , doesn't work as expected

replace print message with default parameter (p/d/n)

* Update header

- Add Github link
- Clear up some explanations

* Fix: path to grub-mkconfig_lib

. "$pkgdatadir/grub-mkconfig_lib" doesn't work on some distribution
Replaced by . "$datarootdir/grub/grub-mkconfig_lib"

* Fix: matches kernel & initramfs

matches kernel & initramfs doesn't work as expected
2018-04-19 15:45:59 +02:00
Antynea
c5da4014ae Update readme to v3.xx
Update readme to v3.xx

GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES="true" 
Doesn't exist anymore

GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker" "nosnapshot")
Delete "nosnapshot" it is confusing

New option available :
GRUB_BTRFS_DISABLE="true"
(Disable grub-btrfs)
2018-04-17 12:18:56 +02:00
Antynea
8508cac7d8 GRUB shouldn't break anymore (#46)
* Update 41_snapshots-btrfs

Enhanced error handling :
	- new function available: print_error
	- if btrfs-progs is not present, print a error and exit

New options in etc/default/grub 
	- disable this script
		
Enhanced menuentries:
	- menuentries is now store in new grub configfile (/boot/grub/grub.cfg)
	- use new functions for make a menuentry: make_menu_entries and entry
	- harmonize menuentry with matching version kernel&initramfs # initramfs-linux-fallback is include and not boot with intel-ucode if exist , same as original patch in GRUB for Arch Linux
	- make a menuentry in Grub menu (grub.cfg) to load our configfile

Enhanced /boot detection:
	- create two separate function for make menuentries, if /boot is on a separate partition, use function boot_separate, else, boot_bounded
	- if no kernel found, print a message and exit
	- if no initramfs found, print a message and exit

Delete function: boot_dir
No longer uses gettext_printf function of grub-mkconfig_lib

New function to detect kernel:
	- add all original standard kernel
	- verifying if kernel exist before to continue

New functionto  detect initramfs:
	- add all original standard initramfs
	- verifying if initramfs exist before to continue
	
New function to detect microcode

New counter:
	- add a counter to show a warning if the total menuentries made exceeds 250 entries

Purge some obsolete code

Size tabulation is now 4
2018-04-16 21:43:47 +02:00
Maxim Baz
a5a96fad08 Set default value of GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES to true 2018-04-06 16:28:36 +02:00
Maxim Baz
66a06be198 Set default value of GRUB_BTRFS_LIMIT to 50 2018-04-06 16:28:36 +02:00
Maxim Baz
c44eda0913 Skip ignored snapshots during generating entries, not after 2018-04-06 16:28:36 +02:00
Maxim Baz
f0b5d194c7 Add note about GRUB_BTRFS_SNAPPER_CONFIG to README 2018-04-01 21:50:13 +02:00
Maxim Baz
773a8bfb76 Support selecting snapper's config, default to 'root' (#41) 2018-04-01 21:38:22 +02:00
Antynea
1b40cfee20 Update 41_snapshots-btrfs
Update 41_snapshots-btrfs
2018-02-03 22:59:03 +01:00
Antynea
358dedc392 Update 41_snapshots-btrfs
Update 41_snapshots-btrfs
2018-02-03 22:57:04 +01:00
Antynea
55dc182b34 Update README.md 2018-02-03 22:31:43 +01:00
Nathan Parsons
23ddb063cb Add systemd service configuration for grub updating (#38)
* Add systemd service configuration for grub updating

This configuration file causes `update-grub` to be run after
Snapper's cleanup and timeline services are run by systemd

* Make invoked command more universal

* Note the need to run systemctl daemon-reload
2018-02-03 21:50:40 +01:00
Antynea
ca51d74265 Update README.md 2018-01-26 11:00:55 +01:00
Antynea
f8937a3fc7 Update README.md 2018-01-26 10:58:04 +01:00
Antynea
9265eb96de Update README.md 2018-01-26 10:55:45 +01:00
Antynea
72edee3d1c Update README.md 2018-01-26 10:54:37 +01:00
Antynea
d24ba197a8 Update README.md 2018-01-26 10:53:42 +01:00
Antynea
0e826391f1 Update 41_snapshots-btrfs 2018-01-26 09:19:33 +01:00
Antynea
7166d939fa Update README.md 2018-01-26 09:18:13 +01:00
Antynea
5cfbf46c8c fix Snapper id too long #36
* fix Snapper id too long #36
2018-01-07 00:31:16 +01:00
Antynea
12cb591307 Update README.md 2018-01-04 10:06:41 +01:00
Maxim Baz
49c64425eb Use snapper's snapshot description if available, fixes #34 (#35)
* Use snapper's snapshot description if available, fixes #34

* List snapper's snapshot from all configs

* fix: Title format in grub-menu, that didn't work as expected
2018-01-03 21:15:26 +01:00
Antynea
cb4040cd24 fix issue #27
and add "Display name of microcode in menuentry when available"
2016-11-25 01:09:34 +01:00
Antynea
55d5a4c5c2 Merge pull request #26 from daftaupe/patch-1
Update the top-level subvolid from 0 to 5.
2016-11-18 14:40:19 +01:00
Pierre-Alain TORET
bfa42253e0 Fix typo 2016-11-18 14:23:23 +01:00
Pierre-Alain TORET
13f263ca0c Update the top-level subvolid from 0 to 5.
According to https://btrfs.wiki.kernel.org/index.php/SysadminGuide#Subvolumes, the toplevel subvolume is 5 not 0, so I guess that's what should be used here.
Also fixed a few typos.
2016-11-18 12:10:59 +01:00
Antynea
18e36190f4 Update README.md 2016-05-04 16:19:45 +02:00
Antynea
f4c02dac09 add "Create entries with matching version number instead of all possible combinations of kernel and initramfs"
* GRUB_BTRFS_CREATE_ONLY_HARMONIZED_ENTRIES="false" 
-----> (Create entries with matching version number instead of all possible combinations of kernel and initramfs)
2016-05-04 13:46:31 +02:00
Antynea
86c8d0a0e8 Merge pull request #22 from anyc/master
Create only entries with matching version numbers and one small improvement
2016-05-03 16:26:15 +02:00
anyc
9fcdab5277 create only entries where kernel and initramfs have the same version number 2016-05-03 16:15:20 +02:00
anyc
87932d900d use safe temporary directory 2016-05-03 11:19:33 +02:00
Antynea
f0c50d1d76 Fix : GRUB_BTRFS_LIMIT (Limit the number of snapshots populated in the GRUB menu.)
Fix : When a value =< 0, script stop correctly
fix : When a value => 1, script stop when the value is reached

e.g :
 - GRUB_BTRFS_LIMIT="0"
   script doesn't detect snapshot

 - GRUB_BTRFS_LIMIT"1" or "2" "etc..."
   script will stop the snapshot detection when value is reached
2016-04-22 15:29:38 +02:00
Antynea
87a94c19c2 Merge pull request #21 from Psykar/patch-1
Readme typos and grammar
2016-04-19 02:49:01 +02:00
Louis des Landes
c8a7214e22 Readme typos and grammar 2016-04-19 10:46:09 +10:00
Antynea
befb66e801 Update README.md 2016-04-19 02:30:07 +02:00
Antynea
7213d04a42 Update README.md 2016-04-19 02:29:09 +02:00
Antynea
5ea4c86400 Enhanced
add a option to : specific path to ignore during run grub-mkconfig
e.g :
# Found Snapshot: 2016-03-31 10:26:52 var/lib/docker/btrfs/subvolumes/74040aee4fa

docker is not a real snapshot available to boot
add : GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker") to your /etc/default/grub
and this path will be skip during run grub-mkconfig

Warning : copy exactly the right path (var/lib/docker , not /var/lib/docker/), do not put the full path
2016-04-19 02:28:19 +02:00
Antynea
f17ce68fb3 Merge pull request #19 from Antynea/v1.xx
Enhanced
2016-04-19 02:23:33 +02:00
Antynea
7720cec5f9 Enhanced
- clean code
- add a option to : specific path to ignore during run grub-mkconfig
e.g :
# Found Snapshot: 2016-03-31 10:26:52 var/lib/docker/btrfs/subvolumes/74040aee4fa

docker is not a real snapshot available to boot
add : GRUB_BTRFS_IGNORE_SPECIFIC_PATH=("var/lib/docker") to your /etc/default/grub
and this path will be skip during run grub-mkconfig

Warning : copy exactly the right path (var/lib/docker , not /var/lib/docker/), do not put the full path
2016-04-19 02:18:24 +02:00
Antynea
b4bd7b952c clean code 2016-04-18 17:58:57 +02:00
Antynea
56c11b8e2a - overhaul
- add two new custom variable to /etc/default/grub :
* GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true"
(Show Total of snapshots found during run "grub-mkconfig")

* GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="true"
(Show snapshots found during run "grub-mkconfig")
2016-04-18 17:31:57 +02:00
Antynea
d469db0a2d - fix bug issue #18 :
if no snap found, menu generate correctly, and show a warning
- overhaul
- add two new custom variable to /etc/default/grub :
* GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true"
(Show Total of snapshots found during run "grub-mkconfig")

* GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="true"
(Show snapshots found during run "grub-mkconfig")
2016-04-18 17:31:33 +02:00
Antynea
6ae56dbaf6 Merge pull request #16 from wesbarnett/master
Add GRUB_BTRFS_LIMIT 
add GRUB_BTRFS_SUBVOLUME_SORT
2016-03-19 16:35:54 +01:00
James Barnett
f820de4759 add sorting options 2016-03-19 08:19:10 -05:00
James Barnett
59164367e7 cleanup 2016-03-19 08:11:47 -05:00
James Barnett
f256338074 Add GRUB_BTRFS_LIMIT
Allow user to limit the number of snapshots listed in GRUB. This also reverses
the order of the snapshots such that the more recent ones come first. That is,
if a user specifies GRUB_BTRFS_LIMIT=10, then only the 10 most recent snapshots
will be shown. The default limit is 100, which seems very large. The more
snapshots in the GRUB menu, the longer the system takes to boot.
2016-03-18 16:46:11 -05:00
Antynea
52ab9dbe95 Merge pull request #14 from Antynea/v1.xx
fix: incorrect detection "$boot_dir_real_path" for initramfs
2016-02-15 03:44:10 +01:00
Antynea
28e9524ca5 fix: incorrect detection "$boot_dir_real_path" for initramfs 2016-02-08 00:01:42 +01:00
10 changed files with 769 additions and 281 deletions

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

@@ -1,295 +1,542 @@
#! /usr/bin/env bash
#
#
#################################################################################################################################################
# Written by: Antynea #
# #
# Purpose: Include btrfs snapshots at boot options (grub-menu). #
# #
# What this script does: #
# - Automatically List snapshots existing on root partition (btrfs). #
# - Automatically Detect if "/boot" is in separate partition. #
# - Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots. (For custon name, see below.) #
# - Automatically Create corresponding "menuentry" in grub.cfg , which ensures a very easy rollback. #
# #
# How to use it: #
# - Add this lines to /etc/default/grub: #
# #
# * GRUB_BTRFS_SUBMENUNAME="ArchLinux Snapshots" #
# (Name menu appearing in grub.) #
# * GRUB_BTRFS_PREFIXENTRY="Snapshot:" #
# (Add a name ahead your snapshots entries.) #
# * GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="true" #
# (Show full path snapshot or only name) #
# * GRUB_BTRFS_TITLE_FORMAT="p/d/n" #
# (Custom title, shows/hides p"prefix" d"date" n"name" in grub-menu, separator "/", custom order available) #
# * GRUB_BTRFS_NKERNEL=("vmlinuz-linux") #
# (Use only if you have custom kernel name or auto-detect failed.) #
# * GRUB_BTRFS_NINIT=("initramfs-linux.img" "initramfs-linux-fallback.img") #
# (Use only if you have custom initramfs name or auto-detect failed.) #
# * GRUB_BTRFS_INTEL_UCODE=("intel-ucode.img") #
# (Use only if you have custom intel-ucode or auto-detect failed.) #
# #
# - Generate grub.cfg (on Archlinux use grub-mkconfig -o /boot/grub/grub.cfg) #
# #
# - grub-btrfs automatically generates snapshots entries. #
# - You will see it appear different entries (e.g : Snapshot: [2014-02-12 11:24:37] my snapshot name overkill) #
# #
# #
# To do: #
# # #
# * Display name of microcode in menuentry when available #
# #
#################################################################################################################################################
# Written by: Antynea
# BTC donation address: 1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt
# Github: https://github.com/Antynea/grub-btrfs
#
# Purpose:
# Improves Grub by adding "btrfs snapshots" to the Grub menu.
# You can start your system on a "snapshot" from the Grub menu.
# Supports manual snapshots, snapper ...
# Warning : booting on read-only snapshots can be tricky
# (Read about it, https://github.com/Antynea/grub-btrfs#warning-booting-on-read-only-snapshots-can-be-tricky)
#
# What this script does:
# - Automatically List snapshots existing on root partition (btrfs).
# - Automatically Detect if "/boot" is in separate partition.
# - Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots.
# - Automatically Create corresponding "menuentry" in grub.cfg
# - Automatically detect snapper and use snapper's snapshot description if available.
# - Automatically generate grub.cfg if you use the provided systemd service.
#
# Installation:
# - Run `make install` or look into Makefile for instructions on where to put each file.
#
# Customization:
# Refer to config for the list of available options and their default values.
# Place your configurations to /etc/default/grub-btrfs/config.
#
# Automatically update Grub
# If you would like Grub to automatically update when a snapshots is made or deleted:
# - Use systemctl start/enable grub-btrfs.path
# - grub-btrfs.path automatically (re)generates grub.cfg when a modification appears in /.snapshots folder (by default).
# - If your snapshots aren't mounted in /.snapshots, you must modify the watch folder using systemctl edit grub-btrfs.path
# - See https://github.com/Antynea/grub-btrfs#automatically-update-grub
#
# Special thanks for assistance and contributions:
# - My friends
# - All contributors on Github
#
set -e
#prefix="/usr"
#exec_prefix="${prefix}"
prefix="/usr"
exec_prefix="/usr"
datarootdir="/usr/share"
#datadir="${datarootdir}"
sysconfdir="/etc"
grub_btrfs_config="${sysconfdir}/default/grub-btrfs/config"
. "${datarootdir}/grub/grub-mkconfig_lib"
[[ -f "$grub_btrfs_config" ]] && . "$grub_btrfs_config"
. "$datarootdir/grub/grub-mkconfig_lib"
. "${sysconfdir}/default/grub"
######################################
### Variables in /etc/default/grub ###
######################################
## Choice of method
choise_of_method=${GRUB_BTRFS_METHOD:-"1"}
### Variables in /etc/default/grub-btrfs/config
## Disable Grub-btrfs (default=active)
[[ "${GRUB_BTRFS_DISABLE:-"false"}" == "true" ]] && exit 0
## Submenu name
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"ArchLinux Snapshots"}
distro=$(awk -F "=" '/^NAME=/ {gsub(/"/, "", $2); print $2}' /etc/os-release)
submenuname=${GRUB_BTRFS_SUBMENUNAME:-"${distro:-Linux} snapshots"}
## Prefix entry
prefixentry=${GRUB_BTRFS_PREFIXENTRY:-"Snapshot:"}
## Show full path snapshot or only name
path_snapshot=${GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT:-"true"}
## Title format
title_format=${GRUB_BTRFS_TITLE_FORMAT:-"p/d/n"}
## Kernel(s) name(s)
nkernel=("${GRUB_BTRFS_NKERNEL[@]}")
## Initramfs name(s)
ninit=("${GRUB_BTRFS_NINIT[@]}")
## Microcode(s) name(s)
microcode=("${GRUB_BTRFS_INTEL_UCODE[@]}")
## Limit snapshots to show in the Grub menu
limit_snap_show="${GRUB_BTRFS_LIMIT:-50}"
## How to sort snapshots list
btrfssubvolsort=(--sort="${GRUB_BTRFS_SUBVOLUME_SORT:-"-rootid"}")
## Snapper's config name
snapper_config=${GRUB_BTRFS_SNAPPER_CONFIG:-"root"}
## Customize GRUB directory, where "grub.cfg" file is saved
grub_directory=${GRUB_BTRFS_GRUB_DIRNAME:-"/boot/grub"}
## Customize BOOT directory, where kernels/initrams/microcode is saved.
boot_directory=${GRUB_BTRFS_BOOT_DIRNAME:-"/boot"}
## Password protection management for submenu
# Protection support for submenu (--unrestricted)
case "${GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU:-"false"}" in
true) unrestricted_access_submenu="--unrestricted ";;
*) unrestricted_access_submenu=""
esac
# Authorized users (--users foo,bar)
if [ ! -z "${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS}" ] ; then
protection_authorized_users="--users ${GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS} "
fi
########################
### variables script ###
########################
## Internationalization (default : english)
export TEXTDOMAIN=grub-btrfs-git
export TEXTDOMAINDIR="/usr/share/locale"
## hints string
hs_boot=$(${grub_probe} --target="hints_string" "/boot" 2>/dev/null)
## UUID of the boot partition
boot_uuid=$(${grub_probe} --target="fs_uuid" "/boot" 2>/dev/null)
## Type filesystem of boot partition
boot_fs=$(${grub_probe} --target="fs" "/boot" 2>/dev/null)
## UUID of the root partition
root_uuid=$(${grub_probe} "/" --target="fs_uuid" 2>/dev/null)
### variables script
## Probe info "Boot partition"
# Boot device
boot_device=$(${grub_probe} --target=device ${boot_directory})
# hints string
boot_hs=$(${grub_probe} --device ${boot_device} --target="hints_string" 2>/dev/null)
# UUID of the boot partition
boot_uuid=$(${grub_probe} --device ${boot_device} --target="fs_uuid" 2>/dev/null)
# Type filesystem of boot partition
boot_fs=$(${grub_probe} --device ${boot_device} --target="fs" 2>/dev/null)
## Probe info "Root partition"
# Type filesystem of root partition
root_fs=$(${grub_probe} --target="fs" / 2>/dev/null)
# Root device
root_device=$(${grub_probe} --target=device /)
# UUID of the root partition
root_uuid=$(${grub_probe} --device ${root_device} --target="fs_uuid" 2>/dev/null)
## Parameters passed to the kernel
kernel_parameters="$GRUB_CMDLINE_LINUX $GRUB_CMDLINE_LINUX_DEFAULT"
## Mount point location
gbgmp="/tmp/gbgmp"
gbgmp=$(mktemp -d)
## Class for theme
CLASS="--class snapshots --class gnu-linux --class gnu --class os"
## save IFS
oldIFS=$IFS
## boot_dir (auto-detect if /boot is separate partition or not)
boot_dir()
{
boot_dir="$gbgmp/$snap_dir_name/boot"
[[ "$root_uuid" != "$boot_uuid" ]] && boot_dir="/boot"
echo "$boot_dir"
## Detect uuid requirement (lvm,btrfs...)
check_uuid_required() {
if [ "x${root_uuid}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
|| ! test -e "/dev/disk/by-uuid/${root_uuid}" \
|| ( test -e "${root_device}" && uses_abstraction "${root_device}" lvm ); then
LINUX_ROOT_DEVICE=${root_device}
else
LINUX_ROOT_DEVICE=UUID=${root_uuid}
fi
}
### Error Handling
print_error()
{
local arg="$@"
local nothing_to_do="If you think an error has occurred , please file a bug report at \" https://github.com/Antynea/grub-btrfs \"\nNothing to do. Abort.\n"
printf "${arg}\n${nothing_to_do}" >&2 ;
exit 0
}
##############
### Script ###
##############
test_btrfs()
{
[[ "$root_fs" != "btrfs" ]] && print_error "Root partition isn't a btrfs filesystem.\nThis script only supports snapshots of the btrfs filesystem."
set +e
type btrfs >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
print_error "Unable to retrieve info from btrfs filesystem, make sure you have btrfs-progs on your system."
fi
set -e
}
### BEGIN auto detect ###
### Script
## Create entry
entry()
{
echo "$@" >> "$grub_directory/grub-btrfs.cfg"
}
## menu entries
snapshots_entry()
make_menu_entries()
{
## \" required for snap,kernels,init,microcode with space in their name
echo " submenu '"${title_menu[*]}"' {
submenu '---> "${title_menu[*]}" <---' { echo }
"
for k in "${name_kernel[@]}"; do
for i in "${name_initramfs[@]}"; do
for u in "${name_microcode[@]}"; do
echo "\
menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid'{
$(save_default_entry)
if [ x\$feature_all_video_module = xy ]; then
insmod all_video
fi
set gfxpayload=keep
insmod ${boot_fs}
if [ x\$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root ${hs_boot} ${boot_uuid}
else
search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
echo 'Loading Kernel: "${k}" ...'
linux \"${boot_dir_real_path}/"${k}"\" root=UUID=${root_uuid} rw rootflags=subvol=\""${snap_dir_name}"\" ${kernel_parameters}\
"
if [ -f "$(boot_dir)"/"${u}" ] ; then
echo "\
echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...'
initrd \"${boot_dir_real_path}/"${u}"\" \"/"${snap_dir_name}"/boot/"${i}"\""
else
echo "\
echo 'Loading Initramfs: "${i}" ...'
initrd \"${boot_dir_real_path}/"${i}"\""
fi
echo " }"
done
done
done
echo " }"
entry "submenu '$title_menu' {
submenu '---> $title_menu <---' { echo }"
for k in "${name_kernel[@]}"; do
[[ ! -f "${boot_dir}"/"${k}" ]] && continue;
kversion=${k#*"-"}
for i in "${name_initramfs[@]}"; do
prefix_i=${i%%"-"*}
suffix_i=${i#*"-"}
alt_suffix_i=${i##*"-"}
if [ "${kversion}" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}.img" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}-fallback.img" = "${suffix_i}" ]; then i="${i}";
elif [ "${kversion}.gz" = "${suffix_i}" ]; then i="${i}";
else continue ;
fi
for u in "${name_microcode[@]}"; do
if [[ "${name_microcode}" != "x" ]] ; then
entry "
menuentry '"${k}" & "${i}" & "${u}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
else
entry "
menuentry '"${k}" & "${i}"' ${CLASS} "\$menuentry_id_option" 'gnulinux-snapshots-$boot_uuid' {"
fi
entry "\
if [ x\$feature_all_video_module = xy ]; then
insmod all_video
fi
set gfxpayload=keep
insmod ${boot_fs}
if [ x\$feature_platform_search_hint = xy ]; then
search --no-floppy --fs-uuid --set=root ${boot_hs} ${boot_uuid}
else
search --no-floppy --fs-uuid --set=root ${boot_uuid}
fi
echo 'Loading Snapshot: "${snap_date_time}" "${snap_dir_name}"'
echo 'Loading Kernel: "${k}" ...'
linux \"${boot_dir_root_grub}/"${k}"\" root="${LINUX_ROOT_DEVICE}" rw ${kernel_parameters} rootflags=subvol=\""${snap_dir_name}"\""
if [[ "${name_microcode}" != "x" ]] ; then
entry "\
echo 'Loading Microcode & Initramfs: "${u}" "${i}" ...'
initrd \"${boot_dir_root_grub}/"${u}"\" \"${boot_dir_root_grub}/"${i}"\""
else
entry "\
echo 'Loading Initramfs: "${i}" ...'
initrd \"${boot_dir_root_grub}/"${i}"\""
fi
entry " }"
count_warning_menuentries=$((1+$count_warning_menuentries))
done
done
done
entry "}"
}
## Trim a string from leading and trailing whitespaces
trim() {
local var="$*"
var="${var#"${var%%[![:space:]]*}"}"
var="${var%"${var##*[![:space:]]}"}"
echo -n "$var"
}
## List of snapshots on filesystem
snapshot_list()
{
for snap in $(btrfs subvolume list -sa /); do
IFS=$oldIFS
snap=($snap)
local snap_path_name=${snap[@]:13:${#snap[@]}}
# Discard deleted snapshots
if [ "$snap_path_name" = "DELETED" ]; then continue; fi
[[ ${snap_path_name%%"/"*} == "<FS_TREE>" ]] && snap_path_name=${snap_path_name#*"/"}
echo ${snap[@]:10:2} ${snap_path_name}
done
# Query info from snapper if it is installed
type snapper >/dev/null 2>&1
if [ $? -eq 0 ]; then
if [ -s "/etc/snapper/configs/$snapper_config" ]; then
printf "Info: snapper detected, using config '$snapper_config'\n" >&2
local snapper_ids=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | cut -d'|' -f 1))
local snapper_types=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | cut -d'|' -f 2))
IFS=$'\n'
local snapper_descriptions=($(snapper --no-dbus -t 0 -c "$snapper_config" list --disable-used-space | tail -n +3 | rev | cut -d'|' -f 2 | rev))
else
printf "Warning: snapper detected but config '$snapper_config' does not exist\n" >&2
fi
fi
IFS=$'\n'
# Parse btrfs snapshots
local entries=()
local ids=()
local max_entry_length=0
for snap in $(btrfs subvolume list -sa "${btrfssubvolsort}" /); do
IFS=$oldIFS
snap=($snap)
local snap_path_name=${snap[@]:13:${#snap[@]}}
# Discard deleted snapshots
if [ "$snap_path_name" = "DELETED" ]; then continue; fi
[[ ${snap_path_name%%"/"*} == "<FS_TREE>" ]] && snap_path_name=${snap_path_name#*"/"}
# ignore specific path during run "grub-mkconfig"
if [ ! -z "${GRUB_BTRFS_IGNORE_SPECIFIC_PATH}" ] ; then
for isp in ${GRUB_BTRFS_IGNORE_SPECIFIC_PATH[@]} ; do
[[ "${snap_path_name}" == "${isp}" ]] && continue 2;
done
fi
if [ ! -z "${GRUB_BTRFS_IGNORE_PREFIX_PATH}" ] ; then
for isp in ${GRUB_BTRFS_IGNORE_PREFIX_PATH[@]} ; do
[[ "${snap_path_name}" == "${isp}"/* ]] && continue 2;
done
fi
# detect if /boot directory exists
[[ ! -d "$gbgmp/$snap_path_name/boot" ]] && continue;
local id="${snap_path_name//[!0-9]}" # brutal way to get id: remove everything non-numeric
ids+=("$id")
local entry="${snap[@]:10:2} | ${snap_path_name}"
entries+=("$entry")
# Find max length of a snapshot entry, needed for pretty formatting
local length="${#entry}"
[[ "$length" -gt "$max_entry_length" ]] && max_entry_length=$length
done
# Find max length of a snapshot type, needed for pretty formatting
local max_type_length=0
for id in "${ids[@]}"; do
for j in "${!snapper_ids[@]}"; do
local snapper_id="${snapper_ids[$j]//[[:space:]]/}"
if [[ "$snapper_id" == "$id" ]]; then
local snapper_type=$(trim "${snapper_types[$j]}")
local length="${#snapper_type}"
[[ "$length" -gt "$max_type_length" ]] && max_type_length=$length
fi
done
done
for i in "${!entries[@]}"; do
local id="${ids[$i]}"
local entry="${entries[$i]}"
for j in "${!snapper_ids[@]}"; do
local snapper_id="${snapper_ids[$j]//[[:space:]]/}"
# remove other non numeric characters
snapper_id="${snapper_id//\*/}"
snapper_id="${snapper_id//\+/}"
snapper_id="${snapper_id//-/}"
if [[ "$snapper_id" == "$id" ]]; then
local snapper_type=$(trim "${snapper_types[$j]}")
local snapper_description=$(trim "${snapper_descriptions[$j]}")
printf -v entry "%-${max_entry_length}s | %-${max_type_length}s | %s" "$entry" "$snapper_type" "$snapper_description"
break
fi
done
echo "$entry"
done
IFS=$oldIFS
}
## Detect kernels in "/boot"
detect_kernel()
{
## Arch original kernel (auto-detect)
for akernel in "$(boot_dir)"/vmlinuz-* ; do
list_kernel+=("$akernel")
done
list_kernel=()
# Original kernel (auto-detect)
for okernel in "${boot_dir}"/vmlinuz-* \
"${boot_dir}"/vmlinux-* \
"${boot_dir}"/kernel-* ; do
[[ ! -f "${okernel}" ]] && continue;
list_kernel+=("$okernel")
done
## Custom name kernel in GRUB_BTRFS_NKERNEL
if [ ! -z "${nkernel}" ] ; then
for ckernel in "${nkernel[@]}" ; do
[[ ! -f /"$(boot_dir)"/"${ckernel}" ]] && continue;
list_kernel+=("$ckernel")
done
fi
# Custom name kernel in GRUB_BTRFS_NKERNEL
if [ ! -z "${GRUB_BTRFS_NKERNEL}" ] ; then
for ckernel in "${boot_dir}/${GRUB_BTRFS_NKERNEL[@]}" ; do
[[ ! -f "${ckernel}" ]] && continue;
list_kernel+=("$ckernel")
done
fi
}
## Detect initramfs in "/boot"
detect_initramfs()
{
## Arch original initramfs (auto-detect)
for ainitramfs in "$(boot_dir)"/initramfs-* ; do
list_initramfs+=("$ainitramfs")
done
## Custom name initramfs in GRUB_BTRFS_NINIT
if [ ! -z "$ninit" ] ; then
for cinitramfs in "${ninit[@]}" ; do
[[ ! -f /"$(boot_dir)"/"${cinitramfs}" ]] && continue;
list_initramfs+=("$cinitramfs")
done
fi
list_initramfs=()
# Original initramfs (auto-detect)
for oinitramfs in "${boot_dir}"/initrd.img-* \
"${boot_dir}"/initrd-*.img \
"${boot_dir}"/initrd-*.gz \
"${boot_dir}"/initramfs-*.img \
"${boot_dir}"/initramfs-*.gz ; do
[[ ! -f "${oinitramfs}" ]] && continue;
list_initramfs+=("$oinitramfs")
done
# Custom name initramfs in GRUB_BTRFS_NINIT
if [ ! -z "${GRUB_BTRFS_NINIT}" ] ; then
for cinitramfs in "${boot_dir}/${GRUB_BTRFS_NINIT[@]}" ; do
[[ ! -f "${cinitramfs}" ]] && continue;
list_initramfs+=("$cinitramfs")
done
fi
}
## Detect microcode in "/boot"
detect_microcode()
{
## Arch original intel microcode
for aucode in "$(boot_dir)"/intel-ucode.img ; do
list_ucode+=("$aucode")
done
list_ucode=()
# Original intel/amd microcode (auto-detect)
# See "https://www.gnu.org/software/grub/manual/grub/html_node/Simple-configuration.html"
for oiucode in "${boot_dir}"/intel-uc.img \
"${boot_dir}"/intel-ucode.img \
"${boot_dir}"/amd-uc.img \
"${boot_dir}"/amd-ucode.img \
"${boot_dir}"/early_ucode.cpio \
"${boot_dir}"/microcode.cpio; do
[[ ! -f "${oiucode}" ]] && continue;
list_ucode+=("$oiucode")
done
## Custom name microcode in GRUB_BTRFS_INTEL_UCODE
if [ ! -z "$microcode" ] ; then
for cucode in "${microcode[@]}" ; do
[[ ! -f /"$(boot_dir)"/"${cucode}" ]] && continue
list_ucode+=("$cucode")
done
fi
# Custom name microcode in GRUB_BTRFS_CUSTOM_MICROCODE
if [ ! -z "${GRUB_BTRFS_CUSTOM_MICROCODE}" ] ; then
for cucode in "${boot_dir}/${GRUB_BTRFS_CUSTOM_MICROCODE[@]}" ; do
[[ ! -f "${cucode}" ]] && continue
list_ucode+=("$cucode")
done
fi
if [ -z "${list_ucode}" ]; then list_ucode=(x); fi
}
## Show full path snapshot or only name
path_snapshot()
{
case "${path_snapshot}" in
true) name_snapshot=("${snap_dir_name}");;
*) name_snapshot=("${snap_dir_name#*"/"}")
esac
case "${GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT:-"true"}" in
true) name_snapshot=("${snap_full_name}");;
*) name_snapshot=("${snap_full_name#*"/"}")
esac
}
## Title format in grub-menu
title_format()
{
case "${title_format}" in
p/d/n) title_menu=("${prefixentry}" "${snap_date_time}" "${name_snapshot}");;
p/n/d) title_menu=("${prefixentry}" "${snap_dir_name}" "${snap_date_time}");;
p/d) title_menu=("${prefixentry}" "${snap_date_time}");;
p/n) title_menu=("${prefixentry}" "${snap_dir_name}");;
d/n) title_menu=("${snap_date_time}" "${snap_dir_name}");;
n/d) title_menu=("${snap_dir_name}" "${snap_date_time}");;
p) title_menu=("${prefixentry}");;
d) title_menu=("${snap_date_time}");;
n) title_menu=("${snap_dir_name}");;
*) gettext_printf $"# Warning: GRUB_BTRFS_TITLE_FORMAT=${title_format}, syntax error \n" >&2
esac
case "${GRUB_BTRFS_TITLE_FORMAT:-"p/d/n"}" in
p/n/d) title_menu="${prefixentry} ${name_snapshot} ${snap_date_time}";;
p/d) title_menu="${prefixentry} ${snap_date_time}";;
p/n) title_menu="${prefixentry} ${name_snapshot}";;
d/n) title_menu="${snap_date_time} ${name_snapshot}";;
n/d) title_menu="${name_snapshot} ${snap_date_time}";;
p) title_menu="${prefixentry}";;
d) title_menu="${snap_date_time}";;
n) title_menu="${name_snapshot}";;
*) title_menu="${prefixentry} ${snap_date_time} ${name_snapshot}"
esac
}
## List of kernels, initramfs and microcode in snapshots
list_kernels_initramfs()
boot_bounded()
{
IFS=$'\n'
for item in $(snapshot_list); do
IFS=$oldIFS
item=($item)
snap_dir_name=${item[@]:2:${#item[@]}}
[[ ! -d "$gbgmp/$snap_dir_name/boot" ]] && continue;
snap_date_time=${item[@]:0:2}
gettext_printf $"# Found Snapshot: %s\n" "${snap_date_time} ${snap_dir_name}" >&2 ;
unset list_kernel
detect_kernel
name_kernel=("${list_kernel[@]##*"/"}")
# echo "kernel = ${name_kernel[*]}"
unset list_initramfs
detect_initramfs
name_initramfs=("${list_initramfs[@]##*"/"}")
# echo "initramfs = ${name_initramfs[*]}"
unset list_ucode
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
# echo "ucode = ${name_microcode[*]}"
boot_dir_real_path="$(make_system_path_relative_to_its_root "$(boot_dir)")"
## Create menu entries
# name snpashot
path_snapshot
# title menu custom
title_format
# echo "${title_menu[*]}"
snapshots_entry
done
IFS=$oldIFS
# Initialize menu entries
IFS=$'\n'
for item in $(snapshot_list); do
[[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0
IFS=$oldIFS
snap_full_name="$(echo "$item" | cut -d'|' -f2-)" # do not trim it to keep nice formatting
snap_dir_name="$(echo "$item" | cut -d'|' -f2)"
snap_dir_name="$(trim "$snap_dir_name")"
snap_date_time="$(echo "$item" | cut -d' ' -f1-2)"
snap_date_time="$(trim "$snap_date_time")"
boot_dir="$gbgmp/$snap_dir_name$boot_directory"
# Kernel (Original + custom kernel)
detect_kernel
if [ -z "${list_kernel}" ]; then continue; fi
name_kernel=("${list_kernel[@]##*"/"}")
# Initramfs (Original + custom initramfs)
detect_initramfs
if [ -z "${list_initramfs}" ]; then continue; fi
name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode)
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
# show snapshot found during run "grub-mkconfig"
if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]]; then
printf "Found snapshot: %s\n" "$item" >&2 ;
fi
# Show full path snapshot or only name
path_snapshot
# Title format in grub-menu
title_format
# convert /boot directory to root of GRUB (e.g /boot become /)
boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")"
# Make menuentries
make_menu_entries
### Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+$count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break;
# Limit generation of menuentries if exceeds 250
# [[ $count_warning_menuentries -ge 250 ]] && break;
done
IFS=$oldIFS
}
### END auto detect ###
boot_separate()
{
boot_dir="${boot_directory}"
# convert /boot directory to root of GRUB (e.g /boot become /)
boot_dir_root_grub="$(make_system_path_relative_to_its_root "${boot_dir}")"
### Choice of method ###
if [ ${choise_of_method} = "1" ] ; then
gettext_printf "###### - Grub-btrfs: Auto-detect - ######\n" >&2 ;
[[ ! -d $gbgmp ]] && mkdir -p $gbgmp
mount -o subvolid=0 /dev/disk/by-uuid/$root_uuid $gbgmp/
echo "submenu '${submenuname}' {"
list_kernels_initramfs ;
echo "}"
umount $gbgmp
gettext_printf "###### - Grub-btrfs: Auto-detect - ######\n" >&2 ;
# Kernel (Original + custom kernel)
detect_kernel
if [ -z "${list_kernel}" ]; then print_error "Kernels not found."; fi
name_kernel=("${list_kernel[@]##*"/"}")
# Initramfs (Original + custom initramfs)
detect_initramfs
if [ -z "${list_initramfs}" ]; then print_error "Initramfs not found."; fi
name_initramfs=("${list_initramfs[@]##*"/"}")
# microcode (auto-detect + custom microcode)
detect_microcode
name_microcode=("${list_ucode[@]##*"/"}")
# Initialize menu entries
IFS=$'\n'
for item in $(snapshot_list); do
[[ ${limit_snap_show} -le 0 ]] && break; # fix: limit_snap_show=0
IFS=$oldIFS
snap_full_name="$(echo "$item" | cut -d'|' -f2-)" # do not trim it to keep nice formatting
snap_dir_name="$(echo "$item" | cut -d'|' -f2)"
snap_dir_name="$(trim "$snap_dir_name")"
snap_date_time="$(echo "$item" | cut -d' ' -f1-2)"
snap_date_time="$(trim "$snap_date_time")"
# show snapshot found during run "grub-mkconfig"
if [[ "${GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND:-"true"}" = "true" ]]; then
printf "Found snapshot: %s\n" "$item" >&2 ;
fi
# Show full path snapshot or only name
path_snapshot
# Title format in grub-menu
title_format
# Make menuentries
make_menu_entries
# Limit snapshots found during run "grub-mkconfig"
count_limit_snap=$((1+$count_limit_snap))
[[ $count_limit_snap -ge $limit_snap_show ]] && break;
# Limit generation of menuentries if exceeds 250
# [[ $count_warning_menuentries -ge 250 ]] && break;
done
IFS=$oldIFS
}
### Start
printf "Detecting snapshots ...\n" >&2 ;
# Only support btrfs snapshots
test_btrfs
# Delete existing config
#rm -f --preserve-root "$grub_directory/grub-btrfs.cfg"
> "$grub_directory/grub-btrfs.cfg"
# Create mount point then mounting
[[ ! -d $gbgmp ]] && mkdir -p $gbgmp
mount -o subvolid=5 /dev/disk/by-uuid/$root_uuid $gbgmp/
# Count menuentries
count_warning_menuentries=0
# Count snapshots
count_limit_snap=0
# detect uuid requirement
check_uuid_required
# Detects if /boot is a separate partition
if [[ "${GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION:-"false"}" == "true" ]]; then
printf "Info: Override boot partition detection : enable \n" >&2 ;
boot_separate
else
if [[ "$root_uuid" != "$boot_uuid" ]]; then
printf "Info: Separate boot partition detected \n" >&2 ;
boot_separate
else
printf "Info: Separate boot partition not detected \n" >&2 ;
boot_bounded
fi
fi
### End choice of method ###
# unmounting mount point
umount $gbgmp
# Show warn, menuentries exceeds 250 entries
[[ $count_warning_menuentries -ge 250 ]] && printf "Generated ${count_warning_menuentries} total GRUB entries. You might experience issues loading snapshots menu in GRUB.\n" >&2 ;
# printf "menuentries = $count_warning_menuentries \n" >&2 ;
# Show total found snapshots
if [[ "${GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND:-"true"}" = "true" && ! -z "${count_limit_snap}" && "${count_limit_snap}" != "0" ]]; then
printf "Found ${count_limit_snap} snapshot(s)\n" >&2 ;
fi
# if no snapshot found, exit
if [[ "${count_limit_snap}" = "0" || -z "${count_limit_snap}" ]]; then
print_error "No snapshots found."
fi
# Make a submenu in GRUB (grub.cfg)
cat << EOF
submenu '${submenuname}' ${protection_authorized_users}${unrestricted_access_submenu}{
configfile "\${prefix}/grub-btrfs.cfg"
}
EOF
### End

31
Makefile Normal file
View File

@@ -0,0 +1,31 @@
PKGNAME ?= grub-btrfs
PREFIX ?= /usr
SHARE_DIR = $(DESTDIR)$(PREFIX)/share
LIB_DIR = $(DESTDIR)$(PREFIX)/lib
.PHONY: install
install:
@install -Dm755 -t "$(DESTDIR)/etc/grub.d/" 41_snapshots-btrfs
@install -Dm644 -t "$(DESTDIR)/etc/default/grub-btrfs/" config
@install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.service
@install -Dm644 -t "$(LIB_DIR)/systemd/system/" grub-btrfs.path
@install -Dm644 -t "$(SHARE_DIR)/licenses/$(PKGNAME)/" LICENSE
@install -Dm644 "initramfs/Arch Linux/overlay_snap_ro-install" "$(LIB_DIR)/initcpio/install/grub-btrfs-overlayfs" # Arch Linux only
@install -Dm644 "initramfs/Arch Linux/overlay_snap_ro-install" "$(LIB_DIR)/initcpio/install/grub-btrfs-overlayfs" # Arch Linux only
@install -Dm644 -t "$(SHARE_DIR)/doc/$(PKGNAME)/" README.md
@install -Dm644 "initramfs/readme.md" "$(SHARE_DIR)/doc/$(PKGNAME)/initramfs-overlayfs.md"
uninstall:
rm -f "$(DESTDIR)/etc/grub.d/41_snapshots-btrfs"
rm -f "$(DESTDIR)/etc/default/grub-btrfs/config"
rm -f "$(LIB_DIR)/systemd/system/grub-btrfs.service"
rm -f "$(LIB_DIR)/systemd/system/grub-btrfs.path"
rm -f "$(SHARE_DIR)/licenses/$(PKGNAME)/LICENSE"
rm -f "$(DESTDIR)/boot/grub/grub-btrfs.cfg"
rm -f "$(LIB_DIR)/initcpio/install/grub-btrfs-overlayfs" # Arch Linux only
rm -f "$(LIB_DIR)/initcpio/hooks/grub-btrfs-overlayfs" # Arch Linux only
rm -rf "$(SHARE_DIR)/doc/$(PKGNAME)/" README.md
rm -rf "$(SHARE_DIR)/doc/$(PKGNAME)/initramfs-overlayfs.md"
rmdir --ignore-fail-on-non-empty "$(DESTDIR)/etc/default/grub-btrfs"

112
README.md
View File

@@ -1,73 +1,75 @@
[![GitHub release](https://img.shields.io/github/release/Antynea/grub-btrfs.svg)](https://github.com/Antynea/grub-btrfs)
### 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
This is a version 1.xx of grub-btrfs
This is a version 4.xx of grub-btrfs
##### BTC donation address: `1Lbvz244WA8xbpHek9W2Y12cakM6rDe5Rt`
##
### Description
Improves Grub by adding "btrfs snapshots" to the Grub menu.
#### Description
You can start your system on a "snapshot" from the Grub menu.
Supports manual snapshots, snapper, timeshift ...
grub-btrfs, Include btrfs snapshots at boot options. (grub menu)
##### Warning: booting on read-only snapshots can be tricky
#### What does grub-btrfs v1.xx do :
If you choose to do it, `/var/log` or even `/var` must be on a separate subvolume.
Otherwise, make sure your snapshots are writeable.
See [this ticket](https://github.com/Antynea/grub-btrfs/issues/92) for more info.
Simple rollback using snapshots you made previously.
This project includes its own solution.
Refer to the [documentation](https://github.com/Antynea/grub-btrfs/blob/master/initramfs/readme.md).
##
### What does grub-btrfs v4.xx do :
* Automatically List snapshots existing on root partition (btrfs).
* Automatically Detect if "/boot" is in separate partition.
* Automatically Detect kernel, initramfs and intel/amd microcode in "/boot" directory on snapshots.
* Automatically Create corresponding "menuentry" in `grub.cfg`
* Automatically detect snapper and use snapper's snapshot description if available.
* Automatically generate `grub.cfg` if you use the provided systemd service.
* Automatically Detect kernel, initramfs and intel microcode in "/boot" directory on snapshots. (For custon name, see below.)
##
### Installation :
#### Arch Linux
* Automatically Create corresponding "menuentry" in grub.cfg , which ensures a very easy rollback.
```
pacman -S grub-btrfs
```
#### Manual
#### How to use it:
* Run `make install` or look into Makefile for instructions on where to put each file.
Add this lines to /etc/default/grub:
NOTE: Generate your Grub menu after installation for the changes to take effect.
On Arch Linux use `grub-mkconfig -o /boot/grub/grub.cfg`.
* GRUB_BTRFS_SUBMENUNAME="ArchLinux Snapshots"
##
### Customization:
(Name menu appearing in grub.)
You have the possibility to modify many parameters in `/etc/default/grub-btrfs/config`.
See [config file](https://github.com/Antynea/grub-btrfs/blob/master/config) for more information.
* GRUB_BTRFS_PREFIXENTRY="Snapshot:"
##
### Automatically update grub
If you would like Grub to automatically update when a snapshot is made or deleted:
* Use `systemctl start/enable grub-btrfs.path`.
* `grub-btrfs.path` automatically (re)generates `grub.cfg` when a modification appears in `/.snapshots` folder (by default).
* If your snapshots aren't mounted in `/.snapshots`, you must modify the watch folder using `systemctl edit grub-btrfs.path`.
* For example: Timeshift mount its snapshots in `/run/timeshift/backup/timeshift-btrfs/snapshots` folder.
(Add a name ahead your snapshots entries.)
* GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="true"
(Show full path snapshot or only name)
* GRUB_BTRFS_TITLE_FORMAT="p/d/n"
(Custom title, shows/hides p"prefix" d"date" n"name" in grub-menu, separator "/", custom order available)
* GRUB_BTRFS_NKERNEL=("vmlinuz-linux")
(Use only if you have custom kernel name or auto-detect failed.)
* GRUB_BTRFS_NINIT=("initramfs-linux.img" "initramfs-linux-fallback.img")
(Use only if you have custom initramfs name or auto-detect failed.)
* GRUB_BTRFS_INTEL_UCODE=("intel-ucode.img")
(Use only if you have custom intel-ucode or auto-detect failed.)
Generate grub.cfg (on Archlinux use grub-mkconfig -o /boot/grub/grub.cfg )
grub-btrfs automatically generates snapshots entries.
You will see it appear differents entries (e.g : Snapshot: [2014-02-12 11:24:37] my snapshot name overkill )
#### TO DO
* Display name of microcode in menuentry when available
## discussion
Pour les francophones : https://forums.archlinux.fr/viewtopic.php?f=18&t=17177
Use `systemctl edit grub-btrfs.path`.
Then wrote:
```
[Path]
PathModified=/run/timeshift/backup/timeshift-btrfs/snapshots
```
and finally save.
* You can view your change to `systemctl cat grub-btrfs.path`.
* To revert change use `systemctl revert grub-btrfs.path`.
##
### Special thanks for assistance and contributions
* [maximbaz](https://github.com/maximbaz)
* [All contributors](https://github.com/Antynea/grub-btrfs/graphs/contributors)
##

111
config Normal file
View File

@@ -0,0 +1,111 @@
#!/usr/bin/env bash
# Disable grub-btrfs.
# Default: "false"
#GRUB_BTRFS_DISABLE="true"
# Name appearing in the Grub menu.
# Default: "Use distribution information from /etc/os-release."
#GRUB_BTRFS_SUBMENUNAME="Arch Linux snapshots"
# Add a name ahead your snapshots entries in the Grub menu.
# Default: "Snapshot:"
#GRUB_BTRFS_PREFIXENTRY="Snapshot:"
# Show full path snapshot or only name in the Grub menu, weird reaction with snapper.
# Default: "true"
#GRUB_BTRFS_DISPLAY_PATH_SNAPSHOT="false"
# Custom title.
# shows/hides p"prefix" d"date" n"name" in the Grub menu, separator "/", custom order available.
# Default: "p/d/n"
#GRUB_BTRFS_TITLE_FORMAT="p/d/n"
# Limit the number of snapshots populated in the GRUB menu.
# Default: "50"
#GRUB_BTRFS_LIMIT="50"
# Sort the found subvolumes by "ogeneration" or "generation" or "path" or "rootid".
# # See Sorting section to https://btrfs.wiki.kernel.org/index.php/Manpage/btrfs-subvolume#SUBCOMMAND
# "-rootid" means list snapshot by new ones first.
# Default: "-rootid"
#GRUB_BTRFS_SUBVOLUME_SORT="+ogen,-gen,path,rootid"
# Show snapshots found during run "grub-mkconfig"
# Default: "true"
#GRUB_BTRFS_SHOW_SNAPSHOTS_FOUND="false"
# Show Total of snapshots found during run "grub-mkconfig"
# Default: "true"
#GRUB_BTRFS_SHOW_TOTAL_SNAPSHOTS_FOUND="true"
# By default, "grub-btrfs" automatically detects most existing kernels.
# If you have one or more custom kernels, you can add them here.
# Default: ("")
#GRUB_BTRFS_NKERNEL=("kernel-custom" "vmlinux-custom")
# By default, "grub-btrfs" automatically detects most existing initramfs.
# If you have one or more custom initramfs, you can add them here.
# Default: ("")
#GRUB_BTRFS_NINIT=("initramfs-custom.img" "initrd-custom.img" "otherinit-custom.gz")
# By default, "grub-btrfs" automatically detects most existing microcodes.
# If you have one or more custom microcodes, you can add them here.
# Default: ("")
#GRUB_BTRFS_CUSTOM_MICROCODE=("custom-ucode.img" "custom-uc.img "custom_ucode.cpio")
# Ignore specific path during run "grub-mkconfig".
# Only exact paths are ignored.
# e.g : if `specific path` = @, only `@` snapshot will be ignored.
# Default: ("@")
GRUB_BTRFS_IGNORE_SPECIFIC_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")
GRUB_BTRFS_IGNORE_PREFIX_PATH=("var/lib/docker" "@var/lib/docker" "@/var/lib/docker")
# By default "grub-btrfs" automatically detects your boot partition,
# either located at the system root or on a separate partition,
# but cannot detect if it is in a subvolume.
# Change to "true" if you have a boot partition in a different subvolume.
# Default: "false"
#GRUB_BTRFS_OVERRIDE_BOOT_PARTITION_DETECTION="true"
# Location of the folder containing the "grub.cfg" file.
# Use by grub-btrfs to save the file "grub-btrfs.cfg".
# Might be grub2 on some systems.
# For example, on Fedora with EFI : "/boot/efi/EFI/fedora"
# Default: "/boot/grub"
#GRUB_BTRFS_GRUB_DIRNAME="/boot/grub2"
# Location of kernels/initramfs/microcode.
# Use by "grub-btrfs" to detect the boot partition and the location of kernels/initrafms/microcodes.
# Default: "/boot"
#GRUB_BTRFS_BOOT_DIRNAME="/boot"
# Name/path of grub-mkconfig, use by "grub-btrfs.service"
# Might be 'grub2-mkconfig' on some systems
# For example, on Fedora : "/sbin/grub2-mkconfig"
# Default: /usr/bin/grub-mkconfig
#GRUB_BTRFS_MKCONFIG=/usr/bin/grub2-mkconfig
# Snapper
# Snapper's config name to use
# Default: "root"
#GRUB_BTRFS_SNAPPER_CONFIG="root"
# Password protection management for submenu,snapshots
# Refer to the Grub documentation https://www.gnu.org/software/grub/manual/grub/grub.html#Authentication-and-authorisation
# and this comment https://github.com/Antynea/grub-btrfs/issues/95#issuecomment-682295660
#
# Add authorized usernames separate by comma (foo,bar)
# When Grub's password protection is enabled, the superuser is authorized by default, it isn't necessary to add it
# Default: ""
#GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS="foo,bar"
#
# Disable authentication support for submenu of Grub-btrfs only (--unrestricted)
# doesn't work if GRUB_BTRFS_PROTECTION_AUTHORIZED_USERS isn't empty
# Default: "false"
#GRUB_BTRFS_DISABLE_PROTECTION_SUBMENU="true"

8
grub-btrfs.path Normal file
View File

@@ -0,0 +1,8 @@
[Unit]
Description=Monitors for new snapshots
[Path]
PathModified=/.snapshots
[Install]
WantedBy=multi-user.target

11
grub-btrfs.service Normal file
View File

@@ -0,0 +1,11 @@
[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=/bin/bash -c 'if [ -s "${GRUB_BTRFS_DIRNAME:-/boot/grub}/grub-btrfs.cfg" ]; then /etc/grub.d/41_snapshots-btrfs; else ${GRUB_BTRFS_MKCONFIG:-/usr/bin/grub-mkconfig} -o ${GRUB_BTRFS_DIRNAME:-/boot/grub}/grub.cfg; fi'

View File

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

View File

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

45
initramfs/readme.md Normal file
View File

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

Binary file not shown.