FreeBSD: Building software from ports (2/2)

My previous post discussed what ports are, where they can be found on FreeBSD and what the files of which a port is composed of look like. This post will now detail how to use ports to build software on FreeBSD (the other BSDs have ports trees that work somewhat similar but are not identical. There are important differences!).

Packages and ports: A word of warning

The ports system works hand in hand with FreeBSD’s package manager Pkg. It makes little difference if some software on your machine was installed via a package or directly from ports – packages are in fact actually built from ports! Still it is not really recommended to mix packages and ports. In past times it was strongly discouraged. Things have changed since then. I’ve done it a lot – and mostly got away with it. Don’t rely on it, though, especially if you’re new to the whole topic. Feel free to do it on a test system and be completely happy – or face subtle and annoying breakage. You cannot know up front.

What’s the deal here? Modern software is a complex thing. Most programs rely on other programs or external libraries. A lot of programs can be configured at run time in certain ways. There are however decisions about program functionality that have to be made at compile time. The ports system allows you to build software with compile-time options other than the default. Pre-compiled packages have no chance to know that you choose to deactivate an option when you built a library yourself that they make use of. They assume that this feature is present (it was available on the system the package was built on after all!). And what can one poor program do in that case? Crash, explode, malfunction… A lot of things.

And then there’s the problem of mixing versions which can lead to all kinds of fun. If you stick with either ports or packages, you always have a consistent system with versions that are known to play together well (as long as the maintainers do their job well – we’re all humans and errors do occur).

Just keep that in mind when thinking about mixing programs installed from packages and ports on one system. You can do that. But it doesn’t mean you should. Enabling more options is generally safer than removing ones set by default. It can still have consequences. This is Unix though. Do whatever you see fit – and claim the responsibility. Your choice.

Most basic ports building

Building a software from ports is extremely easy. Go to the directory of a port and type make. Yes, that’s all! Let’s assume the port has no unsatisfied dependencies. The ports system will then check to see if the source code tarball is present in /usr/ports/distfiles. If it isn’t, it will automatically download it. Then it extracts the source code, prepares everything for the compilation and compiles it.

Building the ‘pkg’ port

On my fresh example system I build the Pkg manager from ports first – it’s needed for every other port anyway. Once everything has finished I get my shell back.

Building of Pkg completed

Installing the program is just as easy: Use make install

Installing the newly built port

That’s it, Pkg is now installed. We’re basically done with that port. However there’s still the “work” directory left over from the building process. To tidy up our port’s directory we can issue make clean.

Cleaning up after the build

Dependency handling

On to a just slightly more complex example. I want to build and install an old version of the LUA interpreter which depends on another port, libedit. Of course I could build devel/libedit first and then lang/lua51. In that case it wouldn’t be so bad. But if you think of larger programs with hundreds of dependencies that approach would be a nightmare.

So what to do about it? Well, nothing actually. The ports system takes care of it automatically! Just have it build LUA and it will figure out that it has to build the dependency first.

Building, installing and cleaning up in one command

The parameters to make that we used above are called make targets, BTW, and can be combined. That means it’s perfectly fine to issue make install clean together as you can see in the picture above.

Dependencies are handled automatically

The clean make target is also applied to all ports that were built as a dependency for the current port. Things like this make ports very convenient to use.

More on make and targets

Make targets can depend on other make targets. When you issue make install these are the targets that are actually run:

  • make config (more on that in a minute)
  • make fetch (fetch all files needed to build the port)
  • make checksum (check integrity of downloaded file(s))
  • make depends (check for missing dependencies and build/install those)
  • make extract (extract distfile(s) for the port)
  • make patch (apply patches for this port, if any)
  • make build (actually build the port)
  • make install (install the newly-built program)

If you type make checksum for example, all targets up to and including that one will run (that is config, fetch and checksum in that case). Running just make without any target will assume the default target which is equivalent to make build.

Also make will take an argument to look for the Makefile in another directory if you wish. So instead of doing e.g. this:

# cd /usr/ports/archivers/bzip2
# make install clean

you could also simply do this:

# make -C /usr/ports/archivers/bzip2 install clean

You’re in control: Ports options

So far it’s all nice and well but there’s no real advantage to using ports instead of packages. May I introduce ports options? Let’s say you we want to build BASH. If issue make in shells/bash, this is what happens:

Build options for BASH

The port ports-mgmt/dialog4ports is fetched and installed. It’s so small that you might miss it but it’s quite important. It’s needed to display the menu in the picture above which lets you set various options for the port.

You can now e.g. choose to not install the documentation if you’re short on space on a small or embedded system (sure, you wouldn’t actually compile on such a system, but that’s only an example, right?). If you don’t want BASH to support any foreign languages, deselect NLS. In case you feel that BASH’s built-in help is useless (did you ever issue the help command when you ran BASH?), you can cut that feature. Things like that.

If you see the option configuration for a port the first time, you see the default configuration. In general it’s a good idea to leave options alone if you’re in doubt what they do (do a little research if you have the time). Of course you’re also free to experiment with them. It’s your system.

Once you’re happy, accept your selection and the source tarball is being fetched, extracted, etc. You know the score.

Build options for bison

But what’s that? Another configuration menu (for bison)? And another (m4) and another (texinfo), etc… It’s 8 menus for a rather basic program like BASH! And worse: The building process will run and build dependencies and when a port with options is reached, the process is interrupted and prompts the user.

Now imagine you’re building a whole graphical desktop like MATE… Currently even the basic desktop would build no less that 338 dependency packages on a fresh system! And there’s quite a few ports on the list which build rather heavy software that takes it’s time compiling. It would totally make sense to let it build over night or at least not require you to keep staring at the screen, waiting for the next options selection to confirm, right?

Recursive operations

Exactly that’s why recursive operations are supported by the ports system. The standard make target that was implicitly run to open the options dialog is make config. The recursive option which would run the same on each and every port that’s listed as a dependency for the current port is make config-recursive.

If you want to build MATE as mentioned in the previous example, that would start a true marathon of options for you to configure. However it’s still a lot better to be able to do this up front so that the build process can run uninterruptedly afterwards.

Oh, and don’t be surprised if you went through it all only to find that still another configuration dialog pops up later! Why? Most likely you enabled an option on some package that made it depend on another package that’s not a dependency by default. And that package may need to have its options configured, too. So if you changed any options it makes sense to run make config-recursive again until no more new option dialog windows are displayed!

Recursively fetching distfiles for security/sudo

You can also do make fetch-recursive to fetch the distfiles for the current port and all dependencies. Again: Keep in mind that enabling more options may lead to new dependencies. If you want to make sure that you have all the distfiles, you might want to run make fetch-recursive again after changing ports options.

Other things to know

Wonder where the all the options are saved? They are stored in text files in /var/db/ports/category_portname. But there’s no need to edit or delete them; if you want to get rid of them, there’s make rmconfig to do that. Also make rmconfig-recursive exists if you feel like blowing away a huge amount of them.

Ports options in /var/db/ports

Another thing that comes in handy is make build-depends-list which will show you a list of ports that will be built as build dependencies for your current port. If you want to see the runtime dependencies you would use make run-depends-list. And then there’s also make all-depends-list which will show you each and every port that would be installed if you chose to build the current port.

Showing port dependencies

You should also know that you can deinstall a port by using make deinstall. Yes, it is also possible to remove the package using pkg delete but that will lead to a problem. The ports infrastructure keeps track of installed ports separately and Pkg does not know anything about this. So even if your package is removed, the Ports infrastructure will insist that it is still installed and there’s something very wrong with your system!

Now what to do if you have that case? Use make reinstall to install the package again even though ports thinks that it’s already installed.

More on ports?

To be honest, there’s quite a bit more to ports than I could cover here. You may want to man 7 ports to see what other targets are available and what they do. Also we haven’t even touched how to keep your system updated when using ports!

The ports infrastructure is a great means of installing customized programs on your system. It’s quite easy to use as you’ve seen. But things can be made even easier – which is why there are helper tools available. I will write a follow-up article covering those (not the next one, though). But for now enjoy all of those new possibilities with software on your FreeBSD machines!

Advertisements

FreeBSD: Building software from ports (1/2)

In my previous two (link) posts (link) I wrote about using Pkg, FreeBSD’s package manager.

Pre-built binary packages are convenient to use but sometimes you need some more flexibility, want an application that cannot not be distributed in binary form due to license issues (or have some other requirements). Building software by hand is certainly possible – but with all the things involved, this can be a rather tedious process. It’s also slow, error-prone and there’s often no clean way to get rid of that stuff again. FreeBSD Ports to the rescue!

This first part is meant as a soft introduction to FreeBSD’s ports, assuming no prior knowledge (if I fail to explain something, feel free to comment on this post). It will give you enough background information to understand ports enough to start using them in the next article.

What “Ports” are

When programmers talk about porting something over, what they originally meant is this: Take an application that was written with one processor architecture in mind (say i386) and modify the source so that it runs on another (arm64 for example) afterwards. The term “porting” is also used when modifying the source of any program to make it run on another OS. The version that runs on the other architecture/OS is called a port of the original program to a different platform.

FreeBSD uses the term slightly differently. There’s a lot of software written e.g. for Linux that will build and work on FreeBSD just fine as it is. Even though it does not require any changes, that software might be ported to FreeBSD. So in this case “porting” does not mean “make it work at all” but make it easily available. This is done by creating a port for any program. That term doesn’t mean a variant of the source code in this case but rather a means to give you easy access to that software on FreeBSD.

So what is a port in FreeBSD? Actually a port is a directory with a bunch of files in it. The heart of it is one file that basically is a recipe if you will. That recipe contains everything needed to build and install the port (and thus have the application installed on your machine in the end). Following this metaphor you could think of all the ports as a big cookbook. Formally it is known as the Ports collection. All those files in your filesystem related to ports are refered to as the Ports tree.

How to get the Ports tree

There are several options to obtain a copy of the ports tree. When you install FreeBSD you can decide whether or not to install it, too. I usually don’t do that because on systems that use binary packages only. It wastes only about 300 MB of space, but more importantly consists of almost 170.000 files (watch your inodes on embedded devices!). Take a look at /usr/ports: If that directory is empty your system is currently missing the ports tree.

The simplest way to get it is by using portsnap:

# portsnap fetch extract

If you want to update the tree later, you can use:

# portsnap fetch update

Another way is to use Subversion. This is more flexible: With portsnap you always get the current tree while Subversion also allows you to checkout older revisions, too. If you plan to become a ports developer, you will probably want to use Subversion for tools like svndiff. If you just want to use ports, portsnap should actually suffice. All currently supported versions of FreeBSD contain a light-weight version of Subversion called svnlite.

Here’s how to checkout the latest tree:

# svnlite checkout https://svn.freebsd.org/ports/head /usr/ports

If you want to update it later run:

# svnlite update /usr/ports

Old versions of the tree

You normally shouldn’t need these but it’s good to know that they exist. Using Subversion you can also retrieve old trees. Be sure that /usr/ports is empty (including for Subversion’s dot directories) or Subversion will see that there’s already something there and won’t do the checkout. If for example you want the ports tree as it existed in 2016Q4, you can retrieve it like this:

# svnlite checkout https://svn.freebsd.org/ports/branches/2016Q4 /usr/ports

There are also several tags available that allow to get certain trees. Maybe you want to see which ports were available when FreeBSD 9.2 was released. Get the tree like this:

# svnlite checkout https://svn.freebsd.org/ports/tags/RELEASE_9_2_0 /usr/ports

And if you need the last tree that is guaranteed to work with 9.x there’s another special tag for it:

# svnlite checkout https://svn.freebsd.org/ports/tags/RELEASE_9_EOL /usr/ports

Keep in mind though that using old trees is risky because they contain program versions with vulnerabilities that have since been found! Also mind that it’s NOT a smart thing to simply get the tree for RELEASE_7_EOL because it still holds a port for PHP 5.2 and you thought that it would be cool to offer your customers as many versions as possible. Yes, it may be possible that you can still build it if you invest some manual work. But no, that doesn’t make it a good idea at all.

Oh, and don’t assume that old ports trees will be of any use on modern versions of FreeBSD! The ports architecture changed quite a bit over time, the most notable change being the replacement of the old pkg_* tools with the new Pkg. Ports older than a certain time definitely won’t build in their old, unmodified state today (and I say it again: You really shouldn’t bother unless you have a very special case).

Port organization

Take a look at the contents of /usr/ports on a system that has the tree installed. You will find over 60 directories there. There are a few special ones like distfiles (where tarballs with program’s source code get stored – might be missing initially) or Mk that holds include files for the ports infrastructure. The others are categories.

If you’re looking for a port for Firefox, that will be in www. GIMP is in graphics and it’s probably no surprise that Audacious (a music player) can be found in audio. Some program’s categories will be less obvious. LibreOffice is in editors which is not so bad. But help2man for example is in misc and not in converters or devel as at least I would expect if I didn’t know. In general however after a while of working with ports you will have a pretty good chance to guess where things are.

Say we are interested in the port for the window manager Sawfish for example. It’s located in /usr/ports/x11-wm/sawfish. Let’s take a closer look at that location and take it apart:

/usr/ports is the “ports directory”.
x11-wm (short for X11 window managers) is the category.
sawfish is the individual port’s name.

When referring to where a port lives, you can omit the ports directory since everybody is assumed to know where it is. The important information when identifying a port is the category and the name. Together those form what is known as the port origin (x11-wm/sawfish in our case).

How to find a port in the tree

There are multiple methods to find out the origin for the port you are looking for. Probably the simplest one is using whereis. If we didn’t know that sawfish is in x11-wm/sawfish we could do this:

% whereis sawfish
sawfish: /usr/ports/x11-wm/sawfish

This does however only work if you know the exact name of the port. And there’s a little more to it: Sometimes the name of a port and a package differ! This is often the case for Python-based packages. I have SaltStack installed, for example. It’s a package called py27-salt:

% pkg info -x salt
py27-salt-2017.7.1_1

If we were to look for that, we wouldn’t find it:

% whereis py27-salt
py27-salt:

So where is the port for the package?

% pkg info py27-salt
py27-salt-2017.7.1_1
Name           : py27-salt
[...]
Origin         : sysutils/py-salt
[...]

Here you can see that the port’s name is py-salt! The “27” gets added when the package is created and reflects the version of Python that it’s build against. You may also see some py3-xyz ports. In those cases the name reflects that the port cannot be built with Python 2.x. The package will still be called py36-xyz, though (or whatever the default Python 3.x version is at that time)!

When discussing package management I recommended FreshPorts and when working with ports it can be useful, too. Search for some program’s name and it might be easier for you to find the package name and the port origin for it!

What a port looks like

Let’s take a look at the port for the zstd compression utility:

% ls /usr/ports/archivers/zstd/
distinfo	Makefile	pkg-descr	pkg-plist

So what have we here? The simplest file is pkg-descr. Each package has a short and a long package description – this file is what contains the latter: A detailed description that should give you a good idea whether this port would satisfy your needs:

% cat /usr/ports/archivers/zstd/pkg-descr
Zstd, short for Zstandard, is a real-time compression algorithm providing
high compression ratios.  It offers a very wide range of compression vs.
speed trade-offs while being backed by a very fast decoder.  It offers
[...]

Then there’s a file called distinfo. It lists all files that need to be downloaded to build the port (usually the program’s source code). It also contains a checksum and the file’s size to make sure that the valid file is being used (an archive could get corrupted during the transfer or you could even get an archive that somebody tempered with!):

% cat /usr/ports/archivers/zstd/distinfo 
TIMESTAMP = 1503324578
SHA256 (facebook-zstd-v1.3.1_GH0.tar.gz) = 312fb9dc75668addbc9c8f33c7fa198b0fc965c576386b8451397e06256eadc6
SIZE (facebook-zstd-v1.3.1_GH0.tar.gz) = 1513767

There’s usually also pkg-plist. It lists all the files that are installed by the port:

% cat /usr/ports/archivers/zstd/pkg-plist 
bin/unzstd
bin/zstd
bin/zstdcat
[...]
lib/libzstd.so.%%PORTVERSION%%
libdata/pkgconfig/libzstd.pc
man/man1/unzstd.1.gz
man/man1/zstd.1.gz
man/man1/zstdcat.1.gz

And finally there’s the Makefile. This is where all the magic happens. If you’re a programmer or you have built software from source before, there’s a high chance that you’re at least somewhat familiar with a tool called make. It processes Makefiles and then does as told by those. While it’s most often used to compile software it can actually be used for a wide variety of tasks.

If you don’t have at least some experience with them, Makefiles look pretty much obscure and creating them seems like a black art. If you’ve ever looked at a complicated Makefile, you may be worried to hear that to use ports you have to use make. Don’t be. The people who take care of the Ports infrastructure are the ones who really need to know how to deal with all the nuts and bolts of make. They’ve already solved all the common tasks so that the porters (those people who create the actual ports) can rely on it. This is done by including other Makefiles and it manages to hide away all the scariness. And for you as a user things are even simpler as you can just use what others created for you!

Let’s take a look at the Makefile for our example port:

% cat /usr/ports/archivers/zstd/Makefile 
# Created by: John Marino <marino@FreeBSD.org>
# $FreeBSD: head/archivers/zstd/Makefile 448492 2017-08-21 20:44:02Z sunpoet $

PORTNAME=	zstd
PORTVERSION=	1.3.1
DISTVERSIONPREFIX=	v
CATEGORIES=	archivers

MAINTAINER=	sunpoet@FreeBSD.org
COMMENT=	Zstandard - Fast real-time compression algorithm

LICENSE=	BSD3CLAUSE GPLv2
[...]
post-patch:
	@${REINPLACE_CMD} -e 's|INSTALL_|BSD_&|' ${WRKSRC}/lib/Makefile ${WRKSRC}/programs/Makefile

.include <bsd.port.mk>

Now that doesn’t look half bad for a Makefile, does it? In fact it’s mostly just defining Variables! The only line that looks somewhat complex is the “post-patch” command (which is also less terrifying than it first looks – if you know sed you can surely guess what it’ll do).

There can actually be more files in some ports. If FreeBSD-specific patches are required to build the port, those are included in the ports tree. You can find them in a sub-directory called files located in the port’s directory. Here’s an example:

% ls /usr/ports/editors/vim/files/
patch-src-auto-configure        vietnamese_viscii.vim
patch-src-installml.sh          vimrc

The patches there are named after the files that they apply to. Every patch in the files directory is automatically applied when building the port.

What’s next?

Alright. With that we’ve got a basic overview of what Ports are covered. The next post will show how to actually use them to build and install software.

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.

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. 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.

But as mentioned before, DragonFlyBSD 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.

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 “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 (or some of them) 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 previous 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. 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 of 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 goes wrong? 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 come from? This is where 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 where it belongs:

% 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 later 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 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 overwrite 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 now: The ports tree.

Edit: I got the patch level wrong with the version schema as leper pointed out in the comments. The wrong claim was removed.

FreeBSD package management with Pkg (1/2)

FreeBSD is a server operating system popular among more experienced administrators. It’s also often used in appliances or embedded products and it makes a nice desktop, too, if you are a bit more proficient with it. Sure, you don’t read about it all the time. This is because of two things: 1) Linux is usually absorbing most of the attention 2) FreeBSD just silently and reliably does its job. FreeBSD is also the basis of some special-purpose open source operating systems.

Are you new to FreeBSD? You’ve picked a good time to take a look: Version 11.1 has been released recently and a lot of people who have wanted to give it a spin for a while are getting an ISO and try it out. Also OPNsense 17.7, a popular router/firewall OS has been released, also not too long ago.

If you’re coming e.g. from OPNsense, you have a nice WebGUI at your hands that makes controlling and maintaining easy. That does not mean that you wouldn’t benefit from knowing more about how to do package management by hand, however. OPNsense is built on top of FreeBSD which means that you have all the power of that operating system available if you know what to do if the WebGUI doesn’t provide a simple option to do it!

Pkg – where is it?

If you’re using a FreeBSD-based project like OPNsense or a desktop spin like GhostBSD or TrueOS, it’s located in /usr/local/sbin/pkg. With vanilla FreeBSD it’s almost certainly in the same place of course, if you’ve been using the system for a while. What do I mean by that? Well, in the previous post about the history of *nix package management I made the claim that modern FreeBSD comes without a package manager. And that’s actually true! Take a look at the path mentioned above. See what I mean?

FreeBSD uses the directory tree under /usr/local for programs that are installed as add-on packages, i.e. software that is not part of the base system. Yes, that means that even the package manager is a package! How does that work? Well, there’s also /usr/sbin/pkg, which is part of the base system. If pkg is not present on the system, it’s able to bootstrap it as the first package on the system. If the package manager is already installed, it simply acts as a wrapper (thanks to its location and the default PATH variable it takes precedence over the actual pkg). Bootstrapping is as easy as pressing ‘y’, so we don’t really need to cover it beyond this.

Sounds a bit strange, right? Yes, but there’s a good reason for this. Pkg’s life begun as pkg-ng when FreeBSD still used the old pkg_* tools, so it made sense to develop it outside of the base system. But why wasn’t it imported into the base system when the old tools were retired? Actually, FreeBSD maintains ABI stability for the base system for the life-cycle of a release (e.g. 11). The last point release of the 10 branch, FreeBSD 10.4, is just about a month away from now. If pkg had been part of the base, that would mean the new release would have to ship with pkg 1.2 since 1.2.4 was the version available when 10.0 was released! The 11 branch would ship with 1.8, as 1.8.7 was the current version when FreeBSD 11.0 was released.

That would have meant slower progress, since no package would have been allowed to depend on features introduced after 1.2 until 10.4 went EOL – which might be as far away as somewhere near the end of 2019! Fortunately pkg is a package and thus could be improved rapidly: All versions of FreeBSD have pkg 10.1 today instead of 1.8 – or even 1.2.

How to get help?

If you have no idea how to use pkg, you can use pkg help. This will show a list of supported options and commands. And if you want to know even more, you can always type man pkg. There are also man pages for most of the pkg commands, usually named pkg-command. As a shortcut to those, you could also type pkg help command which will display the correct man page.

On the long run it’s not a bad idea to read a bit more about pkg, but if you are just getting started, all the possibilities might overwhelm you. So let’s discuss a few practical examples to get you up to speed easily and quickly, shall we?

Finding packages

As long as you just use pkg to gather information, you can run it as any user. Modifying anything needs root privileges, of course.

By default pkg operates on remote a repository. A repo (common abbreviation) is simply a place where packages are stored and kept accessible together with an index file. To be of any use, pkg needs that index and (with the default configuration) will fetch (or update if it deems the local copy too old) it before performing any action you might want it to do. If you just want to get/update the index, you can run pkg update:

# pkg update
Updating FreeBSD repository catalogue...
Fetching meta.txz: 100%    944 B   0.9kB/s    00:01    
Fetching packagesite.txz: 100%    6 MiB 548.9kB/s    00:11    
Processing entries: 100%
FreeBSD repository update completed. 26602 packages processed.
All repositories are up to date.

Provided you can connect to the repo, this will fetch the latest index and process it. Pkg uses a local sqlite database created from the index so that it can quickly and nicely get information from it.

To see if a package in any configured repository is available for installation, use pkg search:

% pkg search bash
bash-4.4.12_2                  GNU Project's Bourne Again SHell
bash-completion-2.5,1          Programmable completion library for Bash
bash-static-4.4.12_2           GNU Project's Bourne Again SHell
bashc-3.2.33.0_1               GNU bash shell extended with visual two-panel file browser
checkbashisms-2.15.10          Check for the presence of bashisms
erlang-mochiweb-basho-2.9.0p2  Erlang library for building lightweight HTTP servers (Basho fork)
mybashburn-1.0.2_4             Ncurses CD burning bash script
p5-Bash-Completion-0.008_1     Extensible system to provide bash completion
p5-Term-Bash-Completion-Generator-0.02.8_1 Generate bash completion scripts

Pkg returns a list of hits, each with package name and version as well as a short comment to give you an idea what the package actually is. If you know either the package name or part of the name, searching is easy enough.

Now let’s assume you are looking for a light-weight web browser but you forgot the name! Since it’s not very likely that the package’s name contains “browser”, how do you search for it? You could simply search the comments e.g. for “web browser”, but that would lead to quite a list. Do you remember anything else about the browser? Let’s say we know that it uses the FLTK toolkit. Let’s see if we can find that package:

% pkg search -c "web browser" | grep -i FLTK                            
dillo-3.0.5                    Fast, small graphical Web browser built upon fltk

There we are, the browser’s name is dillo! If even searching in the comments doesn’t yield what you are searching for, you might even resort to pkg search -D keyword. This will search in the detailed description that each package comes with. Just be prepared for a lot of hits and a wall of text if you’re using common keywords.

Web-based package search

In many cases it’s not a bad idea to use a web-based search. That is what the site FreshPorts provides among other things.

If you’re trying to get into FreeBSD, this is a site that you might want to bookmark. Quite possibly it’ll come in handy rather often. Also spend a little while exploring what it offers. Getting familiar with it is in fact time will spent.

Installing packages

To install a package, just issue pkg install pkgname:

# pkg install chocolate-doom
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 7 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        chocolate-doom: 2.3.0
        sdl_net: 1.2.8_3
        doom-data: 1.0_1
        sdl_mixer: 1.2.12_12
        smpeg: 0.4.4_14
        timidity: 0.2i_1
        libmikmod: 3.3.8

Number of packages to be installed: 7

The process will require 22 MiB more space.
11 MiB to be downloaded.

Proceed with this action? [y/N]:

Just answer y to make pkg fetch and install those packages (any PC without DooM installed just isn’t quite complete after all – I still stick to that even though I haven’t found time to actually fire up that game in years!).

What’s installed?

To query the package database, use pkg info. Without any further arguments this will return a list of all installed packages (so you probably want to pipe it into a pager like less). Searching for a specific package? You can definitely do that using your standard Unix tools, but hold that grep right now! There’s a better way:

% pkg info -x mate-t
ghostbsd-mate-themes-1.4
mate-terminal-1.18.1
mate-themes-3.22.12

The -x switch enables searching with regular expressions. The search in my example shows all packages that contain “mate-t”. You may even want to get used to adding -i, too, which enables case-insensitive search – just in case (there aren’t that many packages in FreeBSD that contain uppercase letters, but some do).

If you found your package, just use pkg info [packagename] (without the square brackets, of course) to get a whole lot of information about the package! But that’s probably more than you wanted and it makes sense to know a few more switches that just give you some specific information.

A nice one is -D. Forget what that post-install message was that told you how to actually get your package to work? This option prints it again:

% pkg info -D chromium
chromium-60.0.3112.101:
Always:
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
[...]

Use -d to query information about a package’s dependencies:

% pkg info -d galculator
galculator-2.1.4:
	pango-1.40.6
	gtk3-3.22.15
	gtk-update-icon-cache-2.24.29
	gdk-pixbuf2-2.36.6
	cairo-1.14.8_1,2
	glib-2.50.2_4,1
	gettext-runtime-0.19.8.1_1
	atk-2.24.0

With -l you can list all the files that a package installed in your filesystem:

% pkg info -l mksh
mksh-56_1:
        /usr/local/bin/mksh
        /usr/local/man/man1/mksh.1.gz
        /usr/local/share/examples/mksh/dot.mkshrc
        /usr/local/share/licenses/mksh-56_1/ISCL
        /usr/local/share/licenses/mksh-56_1/LICENSE
        /usr/local/share/licenses/mksh-56_1/ML
        /usr/local/share/licenses/mksh-56_1/catalog.mk

Deleting packages

The last one of the basic operations is removing packages. Here in my example I spotted a package called “tracker”, a filesystem indexer that comes with GNOME. If you don’t use that desktop and find it on your system: Kill it with fire! Nuke it from the system with pkg delete:

# pkg delete tracker
Checking integrity... done (0 conflicting)
Deinstallation has been requested for the following 2 packages (of 0 packages in the universe):

Installed packages to be REMOVED:
        tracker-1.6.1_9
        nautilus-3.18.5

Number of packages to be removed: 2

The operation will free 21 MiB.

Proceed with deinstalling packages? [y/N]: y

Deinstalling this package will also get rid of Nautilus as well (since tracker is a dependency for that). Since the GNOME team pretty much ruined that once decent file manager, I’m not going to shed any tears over that loss and press enter. Pkg will then delete all the files associated with the package and un-register it in the package database.

What’s next?

That’s it for the basics in my opinion. The next post will show off a few of the more advanced features that Pkg offers.

The history of *nix package management

Very few people will argue against the statement that Unix-like operating systems conquered the (professional) world due to a whole lot of strong points – one of which is package management. Whenever you take a look at another *nix OS or even just another Linux distro, one of the first things (if not the first!) is to get familiar with how package management works there. You want to be able to install and uninstall programs after all, right?

If you’re looking for another article on using jails on a custom-built OPNsense BSD router, please bear with me. We’re getting there. To make our jails useful we will use packages. And while you can safely expect any BSD or Linux user to understand that topic pretty well, products like OPNsense are also popular with people who are Windows users. So while this is not exactly a follow-up article on the BSD router series, I’m working towards it. Should you not care for how that package management stuff all came to be, just skip this post.

When there’s no package manager

There’s this myth that Slackware Linux has no package manager, which is not true. However Slackware’s package management lacks automatic dependency resolving. That’s a very different thing but probably the reason for the confusion. But what is package management and what is dependency resolving? We’ll get to that in a minute.

To be honest, it’s not very likely today to encounter a *nix system that doesn’t provide some form of package manager. If you have such a system at hand, you’re quite probably doing Linux from Scratch (a “distribution” meant to learn the nuts and bolts of Linux systems by building everything yourself) or have manually installed a Linux system and deliberately left out the package manager. Both are special cases. Well, or you have a fresh install of FreeBSD. But we’ll talk about FreeBSD’s modern package manager in detail in the next post.

Even Microsoft has included Pkgmgr.exe since Windows Vista. While it goes by the name of “package manager”, it turns pale when compared to *nix package managers. It is a command-line tool that allows to install and uninstall packages, yes. But those are limited to operating system fixes and components from Microsoft. Nice try, but what Redmond offered in late 2006 is vastly inferior to what the *nix world had more than 10 years earlier.

There’s the somewhat popular Chocolatey package manager for Windows and Microsoft said that they’d finally include a package manager called “one-get” (apt-get anyone?) with Windows 10 (or was it “nu-get” or something?). I haven’t read a lot about it on major tech sites, though, and thus have no idea if people are actually using it and if it’s worth to try out (I would, but I disagree with Microsoft’s EULA and thus I haven’t had a Windows PC in roughly 10 years).

But how on earth are you expected to work with a *nix system when you cannot install any packages?

Before package managers: Make magic

Unix begun its life as an OS by programmers for programmers. Want to use a program on your box that is not part of your OS? Go get the source, compile and link it and then copy the executable to /usr/local/whatever. In times where you would have just some 100 MB of storage in total (or even less), this probably worked well enough. You simply couldn’t go rampage and install unneeded software anyways, and sticking to the /usr/local scheme you separate optional stuff from the actual operating system.

More space became available however and software grew bigger and more complex. Unix got the ability to use libraries (“shared objects”), ELF executables, etc. To solve the task of building more complicated software easily, make was developed: A tool that read a Makefile which told it exactly what to do. Software begun shipping not just with the source code but also with Makefiles. Provided that all dependencies existed on the system, it was quite simple to build software again.

Compilation process (invoked by make)

Makefiles also provide a facility called “targets” which made a single file support multiple actions. In addition to a simple make statement that builds the program, it became common to add a target that allowed for make install to copy the program files into their assumed place in the filesystem. Doing an update meant building a newer version and simply overwriting the files in place.

Make can do a lot more, though. Faster recompiles by to looking at the generated file’s timestamp (and only rebuilding what has changed and needs to be rebuilt) and other features like this are not of particular interest for our topic. But they certainly helped with the quick adoption of make by most programmers. So the outcome for us is that we use Makefiles instead of compile scripts.

Dependency and portability trouble

Being able to rely on make to build (and install) software is much better than always having to invoke compiler, linker, etc. by hand. But that didn’t mean that you could just type “make” on your system and expect it to work! You had to read the readme file first (which is still a good idea, BTW) to find out which dependencies you had to install beforehand. If those were not available, the compilation process would fail. And there was more trouble: Different implementations of core functionality in various operating systems made it next to impossible for the programmers to make their software work on multiple Unices. Introduction of the POSIX standard helped quite a bit but still operating systems had differences to take into account.

Configure script running

Two of the answers to the dependency and portability problems were autoconf and metaconf (the latter is still used for building Perl where it originated). Autoconf is a tool used to generate configure scripts. Such a script is run first after extracting the source tarball to inspect your operating system. It will check if all the needed dependencies are present and if core OS functionality meets the expectations of the software that is going to be built. This is a very complex matter – but thanks to the people who invested that tremendous effort in building those tools, actually building fairly portable software became much, much easier!

How to get rid of software?

Back to make. So we’re now in the pleasant situation that it’s quite easy to build software (at least when you compare it to the dark days of the past). But what would you do if you want to get rid of some program that you installed previously? Your best bet might be to look closely at what make install did and remove all the files that it installed. For simple programs this is probably not that bad but for bigger software it becomes quite a pain.

Some programs also came with an uninstall target for make however, which would delete all installed files again. That’s quite nice, but there’s a problem: After building and installing a program you would probably delete the source code. And having to unpack the sources again to uninstall the software is quite some effort if you didn’t keep it around. Especially since you probably need the source for exactly the same version as newer versions might install more or other files, too!

This is the point where package management comes to the rescue.

Simple package management

So how does package management work? Well, let’s look at packages first. Imagine you just built version 1.0.2 of the program foo. You probably ran ./configure and then make. The compilation process succeeded and you could now issue make install to install the program on your system. The package building process is somewhat similar – the biggest difference is that the install destination was changed! Thanks to the modifications, make wouldn’t put the executable into /usr/local/bin, the manpages into /usr/local/man, etc. Instead make would then put the binaries e.g. into the directory /usr/obj/foo-1.0.2/usr/local/bin and the manpages into /usr/obj/foo-1.0.2/usr/local/man.

Installing tmux with installpkg (on Slackware)

Since this location is not in the system’s PATH, it’s not of much use on this machine. But we wanted to create a package and not just install the software, right? As a next step, the contents of /usr/obj/foo-1.0.2/ could be packaged up nicely into a tarball. Now if you distribute that tarball to other systems running the same OS version, you can simply untar the contents to / and achieve the same result as running make install after an unmodified build. The benefit is obvious: You don’t have to compile the program on each and every machine!

So far for primitive package usage. Advancing to actual package management, you would include a list of files and some metadata into the tarball. Then you wouldn’t extract packages by hand but leave that to the package manager. Why? Because it would not only extract all the needed files. It will also record the installation in its package database and keep the file list around in case it’s needed again.

Uninstalling tmux and extracting the package to look inside

Installing using a package manager means that you can query it for a list of installed packages on a system. This is much more convenient than ls /usr/local, especially if you want to know which version of some package is installed! And since the package manager keeps the list of files installed by a package around, it can also take care of a clean uninstall without leaving you wondering if you missed something when you deleted stuff manually. Oh, and it will be able to lend you a hand in upgrading software, too!

That’s about what Slackware’s package management does: It enables you to install, uninstall and update packages. Period.

Dependency tracking

But what about programs that require dependencies to run? If you install them from a package you never ran configure and thus might not have the dependency installed, right? Right. In that case the program won’t run. As simple as that. This is the time to ldd the program executable to get a list of all libraries it is dynamically linked against. Note which ones are missing on your system, find out which other packages provide them and install those, too.

Pacman (Arch Linux) handles dependencies automatically

If you know your way around this works ok. If not… Well, while there are a lot of libraries where you can guess from the name which packages they would likely belong to, there are others, too. Happy hunting! Got frustrated already? Keep saying to yourself that you’re learning fast the hard way. This might ease the pain. Or go and use a package management system that provides dependency handling!

Here’s an example: You want to install BASH on a *nix system that just provides the old bourne shell (/bin/sh). The package manager will look at the packaging information and see: BASH requires readline to be installed. Then the package manager will look at the package information for that package and find out: Readline requires ncurses to be present. Finally it will look at the ncurses package and nod: No further dependencies. It will then offer you to install ncurses, readline and BASH for you. Much easier, eh?

Xterm and all dependencies downloaded and installed (Arch Linux)

First package managers

A lot of people claim that the RedHat Package Manager (RPM) and Debian’s dpkg are examples of the earliest package managers. While both of them are so old that using them directly is in fact inconvenient enough to justify the existence of another program that allows to use them indirectly (yum/dnf and e.g. apt-get), this is not true.

PMS (short for “package management system”) is generally regarded to be the first (albeit primitive) package manager. Version 1.0 was ready in mid 1994 and used on the Bogus Linux distribution. With a few intermediate steps this lead to the first incarnation of RPM, Red Hat’s well-known package manager which first shipped with Red Hat Linux 2.0 in late 1995.

FreeBSD 1.0 (released in late 1993) already came with what is called the ports tree: A very convenient package building framework using make. It included version 0.5 of pkg_install, the pkg_* tools that would later become part of the OS! I’ll cover the ports tree in some detail in a later article because it’s still used to build packages on FreeBSD today.

Part of a Makefile (actually for a FreeBSD port)

Version 2.0-RELEASE (late 1994) shipped the pkg_* tools. They consisted of a set of tools like pkg_add to install a package, pkg_info to show installed packages, pkg_delete to delete packages and pkg_create to create packages.

FreeBSD’s pkg_add got support for using remote repositories in version 3.1-RELEASE (early 1999). But those tools were really showing their age when they were put to rest with 10.0-RELEASE (early 2014). A replacement has been developed in form of the much more modern solution initially called pkg-ng or simply pkg. Again that will be covered in another post (the next one actually).

With the ports tree FreeBSD undoubtedly had the most sophisticated package building framework of that time. Still it’s one of the most flexible ones and a bliss to work with compared to creating DEB or RPM packages… And since Bogus’s PMS was started at least a month after pkg_install, it’s even entirely possible that the first working package management tool was in fact another FreeBSD innovation.

FreeBSD jails (2/2): 4.11 sentenced to jail

Ok, after introducing FreeBSD’s jails and jail frameworks in the previous post, it’s time to actually put that 4.11 system that was built in February behind bars. Before turning towards that special case, though, we’ll have a look at how to use iocage (one of the jail management frameworks).

Creating and starting an 11.0 jail

We’ve built iocage from ports last time, so let’s just jump right into it and try out one of the most important commands:

# iocage list

Iocage initialized

Not too surprisingly, the jail list is empty. But the important thing here is that iocage automatically created its infrastructure when run for the first time. This is generally fine; if you happen to have more than one ZFS pool, though, you may want to manually activate one for iocage usage.

The next thing to do is to fetch the distribution tarballs for the FreeBSD version that shall populate the jails you want to create:

# iocage fetch -r 11.0-RELEASE

Fetching the 11.0 release

This process will also update the kernel and userland to the latest available version of the selected release. I chose 11.0 because that’s the latest right now and obviously 4.11 is not available!

You can actually skip fetching the release as iocage will do it automatically if you create the jail, but doing it beforehand doesn’t hurt. Now let’s create our first jail:

# iocage create tag=fbsd11 ip4_addr="em0|192.168.2.10/24" -r 11.0-RELEASE

Jail ‘fbsd11’ created!

Each jail has a UUID. This one’s UUID begins with 99a9941a. You can interact with jails by using that UUID. But if you’ve got a lot of jails it would be pretty hard to keep track of which one is which. For that reason you can assign a tag to a jail that you can use to identify it. We’ve effectively given our jail a name: fbsd11. In general it’s a good idea to name it in a way that helps you (or your co-workers) to understand what the jail is used for. You may choose something like “postgres-jail” that includes the technology used, “loadbalancer” to describe its function or whatever fits your needs.

We’ve also assigned the jail an ipv4 address, 192.168.2.10 in this case, noted the subnet in CIDR notation and specified which NIC to use it on. Listing jails shows all that information at a glance.

The jail is ready to be started:

# iocage start fbsd11

Starting the jail

As you can see here from the ifconfig output, the ip address was not yet assigned to the NIC. According to iocage the jail has been started successfully. Let’s take a look at it:

# iocage list

The jail is running

The state for our jail has changed to “up”. Also the ip has been automatically assigned to our network interface when iocage started the jail. When the jail is stopped, it is also automatically removed again.

Using the jail

Iocage offers some means to interact jails without actually “entering” them, like e.g. installing packages, etc. The easiest way to use a jail however, is to get a shell prompt inside the jail (think entering a chroot environment). That’s what we’re going to do next:

# iocage console fbsd11

Entering the jail console

Looks pretty much like we just logged into a FreeBSD system, huh? Well, we basically did just that. With the big difference of not being a full OS (which would be the case with a VM for example) but a jail with just a FreeBSD 11.0 userland (that is running on the host machine’s kernel).

Ok, I bootstrapped pkg and then installed nginx:

Installing the nginx webserver

This also proves that the network is working since we’re receiving the packages to install from. There’s also nothing special in doing this, just use pkg the way you’re used to. For the most part it’s behaving just like a regular FreeBSD system. There are a few exceptions. One of the most notable ones is the fact that by default you won’t be able to use the ping command. You can enable jails to use ping using a sysctl but this affects the jails security and therefore is disabled by default.

Let’s start nginx next:

Nginx is running

Again it’s nothing special. Nginx is running and bound to port 80. Does it do what you’d expect it to?

Testing and destroying the jail

Nginx’s default page

Yes, the webserver is happily serving the default page when accessed from other computers on the LAN! It doesn’t make much of a difference from running nginx on the host system – unless somebody manages to use an exploit. Nginx is privilege separated and thus probably not a good example. But think about a case where an intruder manages to get into your system and get root privileges. That’s pretty bad, yes. But if the application was running in a jail, the damage is at least contained and the other jails as well as the host system are unaffected. (That and it’s much easier to tear that jail down and create a new one compared to having to reinstall the whole host system and setup several applications again!)

Alright. Let’s take a quick look at where the jail data is kept:

Taking a look at iocage’s directory structure

Iocage created the /iocage dataset. The most important path is /iocage/jail. All the jails are in there (named after their UUID). To make accessing them easier, there’s /iocage/tags: Here you’ll find symlinks named after the jail’s tags which are pointing to the actual directories with the data.

Each jail consists of a configuration file, an fstab and a “root” directory (which holds all the files).

This jail has served its purpose and is no longer needed. So let’s get rid of it! First exit the jail like you would exit a chroot (e.g. CTRL-D out of it) before you proceed:

# iocage stop fbsd11
# iocage destroy fbsd11

Stopping and destroying the jail

You cannot destroy a running jail. Therefor it must be stopped first and can then be destroyed.

Creating the 4.11 jail

That has been pretty easy and straight forward, right? And here’s the good news: Jailing the 4.11 system isn’t that difficult, either. I created a tarball of the complete filesystem on the FreeBSD 4.11 server, xz compressed it and scp’d that onto the jailhost. Now we’ll create another 11.0 jail, delete the filesystem and extract the old OS data into the same place:

# iocage create tag=fbsd4.11 ip4_addr="em0|192.168.2.10/24" -r 11.0-RELEASE
# cd /iocage/tags/fbsd4.11/root
# rm -rf * .*
# tar xvJf /path/to/tarball.xz

Creating a new jail and putting the 4.11 OS into it

The old device nodes won’t work on a current kernel and have to be removed. The same goes for the old proc filesystem. We also don’t need any kernels or kernel modules. And /boot is obsolete in a jail, too. So it’s a good idea to get rid of all that:

# rm dev/*
# rm kernel*
# rm -rf boot
# rm -rf modules*
# rm -rf proc/*

Deleting unneeded parts of 4.11

The old userland and the additional data remains. Let’s try to start the jail now:

# iocage stop fbsd11

Starting the 4.11 jail

Uhh… This doesn’t look good. Iocage tries to do things that won’t work with a 4.11 userland (anything older than 9.3 is unsupported with iocage, anyways!). But fortunately that looks worse than it actually is:

It errors out… but it’s running!

Despite those errors the jail is up and running! Can we get console access?

Inside the 4.11 jail

# iocage console fbsd4.11

Entering the console works, too!

Yes, we can! Let’s make 4.11 great again! Time to install a webserver in this jail, too. Since we still have Pkgsrc in place, that’s an easy thing to do:

# cd /usr/pkgsrc/16/www/nginx
# bmake install clean clean-depends

Building nginx on 4.11 through Pkgsrc

I decided to modify nginx’s default starting page so it looks a little different from the stock one. Nginx can be started simply by executing the daemon. However all the system utilities regarding process management don’t work! And sockstat is not working either.

Starting nginx, but tools like ps don’t work!

Does nginx actually run? There’s an easy way to test that. Let’s just open up a browser on another pc and see if we can get the modified webpage.

Nginx is able to serve the webpage from the 4.11 jail!

It works! Yes, it was actually that easy. Jails are not necessarily a complicated thing at all (they can be more complicated than that of course, if you’re doing more advanced stuff). But… No ps, no top, no kill… How are you supposed to work with a 4.11 jail?

Peter Wemm suggested using statically compiled binaries from the host system like those in /rescue. And that’s actually a great idea! If you copy /rescue over into the jail, it at least provides some tools to work with.

Thanks to /rescue process management is possible

Things like top would be nice, too, of course. But to be honest, I don’t know how to statically build them. If anybody knows, please comment and share your wisdom!

More about jails?

This article merely gave a very basic introduction to the topic (plus a little “stunt”). You can do a lot more with jails. I might write about it again in the future but I haven’t decided, yet (feel free to comment and tell me what you’re interested in!). But I wanted to at least give you an idea what other things there are to explore.

If you have a server with only one ip you can still use jails. The solution to this is to give the jails internal network addresses (like 192.168.x.x) and then use Pf to do network address translation (NAT). It took me a bit to figure out how this works (there are things on the net that are better documented) but in the end it’s not that complicated.

With VIMAGE/VNET you can give your jails their own virtual network stack. That way you can even use a firewall inside the jail and assign multiple ip addresses!

Jails support quotas of various kinds. You can limit the amount of CPU that one jail may occupy, limit file system IO, etc. Lots of possibilities with this.

And of course iocage has many nice features. You can e.g. create jail templates with some software already installed and quickly create jails from those. There are multiple jail types like e.g. thin-provisioned jails. You can clone and snapshot jail. And you can have jails started automatically when your server boots.

In the previous article I said “think containers” when you’re completely new to jails. Now you’ve seen a bit of what they can do and have a better idea of what they are. So stop “thinking containers” now. These are two things that are somewhat related but they are not the same thing. Linux’s containers can do things that jails were never designed for (e.g. sharing namespaces). But jails have one huge advantage over containers: While containers are only a means for logical separation, jails were designed for security right from the start. Sure, people are working on making Linux’s containers more secure. But if there’s one thing that we should have learned by now, it is this: Retrofitting security into something is not really going to work… And jails are pretty flexible, too. You might not have missed them when you didn’t know that they exist. But get used to using them once and you’ll think differently about a lot of things and make use of them for more and more things. Jails are a great feature of FreeBSD.

FreeBSD jails (1/2): Introduction and frameworks

This is the first part of a followup to the 4.11 mini-series of posts that I published here on my blog ([1], [2], [3] & [4]). Those posts covered installing an old FreeBSD 4.11 system and using pkgsrc to update some parts of the system from versions released in the last millennium (!) to those of today (or rather from December 2016).

Now we’re going one step further: We’ll migrate a 4.11 system into a jail on a fresh FreeBSD 11.0 host system! This will be dealt with in the next post. In this part I’ll introduce the jail concept for people who are not familiar with it, discuss some jail management frameworks and do a bit of preparation work.

Motivation

Why to send that old system to a jail? We’ve already done a bit of work on a 4.11 system. But that next step tightens security much more since we have a recent kernel, can make use of a state-of-the-art firewall, etc. This is not actually my main concern however. Those remaining machines are running internal processes, so security is nice but not critical. What is critical and really frightens me, is the age of the hard drives that they use… When you do a df and see that the total capacity of a drive is way below 100 GB, you can guess that drives like that have not been sold for… quite some years now! And knowing that drives are rather perfidious little things, I’d rather get rid of those as soon as possible.

What makes things worse: This is 4.11. There’s no GEOM available and thus no gmirror or anything. Yes, there are backups. But I’d rather not have to mess with something like that just to restore a system that should have been decommissioned years ago!

What are FreeBSD jails?

If you’re new to FreeBSD, you may have heard about jails without knowing what they actually are. If you’ve got a Solaris background, think zones. If you’re a Linux user, think containers. FreeBSD people usually cannot understand today’s container hype for the very simple reason that this OS has had jails for ages now (they were first available on development versions at the very end of the 20th century!). You are probably familiar with docker, Linux’s cgroups and all those facilities. FreeBSD basically does the same thing: Provide much enhanced but still very light-weight chroot environment.

The system in that jail is isolated from the actual host operating system so that escaping it isn’t trivial and requires special (insecure) settings. In general jails are meant to be secure after all, aren’t they? You can also give jails their own virtual network stack, you can cap their resource usage, and so on. It’s a mature, stable and secure way to do containerization of applications – or whole operating system installations.

Since FreeBSD is pretty good at keeping compatibility with old releases (for the next major release they are discussing whether to keep compatibility shims that allow executing binaries from commercial UNIX releases of the 80’s!!), it’s very much possible to stuff a 4.11 userland into a jail running on a recent version of the operating system. And that’s what we’re going to look at after getting some of the basics out of the way.

Jail frameworks

Jails in FreeBSD can be created and managed manually. We’re talking *nix here, after all! However there are several jail management frameworks available that promise to make things even easier or at least more convenient. If you want to get started with jails, I suggest that you pick a framework that sounds good to you feature-wise and simply begin playing with it. The whole thing is not that complicated actually.

If you’re just getting started, don’t bother with sysutils/warden. It was a popular jail manager created for PC-BSD but it is considered obsolete now.

One true classic among the jail frameworks is sysutils/ezjail. It still does the job and a lot of people continue to use it simply because they are already familiar with it. It allows for things like thin-provisioned jails that use a “base jail” which holds a complete FreeBSD userland, and uses nullmount to make that accessible in other jails. This makes updating very quick and convenient. It also leaves the base system read-only which may be another nice security feature at the cost of decreased flexibility. On the plus side Ezjail is independent on filesystems and thus works on UFS, too.

Then there was sysutils/iocage, a modern approach that made use of ZFS properties to store certain values. For that reason it demands at least one zpool on the system to be usable. It had been implemented in shell code which made it easy to read for admins who don’t have a lot of coding experience. It has however been rewritten and the old shell version is declared obsolete. If you like the idea of having it written in shell, take a look at sysutils/iocell, which is a fork of the last shell version and is actively maintained.

The new version of iocage is implemented in Python (initially it was announced to be rewritten in Go but that decision was revoked). Another warning: sysutils/py-iocage is the wrong version, too! Do not use it. The rewrite initially supported Python 2.7 – which is what this port is all about – but newer versions dropped support for that and now require Python 3.6. So the actual port you should use is sysutils/py3-iocage! That version requirement makes sense but unfortunately it leads to iocage not being available from packages (as FreeBSD’s default version of Python 3 is still 3.3 currently). So you probably need to build it from ports.

There’s one more framework that I want to mention: sysutils/cbsd. It is an advanced system that not only does jails but also allows to manage bhyve (FreeBSD’s modern hypervisor). If you’re looking for something more comprehensive you may well give it a try.

Choosing my framework

When I first wanted to get into jails, I tried out ezjail. It worked well for me and I’d still use it on a system with no ZFS available. When I have ZFS, though, I liked the iocage approach. Cbsd looks quite good but I didn’t do too much with it because I require things to be scriptable (like using the framework through SaltStack states – there’s even a Salt Formula for iocage, but that’s for the old implementation) and that doesn’t seem to be what they focus on. So when the shell based iocage was deprecated, I moved to iocell and then I was torn to stick with that or to return to the new iocage. In the end I opted for at least giving the rewrite a chance. Since it does its thing quite nicely, I’ve adopted that and will use it here.

You can of course use any other framework if you prefer a different one. Or you could setup your jail by hand – if you’re thinking about that, definitely take a look at this article by M. W. Lucas whom I actually have to thank not only for his post but kind of for this one as well. The thought of jailing the old systems crossed my mind once or twice, but if he hadn’t written about it in the past, I don’t think I’d ever have tried it (no, I read his post back in the day when he published it; yes, I wanted to try this for over three years now before I finally found some time to give it a shot!).

Preparations

Let’s install iocage first. Like stated before, we will have to build it from ports. Assuming a system that does not have a ports tree installed, this is how you can do it (there are better (cleaner) ways to build packages from ports, I planned to do a post about that topic since December!) but this old method still works:

# portsnap fetch extract
# cd /usr/ports/sysutils/py3-iocage
# make config-recursive
# make install clean

The new iocage needs a UTF-8 locale set on the system or it won’t run. Unfortunately this is not the standard in FreeBSD (this is something that I really hope for in FreeBSD 12!). There are multiple ways to do this, my preferred one to set it in /etc/login.conf:

Look for default:\ – it is followed by a block of indented lines, the last one being :umask=022:. Add another backslash at the end to make the block continue and add two more lines to it:

:charset=UTF-8:\
:lang=en_US.UTF-8:

Login configuration is one of the few things where the actual values are in fact stored in a database. The changes that you made to the text file won’t take effect even if you log out and back in. First run another command to update the DB according to the changes in the text file:

cap_mkdb /etc/login.conf

Now log out and back in. Try echoing $LANG – that should print the UTF locale’s name. If it does, you are set.

What’s next?

The next post will demonstrate how to use iocage to manage jails and show how to jail a FreeBSD 4.11 system so it runs on a FreeBSD 11 host.