The ports collection is the toolkit to build OpenBSD packages. Installing software from ports takes longer than installing via packages, is more error-prone, and requires a deeper understanding of the system and the add-on software than packages demand. You can’t get packages for every possible situation, however (one particularly annoying example is when the license for a particular piece of software makes it illegal for the OpenBSD project to create and distribute packages), and sometimes ports are the only way to get third-party software on your OpenBSD system short of compiling it yourself.
What makes ports interesting is their level of automation. With one command, a port can find the source code for a program, download it, verify its integrity, apply any patches needed to make it run on OpenBSD, toggle any flags needed for any custom features of your system, build the code into actual binaries, produce a package, and install it. If you have compiled software on other platforms, you’ll quickly realize how ports simplify building software.
Like packages, ports work only on the version of OpenBSD for which they are released. That means that you must use the OpenBSD 5.4 ports collection on OpenBSD 5.4; the 5.5 ports collection won’t work. Oh, it might look like it works sometimes, but the software will fail unpredictably, and no one will have sympathy for you (sympathy for your coworkers, perhaps, but not for you).
When you upgrade OpenBSD, the expectation is that you will upgrade your ports collection and all installed packages to the precise matching version. You might be able to use older packages on a newer OpenBSD, as long as you don’t delete the older shared libraries required by the software.
The ports tree is usually installed in /usr/ports. If you want the ports tree, you must manually fetch the ports.tar.gz file from your OpenBSD release and extract it under /usr.
I suggested this way back in Chapter 4, but you can also get the ports tree and keep the files up to date using cvs(1)
, as covered in Chapter 20. Look in this directory, and you’ll find a whole bunch of directories and files.
The INDEX file contains a list of every port in the system, in alphabetical order but machine-readable format. You can search this file for ports, but I recommend using one of the tools discussed later to do so.
The Makefile contains the basic machine instructions for making the ports system work. While it’s intended for use by make(1)
, you can learn a lot by reading the makefile for any port. Most of the really complicated ports code is in the ports/infrastructure directory, and all of the makefiles in the ports system build on that infrastructure.
The remaining directories are software categories. Each category contains a further layer of directories, and each directory under a category is a port of a specific piece of software. OpenBSD has more than 7600 ports as of this writing, so this hierarchical organization is vital to keeping them in some sort of manageable order.
For example, the following is a listing of the contents of the news directory, which contains programs for using and managing Usenet news. This is one of the smaller categories. Some categories have hundreds of entries, but they’re arranged in much the same way.
CVS leafnode p5-News-Article py-yenc tin Makefile newsfetch p5-News-Newsrc sabnzbd trn aub nn pan sickbeard ubh hellanzb p5-Gateway plor slrn yencode
Like the CVS directory in the main ports tree, the category’s CVS directory contains CVS version control information that doesn’t matter for day-to-day operation. The Makefile contains a list of valid ports within the category. You can build all of the ports in this category using this makefile, although that’s mostly useful only when building packages en masse. (When the OpenBSD Project team builds everything in the ports tree, it uses /usr/ports/infrastructure/bin/dpb.)
Let’s go down another level. Here’s the port for tcsh
, one of my nonnegotiable requirements as a sysadmin:
$ ls /usr/ports/shells/tcsh
CVS Makefile distinfo patches pkg
The CVS directory contains version control information, as in every CVS directory.
The Makefile gives specific instructions for building tcsh
on OpenBSD, including where to get the software and any patches, how to extract it, where the package can be distributed from, and any supported customizations.
The distinfo file contains several different cryptographic hashes for the source code to be downloaded, to avoid building software from compromised source code, and the size of the source file. Newer ports contain only SHA-256 hashes.
While it’s possible (difficult, but possible) to have a compromised file match a specific hash, it’s extremely unlikely that an altered source code file could match hashes computed with several different algorithms and have the same size as the uncompromised code. Even if people figure out how to break a particular hash, use of multiple hashes and the file size make compromising a source file nearly impossible.
The patches directory contains code alterations needed to make this software run on OpenBSD. Some ports have no patches; others have dozens.
Finally, the pkg directory describes the package and lists the files that the complete package must include.
Some ports include other ports. Here are the contents of the emulators/fedora port.
CVS Makefile Makefile.inc base cups motif sdl
The file Makefile.inc is new, as are the subdirectories base, cups, motif, and sdl. The subdirectories are independent ports. These four ports are often installed together, and as a whole, support OpenBSD’s Linux emulation (documented in compat_linux(8)
). All four ports call in the common instructions in Makefile.inc. (The ports tree doesn’t include many of these, but don’t be shocked when you find one.)
The process of building a port creates an installable package and uses a whole bunch of temporary files, source files, and status files. By default, all of these files are placed inside the ports tree itself. While this works, I encourage you to treat /usr/ports as a read-only OpenBSD directory tree, just like /usr/bin, /usr/lib, and so on. Doing so simplifies upgrading and identifying local changes, helps identify what you’ve built from ports, and saves space on the /usr partition.
Build files for ports can range from a few kilobytes to several gigabytes, so it’s best to build ports on a large scratch partition. If you have unpartitioned disk space, create a partition just for building ports. Or use any partition with space, or even an NFS partition.
Configure the ports collection by setting variables in /etc/mk.conf. To use a read-only ports tree, set the variables in these directories:
WRKOBJDIR
. Directory where the software is extracted from source and compiled. These can be deleted and re-created as needed.
PACKAGE_REPOSITORY
. Directory where completed packages are stored. The ports collection builds packages, which you can then install.
PLIST_DB
. Directory where package packing lists are stored.
BULK_COOKIES_DIR
. Directory for storing status cookies during mass builds of packages.
UPDATE_COOKIES_DIR
. Directory for storing status cookies during mass updates of packages.
DISTDIR
. Directory where vendor source code is kept. Source code is usually retained for reuse.
If these directories are owned by your regular user account, you can do a large part of package building without being root.
On one particular test system, I have hundreds of gigabytes free in /home, so I chose to put my package directories there. Here’s my /etc/mk.conf:
WRKOBJDIR=/home/ports/wrkobjdir DISTDIR=/home/ports/distdir PLIST_DB=/home/ports/plist BULK_COOKIES_DIR=/home/ports/bulk_cookies UPDATE_COOKIES_DIR=/home/ports/update_cookies PACKAGE_REPOSITORY=/home/ports/pkgrepo
The ports system will build everything in /home/ports/wrkobjdir. Original source code files go in /home/ports/distdir. The ports system maintains various records in /home/ports/update_cookies and /home/ports/bulk_cookies. Completed packages go into /home/ports/pkgrepo.
If you have a dedicated port-building machine, consider per-release package repositories. For example, I might have three versions of OpenBSD running at any given time. The package-building machine always runs the latest release, but I don’t want to throw away my old packages, so I use a package repository directory like /home/ports/pkgrepo/5.4 for packages built on a 5.4 system.
As with packages, the first problem with ports is finding software you want. (To randomly poke around the ports tree in a pretty interface, see the http://www.openports.se website.) OpenBSD has several ways to search the ports collection, including the ports index, keywords, and via SQL.
The file /usr/ports/INDEX lists all software in the ports tree, sorted by category and then alphabetically. If you have a good idea what your port is called, you can search the file for your preferred software. The index describes each port in a single pipe-delimited line, much like this:
gcpio-2.11|archivers/gcpio||GNU copy-in/out (cpio)|archivers/gcpio/pkg/DESCR|The OpenBSD ports mailing-list <[email protected]>|archivers| STEM->=0.10.38:devel/gettext converters/libiconv|STEM->=0.10.38:devel/gettext|STEM->=0.10.38:devel/gettext|any|y|y|y|y
While the ports tree itself finds this a convenient format, it’s not particularly human-readable. To translate this to a human-friendly format, go into /usr/ports and run make print-index
. (This process goes on for tens of thousands of lines, so feed it to a pager.) Here’s the same port in the human-readable format:
$ cd /usr/ports $ make print-index | less … Port: gcpio-2.11 Path: archivers/gcpio Info: GNU copy-in/out (cpio) Maint: The OpenBSD ports mailing-list <[email protected]> Index: archivers L-deps: STEM->=0.10.38:devel/gettext converters/libiconv B-deps: STEM->=0.10.38:devel/gettext R-deps: STEM->=0.10.38:devel/gettext …
The Port
statement gives the official name of the port and the version of the ported software. This software is called gcpio
, and it’s at version 2.11. The Path
gives the ports tree category and directory where the port can be found—in this case, archivers/gcpio. The Info
line gives a very brief description of the software. This is the GNU version of cpio(1)
. The Maint
, or maintainer, is the person or group responsible for maintaining this software in the ports tree. The OpenBSD ports team supports the gcpio
port. The best-maintained ports usually have an individual as a maintainer, rather than the mailing list.
The final three entries describe other software required by this software. The L-deps
line lists shared libraries, B-deps
lists software needed to build this port, and R-deps
lists the port’s runtime dependencies.
What good does this do? Suppose you’re still hung up on an Apache 2 web server. You can search INDEX for ports beginning with “apache.”
$ grep -i ^apache INDEX … apache-httpd-2.2.20p1|www/apache-httpd||apache HTTP server|www/apache-httpd/pkg/DESCR|The OpenBSD ports mailing-list <[email protected]>|www net| apr-util-*-!ldap:devel/apr-util converters/libiconv devel/pcre|STEM->=1.21: textproc/groff|converters/libiconv|any|y|y|y|y
The first three (omitted) entries are ports related to Apache, but they are not the web server software. The fourth line is our port.
Gathering this information from the index is rather limited, however. If you don’t know the name of the software, or how OpenBSD packages the software, you can’t easily find the port. In that case, try one of the other methods discussed next.
If you don’t know a package’s exact name, try the ports collection’s search feature: make search
and a key scans the index for a specific word. To search for Apache-related software, try this:
$ make search key=apache
On my system, this returns 62 results. You’ll need to scroll through several pages of possibilities, but you’ll find what you want.
You might need to try several possible keywords for a particular package, as some keywords have no hits and others generate too many.
The sqlports
package lets you build a database of the INDEX file, permitting you to search for ports based on highly arbitrary criteria via SQL. For example, say you want to know all ports that depend on libiconv
and expat
. In this case, sqlports
is your friend. Install it from ports or packages, and it will automatically build a database in /usr/local/share/sqlports from INDEX, and then use OpenBSD’s sqlite3
to query the database.
I won’t teach SQL[37] here, but just as an example, here’s how to search for ports whose name includes the string “apache” using sqlports
(which can build much more complex queries than this one):
$ sqlite3 /usr/local/share/sqlports sqlite> select fullpkgname from ports where fullpkgname like '%apache%'; apache-couchdb-1.0.1p2 apache-ant-1.8.2p3 apachetop-0.12.6 apache-httpd-2.2.22 modsecurity-apache-1.9.3p5 p5-Apache-ASP-2.61p0 p5-Apache-DB-0.14p3 …
The Apache httpd
server is the fourth hit, but there are another dozen or so ports. Every name that begins with p5-
is a Perl module.