From nobody Thu May 14 11:59:59 2026 X-Original-To: freebsd-pkg@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gGTRG5GTDz6d1Fh for ; Thu, 14 May 2026 12:00:10 +0000 (UTC) (envelope-from ronald-lists@klop.ws) Received: from smtp-relay-int.realworks.nl (smtp-relay-int.realworks.nl [31.134.205.98]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4gGTRD6c8Sz3GCj for ; Thu, 14 May 2026 12:00:08 +0000 (UTC) (envelope-from ronald-lists@klop.ws) Authentication-Results: mx1.freebsd.org; dkim=pass header.d=klop.ws header.s=rw2 header.b=SJmSLuqy; dmarc=pass (policy=quarantine) header.from=klop.ws; spf=pass (mx1.freebsd.org: domain of ronald-lists@klop.ws designates 31.134.205.98 as permitted sender) smtp.mailfrom=ronald-lists@klop.ws Received: from crmpreview6.colo2.realworks.nl (localhost [127.0.0.1]) by crmpreview6.colo2.realworks.nl (Postfix) with ESMTP id 7B94E200201 for ; Thu, 14 May 2026 13:59:59 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=klop.ws; s=rw2; t=1778760000; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=4k8hdMeqfiiv4wMzgsh8qUIL7trrhuxz1qO2g/6A7Ac=; b=SJmSLuqy0xHN4XCaOOMx0+q6G+VHf9Xo+Isx4PSepAI/+j3Z8XCVc/pDzRtRaUGIiHxFSO XgwaCIuvDX1aeBOjhyg7YF9jqzosIcCq1ZH0D5jsCBD9K91qrVdSzFoBqGBfcgjxsk/Gcw 3KorNLEU8PkuBk55uri95AaKM+upfb20vYe4a5QndLWejdvCx++XqAcSazjXI3qDboNAmj gZijBn02334ttxjH2Z97rFki7TraPAcGXCkN/nz10+1+cxwRqitf2rGN9uJ99PvPMBxop/ VltMD9g+hvm0UQtWyVollP4f3KcnbSMCFfTRp5HWjMsZFOW+9fawlvEqTgMTcA== Date: Thu, 14 May 2026 13:59:59 +0200 (CEST) From: Ronald Klop To: freebsd-pkg@freebsd.org Message-ID: <1733843605.178.1778759999712@localhost> In-Reply-To: References: Subject: Re: pkg-be-plugin: auto-create ZFS boot environments before pkg transactions List-Id: Binary package management and package tools discussion List-Archive: https://lists.freebsd.org/archives/freebsd-pkg List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-freebsd-pkg@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="----=_Part_177_1524544099.1778759999643" X-Mailer: Realworks (795.109) Importance: Normal X-Priority: 3 (Normal) X-Spamd-Result: default: False [-3.29 / 15.00]; NEURAL_HAM_LONG(-1.00)[-1.000]; NEURAL_HAM_MEDIUM(-1.00)[-0.997]; NEURAL_HAM_SHORT(-1.00)[-0.997]; DMARC_POLICY_ALLOW(-0.50)[klop.ws,quarantine]; MID_RHS_NOT_FQDN(0.50)[]; ONCE_RECEIVED(0.20)[]; R_SPF_ALLOW(-0.20)[+ip4:31.134.205.64/26]; R_DKIM_ALLOW(-0.20)[klop.ws:s=rw2]; MIME_GOOD(-0.10)[multipart/alternative,text/plain]; ASN(0.00)[asn:51088, ipnet:31.134.200.0/21, country:NL]; MIME_TRACE(0.00)[0:+,1:+,2:~]; RCVD_COUNT_ONE(0.00)[1]; RCPT_COUNT_ONE(0.00)[1]; MLMMJ_DEST(0.00)[freebsd-pkg@freebsd.org]; RCVD_TLS_LAST(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; FROM_HAS_DN(0.00)[]; ARC_NA(0.00)[]; HAS_X_PRIO_THREE(0.00)[3]; TO_MATCH_ENVRCPT_ALL(0.00)[]; TO_DN_NONE(0.00)[]; PREVIOUSLY_DELIVERED(0.00)[freebsd-pkg@freebsd.org]; DKIM_TRACE(0.00)[klop.ws:+] X-Spamd-Bar: --- X-Rspamd-Queue-Id: 4gGTRD6c8Sz3GCj ------=_Part_177_1524544099.1778759999643 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: quoted-printable Looks useful! Are you planning to create a port for this? Regards, Ronald. =20 Van: Sasha Karcz Datum: donderdag, 14 mei 2026 07:30 Aan: freebsd-pkg@freebsd.org Onderwerp: pkg-be-plugin: auto-create ZFS boot environments before pkg tran= sactions >=20 > Hello, >=20 > I've written a pkg(8) plugin that automatically creates a ZFS boot enviro= nment before each install, upgrade, and deinstall transaction. If a transac= tion leaves the system in a broken state, the pre-transaction BE is there t= o boot into. >=20 > The plugin is called pkg-be-plugin and installs as be.so. It uses libbe(3= ) directly =E2=80=94 no exec of bectl(8) or zfs(8). >=20 > Behaviour >=20 > 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-cr= eated BEs to keep the count at or below a configurable limit, with a minimu= m-age guard so recent rollback points aren't destroyed even when over the l= imit. >=20 > All activity is logged to syslog(3) at LOG_NOTICE for normal operations a= nd LOG_WARNING/LOG_ERR for failures, so admins can grep /var/log/messages t= o find BE names for rollback after a bad transaction. >=20 > Configuration (via /usr/local/etc/pkg/be.conf, UCL format) >=20 > BE_PLUGIN_ENABLED =E2=80=94 master switch (default: true) > BE_PLUGIN_KEEP =E2=80=94 maximum BEs to retain (default: 5) > BE_PLUGIN_NAME_PREFIX =E2=80=94 name prefix (default: pre-pkg) > BE_PLUGIN_MIN_AGE =E2=80=94 minimum age before pruning (default: 7d; prot= ects recent rollback points from being destroyed when count exceeds KEEP) > BE_PLUGIN_STRICT =E2=80=94 abort transaction on BE creation failure (defa= ult: false) > BE_PLUGIN_SKIP_TRANSACTIONS =E2=80=94 comma-separated list of transaction= types to skip (install, upgrade, deinstall) > Non-ZFS systems >=20 > libbe_init() fails on UFS roots and in jails without ZFS access. In non-s= trict mode (the default) this is logged as a warning and the transaction pr= oceeds normally. Strict mode causes a fail-closed abort, which may be appro= priate for ZFS-only fleets. >=20 > Testing >=20 > Tested on FreeBSD 15.0-RELEASE-p5 with the install/upgrade/deinstall tran= saction types, including multi-package transactions, the prune path (over-K= EEP and under-min-age scenarios), and strict-mode behaviour. Unit tests cov= er the config parser and prune sort/filter logic. >=20 > Source >=20 > https://github.com/usenix17/pkg-be-plugin >=20 > Feedback welcome. Specific things I'd appreciate eyes on: >=20 > pkg plugin API usage =E2=80=94 particularly the hook lifecycle (init mult= iple hooks shutdown) and whether PKG_PLUGIN_HOOK_PRE_{INSTALL,UPGRADE,DEINS= TALL} are the right hooks for this purpose, or whether there's a less-surpr= ising place to do BE creation. > libbe nvlist property access =E2=80=94 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, poi= nters welcome. > Prune semantics =E2=80=94 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 stri= ct-count enforcement, the policy is a one-line change. > Sasha Karcz >=20 > =20 > =20 =20 ------=_Part_177_1524544099.1778759999643 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable 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 environment= s 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 t= ransaction leaves the system in a broken state, the pre-transaction BE is t= here to boot into.

The plugin is called pkg-be-plugin and installs as be.so. It uses l= ibbe(3) directly =E2=80=94 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 pref= ix: pr= e-pkg, e.g. pre-pkg-20260514-091532). After creation, it prunes old= er auto-created BEs to keep the count at or below a configurable limit, wit= h 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 operat= ions 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, UC= L format)

    =09
  • BE_= PLUGIN_ENABLED =E2=80=94 master switch (default: true)
  • =09
  • BE_= PLUGIN_KEEP =E2=80=94 maximum BEs to retain (default: 5)
  • =09
  • BE_= PLUGIN_NAME_PREFIX =E2=80=94 name prefix (default: pre-pkg)
  • =09
  • BE_= PLUGIN_MIN_AGE =E2=80=94 minimum age before pruning (default: 7d; pr= otects recent rollback points from being destroyed when count exceeds KEEP)=
  • =09
  • BE_= PLUGIN_STRICT =E2=80=94 abort transaction on BE creation failure (de= fault: false)
  • =09
  • BE_= PLUGIN_SKIP_TRANSACTIONS =E2=80=94 comma-separated list of transacti= on types to skip (install, upgrade, deinstall)

Non-ZFS systems

Testing

Tested on FreeBSD 15.0-RELEASE-p5 with the install/upgrade/deinstal= l transaction types, including multi-package transactions, the prune path (= over-KEEP and under-min-age scenarios), and strict-mode behaviour. Unit tes= ts cover the config parser and prune sort/filter logic.

Source

https://github.co= m/usenix17/pkg-be-plugin

Feedback welcome. Specific things I'd appreciate eyes on:

    =09
  1. pkg plugin API usage =E2=80=94 particularly the hook li= fecycle (init multiple hooks shutdown) and whether PKG_PLUGIN_HOOK_PRE_{INSTALL,U= PGRADE,DEINSTALL} are the right hooks for this purpose, or whether t= here's a less-surprising place to do BE creation.
  2. =09
  3. libbe nvlist property access =E2=80=94 the creation p= roperty is stored as a string of decimal Unix epoch seconds rather than a u= int64. I worked this out via integration testing; if this is documented som= ewhere I missed, pointers welcome.
  4. =09
  5. Prune semantics =E2=80=94 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 co= nsensus prefers strict-count enforcement, the policy is a one-line change.<= /li>

Sasha Karcz

 
 

  ------=_Part_177_1524544099.1778759999643--