The Linux root Filesystem

   


The Linux root Filesystem

The Linux root filesystem contains files and executables that the kernel requires, as well as executables for system administration. In a desktop workstation installation, the kernel mounts a hard disk partition on the / directory. The following directories exist beneath the / directory:

  • /bin and /sbin contain system executables such as init, ifconfig, mount, cd, mkdir, and ping.

  • /lib contains the shared libraries (libc and others) and the Linux dynamic loader.

  • /etc contains system configuration files and scripts.

  • /dev contains special device files.

  • The kernel dynamically creates the /proc directory in memory to provide system information.

  • /usr contains additional programs and libraries.

  • /var contains files that change during runtime, such as lock and log files.

The Trailblazer engineers began to understand the root filesystem contents by examining tbdev1 (the Debian distribution development computer, which is described in Chapter 3, "Selecting a Platform and Installing Tool Sets"). They found that the root filesystem contained 10,734 files and used 67.428MB of hard disk space. They found that a default Red Hat installation contains 29,296 files and uses 382.020MB. Clearly, taking the simple approach of merely copying the contents from a default Debian or Red Hat disk exceeds the storage capability of the engineers' four target platforms, which ranges from 4MB to 16MB. The engineers needed to decide what files are really necessary to boot Linux and execute a bash prompt.

TIP

Developing a root filesystem by examining the Linux boot process from start_kernel to the bash prompt results in a minimum set of required files and gives you an understanding of Linux's interaction with programs and libraries.


Someone suggested that they could just start deleting files and see what happens. That hit-or-miss approach was quickly dismissed. The engineers learned from the Linux boot process that the kernel starts the init process that executes network and system initialization scripts and then executes bash. The engineers then wondered what files are required for init, the network and system initialization, and bash. Then, concern surfaced about this init/bash file approach and the four target platforms. The engineers wondered if they could determine what files are necessary for init and bash, would those same files be required for all architectures? Or would some architecture-based files be missing? No one had an answer other than to say that after the kernel boots, all architectures shared the same source code for init, bash, and the shared libraries. This means that if the engineers determine a root filesystem for one architecture, it should work for the others.

Required Files for init

After the kernel initializes its caches and various hardware devices, it executes the first user process, init, which spawns all other process. In order for init to run, it needs certain files and libraries to be present in the filesystem. On tbdev1, the engineers used a program called ldd to discover init's shared library dependencies. This is the output of ldd:

 root@tbdev1[514]: ldd /sbin/init         libc.so.6 => /lib/libc.so.6 (0x40015000)         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 

The first file the new root filesystem needs is /sbin/init, which requires /lib/libc.so.6 and /lib/ld-Linux.so.2. By reading the man page for init, the engineers determined that init uses a configuration file called /etc/inittab that contains instructions for init. On a desktop or server Linux workstation, the init process initializes the networking and system services, and then it enters a runlevel typically the login process. On the target systems, the engineers are not concerned with runlevels per se; rather, they want to boot the system and get bash running. So they aren't using a predefined runlevel, as in the Unix/Linux world. They are configuring init to simply initialize the network. Then they are configuring init to execute bash without authentication and to respawn bash if bash terminates.

TIP

The kernel completes booting by executing the first user process, init. init's scripts start all the system services. You can configure init to start programs and then to restart them if they terminate.


The engineers examined the /etc/inittab file on the tbdev1 workstation. They then created a simplified version that initializes the network and then executes bash. Here's their simplified inittab file:

 id:2:initdefault: l2:2:wait:/etc/init.d/rcS 1:2435:respawn:/bin/bash 2:6:wait:/etc/init.d/umountfs 

In this version of the /etc/inittab file, id:2:initdefault: tells init the default level to enter. l2:2:wait:/etc/init.d/rcS tells init to run the /etc/init.d/rcS script before entering runlevel 2, and then to wait for completion. 1:2435:respawn:/bin/bash tells init to run /bin/bash and respawn it if bash terminates. 2:6:wait:/etc/init.d/umountfs tells init that upon entering runlevel 6, someone is rebooting the target board, to run the umountfs script and wait for its completion.

Required Files for bash

The bash shell requires libraries to execute. On tbdev1, the engineers again used ldd to discover bash's shared library dependencies. Here is the output of ldd:

 root@tbdev1[516]: ldd /bin/bash         libncurses.so.5 => /lib/libncurses.so.5 (0x40016000)         libdl.so.2 => /lib/libdl.so.2 (0x40055000)         libc.so.6 => /lib/libc.so.6 (0x40059000)         /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 

In addition to init, inittab, rcS, umountfs, ld-linux.so.2, and libc.so.6, the new root filesystem needs bash, libdl.so.2, and libncurses.so.5. The engineers poked around in the /bin, /sbin, and /usr/bin directories and found that the following programs would also be necessary in order to have a functional system: cat, ls, mount, umount, ps, df, kill, ping, chmod, touch, rm, ifconfig, route, telnet, and gdbserver. They checked for shared library and configuration file dependencies, and after a little trial and error, they compiled the root filesystem file list shown in Table 4.1. These files exist in a directory structure that consists of these directories: /bin, /dev, /etc, /etc/init.d, /lib, /proc, /sbin, /tmp, /usr, and /usr/bin. With this root filesystem, the kernel calls init, which initializes the network and then executes bash. A user can then ping other network computers and run helloworld. This booted system will fulfill all seven PBRs.

TIP

The Linux program ldd outputs a list of shared libraries required by a program or library. When adding programs to the root filesystem, you should use ldd to determine whether additional libraries are required.


Table 4.1. The Project Trailblazer Target root Filesystem Files
/bin /dev /etc /lib /sbin /usr/bin
bash Console fstab ld.so.1 ifconfig gdbserver
cat null inittab ld-2.2.3.so init telnet
chmod ram protocols libc.so.6 route  
echo tty resolv.conf libc-2.2.3.so   
df tty0 services libdl.so.2   
kill ttyS0  libdl-2.2.3.so   
ls   libm.so.6   
mount   libm-2.2.3.so   
ping   libncurses.so.5   
ps   libncurses.so.5.2   
rm   libnss_dns.so.2   
sh   libnss_dns-2.2.3.so   
touch   libnss_files.so.2   
umount   libnss_files-2.2.3.so   
   libproc.so.2.0.7   
   libpthread.so.0   
   libpthread-0.0.so   
   libresolv-2.2.3.so   
   librt.so.1   
   librt-2.2.3.so   
   libstdc++-3-libc6.1-2-2.10.0.so   
   libstdc++-libc6.1-2.so.3   
   libutil.so.1   
   libutil-2.2.3.so   

The root Filesystem Binary Files: Compile or Download?

The engineers determined that it would be easy to find all these files for the i386 platforms. They could just copy them from the tbdev1 computer. The ARM and PowerPC versions would require cross-compiling. Although this list is short compared to the Debian base installation of 10,734 files, cross-compiling all these executables would require significant effort. The most current source code would have to be located and downloaded. The individual makefiles would require modification for cross-compiling and library linking. Finally, the code would need to be compiled. The engineers thought that there must be an easier way, that someone else had probably already done this ARM and PowerPC cross-compiling. During their initial research, the engineers found that the Debian Linux site (www.debian.org) contains source and compiled binaries for Alpha, ARM, i386, m68k, PowerPC, and SPARC processors. This availability of compiled binaries looked promising, until the engineers investigated the source code versions. The Debian software distribution lags behind current versions of open-source software. Debian publicly acknowledges this and distributes software "when it's time." In addition, the Debian versions of PowerPC binaries are compiled for microprocessors that have floating-point units. The Trailblazer RPX-CLLF target board uses a Motorola MPC860 that doesn't have a floating-point unit. They decided to look elsewhere.

Recently, MontaVista software released Hard Hat Linux (HHL), version 2 using kernel version 2.4.2.1 MontaVista distributes two varieties of HHLv2: the Journeyman and the Professional editions. The Journeyman edition caught the engineers' attention because it supports i386, ARM, and PowerPC, specifically the MPC8xx processors and it's free. The Journeyman CD contents as well as CD images are publicly available at the MontaVista FTP site (ftp.mvista.com/pub/Journeyman).

TIP

Some PowerPC microprocessors don't have a floating-point unit and don't execute floating-point instructions gracefully. When executing PowerPC programs, you should make sure they have been compiled correctly for your microprocessor.


MontaVista's HHLv2 isn't just a repackaging of the open-source GNU software. MontaVista's engineers are considered leading developers in architecture porting issues and development activities. They have incorporated much of their work (via patches) into the MontaVista distribution. All their architecture-specific work for the kernel and other GNU software is incorporated into the HHLv2 source and binaries. The Project Trailblazer engineers, who aren't architecture experts, were excited that they wouldn't have to become experts just to get their target platforms booted. The engineers decided that instead of reinventing the wheel, they could use MontaVista's Journeyman product, including the Journeyman cross-compiled versions of the programs for their ARM and PowerPC root filesystem. After a successful booting of both the ARM and PowerPC target platforms, they decided to use Journeyman for i386 root filesystem as well. This decision simplified their lives in ways they didn't imagine. Building a root filesystem for all the target platforms eventually involved running a script that would download the Journeyman Red Hat Package Management (RPM) binaries, extract the files, copy various binary programs to the new root filesystem, and create all the configuration files. This script, called buildrootfilesystem, is shown in Listing 4.1 and can be found at www.embeddedlinuxinterfacing.com/chapters/04/buildrootfilesystem.

Listing 4.1 The buildrootfilesystem Script

[View full width]

 #!/bin/bash # buildrootfilesystem v0.2 10/23/01 # www.embeddedlinuxinterfacing.com # # The original location of this script is # http://www.embeddedlinuxinterfacing.com/chapters/04/buildrootfilesystem # # Copyright (C) 2001 by Craig Hollabaugh # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU Library General Public License as published by # the Free Software Foundation; either version 2 of the License, or (at your # option) any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License # for more details. # # You should have received a copy of the GNU Library General Public License # along with this program; if not, write to the Free Software Foundation, # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # umask 022 SRCFILELOC=/root/cross BUILDLOC=$SRCFILELOC/builds case "$1" in "ppc" ) ARCH=powerpc TARGET=powerpc-linux MVRPMLOC=ftp://ftp.mvista.com/pub/Journeyman/cd2/ppc_8xx/apps/ #MVRPMLOC=http://www.embeddedlinuxinterfacing.com/ftp.mvista.com/pub/ Journeyman/cd2/ graphics/ccc.gifppc_8xx/apps/ TEMPFSLOC=$BUILDLOC/$ARCH-rootrpms/opt/hardhat/devkit/ppc/8xx/target/ ;; "arm" ) ARCH=arm TARGET=arm-linux MVRPMLOC=ftp://ftp.mvista.com/pub/Journeyman/cd1/arm_sa_le/apps/ #MVRPMLOC=http://www.embeddedlinuxinterfacing.com/ftp.mvista.com/pub/ Journeyman/cd1/ graphics/ccc.gifarm_sa_le/apps/ TEMPFSLOC=$BUILDLOC/$ARCH-rootrpms/opt/hardhat/devkit/arm/sa_le/target/ ;; "i386" ) ARCH=i386 TARGET=i386 MVRPMLOC=ftp://ftp.mvista.com/pub/Journeyman/cd1/x86_586/apps/ #MVRPMLOC=http://www.embeddedlinuxinterfacing.com/ftp.mvista.com/pub/ Journeyman/cd1/ graphics/ccc.gifx86_586/apps/ TEMPFSLOC=$BUILDLOC/$ARCH-rootrpms/opt/hardhat/devkit/x86/586/target/ ;; * )     echo -n "Usage " `basename $0`     echo " i386|arm|ppc [ramdisk]"     exit 1 ;; esac # # Step 1 - Determine what packages to download # echo Step 1 - Determine what packages to download PACKAGES="glibc-2 bash procps textutils fileutils shellutils sysvinit netbase libncurses  graphics/ccc.giflibstdc mount telnet-client net-tools ping gdbserver modutils" echo packages are $PACKAGES echo Step 1 - Complete echo .htm# # Step 2 - Create build and new target root filesystem directories # echo Step 2 - Create build and new target root filesystem directories if [ ! -e /tftpboot ] then     mkdir /tftpboot fi if [ ! -e $SRCFILELOC ] then     mkdir $SRCFILELOC fi if [ ! -e $BUILDLOC ] then     mkdir $BUILDLOC fi ROOTFSLOC=/tftpboot/$ARCH-rootfs echo Creating root file system for $ARCH rm -rf $ROOTFSLOC mkdir  $ROOTFSLOC if [ ! -e $BUILDLOC/$ARCH-rootrpms ] then     mkdir  $BUILDLOC/$ARCH-rootrpms fi cd $ROOTFSLOC mkdir       dev etc etc/init.d bin sbin lib usr usr/bin proc tmp chmod 755 . dev etc etc/init.d bin sbin lib usr usr/bin proc tmp echo Step 2 - Complete echo .htm# # Step 3 - Download the packages # echo Step 3 - Download the packages cd $BUILDLOC/$ARCH-rootrpms lynx -dump $MVRPMLOC | grep ftp > /tmp/rpmlist for i in $PACKAGES do     a=`grep $i /tmp/rpmlist`     rpmurl=`echo $a | cut -d " " -f 2` #    echo $rpmurl     rpm=`basename $rpmurl` #    echo $rpm     if [ ! -f $BUILDLOC/$ARCH-rootrpms/$rpm ]     then         echo Getting $rpm         wget $rpmurl     else         echo Have $rpm     fi done echo Step 3 - Complete echo .htm# # Step 4 - Extract the package's contents into a temporary directory # echo Step 4 - Extract the package\'s contents into a temporary directory cd $BUILDLOC/$ARCH-rootrpms # this is the old way, too slow because it converts RPMs everytime #alien -t *rpm #find . -name "*tgz" -exec tar zxvf {} \; #rm -rf *tgz IFS=' ' for rpm in `ls *rpm` do     if [ ! -f $rpm.extracted ]     then         alien -t $rpm         tgz=`ls *tgz`         tar zxvf $tgz         rm -rf $tgz         touch $rpm.extracted     fi done echo Step 4 - Complete echo .htm# # Step 5 - Copy the required programs # echo Step 5 - Copy the required programs echo .htm#lib files cd $TEMPFSLOC/lib cp -av ld*                         $ROOTFSLOC/lib cp -av libc-*                      $ROOTFSLOC/lib cp -av libc.*                      $ROOTFSLOC/lib cp -av libutil*                    $ROOTFSLOC/lib cp -av libncurses*                 $ROOTFSLOC/lib cp -av libdl*                      $ROOTFSLOC/lib cp -av libnss_dns*                 $ROOTFSLOC/lib cp -av libnss_files*               $ROOTFSLOC/lib cp -av libresolv*                  $ROOTFSLOC/lib cp -av libproc*                    $ROOTFSLOC/lib cp -av librt*                      $ROOTFSLOC/lib cp -av libpthread*                 $ROOTFSLOC/lib #libm and libstdc are needed by telnet-client cp -av libm*                       $ROOTFSLOC/lib cd $ROOTFSLOC/usr ln -s http://lib lib cd $TEMPFSLOC/usr/lib cp -av libstdc*                    $ROOTFSLOC/usr/lib #sbin files cd $TEMPFSLOC/sbin cp -av init ifconfig route         $ROOTFSLOC/sbin #bin files cd $TEMPFSLOC/bin cp -av bash cat ls mount umount ps $ROOTFSLOC/bin cp -av df kill ping chmod touch rm $ROOTFSLOC/bin cp -av echo                        $ROOTFSLOC/bin cd $ROOTFSLOC/bin ln -s bash sh #usr/bin files cd $TEMPFSLOC/usr/bin cp -av telnet gdbserver         $ROOTFSLOC/usr/bin #helloworld cd $ROOTFSLOC/tmp cat > helloworld.c << ENDOFINPUT #include <stdio.h> int main(void) {     int i;     for (i = 1; i < 10; i++)     {         printf("Hello world %d times!\n",i);     } } ENDOFINPUT if [ $ARCH == "i386" ] then     gcc -g -o helloworld-$TARGET helloworld.c else     $TARGET-gcc -g -o helloworld-$TARGET helloworld.c fi file helloworld-$TARGET chown -R root.root $ROOTFSLOC/* echo Step 5 - Complete echo .htm# # Step 6 - Strip the required programs # echo Step 6 - Strip the required programs echo .htm# strip it, strip it good if [ $ARCH == "i386" ] then     strip -s -g $ROOTFSLOC/lib/*     strip -s -g $ROOTFSLOC/bin/*     strip -s -g $ROOTFSLOC/sbin/*     strip -s -g $ROOTFSLOC/usr/bin/*     strip -s -g $ROOTFSLOC/usr/lib/* else     $TARGET-strip -s -g $ROOTFSLOC/lib/*     $TARGET-strip -s -g $ROOTFSLOC/bin/*     $TARGET-strip -s -g $ROOTFSLOC/sbin/*     $TARGET-strip -s -g $ROOTFSLOC/usr/bin/*     $TARGET-strip -s -g $ROOTFSLOC/usr/lib/* fi echo Step 6 - Complete echo .htm# # Step 7 - Create configuration files # echo Step 7 - Create configuration files echo .htm#etc files cd $TEMPFSLOC/etc cp -av protocols services                 $ROOTFSLOC/etc cd $ROOTFSLOC/etc cat > fstab << endofinput # <file system>      <mount point>   <type>  <options> <dump>  <pass> proc                 /proc           proc     defaults  0       0 endofinput if [ $# == 2 ] && [ $2 == "ramdisk" ] then   echo "/dev/ram             /               ext2 defaults  0   0" >> fstab else   echo "192.168.1.11:/tftpboot/$ARCH-rootfs / nfs defaults  1   1" >> fstab fi cat > inittab << endofinput id:2:initdefault: l2:2:wait:/etc/init.d/rcS 1:2:respawn:/bin/bash 2:6:wait:/etc/init.d/umountfs endofinput cat > init.d/rcS << endofinput #!/bin/bash /bin/mount -n -o remount,rw / # clear out mtab >/etc/mtab /bin/mount -a echo Starting Network /sbin/ifconfig lo 127.0.0.1 netmask 255.0.0.0 broadcast 127.255.255.255 /sbin/route add -net 127.0.0.0 netmask 255.0.0.0 lo endofinput case "$ARCH" in "powerpc" ) cat >> init.d/rcS << endofinput /sbin/ifconfig eth0 192.168.1.22 netmask 255.255.255.0 /sbin/route add default gw 192.168.1.254 eth0 endofinput ;; "arm" ) cat >> init.d/rcS << endofinput /sbin/ifconfig eth0 192.168.1.21 netmask 255.255.255.0 /sbin/route add default gw 192.168.1.254 eth0 endofinput ;; "i386" ) cat >> init.d/rcS << endofinput /sbin/ifconfig eth0 192.168.1.23 netmask 255.255.255.0 /sbin/route add default gw 192.168.1.254 eth0 endofinput ;; esac chmod 755 init.d/rcS cat > init.d/umountfs << endofinput /bin/echo umounting filesystems and remounting / as readonly /bin/umount -f -a -r /bin/mount -n -o remount,ro / endofinput chmod 755 init.d/umountfs cat > resolv.conf << endofinput domain trailblazerdev nameserver 192.168.1.1 endofinput echo Step 7 - Complete echo .htm# # Step 8 - Create devices in /dev directory # echo Step 8 - Create devices in /dev directory #dev files cd $ROOTFSLOC/dev mknod -m 0666 tty c 5 0 mknod -m 0666 tty0 c 4 0 mknod -m 0666 ttyS0 c 4 64 ln -s ttyS0 console mknod -m 0666 null c 1 3 mknod -m 660 ram b 1 1 chown root.disk ram echo Step 8 - Complete echo .htm# # Step 9 - Prepare the root filesystem for operation on the target board # echo Step 9 - Prepare the root filesystem for operation on the target board if [ $# == 2 ] then   if [ $2 == "ramdisk" ]   then     echo Building $ARCH root filesystem ramdisk     rm -rf /tmp/tmpmnt     mkdir /tmp/tmpmnt     rm -rf /tmp/ramrootfs     dd if=/dev/zero of=/tmp/ramrootfs bs=1k count=8192     mke2fs -F -m 0 -i 2000 /tmp/ramrootfs     mount -o loop -t ext2 /tmp/ramrootfs /tmp/tmpmnt     cd /tmp/tmpmnt     cp -av $ROOTFSLOC/* .     cd /tmp     umount /tmp/tmpmnt     cat /tmp/ramrootfs | gzip -9 > /tftpboot/$ARCH-ramdisk.gz     if [ $ARCH == "powerpc" ]     then       cp /tftpboot/$ARCH-ramdisk.gz /usr/src/$TARGET/arch/ppc/boot/images/ramdisk.image.gz       echo Copying /tftpboot/$ARCH-ramdisk.gz to /usr/src/$TARGET/arch/ppc/boot/images/ graphics/ccc.giframdisk.image.gz         fi            rm -rf /tmp/ramrootfs         rm -rf /tmp/tmpmnt         echo Your $ARCH root filesystem ramdisk is /tftpboot/$ARCH-ramdisk.gz     fi fi if [ $ARCH == "i386" ] then     echo     echo -n This script is about to work with your /dev/hdc1 partition,     echo is this OK? yes/no?" "     read hdc1ok     if [ $hdc1ok == "yes" ]     then     mkdir $ROOTFSLOC/boot     #dev files     cd $ROOTFSLOC/dev     rm -rf console     mknod console c 5 1     chmod 666 console     mknod hda b 3 0     mknod hda1 b 3 1     mknod hda2 b 3 2     chmod 666 hda*     #/boot files     cp /boot/boot.b $ROOTFSLOC/boot     cp /usr/src/linux/arch/i386/boot/bzImage $ROOTFSLOC/boot/bzImage     TMPMOUNT=/tmp/tmpmnt cat > /tmp/lilo.conf.1 << ENDOFINPUT # this is a special lilo.conf file used to install lilo on the /dev/hdc drive # when the machine is booted from the /dev/hda drive. Don't run lilo with this # conf file if you booted the machine from this second drive. disk=/dev/hdc bios=0x80         # This tells LILO to treat hdc as hda boot=/dev/hdc                   # install boot on hdc map=$TMPMOUNT/boot/map          # location of the map file install=$TMPMOUNT/boot/boot.b   # boot file to copy to boot sector prompt                          # show LILO boot: prompt timeout=10                      # wait a second for user input image=$TMPMOUNT/boot/bzImage    # kernel location label=linux                     # kernel label root=/dev/hda1                  # root image location after you                                 # finalize disk location read-only                       # mount root as read only ENDOFINPUT cat > $ROOTFSLOC/etc/fstab << endofinput # <file system> <mount point> <type> <options>                   <dump> <pass> /dev/hda1        /             ext2    defaults,errors=remount-ro  0      1 proc             /proc          proc    defaults                   0       0 endofinput     e2fsck -y /dev/hdc1     rm -rf $TMPMOUNT     mkdir $TMPMOUNT     mount /dev/hdc1 $TMPMOUNT     echo -n "Do you want to erase the /dev/hdc1 partition, continue yes/no? "     read deleteall     if [ $deleteall == "yes" ]     then         # this deletes everything on your partition, WATCH OUT!!         rm -rf $TMPMOUNT/*         mkdir $TMPMOUNT/lost+found     fi     cp -av $ROOTFSLOC/* $TMPMOUNT     /sbin/lilo -C /tmp/lilo.conf.1     cd /     umount $TMPMOUNT     rm -rf $TMPMOUNT     e2fsck -y /dev/hdc1 fi #hdc1ok fi echo Step 9 - Complete echo echo Your $ARCH root filesystem         is  $ROOTFSLOC 

       
    Top


    Embedded LinuxR. Hardware, Software, and Interfacing
    Embedded LinuxR. Hardware, Software, and Interfacing
    ISBN: N/A
    EAN: N/A
    Year: 2001
    Pages: 103

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net