One of the more intriguing capabilities of the BSD operating systems is their ability to run binaries for other Unix-like operating systems. I recently found myself requiring the commercial PGP Command Line for a project. Rather than install a Linux box just for this one piece of software, I jumped through some hoops and made it work perfectly on one of my existing FreeBSD systems. Getting a random piece of commercial Linux software running on a FreeBSD system isn't always as transparent as you might like, but you can do it with a minimum of fuss if you have a few extra troubleshooting skills.
Those of you familiar with OpenPGP are probably wondering why I wouldn't just use GnuPG. While GnuPG handles pure OpenPGP functions quite well, PGP Command Line has specific abilities that GnuPG lacks. For example, some government standards require that a company be able to decrypt data even if the private key owner is unwilling to provide the private key. PGP software uses an Additional Decryption Key (ADK) to support this. (After guarding my private keys for years, I freely admit that the idea of ADK makes my bowels churn--but as it's not mandatory, I can see where a corporation would need this.) PGP Command Line also has the ability to make self-extracting PGP Zip files, which is rather useful. There's always the IDEA patent issue--although if you need IDEA, you probably have other problems! PGP Command Line comes in a .zip file containing the binaries for all the supported platforms and a few instructions in PDF format. You also get license codes tied to your name, organization, and email address.
To run Linux software on FreeBSD, you must configure your FreeBSD system, use the RPM package management tool to install it in the Linux environment, and finally tune the installed software to match the requirements of the Linux subsystem. The first part is well documented, but the rest is murky to many BSD administrators.
Start by confirming that your FreeBSD system is configured to run Linux binaries. Your kernel must have the Linux mode kernel module loaded. The simplest way to check is with
# kldstat | grep linux 7 1 0xc1c7b000 18000 linux.ko #
If you don't get anything back, go to /etc/rc.conf and add an entry to enable Linux mode.
You also need a subset of a standard Linux userland under /usr/compat/linux. I used a Red Hat 9 userland for this article, as found in /usr/ports/emulators/linux_base-rh-9. If you have a dual-boot FreeBSD/Linux system and are willing to play around a little, you might want to mount your Linux userland under /usr/compat/. While you might encounter different issues if you use a different version of Linux userland, the general process given here will still be valid.
Many Linux programs also require a Linux-style procfs. FreeBSD has deprecated procfs in favor of
sysctl(8), but many Linux programs still require it. If you install from a port, the port may configure a Linux procfs for you. If not, add the following line to /etc/fstab:
linproc /compat/linux/proc linprocfs rw 0 0
You cannot mount this filesystem until your Linux userland is installed.
Once your kernel is configured, you have a Linux userland installed, and /etc/fstab lists a Linux procfs, you should reboot your computer. Confirm that everything works with
df(1) before continuing.
If BSD's ports system has spoiled you, RPM may appear obtuse and arcane. It really isn't any worse than
pkg_add--the headaches are simply in different spots. You must use some additional RPM features to install Linux packages on FreeBSD. First, the
--ignoreos flag tells
rpm(8) not to worry about the fact that you're not installing on a Linux box. The
--root option gives the root of the filesystem you're installing in--in this case, /usr/compat/linux. This will prevent overwriting your native FreeBSD binaries!
# sudo rpm -i --ignoreos --dbpath /var/lib/rpm --root \ /compat/linux PGPCommandLine902_Linux.rpm error: failed dependencies: libxml2.so.2 is needed by pgpcmdln-22.214.171.1240-1 #
PGP Command Line needs libxml2.so.2, and it's not available on the system. Did I mention that RPM had its own headaches? Dependency is one of them. The BSD ports system mostly eliminates dependency problems, so this kind of issue tends to give us fits. Linux users all have their favorite ways to solve dependency problems, but here's the method that works for me. First, confirm that this library really isn't on your system.
# locate xml | grep compat/linux /usr/compat/linux/share/xml /usr/compat/linux/usr/bin/xmlwf /usr/compat/linux/usr/share/man/man1/xmlwf.1.gz #
OK, it's really not there. Go to an RPM search site and find the appropriate RPM. I find that rpmfind.net gives me the best results, but you might have your own favorites. Choose only an RPM built for the Linux userland you have on your system. You wouldn't think of installing a FreeBSD 7 package on your FreeBSD 4 system, and Linux doesn't like that sort of thing any better. Once you download and install the RPM, try to install PGP Command Line again.
# sudo rpm -i --ignoreos --dbpath /var/lib/rpm --root /compat/linux \ libxml2-2.5.4-3.rh9.i386.rpm # sudo rpm -i --ignoreos --dbpath /var/lib/rpm --root /compat/linux \ PGPCommandLine902_Linux.rpm #
rpm(8) returns silently, the install was successful.
I always wonder exactly what a precompiled package installs on my system, but this curiosity becomes vital when running programs in Linux mode. FreeBSD installs the smallest possible subset of Linux, but many programs expect to have a full Linux userland available, and these dependencies are not always recorded in the RPM file. You must confirm that the program has everything required and that your Linux environment is properly configured to support this software.
rpm(8) maintains a small database of installed packages and can tell you exactly what it installed, what files it contained, and which packages have which dependencies. Start by asking the RPM database for a list of all the installed packages. The list is in order by install date, so you want the very last entries.
# rpm --root /compat/linux --query -a glibc-2.3.2-27.9.7 glibc-common-2.3.2-27.9.7 ... libxml2-2.5.4-3.rh9 pgpcmdln-126.96.36.1990-1 #
RPM knows PGP Command Line as
pgpcmdln-188.8.131.520-1. Now ask for the contents of that package with
--query option. You might want to capture the output of this command, as you need it to finish configuring the software.
# rpm --root /compat/linux --query pgpcmdln -l /usr/bin/pgp /usr/bin/pgp-agent /usr/lib /usr/lib/debug ...
The two critical parts of installing a program to run under Linux mode are making sure that Linux's
ldconfig(8) knows about any included libraries and binary branding.
ldconfig(8) at boot time by reading /etc/ld.so.conf. PGP installs all of its libraries directly under /usr/lib, which is already listed. If this had changed, you would need to edit ld.so.conf and use Linux's
ldconfig(8) program to update the shared library cache, /compat/linux/etc/ld.so.cache.
Now you need to check the branding on the executables. Branding a library identifies the operating system it is built to run on. FreeBSD uses this brand to determine whether an executable is a native FreeBSD program or whether it must treat the program as a foreign program. PGP Command Line includes two binaries, /usr/compat/linux/usr/bin/pgp and /usr/compat/linux/usr/bin/pgp-agent. Branding might or might not be necessary for the proper operation of any given piece of software, but it's worth it to be careful. The
brandelf(1) program identifies the brand on a particular executable. PGP Command Line includes two executables, /usr/local/bin/pgp and /usr/local/bin/pgp-agent.
# cd /usr/compat/linux/usr/bin # brandelf pgp* File 'pgp' is of brand 'SVR4' (0). File 'pgp-agent' is of brand 'SVR4' (0). #
All programs run under Linux mode should have Linux brands. FreeBSD supports only SVR4, Linux, and native FreeBSD binaries, and will not let you assign unsupported brands to binaries. Use the
-t flag to assign a brand to a binary.
# sudo brandelf -t Linux pgp*
Finally, I want these binaries available in my regular
$PATH. Adding /compat/linux/usr/bin to
$PATH is not highly recommended, as you generally want to execute native versions of your programs or at least know that you're using Linux mode. This is easy with symlinks:
# sudo ln -s /usr/compat/linux/usr/bin/pgp /usr/local/bin/ # sudo ln -s /usr/compat/linux/usr/bin/pgp-agent /usr/local/bin/ # rehash
Once all this is done, you should be able to run the program:
# pgp --h /home/mwlucas:unknown (3078:could not create directory, Permission denied) #
Here's the good news: the program runs! The bad news is, it chokes on something. This error is listed in the PGP Command Line manual, but the description isn't exactly helpful. The trick here is to figure out what it wants to open.
Once you learn how to use
truss(1), you'll wonder how you ever solved any problems without it.
truss watches a running program and lists the system calls it makes. Whenever I have a problem getting a program to run in Linux mode, I run it under
truss and gather all sorts of details.
One drawback to
truss is that it requires a FreeBSD-native procfs. While procfs is not part of the FreeBSD new world order, it is still required on rare occasions. I recommend adding an entry for /proc to /etc/fstab but marking it
noauto so that it is not automatically mounted at boot. That way, you only have to remember to type
mount /proc before running
truss, instead of digging through the
procfs(5) man page.
proc /proc procfs rw,noauto 0 0
Once you have /proc mounted, run your Linux program under
truss. This will generate a lot of output, so you might want to use
script(1) to capture the output. Simply asking the version generates 308 lines of
truss output to skim through for the error. The simplest thing to do is to search the
truss output for
directory. Near the end of the output are several lines like:
# truss pgp --version ... linux_open("/home/mwlucas/.pgp/randseed.rnd",0x8002,00) ERR#2 'No such file or directory' linux_open("/home/mwlucas/.pgp/randseed.rnd",0x80c1,0600) ERR#2 'No such file or directory' linux_open("/home/mwlucas/.pgp/randseed.rnd",0x8002,00) ERR#2 'No such file or directory' ...
Aha! PGP Command Line can't open /home/mwlucas/.pgp directory, as the directory doesn't exist. Once I create a .pgp directory, I get:
# pgp --version PGP Command Line 9.0.2 build 560 Copyright (C) 2005 PGP Corporation All rights reserved.
A few more complicated tests show that the software runs exactly as documented in the PGP Command Line manual. While I'm not sure I could get official corporate support for this install, everything I've tried works perfectly. I get excellent results installing Linux programs on FreeBSD by configuring the environment properly, branding the software correctly, and using
truss(1) to identify problems. Good luck!
Michael W. Lucas
Read more Big Scary Daemons columns.
Return to the BSD DevCenter.
Copyright © 2009 O'Reilly Media, Inc.