BSD Ports

Who is behind, what breaks, what depends on it

Version history, how far each BSD lags the others, deprecated lists, dependency graphs, a watchlist, an API and three more trees.

Three days ago this site could tell you which version of a port each BSD ships. Now it can also tell you which system got there first, since when the others have been behind, what is about to be removed, and how many ports go down with it. Most of what was added this week answers one of those questions.

More of the BSD world

Three trees joined the five:

  • pkgsrc-wip, about 5,800 packages that are not in pkgsrc yet, at /netbsd/wip/<name>/. They are built from source only, so their pages say so and give the make install line instead of pkgin.
  • FreeBSD's derivatives: HardenedBSD, GhostBSD and OPNsense. Most of what they ship is FreeBSD's ports, so those appear as one more row on FreeBSD's page. Their own ports, 45, 173 and 237 of them, get pages of their own.
  • pkgsrc platforms: a NetBSD package page now lists its version on NetBSD 10.1 for x86_64 and aarch64, on SmartOS and on macOS 15, because pkgsrc is used on all of them.

Vulnerabilities now cover more than FreeBSD. VuXML is applied to DragonFly's DPorts and to the derivatives. NetBSD's pkg-vulnerabilities is read for pkgsrc. That list has no dates, so an entry is dated by the day this site first saw it. "Latest vulnerabilities" lists each advisory once, with every system and port it hits.

Comparing versions the way upstream numbers them

nginx 1.30.6_1,3 on FreeBSD and nginx 1.30.6 on OpenBSD are the same release. The suffixes are packaging bookkeeping: _1 and ,1 on FreeBSD, p0 and v0 on OpenBSD, nb2 in pkgsrc. They are now dropped before versions are compared, and the newest one is marked. Each row also shows the port's known vulnerabilities, its status and its maintainer in that system.

Software that lives in more than one lineage (FreeBSD's family, OpenBSD, pkgsrc) gets one page at /compare/<name>/. There are 11,877 of them.

How far behind each BSD is

Every port now has a version history: each version, the day it arrived and the commit that brought it. It is read from the trees' git history, only the commits since the last refresh. For the systems without a tree it comes from what each refresh sees. Once a version is known per day, it is easy to say since when another system has had a newer one. A comparison row that is not the newest says so, and /freshness/ counts it:

Ports at the newest version: FreeBSD 94%, OpenBSD 77%, NetBSD 68%, DragonFly BSD 62%, MidnightBSD 54%

FreeBSD's ports tree is the largest and the busiest, so few systems get a release before it. When one does, FreeBSD's median wait is 44 days. DPorts is built from FreeBSD's tree after a delay, which explains most of DragonFly's 62% and its 72-day median. MidnightBSD has the same median.

One limit: the clones are shallow, and history reaches back to early July. No port can be more than about 115 days behind yet. Ports that fell behind before that, or whose date is not known, are counted as "behind, since unknown" (1,285 of FreeBSD's). The figure gets more accurate every week.

What is about to go, and what goes with it

/status/ lists deprecated ports, soonest to expire first, then broken, ignored, forbidden and restricted ones. As of this build, FreeBSD has 241 deprecated and 66 broken. The top of the list is the interesting part:

Port Expired Ports that need it
lang/python27 2020-12-31 83
databases/db5 2022-06-30 69
textproc/xmlto 2025-12-31 29

Python 2.7 expired almost six years ago and is still in the tree, because 83 ports need it. The count explains why the date was not kept. Each port page now also has a dependency graph: what needs the port on the left, what it needs on the right. A vulnerable port also says how many ports depend on it at any depth, which is a better measure of urgency than the advisory alone.

For the people doing the work

  • Maintainer pages open with what to act on: ports with known vulnerabilities, behind another BSD, deprecated, broken or expiring.
  • Changes (/changes/) shows the week day by day: new ports, new versions and removed ports, for every system or for one.
  • Report a problem opens each project's own channel the way it prefers to be told: a prefilled Bugzilla form for FreeBSD, a mail to ports@ for OpenBSD, a mail to pkgsrc-users@ for NetBSD. The subject line is already category/port: , as their lists expect.
  • Related ports links the same software in the same system: one homepage, or one name with a different version or variant (lua51, lua54).

A watchlist without an account

Watch on a port page adds it to /watchlist/. On every visit the list checks each port against its current data and shows what changed since you last looked: a new version, a vulnerability found or fixed, a new status or maintainer, another system moving ahead. The list lives in your browser's local storage. Nothing is sent to this site, there is no login, and export and import move the list between browsers.

The same data as JSON

Every page with data now has an index.json beside it: ports, comparisons, categories, systems, freshness, status and changes. They are written in the same build as the HTML, so the two never disagree. They are served with CORS for any origin and a 30-minute cache, and documented at /api/ with a console to try each call. The watchlist reads them too.

What it cost

The comparison pages made the build about 10% slower and added 0.6 GB to its peak memory. The build now runs with Go's memory limit set to 5 GiB. That brought the peak on the whole tree from 7.4 to 5.2 GB for about 5% more time. The version history cost about 20 seconds once, on the first run. After that, a refresh does not take measurably longer. The benchmarks page keeps the running numbers.

← All posts