11.3. BusyBox OperationWhen you build BusyBox, you end up with a binary called, you guessed it, busybox. BusyBox can be invoked from the binary name itself, but it is more usually launched via a symlink. When BusyBox is invoked without command line parameters, it produces a list of the functions that were enabled via the configuration. Listing 11-3 shows such an output (it has been formatted slightly to fit the page width). Listing 11-3. BusyBox Usage
From Listing 11-3, you can see the list of functions that are enabled in this BusyBox build. They are listed in alphabetical order from ash (a shell optimized for small memory footprint) to zcat, a utility used to decompress the contents of a compressed file. This is the default set of utilities enabled in this particular BusyBox snapshot. To invoke a particular function, execute busybox with one of the defined functions passed on the command line. Thus, to display a listing of files in the current directory, execute this command: [root@coyote]# ./busybox ls Another important message from the BusyBox usage message in Listing 11-3 is the short description of the program. It describes BusyBox as a multicall binary, combining many common utilities into a single executable. This is the purpose of the symlinks mentioned earlier. BusyBox was intended to be invoked by a symlink named for the function it will perform. This removes the burden of having to type a two-word command to invoke a given function, and it presents the user with a set of familiar commands for the similarly named utilities. Listings 11-4 and 11-5 should make this clear. Listing 11-4. BusyBox Symlink StructureTop Level
Listing 11-4 shows the target directory structure as built by the BusyBox package via the make install command. The executable busybox file is found in the /bin directory, and symlinks have been populated throughout the rest of the structure pointing back to /bin/busybox. Listing 11-5 expands on the directory structure of Listing 11-4. Listing 11-5. BusyBox Symlink StructureTree Detail
The output of Listing 11-5 has been significantly truncated for readability and to avoid a three-page listing. Each line containing an ellipsis (...) indicates that this listing has been pruned to show only the first few and last few entries of that given directory. In actuality, more than 100 symlinks can be populated in these directories, depending on what functionality you have enabled using the BusyBox configuration utility. Notice the busybox executable itself, the second entry from the /bin directory. Also in the /bin directory are symlinks pointing back to busybox for ash, cat, cp... all the way to zcat. Again, the entries between cp and zcat have been omitted from this listing for readability. With this symlink structure, the user simply enters the actual name of the utility to invoke its functionality. For example, to configure a network interface using the busybox ifconfig utility, the user might enter a command similar to this: $ ifconfig eth1 192.168.1.14 This would invoke the busybox executable through the ifconfig symlink. BusyBox examines how it was calledthat is, it reads argv[0] to determine what functionality is executed. 11.3.1. BusyBox InitNotice the symlink in Listing 11-5 called init. In Chapter 6 "System Initialization," you learned about the init program and its role in system initialization. Recall that the kernel attempts to execute a program called /sbin/init as the last step in kernel initialization. There is no reason why BusyBox can't emulate the init functionality, and that's exactly how the system illustrated by Listing 11-5 is configured. BusyBox handles the init functionality. BusyBox handles system initialization differently from standard System V init. A Linux system using the System V (SysV) initialization as described in Chapter 6 requires an inittab file accessible in the /etc directory. BusyBox also reads an inittab file, but the syntax of the inittab file is different. In general, you should not need to use an inittab if you are using BusyBox. I agree with the BusyBox man page: If you need run levels, use System V initialization.[2]
Let's see what this looks like on an embedded system. We have created a small root file system based on BusyBox. We configured BusyBox for static linking, eliminating the need for any shared libraries. Listing 11-6 contains a tree listing of this root file system. We built this small file system using the steps outlined in Chapter 9, "File Systems," Section 9.10, "Building a Simple File System." We do not detail the procedure again here. The files in our simple file system are those shown in Listing 11-6. Listing 11-6. Minimal BusyBox Root File System
This BusyBox-based root file system occupies little more than the size needed for busybox itself. In this configuration, using static linking and supporting nearly 100 utilities, the BusyBox executable came in at less than 1MB: # ls -l /bin/busybox -rwxr-xr-x 1 root root 824724 Dec 3 2005 /bin/busybox Now let's see how this system behaves. Listing 11-7 captures the console output on power-up on this BusyBox-based embedded system. Listing 11-7. BusyBox Default Startup
The example of Listing 11-7 was run on an embedded board configured for NFS root mount. We export a directory on our workstation that contains the simple file system image detailed in Listing 11-6. As oneof the final steps in the boot process, the Linux kernel on our target board mounts a root file system via NFS. When the kernel attempts to execute /sbin/init, it fails because there is no /sbin/init on our file system. However, as we have seen, the kernel also attempts to execute /bin/sh. In our BusyBox-configured target, this succeeds, and busybox is launched via the symlink /bin/sh on our root file system. The first thing BusyBox displays is the complaint that it can't find /etc/init.d/rcS. This is the default initialization script that BusyBox searches for. Instead of using inittab, this is the preferred method to initialize an embedded system based on BusyBox. When it has completed initialization, BusyBox displays a prompt asking the user to press Enter to activate a console. When it detects the Enter key, it executes an ash shell session waiting for user input. The final message about job control is a result of the fact that we are creating the system console on a serial terminal. The Linux kernel contains code to disable job control if it detects the console on a serial terminal. This example produced a working system, with nearly 100 Linux utilities available, including core utilities, file utilities, network support, and a reasonably capable shell. You can see that this simple package provides a powerful platform upon which to build your own system applications. Of course, it should be noted that without any support for libc and other system libraries, you would face a formidable task implementing your applications. You would have to provide support for all the usual system calls and other library functions that a typical C program relies on. Alternatively, you could statically link your applications against the libraries it depends on, but if you have more than a couple applications using this method, your applications will likely exceed the combined size of linking dynamically and having the shared libraries on your target. 11.3.2. Example rcS Initialization ScriptBefore BusyBox spawns an interactive shell, it tries to execute commands from a script called /etc/init.d/rcS, as shown in Listing 11-7. It is here where your applications come to life in a BusyBox system. A simple rcS initialization script is provided in Listing 11-8. Listing 11-8. Simple rcS BusyBox Startup Script
This simple script is mostly self-explanatory. First, it is important to mount the /proc file system on its reserved mount point, /proc. This is because many utilities get their information from the /proc file system. This is explained more fully in Chapter 9. Next we launch the system loggers as early as possible, to capture any startup problems. Following the system log daemons, we configure the local loopback interface for the system. Again, a number of traditional Linux facilities assume that a loopback interface is present, and if your system has support for sockets configured, you should enable this pseudo interface. The last thing we do before starting a shell is launch the Internet superserver xinetd. This program sits in the background listening for network requests on any configured network interfaces. For example, to initiate a telnet session to the board, xinetd intercepts the request for telnet connection and spawns a telnet server to handle the session. Instead of starting a shell, your own applications can be launched from this rcS initialization script. Listing 11-8 is a simple example of a Telnet-enabled target board running basic services such as system and kernel loggers. 11.3.3. BusyBox Target InstallationThe discussion of BusyBox installation can proceed only when you understand the use and purpose of symlinks. The BusyBox makefile contains a target called install. Executing make install creates a directory structure containing the busybox executable and a symlink tree. This environment needs to be migrated to your target embedded system's root directory, complete with the symlink tree. The symlink tree eliminates the need to type busybox command for each command. Instead, to see a listing of files in a given directory, the user need only type ls. The symlink executes busybox as described previously and invokes the ls functionality. Review Listing 11-4 and Listing 11-5 to see the symlink tree. Note that the BusyBox build system creates links only for the functionality that you have enabled via the configuration utility. The easiest way to populate your root file system with the necessary symlink farm is to let the BusyBox build system do it for you. Simply mount your root file system on your development workstation and pass a PREFIX to the BusyBox makefile. Listing 11-9 shows the procedure. Listing 11-9. Installing BusyBox on Root File System
First we mount the root file system binary image on our desired mount pointin this case, /mnt/remote, a favorite of mine. Then we invoke the BusyBox make install command, passing it a PREFIX specifying where we want the symlink tree and busybox executable file to be placed. As you can see from the listing, the makefile invokes a script called applets/install.sh to do the bulk of the work. The script walks through a file containing all the enabled BusyBox applets and creates a symlink for each one on the path we have specified using the PREFIX. The script is very chatty; it outputs a line for each symlink created. For brevity, only the first few and last few symlink announcements are displayed. The ellipsis in the listing represents those we have eliminated. The message about setuid is also displayed by the install script, to remind you that it might be necessary to make your busybox executable setuid root. This is to allow BusyBox functions that require root access to function properly even when invoked by a nonroot user. This is not strictly necessary, especially in an embedded Linux environment, where it is common to have only a root account on a system. If this is necessary for your installation, the required command (chmod +s) is shown in Listing 11-9. The result of this installation step is that the busybox binary and symlink tree are installed on our target root file system. The end result looks very similar to Listing 11-4. It is useful to note that BusyBox also has an option to enable creation of this symlink tree on the target system at runtime. This option is enabled in the BusyBox configuration and is invoked at runtime by executing busybox with the -install option. You must have the /proc file system mounted on your target system for this support to work. 11.3.4. BusyBox CommandsIn a recent BusyBox snapshot, 197 commands (also called applets) were documented in the man page. There is sufficient support for reasonably complex shell scripts, including support for Bash shell scripting. BusyBox has support for awk and sed, frequently found in Bash scripts. BusyBox supports network utilities such as ping, ifconfig, TRaceroute, and netstat. Some commands are specifically included for scripting support, including true, false, and yes. Spend a few moments perusing Appendix C, "BusyBox Commands," where you can find a summary of each BusyBox command. After you have done so, you will have a better appreciation for the capabilities of BusyBox and how it might be applicable to your own embedded Linux project. As mentioned at the beginning of this chapter, many of the BusyBox commands contain a limited subset of features and options compared to their full-featured counterparts. In general, you can get help on any given BusyBox command at runtime by invoking the command with the --help option. This produces a usage message with a brief description of each supported command option. The BusyBox gzip applet is a useful example of a BusyBox command that has support for a limited set of options. Listing 11-10 displays the output from gzip-help on a BusyBox target. Listing 11-10. BusyBox gzip Applet Usage
The BusyBox version of gzip supports just three command line options. Its full-featured counterpart contains support for more than 15 different command line options. For example, the full-featured gzip utility supports a --list option that produces compression statistics for each file on the command line. No such support exists for BusyBox gzip. This is usually not a significant limitation for embedded systems. We present this information so you can make an informed choice when deciding on BusyBox. When the full capabilities of a utility are needed, the solution is simple: Delete support for that particular utility in the BusyBox configuration and add the standard Linux utility to your target system. |