Here I'm republishing an old blog post of mine originally from September 2017. The article has been slightly improved.

This article references a graphical FreeBSD-based OS that has long been discontinued: TrueOS. When the article was originally written the project was still very much alive.

Originally I got the patch level wrong with the version schema as reader _leper_ pointed out in the comments on the weblog (thanks!). The mistake has been corrected.

FreeBSD package management with Pkg (2/2)

The previous article covered basic operations with FreeBSD's Pkg tool. This second part will deal with some more advanced (or rather intermediate, actually) functionality.

FreeBSD package management with Pkg (1/2)

Good code travels well

My previous two articles have been linked to from the DragonFly Digest (a very valuable resource for topics in BSD and the IT in general that I've been reading for years now and would like to say "thanks!") again.

DragonFly Digest Website

Justin Sherrill pointed out that everything applies to DragonFlyBSD as well - they have adopted Pkg quite a while ago. And in fact you benefit from knowing your way around with Pkg in a lot of places:

FreeBSD obviously and a lot of FreeBSD-derived operating systems like _OPNsense_ and _HardenedBSD_ as well as desktop-oriented offspring like _GhostBSD_ and _TrueOS_.

FreeBSD Website

OPNsense Website

HardenedBSD Website

GhostBSD

But as mentioned before, _DragonFly BSD_ uses it, too. And thanks to the new (and extremely exciting, IMO!) _Ravenports_ project it has already come to Linux and will be available on even more platforms in the future! So getting familiar with it is certainly not a waste of time.

DragonFly BSD Website

Ravenports Website

Package versioning

Before we start updating packages, let's take a look at the versioning scheme. The way FreeBSD versions its packages can be a bit confusing if you first see it. Here's a sample package with a rather complicated version string:

# pkg search opensmtpd | grep OpenBSD
opensmtpd-5.9.2p1_3,1 Security- and simplicity-focused SMTP server from OpenBSD

opensmtpd-5.9.2p1_3,1 - what does that all mean? Well, first we have the package name: _opensmtpd_, followed by a minus. Then there's the upstream version of the program, _5.9.2p1_ in this case.

Then there's the underscore and another number: _3 in this case. This indicates our package is at "revision 3". Any new package starts with a revision of 0. If a port is revised (probably to correct a mistake, add more configure options, etc), the revision number is bumped. So this port has been revised three times without changing the actual upstream version.

And finally, separated by a comma, we have what is called the "epoch". It is used in such cases where the upstream versioning changes. Any package with an epoch of 1 is considered newer than a package without any epoch. Even higher epoch numbers are considered even newer but this is rare. When do you need this? Let's assume some project released a version of 7.2017 but decided that it would be a good idea to release the next version as 5.0. For Pkg it looks like the first one is newer (as it has a higher version number). In such a case you'd set an epoch to make Pkg understand that in fact the other one is the more up-to-date package.

Updating packages

I covered updating the repository information before. Update the actual packages with *pkg upgrade*:

# pkg upgrade
Updating Synth repository catalogue...
Synth repository is up to date.
All repositories are up to date.
Checking for upgrades (30 candidates): 100%
Processing candidates (30 candidates): 100%
Checking integrity... done (0 conflicting)
The following 30 package(s) will be affected (of 0 checked):
Installed packages to be UPGRADED:
xinit: 1.3.4,1 -> 1.3.4_1,1
xerces-c3: 3.1.4 -> 3.2.0_2
virtualbox-ose: 5.1.26 -> 5.1.26_1
vim: 8.0.0962 -> 8.0.1035
sudo: 1.8.20p2_3 -> 1.8.21p1
sqlite3: 3.20.0_2 -> 3.20.1
rubygem-net-ssh: 4.1.0,2 -> 4.2.0,2
rubygem-multi_json: 1.12.1 -> 1.12.2
ruby23-gems: 2.6.12 -> 2.6.13
pulseaudio: 10.0_4 -> 11.0
pciids: 20170727 -> 20170825
p11-kit: 0.23.7 -> 0.23.8
open-vm-tools: 10.1.5_1,2 -> 10.1.10,2
nano: 2.8.6 -> 2.8.7
mesa-libs: 17.1.7 -> 17.1.8
mesa-dri: 17.1.7 -> 17.1.8
libreoffice: 5.3.5_1 -> 5.3.6
libidn2: 2.0.3 -> 2.0.4
libgcrypt: 1.8.0 -> 1.8.1
libdrm: 2.4.82,1 -> 2.4.83,1
hunspell: 1.6.1_1 -> 1.6.2
harfbuzz-icu: 1.4.8 -> 1.5.1
harfbuzz: 1.4.8 -> 1.5.1
gdk-pixbuf2: 2.36.6 -> 2.36.9
e2fsprogs: 1.43.5 -> 1.43.5_1
doas: 6.0p0 -> 6.0p1
chromium: 60.0.3112.101 -> 60.0.3112.113
atril: 1.18.0_1 -> 1.18.1
Installed packages to be REINSTALLED:
keybinder-0.3.1 (options changed)
apache-xml-security-c-1.7.3 (needed shared library changed)
Number of packages to be upgraded: 28
Number of packages to be reinstalled: 2
The process will require 2 MiB more space.
Proceed with this action? [y/N]:

The "packages to be UPGRADED" section is pretty obvious: There's a newer version available. But there are also two packages in this example that are being reinstalled even though no new version is available. Pkg gives the reason for this in parentheses:

_Keybinder_ will be reinstalled because it was compiled with other compile-time options than before (more about this in the next post). The second one depends on xerces-c3, a package in the list of upgradable packages, which is why apache-xml-security-c was rebuilt against the new version of the library.

There are other reasons that packages are to be reinstalled; if you upgraded your OS from one major version to another, the reason might be "ABI has changed". It's also possible that some packages will be deinstalled for an upgrade. This is usually because they conflict with another package that is to be installed. This also means: Do look at what the update is going to do! There is the chance that it would do something that you didn't intend to.

Will this update cause me trouble?

You can never know _for sure_. But there is a means to learn about known issues beforehand. For your important applications it is a good idea to read the so-called "UPDATING information". This is a short text which might contain a heads-up that can be critical to know. To view it, use *pkg updating*. Here's an old example showing how bad it could be to have missed it:

# pkg updating apache22
20140713:
AFFECTS: users of www/apache22
AUTHOR: ohauer@FreeBSD.org
The default version was changed from www/apache22 to www/apache24,
pre-build apache modules and web applications will also reflect this!
In case ports are build by yourself and apache22 is required
use the following command to keep apache22 as default.
# echo "DEFAULT_VERSIONS+=apache=2.2" >> /etc/make.conf

Having missed that one would have had very bad effects... For such reasons it's good practice to read the UPDATING info. You don't actually have to read it and will probably get away with it for quite some time. But it's there for your benefit. So if you choose to ignore it, don't complain if an update finally bites when it finds you off guard!

Blocking updates

Let's stick to the above example and say that we want to do the update - but LibreOffice should not be touched because we're working on an important document currently and don't want to risk layout breakage (minor updates should be no problem but bigger updates are known to sometimes cause trouble). What to do in that case?

Let's _lock_ the package using *pkg lock*:

# pkg lock libreoffice
libreoffice-5.3.5_1: lock this package? [y/N]: y
Locking libreoffice-5.3.5_1

Attempting the upgrade again, Pkg should now show only 27 candidates and leave LibreOffice alone. There are a few good reasons to lock a package - and a lot of bad ones. Resort to locking packages when necessary but don't trifle with it because you're effectively cutting yourself off from updates on some packages. Those could have dependencies. Probably dependencies that they share with other packages. You can see how this gets a lot bigger than "just that one package" rather quickly.

Also if you decide to use locking, make sure to look for locked packages now and then and think over if the lock is still needed! If not, release the lock. But how to find out which packages are locked? _Pkg info_ can help us out:

# pkg info -k -a | grep yes
libreoffice-5.3.5_1 yes

Unlocking works just like you'd probably expect it to:

# pkg unlock libreoffice
libreoffice-5.3.5_1: unlock this package? [y/N]: y
Unlocking libreoffice-5.3.5_1

Package comments

We've locked LibreOffice above - but how do we remember in four months or so _why_ it was locked? This is what we can use an _annotation_ for. Set one with *pkg annotate*:

# pkg annotate -A libreoffice locked-pkgs "This package was locked on 09/10 until I finally finish the manuscript for my fantasy novel!"
libreoffice-5.3.5_1: Add annotation tagged: locked-pkgs with value: This package was locked on 09/10 until I finally finish the manuscript for my fantasy novel!? [y/N]: y
libreoffice-5.3.5_1: added annotation tagged: locked-pkgs

The argument "-A" is to set an annotation to the following package. "locked-pkgs" is a _tag_ - you could call it whatever you want, allowing to "group" packages. And finally the last field is the actual comment string.

Using _pkg info_ and the package name will display the comment among a lot of other information. But it might make more sense to look for all packages that have an annotation with a certain tag:

# pkg annotate -a -S locked-pkgs
libreoffice-5.3.5_1: Tag: locked-pkgs Value: This package was locked on 09/10 until I finally finish the manuscript for my fantasy novel!

If you no longer need the annotation, delete it like this:

# pkg annotate -D libreoffice locked-pkgs
libreoffice-5.3.5_1: Delete annotation tagged: locked-pkgs? [y/N]: y
libreoffice-5.3.5_1: Deleted annotation tagged: locked-pkgs

Are those updates important?

Some updates mean new features, others mean fixing critical security holes. How are you supposed to know? The easy way is to ask Pkg! Use *pkg audit* and it will tell you about known vulnerabilities of the software installed on your system:

pkg audit
libgcrypt-1.8.0 is vulnerable:
libgcrypt -- side-channel attack vulnerability
CVE: CVE-2017-0379
WWW: https://vuxml.FreeBSD.org/freebsd/22f28bb3-8d98-11e7-8c37-e8e0b747a45a.html
chromium-60.0.3112.101 is vulnerable:
chromium -- multiple vulnerabilities
CVE: CVE-2017-5120
CVE: CVE-2017-5119
CVE: CVE-2017-5118
CVE: CVE-2017-5117
CVE: CVE-2017-5116
CVE: CVE-2017-5115
CVE: CVE-2017-5114
CVE: CVE-2017-5113
CVE: CVE-2017-5112
CVE: CVE-2017-5111
WWW: https://vuxml.FreeBSD.org/freebsd/e1100e63-92f7-11e7-bd95-e8e0b747a45a.html
[...]

No way back?

Are you not feeling completely confident about an update? Does your customer demand "a way back" in case something does not work with the new version? You can use *pkg create* to package already installed software:

# pkg create chromium-60.0.3112.101
Creating package for chromium-60.0.3112.101

In this example I've packaged Chromium before updating so that I could reinstall the old version. Keep in mind, though, that this is just an example. If dependencies changed as well, you might not be able to use the old version, even when you reinstalled it! If you want to be really, really cautious, you can use _pkg create -a_ to create packages of all the software currently installed on your system!

The package(s) is/are created in the current directory. I just deinstalled Chromium after creating the package and now want it back. To install software directly from a package (and not a repo), use *pkg add*:

# pkg add chromium-60.0.3112.101.txz
Installing chromium-60.0.3112.101...
Extracting chromium-60.0.3112.101: 100%
Message from chromium-60.0.3112.101:
For correct operation, shared memory support has to be enabled
in Chromium by performing the following command as root :
sysctl kern.ipc.shm_allow_removed=1
To preserve this setting across reboots, append the following
to /etc/sysctl.conf :
kern.ipc.shm_allow_removed=1

Finding the package a file belongs to

In many cases you can probably tell from the path and name of a file which package it belongs to. But sometimes you may wonder: Where does _this_ one come from? That is when *pkg which* is really helpful. Let's pick a file with a non-obvious name and pretend we don't know what it is. We better ask pkg what it belongs to:

% pkg which /usr/local/etc/drirc
/usr/local/etc/drirc was installed by package mesa-dri-17.1.7

Ah, mesa! We better leave that one alone.

Repositories

If you looked closely at the output of my upgrade command, you have seen mention of a repo called Synth. I'll cover that in a later post. But there is something you might want to know about the ordinary repos, too. Modern FreeBSD provides two package repositories: _quarterly_ and _latest_. The latter always holds the newest packages, the former gets version updates every three months and only security fixes in-between. The quarterly repository is a good choice for people who don't want the newest software at all times but prefer a slower-moving environment. Since FreeBSD version 10.2 quarterly is the default.

If you want to use the packages from _latest_, you have to configure pkg to use it. Take a look at the file _/etc/pkg/FreeBSD.conf_ to get an idea of how repo configuration looks like. Then create the necessary directory and another configuration file to override the default:

# mkdir -p /usr/local/etc/pkg/repos
# vi /usr/local/etc/pkg/repos/FreeBSD.conf

Put the following lines in that file:

FreeBSD: {
url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest"
}

Now use _pkg update_ to refresh the repository database.

What's next?

There's a lot more that Pkg can do - and we haven't even touched its main configuration! But the two posts were just meant to introduce you to FreeBSD package management (and chances are that you already know more now than many admins who occasionally use FreeBSD). I might or might not write about more features of Pkg in the future. But next stop for now: The ports tree.

FreeBSD: Building software from ports (1/2)

BACK TO 2017 OVERVIEW