Compare commits
6 Commits
3516f56580
...
1-get-base
Author | SHA1 | Date | |
---|---|---|---|
9ce4de84d7 | |||
83e11af519 | |||
136b1aa99a | |||
01180844e7 | |||
d606ae9688 | |||
2246823d06 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.idea
|
35
README.md
35
README.md
@@ -38,6 +38,8 @@ Hook files from both directories are collectively parsed and executed in lexicog
|
||||
|
||||
For ZFS snapshots intended to save your bacon the `00-*` naming convention is particularly critical. In `/usr/share/libalpm/hooks` you can see for example that when a kernel upgrade happens `60-mkinitcpio-remove.hook` is executed (deleting your existing `vmlinuz-*` kernel image for example at `/boot/vmlinuz-linux`). After that if you're using the `zfs-dkms` package which itself requires `dkms` which in turn installs `71-dkms-remove.hook` this hook removes your ZFS kernel module files. Both the `60-*` and optionally the `71-*` hook (for `zfs-dkms` users) run early due to their naming. If we don't create a snapshot before these hooks run we end up creating a snapshot without kernel image and without ZFS kernel module files. Our `00-*` hook files are executed early enough ensuring that a snapshot can safely return you to a working system.
|
||||
|
||||
## Snapshot selection
|
||||
|
||||
We snapshot datasets that have the `space.quico:auto-snapshot` property set to `true`. By default we further limit datasets to only those that are currently mounted in your active operating system. We identify these by asking `findmnt` for a list of mounted file systems of `fstype=="zfs"` which for example returns:
|
||||
```
|
||||
# findmnt --json --list --output 'fstype,source,target' | \
|
||||
@@ -47,6 +49,8 @@ zpool/root/archlinux
|
||||
```
|
||||
If no dataset (or no _local_ dataset) has the property set correctly no snapshots are done. The script will print an info-level message about that on `pacman` transactions.
|
||||
|
||||
## Snapshot chains
|
||||
|
||||
We retain two different snapshot chains, one for `pacman` transactions that only affect what we are calling _trivial_ packages and a separate chain for _important_ packages. By default only the exact regular expression package name match `^(linux(-zen)?(-headers)?|systemd|zfs-(linux(-zen)?|dkms|utils))$` is considered important so in plain English any one of:
|
||||
|
||||
- `linux`
|
||||
@@ -63,6 +67,8 @@ Whenever an important package is affected by a transaction a snapshot goes into
|
||||
|
||||
The _trivial_ snapshot chain by default keeps 25 snapshots, the _important_ chain keeps 10. The thought process here is that you will likely not futz around with a kernel every day whereas you may very well install arbitrary packages multiple times a day. Snapshots should keep you safe for a low number of weeks up to maybe a full month on an average daily driver system hence the defaults of 10 and 25 snapshots, respectively.
|
||||
|
||||
## Dataset naming and uniqueness
|
||||
|
||||
Snapshots may look like so:
|
||||
```
|
||||
$ zfs list -o name -t all
|
||||
@@ -108,6 +114,31 @@ zpool/root/archlinux@pacman_2023-03-07-0115_1_op:upgr_sev:trv
|
||||
|
||||
Whatever you set as your `pkgs_list_max_length` is still just a best effort as it is subject to ZFS' internal maximum for dataset name length. This limit is currently 255 characters. For a snapshot the dataset name in front of the `@` character plus everything else starting with the `@` character til the end count against the limit. If you'd like e.g. 200 characters allocated to the package list chances are that you'll see fewer characters than that depending on how long your dataset names are on their own.
|
||||
|
||||
## Special characters in package names
|
||||
|
||||
Arch Linux has no qualms with at (`@`) characters and plus (`+`) characters in package names but ZFS very much does take issue with those. Just a heads-up, when constructing a ZFS snapshot name we replace all `@` characters in package names with one dot each (`.`) and we replace all `+` characters with one underscore each (`_`).
|
||||
|
||||
A snapshot name that would appear like so:
|
||||
```
|
||||
$ zfs list -o name -t all
|
||||
NAME
|
||||
zpool
|
||||
zpool/root
|
||||
zpool/root/archlinux
|
||||
zpool/root/archlinux@pacman_2023-03-07-0113_1_op:upgr_sev:trv_pkgs:jdk17-temurin:libc++
|
||||
~~~~~~
|
||||
```
|
||||
We'll create like so instead:
|
||||
```
|
||||
$ zfs list -o name -t all
|
||||
NAME
|
||||
zpool
|
||||
zpool/root
|
||||
zpool/root/archlinux
|
||||
zpool/root/archlinux@pacman_2023-03-07-0113_1_op:upgr_sev:trv_pkgs:jdk17-temurin:libc__
|
||||
~~~~~~
|
||||
```
|
||||
|
||||
Have a look at `pacman-zfs-snapshot.conf` as well, its comments should be clear enough to get you going.
|
||||
|
||||
# Avoiding naming collisions
|
||||
@@ -126,7 +157,7 @@ With these settings it is possible to cause ZFS snapshot name collisions (meanin
|
||||
- They cover the same type of operation (_Install_, _Remove_ or _Upgrade_)
|
||||
- They cover the same list of packages
|
||||
|
||||
The script safeguards against naming collisions by adding a monotoniccally incrementing counter after the timestamp string.
|
||||
The script safeguards against naming collisions by adding a monotonically incrementing counter after the timestamp string.
|
||||
|
||||
For example by running `pacman -S tmux` three times within the same minute (once for an _Install_ operation and two more times for two identical _Upgrade_ operations) your system may generate the following example snapshots:
|
||||
```
|
||||
@@ -138,7 +169,7 @@ zpool/root/archlinux@pacman_2023-03-07-0116_2_op:upgr_sev:trv_pkgs:tmux
|
||||
|
||||
Notice that lines 2 and 3 would collide since their dataset names are virtually identical other than the counter suffix which was incremented by 1 to avoid a collision.
|
||||
|
||||
> This facilitates a hands-off approach to using this script on a daily driver system without risking missing snapshots or employing other more involved approaches to avoid naming collisions.
|
||||
This facilitates a hands-off approach to using this script on a daily driver system without risking missing snapshots or employing other more involved approaches to avoid naming collisions.
|
||||
|
||||
# Rollback
|
||||
|
||||
|
@@ -362,6 +362,11 @@ function do_retention () {
|
||||
function main () {
|
||||
local pkgs_in_transaction
|
||||
pkgs_in_transaction=("${@}")
|
||||
# Replace characters that are valid as Arch Linux package names but invalid as ZFS dataset names with something ZFS
|
||||
# doesn't mind. Replace at characters ('@') indiscriminately with one dot each ('.'), replace plus characters ('+')
|
||||
# with one underscore each ('_').
|
||||
pkgs_in_transaction=("${pkgs_in_transaction[@]//+/_}")
|
||||
pkgs_in_transaction=("${pkgs_in_transaction[@]//@/.}")
|
||||
|
||||
local -a important_pkgs_in_transaction trivial_pkgs_in_transaction
|
||||
split_pkgs_by_importance "${pkgs_in_transaction[@]}"
|
||||
|
Reference in New Issue
Block a user