BusyBox simplifies embedded Linux systems

来源:互联网 发布:js 判断是否是对象 编辑:程序博客网 时间:2024/06/06 20:16

The birth of BusyBox

BusyBox was first written by Bruce Perens in 1996 for the Debian GNU/Linux setup disk. The goal was to create a bootable GNU/Linux system on a single floppy disk that could be used as an install and rescue disk. A single floppy disk can hold around 1.4-1.7MB, so there's not much room available for the Linux kernel and associated user applications.

BusyBox license

BusyBox is licensed under the GNU General Public License (GPL). This means that if you use BusyBox in a project, you must abide by the license. You can view the license on the BusyBox Web site (see the Resources section later in this article). The BusyBox team appears to keep busy by monitoring violators of their license. In fact, they maintain a "Hall of Shame" page to document violations.

BusyBox exploits the fact that the standard Linux utilities share many common elements. For example, many file-based utilities (such as grep and find) require code to recurse a directory in search of files. When the utilities are combined into a single executable, they can share these common elements, which results in a smaller executable. In fact, BusyBox can pack almost 3.5MB of utilities into around 200KB. This provides greater functionality to bootable floppy disks and embedded devices that use Linux. You can use BusyBox with both the 2.4 and 2.6 Linux kernels.

How does BusyBox work?

To make one executable look like many executables, BusyBox exploits a seldom-used feature of argument passing to the main C function. Recall that the C main function is defined as follows:

POSIX environment

While BusyBox aims to provide a relatively complete Portable Operating System Interface (POSIX) environment, that's a desire and not a requirement. The utilities aren't complete, but they do provide the major functionality expected of them.


Listing 1. The C main function

int main( int argc, char *argv[] )

 

In this definition, argc is the number of arguments passed in (argument count) and argv is an array of strings representing options passed in from the command line (argument vector). Index 0 of argv is the program name that was invoked from the command line.

The simple C program shown in Listing 2 demonstrates BusyBox invocation. It simply emits the contents of the argv vector.


Listing 2. BusyBox uses argv[0] to determine which application to invoke

// test.c
#include <stdio.h>

int main( int argc, char *argv[] )
{
int i;

for (i = 0 ; i < argc ; i++) {
printf("argv[%d] = %s/n", i, argv[i]);
}

return 0;
}

 

Invoking this application shows that the first argument invoked is the name of the program. You can rename your executable, and you get the new name upon invocation. Further, you can create a symbolic link to your executable, and you get the symlink name when it's invoked.


Listing 3. Command testing after updating BusyBox with a new command

$ gcc -Wall -o test test.c
$ ./test arg1 arg2
argv[0] = ./test
argv[1] = arg1
argv[2] = arg2

$ mv test newtest
$ ./newtest arg1
argv[0] = ./newtest
argv[1] = arg1

$ ln -s newtest linktest
$ ./linktest arg
argv[0] = ./linktest
argv[1] = arg

 

BusyBox uses symbolic links to make one executable look like many. For each of the utilities contained within BusyBox, a symbolic link is created so that BusyBox is invoked. BusyBox then invokes the internal utility as defined by argv[0].


Configuring and building BusyBox

You can download the latest version of BusyBox from its Web site (see the Resources section). Like most open source programs, it's distributed in a compressed tarball, and you can transform it into a source tree using the command in Listing 4. (If you downloaded a version other than 1.1.1, use the appropriate version number in this and other version-specific commands.)


Listing 4. Untarring BusyBox

$ tar xvfz busybox-1.1.1.tar.gz
$

 

The result is a directory, called busybox-1.1.1, that contains the BusyBox source code. To build the default configuration, which includes almost everything with debugging disabled, use the defconfig make target:

BusyBox source tree

The source tree for BusyBox is well organized. Utilities are categorized based on their use and stored in separate subdirectories. For example, the networking utilities and daemons (such as httpd, ifconfig, and so on) are in the ./networking directory; standard module utilities (including insmod, rmmod and lsmod) are in the ./modutils directory; and editors (such as vi, and stream editors such as awk and sed) are in the ./editors directory. The makefiles and various documents for configuring, building, and installing are at the root of the tree.


Listing 5. Building the default BusyBox configuration

$ cd busybox-1.1.1
$ make defconfig
$ make
$

 

The result is a rather large BusyBox image, but it's the simplest way to get started. You can invoke this new image directly, which results in a simple Help page with the currently configured commands. To test your image, you can also invoke BusyBox with a command to execute, as shown in Listing 6.


Listing 6. Demonstrating BusyBox command execution and the ash shell in BusyBox

$ ./busybox pwd
/usr/local/src/busybox-1.1.1
$ ./busybox ash
/usr/local/src/busybox-1.1.1 $ pwd
/usr/local/src/busybox-1.1.1
/usr/local/src/busybox-1.1.1 $ exit
$

 

In this example, you invoke the pwd (print working directory) command, enter the ash shell within BusyBox, and invoke pwd within ash.


Manual configuration

If you're building an embedded device that has very specific needs, you can manually configure the contents of your BusyBox with the menuconfig make target. If you're familiar with building a Linux kernel, note that menuconfig is the same target for configuring the contents of the Linux kernel. In fact, the ncurses-based application is the same.

Using manual configuration, you can specify the commands to be included in the final BusyBox image. You can also configure the BusyBox environment, such as including support for the United States National Security Agency's (NSA) Security-Enhanced Linux (SELinux), specifying the compiler to use (for cross-compiling in an embedded environment), and whether BusyBox should be compiled statically or dynamically. Figure 1 shows the main screen for menuconfig. Here you can see the different major classes of applications (applets) that you can configure for BusyBox.


Figure 1. BusyBox configuration using menuconfig
BusyBox Configuration with menuconfig

Multiple architecture support

Being able to easily specify the cross-compiler for BusyBox means that you can build BusyBox for a wide variety of architectures. To build BusyBox for your target architecture, you need a cross-compiler and a version of the C library (uClibc or glibc) that has been compiled for the particular target architecture.

To manually configure BusyBox, use the following commands:


Listing 7. Manually configuring BusyBox

$ make menuconfig
$ make
$

 

This provides you with a BusyBox binary that can be invoked. The next step is to build an environment around BusyBox, including the symbolic links that redirect the standard Linux commands to the BusyBox binary. You can do this very simply with the following command:


Listing 8. Building the BusyBox environment

$ make install
$

 

By default, a new local subdirectory is created, called _install, which contains the basic Linux environment. At the root, you'll find a linuxrc program that links to BusyBox. The linuxrc program is useful when building an install or rescue disk (permits a modularized boot prior). Also at the root is a /sbin subdirectory that contains operating system binaries (used primarily for administration), and a /bin subdirectory that contains binaries intended for users. You can then migrate this _install directory into your target environment when building a floppy distribution or embedded initial RAM disk. You can also use the PREFIX option with the make program to redirect the install subdirectory to a new location. For example, the following code segment installs the symlinks using the /tmp/newtarget root directory instead of the ./_install directory:


Listing 9. Installing symlinks to another directory

$ make PREFIX=/tmp/newtarget install
$

 

The links that are created through the install make target come from the busybox.links file. This file is created when BusyBox is compiled, and it contains the list of commands that have been configured. When install is performed, the busybox.links file is checked for the symlinks to create.

The command links to BusyBox can also be created dynamically at runtime using BusyBox. The CONFIG_FEATURE_INSTALLER option enables this feature, which can be performed at runtime as follows:


Listing 10. Creating command links at runtime

$ ./busybox --install -s
$

 

The -s option forces symbolic links to be created (otherwise, hard links are created). This option requires that the /proc file system is present.


BusyBox build options

BusyBox includes several build options to help you build and debug the right BusyBox for you.


Table 1. Some of the make options available for BusyBox

make targetDescriptionhelpShow the complete list of make optionsdefconfigEnable a default (generic) configurationallnoconfigDisable all applications (empty configuration)allyesconfigEnable all applications (complete configuration)allbareconfigEnable all applications, but no subfeaturesconfigText-based configuratormenuconfigN-curses (menu-based) configuratorallBuild the BusyBox binary and documentation (./docs)busyboxBuild the BusyBox binarycleanClean the source treedistcleanCompletely clean the source treesizesEmit the text/data sizes of the enabled applications

When a configuration is defined, you just need to type make to actually build the BusyBox binary. For example, to build BusyBox for all applications, you can do the following:


Listing 11. Building the BusyBox binary

$ make allyesconfig
$ make
$

 


Shrinking BusyBox

If you're really serious about shrinking the size of your BusyBox image, here are two things to keep in mind:

  1. Never build as a static binary (which includes all needed libraries in the image). Instead, if you build as a shared image, it uses the available libraries that are used by other applications (for example, /lib/libc.so.X).
  2. Build with the uClibc, which is a size-optimized C library that was developed for embedded systems, rather than building with the standard glibc (GNU C library).

Options supported in BusyBox commands

The commands in BusyBox don't support all of the options commonly available, but they do contain the options that are used most often. If you need to know which options are supported for a command, you can invoke and use the --help option, as shown in Listing 12.


Listing 12. Invoking the --help option

$ ./busybox wc --help
BusyBox v1.1.1 (2006.04.09-15:27+0000) multi-call binary

Usage: wc [OPTION]... [FILE]...

Print line, word, and byte counts for each FILE, and a total line if
more than one FILE is specified. With no FILE, read standard input.

Options:
-cprint the byte counts
-lprint the newline counts
-Lprint the length of the longest line
-wprint the word counts

$

 

This particular data is available only if the CONFIG_FEATURE_VERBOSE_USAGE option is enabled. Without this option, you won't get the verbose data, but you'll also save about 13KB.


Adding new commands to BusyBox

Adding a new command to BusyBox is simple because of its well-defined architecture. The first step is to choose a location for your new command's source. Select the location based on the type of command (networking, shell, and so on), and be consistent with other commands. This is important because your new command will ultimately show up in the particular configuration menu for menuconfig (in this case, in the Miscellaneous Utilities menu).

For this example, I've called the new command (newcmd) and placed it in the ./miscutils directory. The new command's source is shown in Listing 13.


Listing 13. Source for new command to integrate into BusyBox

#include "busybox.h"

int newcmd_main( int argc, char *argv[] )
{
int i;

printf("newcmd called:/n");

for (i = 0 ; i < argc ; i++) {

printf("arg[%d] = %s/n", i, argv[i]);

}

return 0;
}

 

Next, add your new command source to Makefile.in in the chosen subdirectory. In this example, I update ./miscutils/Makefile.in. Add your new command in alphabetical order to maintain consistency with the existing commands:


Listing 14. Adding command to Makefile.in

MISCUTILS-$(CONFIG_MT)          += mt.o
MISCUTILS-$(CONFIG_NEWCMD) += newcmd.o
MISCUTILS-$(CONFIG_RUNLEVEL) += runlevel.o

 

Next, update the configuration file, again within the ./miscutils directory, to make your new command visible within the configuration process. This file is called Config.in, and your new command is added in alphabetical order:


Listing 15. Adding command to Config.in

config CONFIG_NEWCMD
bool "newcmd"
default n
help
newcmd is a new test command.

 

This structure defines a new config entry (through the config keyword) and then the config option (CONFIG_NEWCMD). Your new command will either be enabled or disabled, so use the bool (Boolean) menu attribute for configuration. Its default is disabled (n for No), and you end with a short Help description. You can see the entire grammar for the configuration syntax in the source tree at ./scripts/config/Kconfig-language.txt.

Next, update the ./include/applets.h file to include your new command. Add the following line to this file, remembering to keep it in alphabetical order. It's important to maintain this order, otherwise your command will not be found.


Listing 16. Adding command to applets.h

USE_NEWCMD(APPLET(newcmd, newcmd_main, _BB_DIR_USER_BIN, _BB_SUID_NEVER))

 

This defines your command name (newcmd), its function name in the Busybox source (newcmd_main), where the link will be created for this new command (in this case, in the /usr/bin directory), and, finally, whether the command has permissions to set the user id (in this case, no).

The penultimate step is to add detailed Help information to the ./include/usage.h file. As you'll see from examples in this file, usage information can be quite verbose. In this case, I've just added a little information so I can build the new command:


Listing 17. Adding help information to usage.h

#define newcmd_trivial_usage"None"
#define newcmd_full_usage"None"

 

The final step is to enable your new command (through make menuconfig and then enable the option in the Miscellaneous Utilities menu) and then build BusyBox with make.

With your new BusyBox available, you can test your new command, as shown in Listing 18.


Listing 18. Testing your new command

$ ./busybox newcmd arg1
newcmd called:
arg[0] = newcmd
arg[1] = arg1
$ ./busybox newcmd --help
BusyBox v1.1.1 (2006.04.12-13:47+0000) multi-call binary

Usage: newcmd None

None

 

That's it! The BusyBox developers made a tool that's not only great but also simple to extend.


Summary

BusyBox is a great tool for building memory-constrained embedded systems and also floppy-disk based systems. BusyBox shrinks the size of a variety of necessary tools and utilities by pulling them together into a single executable and allowing them to share the common aspects of their code. BusyBox is a useful tool for your embedded toolbox and, therefore, worth your time to explore.

 

Resources

Learn

  • uClibc is a reduced memory footprint replacement for glibc. While requiring fewer resources than glibc, porting applications to uClibc typically requires only a recompile.
  • The POSIX FAQ at the Open Group can help you learn more about POSIX. Part three of this specification details shells and utilities in particular.
  • LinuxTiny is a series of patches that reduce the memory and disk footprint of the 2.6 Linux kernel to as little as 2MB of RAM. If you're interested in shrinking the 2.6 Linux kernel, check out this work by Matt Mackall.
  • In the developerWorks Linux zone, find more resources for Linux developers.
  • Stay current with developerWorks technical events and Webcasts.

Get products and technologies

  • Download the latest release of BusyBox. You'll also find the latest news, erratum, and tutorials for using and amending BusyBox.
  • With IBM trial software, available for download directly from developerWorks, build your next development project on Linux.

Discuss

  • Check out developerWorksblogs and get involved in the developerWorks community.

About the author

M. Tim Jones

M. Tim Jones is an embedded software architect and the author of GNU/Linux Application Programming, AI Application Programming, and BSD Sockets Programming from a Multilanguage Perspective.His engineering background ranges from the development of kernels forgeosynchronous spacecraft to embedded systems architecture andnetworking protocols development. Tim is a Consultant Engineer forEmulex Corp. in Longmont, Colorado.

原创粉丝点击