嵌入式linux中文站在线图书

  Previous section   Next section


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梩ypically 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梐nd 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
#!/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

      Previous section   Next section
    Top