This is the Ubuntu/APT counterpart to [zfs-pacman-hook](https://quico.space/quico-os-setup/zfs-pacman-hook). It snapshots selected ZFS datasets before APT invokes `dpkg`, includes affected Debian package names in snapshot names, and prunes old snapshots using separate ordinary and important-package retention chains.
Set `dry_run='true'` in `/etc/apt-zfs-snapshot.conf`, run a harmless APT operation, and inspect the planned names. Set it back to `false` after verifying dataset selection and naming.
The helper runs as root through APT and requires Bash, `zfs`, and `findmnt`.
## APT integration
The hook uses `DPkg::Pre-Install-Pkgs`. APT sends its version-3 package action protocol on the file descriptor named by `APT_HOOK_INFO_FD`. Records contain the package name, old and new versions, version direction, architecture, and action. This captures dependencies selected by APT as well as explicitly requested packages.
Configuration-only records are ignored. If one callback contains multiple operation classes, the marker is `mixd`. In normal Ubuntu use, an `apt-get -y dist-upgrade` produces one useful callback and therefore one snapshot. APT can invoke `dpkg` more than once for complex operations; this implementation creates one snapshot per package-action callback.
By default, datasets with this exact ZFS property are selected:
```bash
zfs set space.quico:auto-snapshot=true rpool/ROOT/ubuntu
```
With `snap_only_local_datasets='true'`, only mounted ZFS datasets are selected. This avoids snapshotting another operating system stored in the same pool. To explicitly select roots, set:
```bash
snapshot_roots='bpool/BOOT rpool/ROOT'
```
Explicit roots bypass property discovery and the mounted-dataset check. Each root is snapshotted recursively, and all roots are passed to one `zfs snapshot -r` command.
The timestamp is UTC by default and is controlled by `date_format` and `timezone`. The counter starts at one and increases if a complete name already exists. This prevents collisions when identical operations happen within the same timestamp interval.
Package names are separated with `package_separator`, which defaults to `:`. Plus signs are replaced with underscores before inclusion in a ZFS name. The package list is shortened by dropping complete names from the end first, then truncating the final remaining name and adding `...` when at least four characters fit. `packages_max_length` is a best effort because the complete ZFS name is limited to 255 characters. If the fixed dataset and metadata fields cannot fit, the hook refuses to create a snapshot.
## Retention
If any affected package matches `important_names`, the snapshot belongs to the important chain. Otherwise it belongs to the trivial chain. The default important expression is:
The defaults retain 25 trivial snapshots and 10 important snapshots. Retention runs only after a successful snapshot and only considers snapshots with this tool's prefix and the current severity marker. Recursive snapshot trees are destroyed with `zfs destroy -r`.
## Configuration
`/etc/apt-zfs-snapshot.conf` is sourced as a Bash fragment. Available parameters are: