<!-- $Id: linuxemu.sgml,v 1.18 1997/03/19 03:15:43 obrien Exp $ -->
<!-- The FreeBSD Documentation Project -->

<chapt><heading>Linux Emulation<label id="linuxemu"></heading>

<p><em>Contributed by &a.handy and &a.rich;</em>

<sect><heading>How to install the Linux emulator</heading>

<p>Linux emulation in FreeBSD has reached a point where it is possible
to run a large fraction of Linux binaries in both a.out and ELF
format.  The linux emulation in the 2.1-STABLE branch is capable of
running Linux DOOM and Mathematica; the version present in
FreeBSD-2.2-RELEASE is vastly more capable and runs all these as well as
Quake, Abuse, IDL, netrek for Linux and a whole host of other
programs.

There are some Linux-specific operating system features that are not
supported on FreeBSD.  Linux binaries will not work on FreeBSD if they
use the Linux /proc filesystem (which is different from the optional
FreeBSD /proc filesystem) or i386-specific calls, such as enabling
virtual 8086 mode.

<p>To tell whether your kernel is configured for Linux
compatibility simply run any Linux binary.  If it
prints the error message
<tscreen>
<verb>
linux-executable: Exec format error. Wrong Architecture.
</verb>
</tscreen>
then you do not have linux compatibility support and
you need to configure and install a new kernel.

Depending on which version of FreeBSD you are running, how you get 
Linux-emulation up will vary slightly:

<sect1><heading>Installing Linux Emulation in 2.1-STABLE</heading>

<p>The GENERIC kernel in 2.1-STABLE is not configured for linux
compatibility so you must reconfigure your kernel for it.  There
are two ways to do this: 1. linking the emulator statically in the
kernel itself and 2. configuring your kernel to dynamically load the
linux loadable kernel module (LKM).

<p>To enable the emulator, add the following to your configuration file
(c.f. /sys/i386/conf/LINT):
<tscreen>
<verb>
options COMPAT_LINUX
</verb>
</tscreen>
If you want to run doom or other applications
that need shared memory
also add the following.
<tscreen>
<verb>
options SYSVSHM
</verb>
</tscreen>
The linux system calls require 4.3BSD system call compatibility.  So
make sure you have the following.
<tscreen>
<verb>
options "COMPAT_43"
</verb>
</tscreen>

If you prefer to statically link the emulator in the kernel rather than
use the loadable kernel module (LKM), then add
<tscreen>
<verb>
options  LINUX
</verb>
</tscreen>
Then run config and install the new kernel as described in the
<ref id="kernelconfig" name="kernel configuration"> section.

If you decide to use the LKM you must also install the loadable
module.   A mismatch of versions between the kernel and loadable
module can cause the kernel to crash, so the safest thing to do is to
reinstall the LKM when you install the kernel.
<tscreen>
<verb>
% cd /usr/src/lkm/linux
% make all install
</verb>
</tscreen>
Once you have installed the kernel and the LKM, you can invoke
`linux' as root to load the LKM.
<tscreen>
<verb>
% linux
Linux emulator installed
Module loaded as ID 0
%
</verb>
</tscreen>
To see whether the LKM is loaded, run `modstat'.
<tscreen>
<verb>
% modstat
Type     Id Off Loadaddr Size Info     Rev Module Name
EXEC      0   3 f0baf000 0018 f0bb4000   1 linux_emulator
%
</verb>
</tscreen>
You can cause the LKM to be loaded when the system boots in either of
two ways.  On FreeBSD 2.2-RELEASE and 2.1-STABLE enable it in
/etc/sysconfig
<tscreen>
<verb>
linux=YES
</verb>
</tscreen>
by changing it from NO to YES.  FreeBSD 2.1 RELEASE and earlier do not
have such a line and on those you will need to edit /etc/rc.local to
add the following line.
<tscreen>
<verb>
linux
</verb>
</tscreen>

<sect1><heading>Installing Linux Emulation in 2.2-RELEASE and later</heading>

<p>It is no longer necessary to specify ``options LINUX''
or ``options COMPAT_LINUX''.  Linux emulation is done with an LKM 
(``Loadable Kernel Module'') so it can be installed on the fly without
having to reboot.  You will need the following things in your startup files, 
however:
<enum>
<item> In /etc/sysconfig, you need the following line:
<tscreen>
<verb>
linux=YES
</verb>
</tscreen>
<item> This, in turn, triggers the following action in /etc/rc.i386:
<tscreen>
<verb>
# Start the Linux binary emulation if requested.
if [ "X${linux}" = X"YES" ]; then
        echo -n ' ';            linux
        # XXX BOGUS - Linux script shouldn't make any output on success
fi
</verb>
</tscreen>
</enum>

<p>If you want to verify it is running, modstat will do that:
<tscreen>
<verb>
% modstat
Type     Id Off Loadaddr Size Info     Rev Module Name
EXEC      0   4 f09e6000 001c f09ec010   1 linux_mod
%
</verb>
</tscreen>
However, there have been reports that this fails on some 2.2-RELEASE and
later systems.  If for some reason you cannot load the linux
LKM, then statically link the emulator in the kernel by adding
<tscreen>
<verb>
options  LINUX
</verb>
</tscreen>
to your kernel config file.  Then run config and install the new
kernel as described in the <ref id="kernelconfig" name="kernel
configuration"> section.

<sect1><heading>Installing Linux Runtime Libraries</heading>

<sect2><heading>Installing using the linux_lib port</heading>

<p>Most linux applications use shared libraries, so you are still not
done until you install the shared libraries.  It is possible to do
this by hand, however, it is vastly simpler to just grab the
linux_lib port:
<tscreen>
<verb>
% cd /usr/ports-current/emulators/linux_lib
% make all install
</verb>
</tscreen>

and you should have a working linux emulator.  Legend (and the mail
archives :-) seems to hold that Linux emulation works best with
linux binaries linked against the ZMAGIC libraries; QMAGIC libraries
(such as those used in Slackware V2.0) may tend to give the
Linuxulator heartburn.  As of this writing (March 1996) ELF emulation
is still in the formulative stages but seems to work pretty well.  Also, 
expect some programs to complain about incorrect minor versions.  In 
general this does not seem to be a problem.

<sect2><heading>Installing libraries manually</heading>

<p>If you do not have the ``ports'' distribution, you can install the
libraries by hand instead.  You will need the Linux shared libraries
that the program depends on and the runtime linker.  Also, you will
need to create a "shadow root" directory, /compat/linux, for Linux
libraries on your FreeBSD system.  Any shared libraries opened by
Linux programs run under FreeBSD will look in this tree first.  So, if
a Linux program loads, for example, /lib/libc.so, FreeBSD will first
try to open /compat/linux/lib/libc.so, and if that does not exist then
it will try /lib/libc.so.  Shared libraries should be installed in the
shadow tree /compat/linux/lib rather than the paths that the Linux
ld.so reports.


FreeBSD-2.2-RELEASE and later works slightly differently with respect to
/compat/linux.  On -CURRENT, all files, not just libraries, are
searched for from the ``shadow root'' /compat/linux.

Generally, you will need to look for the shared libraries that Linux 
binaries depend on only the first few times that you install a Linux 
program on your FreeBSD system. After a while, you will have a sufficient
set of Linux shared libraries on your system to be able to run newly 
imported Linux binaries without any extra work.

<sect2><heading>How to install additional shared libraries</heading>

<p>What if you install the linux_lib port and your application still
complains about missing shared libraries?  How do you know which
shared libraries Linux binaries need, and where to get them?
Basically, there are 2 possibilities (when following these
instructions: you will need to be root on your FreeBSD system to do
the necessary installation steps).

<p>If you have access to a Linux system, see what shared libraries
it needs, and copy them to your FreeBSD system. Example: you have
just ftp'ed the Linux binary of Doom. Put it on the Linux
system you have access to, and check which shared libraries it
needs by running `ldd linuxxdoom':

<tscreen>
<verb>
% ldd linuxxdoom
libXt.so.3 (DLL Jump 3.1) => /usr/X11/lib/libXt.so.3.1.0
libX11.so.3 (DLL Jump 3.1) => /usr/X11/lib/libX11.so.3.1.0
libc.so.4 (DLL Jump 4.5pl26) => /lib/libc.so.4.6.29
</verb>
</tscreen>

<p>You would need go get all the files from the last column, and
put them under /compat/linux, with the names in the first column
as symbolic links pointing to them. This means you eventually have
these files on your FreeBSD system:
<tscreen>
<verb>
/compat/linux/usr/X11/lib/libXt.so.3.1.0
/compat/linux/usr/X11/lib/libXt.so.3 -> libXt.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3.1.0
/compat/linux/usr/X11/lib/libX11.so.3 -> libX11.so.3.1.0
/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29
</verb>
</tscreen>

<p>Note that if you already have a Linux shared library with a
matching major revision number to the first column of the 'ldd'
output, you will not need to copy the file named in the last column to
your system, the one you already have should work. It is advisable to
copy the shared library anyway if it is a newer version, though. You
can remove the old one, as long as you make the symbolic link point to
the new one. So, if you have these libraries on your system:
<tscreen>
<verb>
/compat/linux/lib/libc.so.4.6.27
/compat/linux/lib/libc.so.4 -> libc.so.4.6.27
</verb>
</tscreen>

and you find a new binary that claims to require a later version
according to the output of ldd:
<tscreen>
<verb>
libc.so.4 (DLL Jump 4.5pl26) -> libc.so.4.6.29
</verb>
</tscreen>

If it is only one or two versions out of date in the in the trailing
digit then do not worry about copying /lib/libc.so.4.6.29 too, because
the program should work fine with the slightly older version.
However, if you like you can decide to replace the libc.so anyway, and
that should leave you with:
<tscreen>
<verb>
/compat/linux/lib/libc.so.4.6.29
/compat/linux/lib/libc.so.4 -> libc.so.4.6.29
</verb>
</tscreen>

<p>Please note that the symbolic link mechanism is <em>only</em>
needed for Linux binaries, the FreeBSD runtime linker takes care of
looking for matching major revision numbers itself, you do not need to
worry about that.

<sect2><heading>Configuring the ld.so -- for FreeBSD 2.2-RELEASE only</heading>

<p>This section applies only to FreeBSD 2.2-RELEASE and later.  Those running
2.1-STABLE should skip this section.

<p>Finally, if you run FreeBSD 2.2-RELEASE you must make sure that you
have the Linux runtime linker and its config files on your system. You
should copy these files from the Linux system to their appropriate
place on your FreeBSD system (to the /compat/linux tree):
<tscreen>
<verb>
/compat/linux/lib/ld.so
/compat/linux/etc/ld.so.config
</verb>
</tscreen>

<p>If you do not have access to a Linux system, you should get the
extra files you need from various ftp sites.  Information on where to
look for the various files is appended below. For now, let us assume
you know where to get the files.

<p>
Retrieve the following files (all from the same ftp site to avoid any
version mismatches), and install them under /compat/linux
(i.e. /foo/bar is installed as /compat/linux/foo/bar):
<tscreen>
<verb>
/sbin/ldconfig
/usr/bin/ldd
/lib/libc.so.x.y.z
/lib/ld.so
</verb>
</tscreen>

<p>ldconfig and ldd do not necessarily need to be under /compat/linux,
you can install them elsewhere in the system too. Just make sure they
do not conflict with their FreeBSD counterparts. A good idea would be
to install them in /usr/local/bin as ldconfig-linux and ldd-linux.
<p>
Create the file /compat/linux/etc/ld.so.conf, containing the
directories in which the Linux runtime linker should look
for shared libs. It is a plain text file, containing a directory
name on each line. /lib and /usr/lib are standard, you could
add the following:
<tscreen>
<verb>
/usr/X11/lib
/usr/local/lib
</verb>
</tscreen>

<p>When a linux binary opens a library such as /lib/libc.so the
emulator maps the name to /compat/linux/lib/libc.so internally.  All
linux libraries should be installed under /compat/linux (e.g.
/compat/linux/lib/libc.so, /compat/linux/usr/X11/lib/libX11.so, etc.)
in order for the emulator to find them.

<p>Those running FreeBSD 2.2-RELEASE should run the Linux ldconfig program.
<tscreen>
<verb>
% cd /compat/linux/lib
% /compat/linux/sbin/ldconfig 
</verb>
</tscreen>

<p>Ldconfig is statically linked, so it does not need any shared
libraries to run.  It creates the file /compat/linux/etc/ld.so.cache
which contains the names of all the shared libraries. It should rerun
to recreate this file whenever you install additional shared
libraries.

On 2.1-STABLE do not install /compat/linux/etc/ld.so.cache or run
ldconfig because in 2.1-STABLE the syscalls are implemented
differently and ldconfig is not needed or used.

<p>You should now be set up for Linux binaries which only need a
shared libc. You can test this by running the Linux ldd on
itself. Suppose that you have it installed as ldd-linux, it should
produce something like:
<tscreen>
<verb>
% ldd-linux `which ldd-linux`
libc.so.4 (DLL Jump 4.5pl26) => /lib/libc.so.4.6.29
</verb>
</tscreen>

<p>This being done, you are ready to install new Linux binaries.
Whenever you install a new Linux program, you should check if it needs
shared libraries, and if so, whether you have them installed in the
/compat/linux tree. To do this, you run the Linux version ldd on the
new program, and watch its output.  ldd (see also the manual page for
ldd(1)) will print a list of shared libraries that the program depends
on, in the form majorname (jumpversion) => fullname.

<p>If it prints "not found" instead of fullname it means that you
need an extra library. Which library this is, is shown in majorname,
which will be of the form libXXXX.so.N You will need to find a
libXXXX.so.N.mm on a Linux ftp site, and install it on your
system. The XXXX (name) and N (major revision number) should match;
the minor number(s) mm are less important, though it is advised to
take the most recent version.

<sect1><heading>Configuring the host name resolver</heading>

<p>If DNS does not work or you get the messages
<tscreen>
<verb>
resolv+: "bind" is an invalid keyword
resolv+: "hosts" is an invalid keyword
</verb>
</tscreen>

then you need to configure a /compat/linux/etc/host.conf file
containing:
<tscreen>
<verb>
order hosts, bind
multi on
</verb>
</tscreen>

where the order here specifies that /etc/hosts is searched first and
DNS is searched second.  When /compat/linux/etc/host.conf is not
installed linux applications find FreeBSD's /etc/host.conf and
complain about the incompatible FreeBSD syntax.  You should remove
`bind,' if you have not configured a name-server using the
/etc/resolv.conf file.

<p>Lastly, those who run 2.1-STABLE need to set an the
RESOLV_HOST_CONF environment variable so that applications will know
how to search the host tables.  If you run FreeBSD 2.2-RELEASE can
skip this.  For the /bin/csh shell use:
<tscreen>
<verb>
setenv RESOLV_HOST_CONF /compat/linux/etc/host.conf
</verb>
</tscreen>

For /bin/sh use:
<tscreen>
<verb>
RESOLV_HOST_CONF=/compat/linux/etc/host.conf; export RESOLV_HOST_CONF
</verb>
</tscreen>

<sect1><heading>Finding the necessary files</heading>

<p>Note: the information below is valid as of the time this document
was written, but certain details such as names of ftp sites,
directories and distribution names may have changed by the time you
read this.

<p>Linux is distributed by several groups that make their own set
of binaries that they distribute. Each distribution has its own
name, like ``Slackware'' or ``Yggdrasil''. The distributions are
available on a lot of ftp sites. Sometimes the files are unpacked,
and you can get the individual files you need, but mostly they
are stored in distribution sets, usually consisting of subdirectories
with gzipped tar files in them. The primary ftp sites for the
distributions are:
<verb>
sunsite.unc.edu:/pub/Linux/distributions
tsx-11.mit.edu:/pub/linux/distributions
</verb>

<p>
Some European mirrors:
<verb>
ftp.luth.se:/pub/linux/distributions
ftp.demon.co.uk:/pub/linux/distributions
src.doc.ic.ac.uk:/packages/linux/distributions
</verb>

<p>For simplicity, let us concentrate on Slackware here. This
distribution consists of a number of subdirectories, containing
separate packages.  Normally, they are controlled by an install
program, but you can retrieve files "by hand" too. First of all, you
will need to look in the "contents" subdir of the distribution. You
will find a lot of small text files here describing the contents of the
separate packages. The fastest way to look something up is to retrieve
all the files in the contents subdirectory, and grep through them for
the file you need. Here is an example of a list of files that you
might need, and in which contents-file you will find it by grepping
through them:
<tabular ca=ll>
Library		<colsep>Package		<rowsep>
ld.so		<colsep>ldso   		<rowsep>
ldconfig	<colsep>ldso   		<rowsep>
ldd		<colsep>ldso   		<rowsep>
libc.so.4	<colsep>shlibs 		<rowsep>
libX11.so.6.0	<colsep>xf_lib 		<rowsep>
libXt.so.6.0	<colsep>xf_lib 		<rowsep>
libX11.so.3	<colsep>oldlibs		<rowsep>
libXt.so.3	<colsep>oldlibs		<rowsep>
</tabular>

<p>So, in this case, you will need the packages ldso, shlibs, xf_lib
and oldlibs.  In each of the contents-files for these packages, look
for a line saying ``PACKAGE LOCATION'', it will tell you on which `disk'
the package is, in our case it will tell us in which subdirectory we
need to look.  For our example, we would find the following locations:
<tabular ca=ll>
Package                 <colsep>Location	<rowsep>
ldso                    <colsep>diska2		<rowsep>
shlibs                  <colsep>diska2		<rowsep>
oldlibs                 <colsep>diskx6		<rowsep>
xf_lib                  <colsep>diskx9		<rowsep>
</tabular>

<p>The locations called ``diskXX'' refer to the ``slakware/XX''
subdirectories of the distribution, others may be found in the
``contrib'' subdirectory.  In this case, we could now retrieve the
packages we need by retrieving the following files (relative to
the root of the Slackware distribution tree):
<tscreen>
<verb>
slakware/a2/ldso.tgz
slakware/a2/shlibs.tgz
slakware/x6/oldlibs/tgz
slakware/x9/xf_lib.tgz
</verb>
</tscreen>

<p>Extract the files from these gzipped tarfiles in your
/compat/linux directory (possibly omitting or afterwards
removing files you do not need), and you are done.

<p><bf>See also:</bf>
<verb>
ftp.freebsd.org:pub/FreeBSD/2.0.5-RELEASE/xperimnt/linux-emu/README

/usr/src/sys/i386/ibcs2/README.iBCS2
</verb>

<sect><heading>How to Install Mathematica on FreeBSD<label id="mathematica"></heading>

<p><em>Contributed by &a.rich and &a.chuck</em>

This document shows how to install the Linux binary
distribution of Mathematica 2.2 on FreeBSD 2.1.

<p>Mathematica supports Linux but not FreeBSD as it stands.  So once
you have configured your system for Linux compatibility you have most
of what you need to run Mathematica.

<p>For those who already have the student edition of
Mathematica for DOS the cost of upgrading to the Linux
version at the time this was written, March 1996, was
&dollar;45.00.  It can be ordered directly from Wolfram at
(217) 398-6500 and paid for by credit card.

<sect1><heading>Unpacking the Mathematica distribution</heading>
<p>The binaries are currently distributed by Wolfram on CDROM.
The CDROM has about a dozen tar files, each of which is a binary
distribution for one of the supported architectures.  The one
for Linux is named LINUX.TAR.  You can, for example, unpack this
into /usr/local/Mathematica:
<tscreen>
<verb>
% cd /usr/local
% mkdir Mathematica
% cd Mathematica
% tar -xvf /cdrom/LINUX.TAR
</verb>
</tscreen>

<sect1><heading>Obtaining your Mathematica Password</heading>
<p>Before you can run Mathematica you will have to obtain
a password from Wolfram that corresponds to your
`machine ID.'

<p>Once you have installed the linux compatibility runtime
libraries and unpacked the mathematica you can obtain
the `machine ID' by running the program `mathinfo' in
the Install directory.
<tscreen>
<verb>
% cd /usr/local/Mathematica/Install
% mathinfo
LINUX: 'ioctl' fd=5, typ=0x89(), num=0x27 not implemented
richc.isdn.bcm.tmc.edu   9845-03452-90255
%
</verb>
</tscreen>
So, for example, the `machine ID' of `richc' is `9845-03452-90255'.
You can ignore the message about the ioctl that is not
implemented.  It will not prevent Mathematica from running
in any way and you can safely ignore it, though you
will see the message every time you run Mathematica.

<p>When you register with Wolfram, either by email, phone
or fax, you will give them the 'machine ID' and they will
respond with a corresponding password consisting of
groups of numbers.  You need to add them both along
with the machine name and license number in your
mathpass file.

You can do this by invoking:
<tscreen>
<verb>
% cd /usr/local/Mathematica/Install
% math.install
</verb>
</tscreen>
It will ask you to enter your license number and the
Wolfram supplied password.  If you get them mixed up or
for some reason the math.install fails, That is OK,
because you can simply edit the file 'mathpass' in this
same directory to correct the info manually.

<p>After getting past the password, math.install will ask
you if you accept their canned install defaults, or if
you want to use your own.  If you are like us and
distrust all install programs, you probably want to
specify the actual directories.  Beware.  Although the
math.install program asks you to specify directories,
it will not create them for you, so you should perhaps
have a second window open with another shell so that
you can create them before you give them to the install
program.  Or, if it fails, you
can create the directories and then restart the
math.install program.  The directories we chose to
create beforehand and specify to  math.install were:
<tscreen>
<verb>
/usr/local/Mathematica/bin       for binaries
/usr/local/Mathematica/man/man1  for man pages
/usr/local/Mathematica/lib/X11   for the XKeysymb file
</verb>
</tscreen>
You can also tell it to use /tmp/math.record for the
system record file, where it puts logs of sessions.
After this math.install will continue on to
unpacking things and placing everything where it should
go.

<p>The Mathematica Notebook feature is included separately,
as the X Front End, and you have to install it separately.
To get the X Front End stuff correctly installed, cd
into the /usr/local/Mathematica/FrontEnd directory and
executed the ./xfe.install shell script.  You will have
to tell it where to put things, but you do not have to
create any directories because it uses all the same
directories that had been created for math.install.
When it finished, there should be a new shell script in
/usr/local/Mathematica/bin called "mathematica".

<p>Lastly, you need to modify each of the shell scripts that
Mathematica has installed.  At the beginning of every shell script in
/usr/local/Mathematica/bin add the following line:
<tscreen>
<verb>
XKEYSYMDB=/usr/local/Mathematica/lib/X11/XKeysymDB; export XKEYSYMDB
</verb>
</tscreen>
This tells Mathematica were to find its own version of the key
mapping file XKeysymDB.  Without this you will get pages of error
messages about missing key mappings.

On 2.1-STABLE you need to add the following as well:
<tscreen>
<verb>
RESOLV_HOST_CONF=/compat/linux/etc/host.conf; export RESOLV_HOST_CONF
</verb>
</tscreen>
This tells Mathematica to use the linux version of host.conf.  This
file has a different syntax from FreeBSD's host.conf, so you will get an
error message about /etc/host.conf if you leave this out.

<p>You might want to also modify your /etc/manpath.config file
to read the new man directory, and you may need to edit your
~/.cshrc file to add /usr/local/Mathematica/bin
to your path.

<p>That is about all it takes, With this you should be able
to type "mathematica" and get a really slick looking
Mathematica Notebook screen up.  Mathematica has included
the Motif user interfaces, but it is compiled in statically,
so you do not need the Motif libraries.  Good luck doing this
yourself!

<sect1><heading>Bugs</heading>

<p>The Notebook front end is known to hang sometimes when reading
notebook files with an error messages similar to:
<tscreen>
<verb>
File .../Untitled-1.mb appears to be broken for OMPR.257.0
</verb>
</tscreen>

We have not found the cause for this, but it only affects the
Notebook's X Window front end, not the mathematica engine itself.  So
the command line interface invoked by 'math' is unaffected by this
bug.

<sect1><heading>Acknowledgments</heading>

<p>A well-deserved thanks should go to &a.sos; and &a.peter;
who made linux emulation what it is today, and Michael Smith who
drove these two guys like dogs to get it to the point where it runs
Linux binaries better than linux!   :-) 
