6.6 Main System Applications

Beyond the kernel's functionality and the root filesystem's structure, Linux inherits Unix's very rich command set. The problem is that a standard workstation or server distribution comes equipped with thousands of command binaries, each providing its own set of capabilities. Obviously, developers cannot be expected to cross-compile such a large amount of binaries one by one, nor do most embedded systems require such a large body of binaries.

There are, therefore, two possibilities: either we choose a few select standard commands, or we try to group as many commands as possible into a very few trimmed-down applications that implement the essential overall functionality. In the following, we will start by discussing the first approach. I do not favor this approach, however, because it is tedious at best. Instead, I will mostly focus on the second approach and the various projects that implement it. In particular, we will discuss BusyBox, TinyLogin, and Embutils, which are the main packages used for this purpose.

6.6.1 Complete Standard Applications

If you would like to selectively include some of the standard applications found in mainstream distributions, your best bet is to start with the Linux From Scratch project located at http://www.linuxfromscratch.org/. This project aims at providing explanations and links to packages to help you build your own custom distributions. The Linux From Scratch book available through the project's web site is its main documentation. It includes instructions and links to build each application one by one. For each package, the instructions provide build-time and disk-space estimates.

Alternatively, you can download applications off the Net one by one and follow the instructions of each package for compiling and cross-compiling. Because few packages include full cross-compilation instructions, you may need to look in the packages' Makefiles to determine the appropriate build flags or make the proper modifications for the packages to cross-compile adequately.

6.6.2 BusyBox

The BusyBox project was initiated by Bruce Perens in 1996 to help build install disks for the Debian distribution. Since 1999, the project has been maintained by Erik Andersen, the maintainer of uClibc, first as part of Lineo's open source efforts and currently as a vendor-independent project. During this time, the BusyBox project has grown extensively and is now one of the corner stones of many embedded Linux systems. It is included in most embedded Linux distributions and has a very active user community. The project's current location is http://www.busybox.net/. The project's web site includes documentation, links, and a mailing list archive. The BusyBox package is available under the terms of the GNU GPL from this same web site.

Enthusiasm for BusyBox stems from the functionality it provides while still remaining a very small-sized application. BusyBox implements many commands. Here are a few: ar, cat, chgrp, chmod, chown, chroot, cp, cpio, date, dd, df, dmesg, dos2unix, du, echo, env, expr, find, grep, gunzip, gzip, halt, id, ifconfig, init, insmod, kill, killall, ln, ls, lsmod, md5sum, mkdir, mknod, modprobe, more, mount, mv, ping, ps, pwd, reboot, renice, rm, rmdir, rmmod, route, rpm2cpio, sed, stty, swapon, sync, syslogd, tail, tar, telnet, tftp, touch, traceroute, umount, uname, uuencode, vi, wc, which, and whoami.

Although BusyBox does not support all the options provided by the commands it replaces, the subset it provides is sufficient for most typical uses. See the docs directory of the BusyBox distribution for the documentation in a number of different formats.

BusyBox supports all the architectures covered in Chapter 3. It can be linked both statically and dynamically to either glibc or uClibc. You can also modify the BusyBox default build configuration to remove support for the commands you are unlikely to use.

6.6.2.1 Setup

First, you need to download a copy of the BusyBox package from the project's web site and into your ${PRJROOT}/sysapps directory. For my control module, I will be using BusyBox 0.60.5.

Once the package is extracted, we can move into its directory for the rest of the setup:

$ cd ${PRJROOT}/sysapps/busybox-0.60.5

Although the CVS version includes a terminal-based menu utility for configuring options, such as the one I described for uClibc in Chapter 4, the main stable version, such as the one I'm using, has to be configured by editing the appropriate file. The main file for configuring options is Config.h. This file contains C-language #define statements for each option. By commenting out an option's #define using // (slash slash) you effectively disable this option.

There are two types of options that can be configured: command support options and feature support options. Disabling or enabling a command support option removes or adds the corresponding command. Changing the #define BB_MKNOD line to //#define BB_MKNOD disables support for the mknod command in BusyBox. Feature support options have a similar behavior. Features, however, are not necessarily related to a particular command. Consequently, every #define BB_FEATURE_... line is preceded with a comment line describing the feature.

Make sure you verify the command support options selected by default. Some important commands, such as ifconfig, insmod, and ping, are disabled by default.

In addition to the configuration file, the main Makefile contains a few flags to control the way BusyBox is built. Most of these flags are used during the development of BusyBox for debugging purposes and are disabled in the standard distribution. The only flag you may be interested in modifying is the DOSTATIC flag. When set to true, the resulting BusyBox binary is statically linked with the C library. The default value of DOSTATIC is false, causing the binary to be dynamically linked. You can change this either by modifying the Makefile or by adding DOSTATIC=true as part of the make command.

Once BusyBox is configured, we can compile and install it. When linking with glibc, use the following command:

$ make TARGET_ARCH=ppc CROSS=powerpc-linux- \
> PREFIX=${PRJROOT}/rootfs all install

The TARGET_ARCH variable is used by the Makefile to determine whether some architecture-dependent optimizations can be carried out. CROSS is used, as in other circumstances, to specify the prefix of the cross-platform development tools. Finally, PREFIX is set to the root filesystem base directory. The Makefile will install all BusyBox's components within this directory.

To build BusyBox with uClibc instead of the GNU C library, use the following command:

$ make TARGET_ARCH=ppc CROSS=powerpc-uclibc- \
> PREFIX=${PRJROOT}/rootfs all install

BusyBox has now been installed on your target's root filesystem and is ready to be used.

6.6.2.2 Usage

To understand how best to use BusyBox, let's first take a look at the components installed on the target's root filesystem by BusyBox's build process. As expected, only one executable was installed, /bin/busybox. This is the single binary with support for all the commands configured using Config.h. This binary is never called directly, however. Instead, symbolic links bearing the original commands' names have been created to /bin/busybox. Such symbolic links have been created in all the directories in which the original commands would be found, including /bin, /sbin, /usr/bin, and /usr/sbin.

When you type a command during the system's normal operation, the busybox command is invoked via the symbolic link. In turn, busybox determines the actual command you were invoking using the name being used to run it. /bin/ls, for instance, points to /bin/busybox. When you type ls, the busybox command is called and it determines that you were trying to use the ls command, because ls is the first argument on the command line.[6]

[6] As any other application, busybox's main( ) function is passed the command line used to invoke it.

Although this scheme is simple and effective, it means you can't use arbitrary names for symbolic links. Creating a symbolic link called /bin/dir to either /bin/ls or /bin/busybox will not work, since busybox does not recognize the dir command.

Note that, though symbolic links are the usual way of linking commands to /bin/busybox, BusyBox can also be instructed to create hard links instead of symbolic ones during its installation. Its behavior at runtime is the same, however, regardless of the type of links being used.

The documentation on the project's web site, which is also provided with the package, describes all the options available for each command supported. In most cases, the options supported by BusyBox have the same function as the options provided by the original commands. For instance, Using the -al options to BusyBox's ls will have the same effect as using the same options with the original ls.

When using one of the shells provided in BusyBox, such as ash, lash, or msh, you will find it convenient to use a /etc/profile file to define a few global variables for all shell users. Here is a sample /etc/profile file for a single-user target:

# Set path
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH

In addition to setting the path, you could set the LD_LIBRARY_PATH environment variable, which is used during the startup of each application to locate the libraries it depends on. Though the default location for libraries is /lib, your system may have libraries located in other directories. If that is the case, you can force the dynamic linker to look for the other libraries by adding the appropriate directory paths to LD_LIBRARY_PATH. As with the PATH environment variable, you can add more directories to the library path by separating each directory path with a colon.

Note that on a workstation or a server LD_LIBRARY_PATH would actually be used only as a temporary holding place for new library paths. Instead, the /etc/ld.so.conf is the file to edit to permanently add another library path. This file is then used by the ldconfig command to generate /etc/ld.so.cache, which is itself read by the dynamic linker to find libraries for dynamically linked applications. Though ldconfig was generated when we compiled glibc in Chapter 4, it is a target binary and cannot be run on the host to generate a target ld.so.cache.

6.6.3 TinyLogin

Much like BusyBox, TinyLogin is a collection of many login utilities into a single binary. TinyLogin is often used in conjunction with BusyBox, although it can be used alone. Both packages are maintained by the same developers and are therefore easy to use together. Because of their common use together, the project developers have integrated all of TinyLogin's functionality into the BusyBox CVS, and once the CVS development version is released as a stable version, it will be possible to rely on a single package instead of two. There are, however, advantages to continue using the TinyLogin functionality separately from BusyBox. Mainly, many of the commands implemented in TinyLogin must run with root privileges, which in turn requires that the TinyLogin binary file belong to the root user and have its "set user" permission bit enabled?a configuration commonly known as "setuid root." Since TinyLogin uses symbolic links in the same way BusyBox does, a single binary containing the functionality of both packages would also result in having commands such as ls and cat run as root, which increases the likeliness that a programming error in one command could be exploited to gain root privileges. Though BusyBox drops its root privileges when unnecessary, and though it can be configured to check a configuration file for those commands requiring root privileges, it remains that using separate packages is the safest setup.

The TinyLogin project's web site is located at http://tinylogin.busybox.net/. It contains documentation, a mailing list archive, links to other sites, and pointers to download the TinyLogin package both using FTP or CVS. For my control module, I will be using TinyLogin 1.2.

As with BusyBox, TinyLogin supports all the architectures we discussed in depth in Chapter 3 and can be linked either statically or dynamically with glibc or uClibc. TinyLogin can effectively replace the following commands: addgroup, adduser, delgroup, deluser, getty, login, passwd, su, sulogin, and vlock.

6.6.3.1 Setup

The first step in installing TinyLogin is to download the package and extract it into your ${PRJROOT}/sysapps directory. Once this is done, we can move into the package's directory for the rest of the setup:

$ cd ${PRJROOT}/sysapps/tinylogin-1.2

The configuration of TinyLogin is done much the same as with BusyBox, by editing the Config.h configuration file and commenting out the unwanted command support options and feature options. TinyLogin also has a Makefile with similar options to BusyBox. The same rules explained above for BusyBox's Config.h file and Makefile also apply to TinyLogin.

Apart from the other options you need to configure, pay special attention to the USE_SYSTEM_PWD_GRP and USE_SYSTEM_SHADOW options in the Makefile. The explanations above the statements in the Makefile provide a good idea about the effect of these options. Mainly, USE_SYSTEM_PWD_GRP should be set to false unless you plan to use glibc's NSS libraries with a properly configured /etc/nsswitch.conf file. If you set this option to false, TinyLogin will directly use the /etc/passwd and /etc/group files instead of using the password and group functions provided by glibc.

Similarly, if you set USE_SYSTEM_SHADOW to false, TinyLogin will use its own shadow functions for accessing shadow passwords. Traditionally, /etc/passwd could be read by anyone in the system and this in turn became a security risk as more and more programs for cracking passwords were available. Hence, the use of so-called shadow passwords became the norm. When in use, the password fields in /etc/passwd only contain filler characters and the real encrypted passwords are stored in /etc/shadow, which can be read only by a process running with root privileges. Note that if you had configured uClibc without shadow password support, setting USE_SYSTEM_SHADOW to true and linking with uClibc will result in a failed build.

As with BusyBox, you can set DOSTATIC to true if you would like TinyLogin to be built statically.

Once you have completed TinyLogin's configuration, you are ready to build the package. (Instead of compiling and installing the package in the same step, as we did for BusyBox, you will first compile and then install for the reasons explained below.)

To compile TinyLogin with glibc, use the following command:

$ make CROSS=powerpc-linux- \
> PREFIX=${PRJROOT}/rootfs all

To compile TinyLogin with uClibc, use the following command:

$ make CROSS=powerpc-uclibc- \
> PREFIX=${PRJROOT}/rootfs all

Once the package has been built, you can now install the package. Because the installation process must setuid the TinyLogin binary, the installation command must be done while logged in as root:

$ su -m
Password:
# make PREFIX=${PRJROOT}/rootfs install
# exit

TinyLogin has now been installed in the target's root filesystem and is ready to be used.

6.6.3.2 Usage

The TinyLogin installation copied only one binary to the root filesystem, /bin/tinylogin. As with BusyBox, symbolic links were created with the original commands' names in the appropriate binary directories.

You will need to create appropriate group, password, and shadow password files (/etc/group, /etc/passwd, and /etc/shadow, respectively) for use by the various TinyLogin commands. Unfortunately, the TinyLogin package does not provide a means to create these files prior to having TinyLogin running on the target. Hence, you will have to copy existing files and edit them manually for use on your target's root filesystem. A simple alternative is to use those files that are part of your workstation setup and keep only those entries for users who will exist on your target as well. Usually, this ends up being only the root user.

The group and password files on your workstation can be copied as-is to your target's /etc directory. You can then edit your target's copies by hand and remove the entries that will not be used on your target. The shadow password file requires a little more care, however, since you may not want to reveal your own workstation's passwords to the users of your embedded system. To create valid entries in your target's shadow file, the simplest method is to create phony users on your workstation, set those users' passwords, and then copy the resulting entries. Here's the entry for a phony "tmp" user I added to my workstation:

tmp:$1$3cdOSELf$XWRLoKIL7vMSfLYbRCWaf/:11880:0:99999:7:-1:-1:0

I set this user's password to "root" for convenience. I then copied this entry as-is to my target's shadow file and edited the username appropriately:

root:$1$3cdOSELf$XWRLoKIL7vMSfLYbRCWaf/:11880:0:99999:7:-1:-1:0

There is now a user known as "root" with the password "root" on my target.

Remember that the password file contains the name of the shell used for each user. Since the command name for the shell provided by BusyBox is sh, and since the default on most workstations is bash, you need to change this to the shell on your target. Here is the password file entry for the root user for the same system:

root:x:0:0:root:/root:/bin/sh

By default, TinyLogin will set the path of each user as follows:

PATH=/bin:/usr/bin

If you would like to change this, you can either create a global /etc/profile file, as I explained earlier, or a .profile file in each user's home directory. You will find the following .profile file useful for the root user:

PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH

For more information on the creation and manipulation of group, password, or shadow password files, and system administration in general, see the Linux System Administrator's Guide from the LDP, Running Linux from O'Reilly, and the Linux From Scratch book I mentioned earlier.

6.6.4 embutils

embutils is a set of miniaturized and optimized replacements for mainstream Unix commands. embutils was written and is maintained by Felix von Leitner, the author of diet libc, with goals very similar to those of diet libc. Currently, embutils supports four of the architectures discussed in Chapter 3, the ARM, the i386, the PPC, and the MIPS. embutils is available from http://www.fefe.de/embutils/.[7]

[7] As with diet libc, the last slash ("/") is important.

Although embutils groups some of the commands in a single binary, its main approach is to provide one small binary for each command. embutils provides the following commands: arch, basename, cat, chmgrp, chmod, chown, chroot, chvt, clear, cp, dd, df, dirname, dmesg, domainname, du, echo, env, false, head, hostname, id, install, kill, ln, ls, md5sum, mesg, mkdir, mkfifo, mknod, mv, pwd, rm, rmdir, sleep, sleep2, soscp, sosln, soslns, sosmv, sosrm, sync, tail, tar, tee, touch, tr, true, tty, uname, uniq, wc, which, whoami, write, and yes.

As with BusyBox, not all the options provided by the full commands are supported, but the subset provided is sufficient for most system operations. In contrast to BusyBox, however, embutils can only be statically linked with diet libc. It can't be linked to any other library. Because diet libc is already very small, the resulting command binaries are reasonably small. In terms of overall size, nevertheless, BusyBox and embutils are fairly similar.

6.6.4.1 Setup

Before we start the setup, you will need to have diet libc installed on your host system as I described in Chapter 4. Now download embutils and extract it in your ${PRJROOT}/sysapps directory. For my control module, for example, I use embutils 0.15. You can then move into the package's directory for the rest of the setup:

$ cd ${PRJROOT}/sysapps/embutils-0.15

There is no configuration capability for embutils. You can, therefore, build the package right away:

$ make ARCH=ppc CROSS=powerpc-linux- all

You can then install embutils:

$ make ARCH=ppc DESTDIR=${PRJROOT}/rootfs prefix="" install

The options and variables used in the build and installation of embutils have the same meaning as those used for diet libc.

6.6.4.2 Usage

The embutils installation procedure has copied quite a few statically linked binaries to your target root filesystem's /bin directory. In contrast to BusyBox, this is the only directory where binaries have been installed.

A BusyBox-like all-in-one binary has also been installed, allinone. This binary reacts the same way as BusyBox when proper symbolic links are created to it. Note that unlike BusyBox, you need to create these symbolic links manually, since they are not created automatically by the installation scripts. allinone provides the following commands: arch, basename, chvt, clear, dmesg, dirname, domainname, echo, env, false, hostname, pwd, sleep, sync, tee, true, tty, uname, which, whoami, and yes.