Re: pkg-be-plugin: auto-create ZFS boot environments before pkg transactions

From: Sasha Karcz <sasha_at_starnix.net>
Date: Thu, 14 May 2026 18:50:32 UTC
Hi!


Thanks for the quick feedback! I was thinking of adding to the ports 
collection after more eyes get on it, but maybe the way to get more eyes 
on it is to add it to the ports collection.


I will work on a PR for that :)


-Sasha

On 5/14/26 6:59 AM, Ronald Klop wrote:
> Looks useful!
>
> Are you planning to create a port for this?
>
> Regards,
> Ronald.
>
> *Van:* Sasha Karcz <sasha@starnix.net>
> *Datum:* donderdag, 14 mei 2026 07:30
> *Aan:* freebsd-pkg@freebsd.org
> *Onderwerp:* pkg-be-plugin: auto-create ZFS boot environments before 
> pkg transactions
>
>     Hello,
>
>     I've written a pkg(8) plugin that automatically creates a ZFS boot
>     environment before each install, upgrade, and deinstall
>     transaction. If a transaction leaves the system in a broken state,
>     the pre-transaction BE is there to boot into.
>
>     The plugin is called pkg-be-plugin and installs as be.so. It uses
>     libbe(3) directly — no exec of bectl(8) or zfs(8).
>
>     *Behaviour*
>
>     On each covered transaction, the plugin calls |libbe_init()| and
>     |be_create()| to snapshot the current BE under a timestamped name
>     (default prefix: |pre-pkg|, e.g. |pre-pkg-20260514-091532|). After
>     creation, it prunes older auto-created BEs to keep the count at or
>     below a configurable limit, with a minimum-age guard so recent
>     rollback points aren't destroyed even when over the limit.
>
>     All activity is logged to syslog(3) at LOG_NOTICE for normal
>     operations and LOG_WARNING/LOG_ERR for failures, so admins can
>     grep |/var/log/messages| to find BE names for rollback after a bad
>     transaction.
>
>     *Configuration* (via |/usr/local/etc/pkg/be.conf|, UCL format)
>
>       * |BE_PLUGIN_ENABLED| — master switch (default: true)
>       * |BE_PLUGIN_KEEP| — maximum BEs to retain (default: 5)
>       * |BE_PLUGIN_NAME_PREFIX| — name prefix (default: |pre-pkg|)
>       * |BE_PLUGIN_MIN_AGE| — minimum age before pruning (default: 7d;
>         protects recent rollback points from being destroyed when
>         count exceeds KEEP)
>       * |BE_PLUGIN_STRICT| — abort transaction on BE creation failure
>         (default: false)
>       * |BE_PLUGIN_SKIP_TRANSACTIONS| — comma-separated list of
>         transaction types to skip (|install|, |upgrade|, |deinstall|)
>
>     *Non-ZFS systems*
>
>     |libbe_init()| fails on UFS roots and in jails without ZFS access.
>     In non-strict mode (the default) this is logged as a warning and
>     the transaction proceeds normally. Strict mode causes a
>     fail-closed abort, which may be appropriate for ZFS-only fleets.
>
>     *Testing*
>
>     Tested on FreeBSD 15.0-RELEASE-p5 with the
>     install/upgrade/deinstall transaction types, including
>     multi-package transactions, the prune path (over-KEEP and
>     under-min-age scenarios), and strict-mode behaviour. Unit tests
>     cover the config parser and prune sort/filter logic.
>
>     *Source*
>
>     https://github.com/usenix17/pkg-be-plugin
>     <https://github.com/usenix17/pkg-be-plugin>
>
>     Feedback welcome. Specific things I'd appreciate eyes on:
>
>      1. *pkg plugin API usage* — particularly the hook lifecycle (init
>         multiple hooks shutdown) and whether
>         |PKG_PLUGIN_HOOK_PRE_{INSTALL,UPGRADE,DEINSTALL}| are the
>         right hooks for this purpose, or whether there's a
>         less-surprising place to do BE creation.
>      2. *libbe nvlist property access* — the |creation| property is
>         stored as a string of decimal Unix epoch seconds rather than a
>         uint64. I worked this out via integration testing; if this is
>         documented somewhere I missed, pointers welcome.
>      3. *Prune semantics* — currently the count can drift above |KEEP|
>         if all candidate BEs are under |MIN_AGE|. Trade-off chosen for
>         the homelab-friendly "never destroy a recent rollback"
>         property. If list consensus prefers strict-count enforcement,
>         the policy is a one-line change.
>
>     Sasha Karcz
>
>