fix(script): Document pkg character replacement (#3)

This commit is contained in:
hygienic-books 2024-07-18 19:47:12 +02:00
parent 83e11af519
commit 9ce4de84d7
2 changed files with 34 additions and 0 deletions

View File

@ -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. 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: 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' | \ # 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. 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: 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` - `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. 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: Snapshots may look like so:
``` ```
$ zfs list -o name -t all $ 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. 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. Have a look at `pacman-zfs-snapshot.conf` as well, its comments should be clear enough to get you going.
# Avoiding naming collisions # Avoiding naming collisions

View File

@ -362,6 +362,9 @@ function do_retention () {
function main () { function main () {
local pkgs_in_transaction local pkgs_in_transaction
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[@]//+/_}")
pkgs_in_transaction=("${pkgs_in_transaction[@]//@/.}") pkgs_in_transaction=("${pkgs_in_transaction[@]//@/.}")