If you've been running FreeBSD for some time, you must have come across freebsd-update(8), the currently offical method of updating your FreeBSD installation. If you ever ran this to do a major release upgrade, you'll also have noticed speed is not one of its strengths... updating a system can easily take half an hour.
(Perhaps a 3.5 kLoC shell script spawning sha256(1) for each changed file is not the royal way to upgrade a system installation...)
Luckily, other people realized this too, and also saw that FreeBSD contains a perfectly cromulent binary package manager already, namely pkg(8).
Thus the pkgbase project was created,
which aims to provide the FreeBSD base system as pkg
binary packages,
so you can install and update the base system as easily as the rest.
This has other benefits as well: you can remove parts of the system you never use,
and also easily install e.g.
debugging packages after the basic install (try that using freebsd-update
!).
As of FreeBSD 14.0 the pkgbase repository is officially maintained, so let's give this a spin. The mechanism is not considered fit for production environments yet, thus we try this in a VM instead.
We start off by using the official release VM image FreeBSD-14.0-RELEASE-amd64.qcow2
.
Usually we'd bring it up to date first using freebsd-update
,
but we can skip this as we want to do the update using pkg
.
Since the VM image fits only 4 GB by default, we need to remove /usr/lib/debug at first to have enough space for switching to pkg.
The steps are documented in the wiki, so I won't repeat them here.
Since we don't want to install debugging symbols and also only need a generic kernel, we save some space using:
# pkg install -r base $(pkg search -r base -q '.*' | grep -v -e dbg- -e mmccam)
This will should be pretty quick now.
The "problem" using pkg
to install this way is that it will create a .pkgsave
for every single file that is being installed that existed before (so, almost every file).
We need to get rid of these .pkgsave
files quickly, which can be done using:
# find / -name '*.pkgsave' -delete
It would be really beneficial if pkg
had an option to not create these .pkgsave
files, at least for the initial installation.
Now, keeping your FreeBSD base system up to date is as easy as running
# pkg update && pkg upgrade
After rebooting, we now can check our system is up to date:
# uname -a FreeBSD pkgbasetest 14.0-RELEASE-p4 FreeBSD 14.0-RELEASE-p4 releng/14.0-n265400-4edf3b80733 GENERIC amd64 # pkg version -Un FreeBSD-ssh FreeBSD-ssh-14.0p4 =
So we got the latest kernel and also the last security announcement.
Let's say we found a bug in yp(8), then we can simply install the debugging symbols for these programs only:
# pkg install FreeBSD-yp-dbg # pkg list FreeBSD-yp-dbg /usr/lib/debug/bin/domainname.debug /usr/lib/debug/usr/bin/ypcat.debug /usr/lib/debug/usr/bin/ypmatch.debug /usr/lib/debug/usr/bin/ypwhich.debug /usr/lib/debug/usr/libexec/ypxfr.debug /usr/lib/debug/usr/sbin/rpc.yppasswdd.debug /usr/lib/debug/usr/sbin/rpc.ypupdated.debug /usr/lib/debug/usr/sbin/rpc.ypxfrd.debug /usr/lib/debug/usr/sbin/yp_mkdb.debug /usr/lib/debug/usr/sbin/ypbind.debug /usr/lib/debug/usr/sbin/ypldap.debug /usr/lib/debug/usr/sbin/yppoll.debug /usr/lib/debug/usr/sbin/yppush.debug /usr/lib/debug/usr/sbin/ypserv.debug /usr/lib/debug/usr/sbin/ypset.debug
Likewise, if you get compelled into debugging the kernel, you can just use
# pkg install FreeBSD-kernel-generic-dbg
and kgdb
etc. will work.
I didn't do a major upgrade yet, but you need to take care yourself to install the new kernel first and then update the userland.
Actually, we can do a system update, as snapshot release are provided via pkgbase as well. Let's flip the repo url in /usr/local/etc/pkg/repos/base.conf to pkg+https://pkg.freebsd.org/${ABI}/base_latest
.
We immediately hit a version mismatch, which we accept:
# pkg update Updating FreeBSD repository catalogue... FreeBSD repository is up to date. Updating base repository catalogue... pkg: Repository base has a wrong packagesite, need to re-create database Fetching meta.conf: 100% 163 B 0.2kB/s 00:01 Fetching packagesite.pkg: 100% 40 KiB 41.2kB/s 00:01 Processing entries: 0% Newer FreeBSD version for package FreeBSD-vi-man: To ignore this error set IGNORE_OSVERSION=yes - package: 1400501 - running kernel: 1400097 Ignore the mismatch and continue? [y/N]: y Processing entries: 100% base repository update completed. 524 packages processed. All repositories are up to date.
However, pkg upgrade
will do nothing. The problem is that the snapshot versions are considered to be behind the release versions; I'm not sure that's intentional, but we can force install the kernel and notice pkg(8) considers this a downgrade:
# pkg install -f FreeBSD-kernel-generic Updating FreeBSD repository catalogue... FreeBSD repository is up to date. Updating base repository catalogue... base repository is up to date. All repositories are up to date. The following 1 package(s) will be affected (of 0 checked): Installed packages to be DOWNGRADED: FreeBSD-kernel-generic: 14.0p4 -> 14.snap20240111062527 [base] Number of packages to be downgraded: 1
After accepting this too and rebooting, we find ourselves in a snapshot kernel of the STABLE
branch:
# uname -a FreeBSD pkgbasetest 14.0-STABLE FreeBSD 14.0-STABLE stable/14-n266270-b4d11915c73f GENERIC amd64
To update (well "downgrade") the rest of the system, we go on as above, but with force:
# pkg install -f -r base $(pkg search -r base -q '.*' | grep -v -e dbg- -e mmccam)
pkg will complain a bit because new *-man
packages have been created which conflict with the old packages where manpages were included, but it can figure out how to fix this itself.
There are also new src
and sys-src
packages which you may want to ignore as well. But using pkg(8) to keep the source tree up to date is also nifty. ;)
Snapshot versions probably should use .99.snapshotYYYYMMDD
, so upgrading to a snapshot is really an upgrade.
There is a naming clash between FreeBSD-ftpd
from base and freebsd-ftpd
from ports... but pkg happily installs both and then can only remove both at once again... huh?
pkg supports package annotations which contain additional metadata; e.g. for the ports packages, we have:
# pkg info screen ... Annotations : FreeBSD_version: 1400097 build_timestamp: 2024-01-05T11:04:30+0000 built_by : poudriere-git-3.4.0 cpe : cpe:2.3:a:gnu:screen:4.9.1:::::freebsd14:x64:1 port_checkout_unclean: no port_git_hash : 8659dcf7d1 ports_top_checkout_unclean: no ports_top_git_hash: a8c72eab47 repo_type : binary repository : FreeBSD
Unfortunately, the pkgbase packages don't contain some of the fields here that would be useful, like build_timestamp
or top_git_hash
.
Still, pkgbase is a definitive improvement over the status quo and I hope it gains more traction and becomes the offcial method for updating.