A utility for creating Root File Systems.
Tony Egan Jan-08
There's a Quickstart below for the impatient.
Also, all the download links are collected at the bottom of this document.
Rfsbuild is intended to help developers create Root File Systems for
embedded systems. This initial release is aimed at the ARM
architecture. It was tested using
ARM-Versatile PB board and using packages from the Fedora ARM
There are two typical environments for embedded system development. One, a native environment where the compilation and build and sometimes even the source editing takes place on the target processor. This requires a target which is powerful enough in terms of speed and resources to support such development.
The other is a cross-development environment where a cross-compiler and build tools are run on a host (typically an x86 PC) to generate code which is then downloaded to the target system. This leverages the power of the PC for the development work and requires nothing from the target except the resources to run the final application.
Rfsbuild can be used in either of these development environments.
rfsbuild utility is a python program which can run on any
architecture that supports Python 2.4 and
yum. The main tools used by
yum and QEMU.
Yum which is also written in Python
is a package management utility used by some major Linux
distributions, most notably Fedora.
Yum depends on a number of
other utilities and libraries including
yum requires a fairly capable linux environment in order to
QEMU is an emulator which runs on Linux and allows binary code for several
different architectures to run on an Intel-based system. The first release
rfsbuild was tested using
qemu-system-arm(0.8.2) emulating an
ARM-Versatile PB system. This can support the Linux environment required
Rfsbuild builds the target RFS from RPM packages. Obviously the RPMs
must have been built for the target architecture. RPMs are available
from many repositories on the Internet. The ARM RPMs used for testing
rfsbuild were produced by the hard work of Lennert Buytenhek and others and
were obtained here:
- Fedora Core 6
http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/core/6/arm/os/ http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/core/updates/6/arm http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/extras/6/arm
- Fedora 8
You will also likely be developing your own RPMs containing your
embedded application. You can make these available to
rfsbuild in a
Rfsbuild supports NFS access to local repositories
saving you the trouble of setting up web access. This is discussed
Rfsbuild takes a list of packages and a list of repositories where the
packages can be found. It passes these on to
yum which installs the RPM
packages into the target RFS.
Yum takes care of all the dependency checking,
downloading and installation of the packages.
Yum must execute on the target
architecture in order to do this properly hence the need for a native system
or an emulated system (QEMU) on which to execute
Here is a sample invocation of
rfsbuild on a PC host:
rfsbuild --repo=c6,http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/core/6/arm/os/ --repo=c6u,http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/core/updates/6/arm --repo=c6e,http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/extras/6/arm --package=bash --package=nfs-utils --server=./startQEMU --rfspath=/newrfs --initrd=0 --verbosity=2
The repositories, specified by
--repo, are the Fedora ARM
repositories mentioned earlier. Each one is prefixed by an arbitrary
unique name, e.g. c6e, which
yum will use in its reporting. RPMs are
--package. You can specify as many repositories and
packages as you like. Keep in mind that dependencies will be handled
automatically. So when you specify
yum will check
its dependencies and install all the other packages required by bash.
More on this later.
--server=./startQEMU parameter specifies a script which starts the
qemu-system-arm emulator. This is a bash script in this release, but it
could be any type of executable. There are some requirements for how it
invokes QEMU which we will discuss below.
Rfsbuild doesn't check the return
from this script, but it may in future revisions.
Rfsbuild uses NFS mounted directories to share information between the
PC host and QEMU. The
--rfspath=/newrfs parameter must specify an
exported directory which can be mounted via NFS from QEMU. The new
RFS will be built in a unique subdirectory of this directory,
/newrfs/build-WuCZTU-12311901/install_root). Existing RFS
sub-directories will not be deleted or overwritten by
--initrd parameter specifies that an init ramdisk image should
be created from the new RFS. It will appear at
/newrfs/build-WuCZTU-12311901/initrd.gz for the example above.
The zero means that
rfsbuild will automatically set the size of
--verbosity parameter tries to reassure the user that
yum is actually
When it starts,
rfsbuild first prints some informative messages then it
copies itself to the directory specified by
--rfspath and creates a run
rfsb which will be used by QEMU to start
rfsbuild in the emulated
environment. Rfsb is created in rfspath.
Rfsbuild then invokes the script
The program specified by
--server is responsible for starting
startQEMU script provided tries to do this in a general
way so that it can easily be adapted to different setups. Most of the
parameters affecting the networking are specified at the top of the
file. You need to edit this to suit your network.
By the way the
startQEMU script uses
sudo. You should make
sure you have a line like:
egan ALL=(ALL) NOPASSWD: ALL
to your /etc/sudoers file.
Simply download the RPM to your x86 host and enter:
sudo rpm -ivh rfsbuild-0.9.0-beta.noarch.rpm
The RPM installs
/usr/bin/rfsbuild and some miscellaneous support
/usr/share/rfsbuildto a work
directory where you can modify them and where you will invoke
- Download the ARM kernel and
initrdto the same work directory.
zImage-- kernel used by QEMU
initrd.gz-- initrd used by QEMU
You may want to rename these and create links using the original names
in your work directory. Then when you want to test a new initrd or a
a new kernel you can just change the links and keep the originals.
Keep in mind that
startQEMU will look for the files "zImage" and
- Create a directory for your new RFS and export it via NFS.
mkdir /newrfs echo "/newrfs *(rw,async,no_root_squash)" >> /etc/exports
Please see the local
Fabrice Bellard's QEMU site for
details of how to set up QEMU to emulate ARM. I have attached an ARM
kernel and initrd which are convenient for
rfsbuild development. It
is assumed that your QEMU installation is able to run the kernel and
initrd provided and is able to access the host via the network so that
it can NFS mount directories. It must also have access to the
repositories specified by the
rfsbuild command. I.e. it must be able
to access the internet.
A key feature of
startQEMU which must not be affected by any
modifications is its method of passing the path of the
script on the kernel command line. When QEMU starts running the
kernel and initrd provided, the root user is automatically logged in
/root/startrfsb script extracts this information from
Startrfsb then mounts the directory specified on the
command line and invokes the
rfsb script. The
rfsb script then starts
rfsbuild in the QEMU environment. It sounds more complicated than it is.
You can test
./startQEMU by invoking it directly on the x86 host without
any parameters. QEMU should start, boot Linux and automatically logon root
and run the
startrfsb script. This should fail harmlessly and leave you in
QEMU at the Linux shell prompt.
To exit QEMU you can enter [Ctl-a] [c] to get to the QEMU monitor and then [q] to quit. If this fails you can always open another shell on the host and enter:
killall -9 qemu-system-arm
To test NFS from QEMU, make sure NFS is enabled on the host and /newrfs is exported. Then invoke:
Where ip is the IP address of your x86 host. QEMU should start, boot Linux
and automatically logon root and run the
startrfsb script. The
script should extract the NFS path from the kernel command line and mount the
ip:/newrfs directory. The script should then fail harmlessly and leave you
in QEMU Linux at the shell prompt. This is assuming there is no
Then you can check that the NFS mount is working in QEMU :
df -a /
If NFS is not working it is likely that QEMU networking is not set up
properly or NFSD on the host is not successfully exporting
Kill QEMU again.
At this point you should have
./startQEMU & NFS working. If not, you need to
do some troubleshooting before continuing.
At some point you will probably want to create your own RPMs in a repository
on a local machine. Once you have created the RPMS just copy them to a
directory on your host, e.g.
/repo and then enter:
You can then follow the procedure for making this repository accessible via
http so that it can be accessed from anywhere.
Rfsbuild supports a simpler
alternative by using a naming convention to specify local repositories which
are accessible via NFS. On the host ensure that the repository directory is
exported via NFS. Then the
--repo parameter in the
will look like:
The three letters "
nfs" are required, followed by the
of the NFS server, followed by ,file ://
followed by the
exported path to the repo. When
rfsbuild sees this name it will
create an alias
nfs1 and mount the repository via NFS prior to
This idea comes from David Zeuthen's livecd-creator program, as does a lot of the code in
rfsbuild. We saw above how to specify packages when invoking
rfsbuild. This can get a bit unwieldy when there are a lot of packages. It would be nice if we could specify one package which in turn specified all the packages we want to install. That is the first function of a Keystone Package.
The other issue we haven't discussed is the ever present need to fix, tweak, modify and customize the RFS after the packages have been installed. RPMs already support post-install scripts but an embedded application often requires different modifications than the desktop application most RPMs are designed for. Different target devices usually require different post install modifications to the RFS. This is also handled by the keystone package.
A Keystone Package is an RPM which encapsulates a set of requirements for a particular RFS. So, you could have a Keystone Package for your router and another Keystone Package for your NAS device and another for your music server. Each would specify the specific set of packages and modifications required for each of those unique devices.
Keystone Packages take advantage of the version control, distribution and install mechanisms already in place for RPMs. You just give a user the appropriate version Keystone Package for his device and it encapsulates all the information needed to generate the RFS for that device perfectly. You don't even have to give him the package. If it is available in a repository on the Internet he just needs to specify it as a parameter to
rfsbuild, and it will automatically be downloaded from the repository and installed.
The mechanism is very simple. A Keystone Package contains one or more special
confscripts which are installed in a dedicated directory,
/etc/rfsbuild. The package can contain miscellaneous other files also as needed just like any RPM but the
confscripts are special.
yumto install the packages specified on the command line.
Yumperforms its normal dependency checking so more packages than those explicitly specified using
--packagearguments may be installed at this time.
When this is finished
confscripts it finds in
/etc/rfsbuildwith the parameter
pkgadd. See the
10-fedora-rfsbuild-mini-glibc.confscript included in the
rfsbuildpackage. If there are multiple
confscripts they will be invoked in alphabetical order. This call to the conf scripts will return a set of additional packages to be installed.
yuma second time to install these. Again,
yumchecks dependencies and installs all required packages.
When the second run of
/etc/rfsbuildagain but this time with the parameter
post. This causes the commands listed in the
postsection of the conf scripts to be executed in a chroot context using the new RFS as root. I.e the new RFS appears to be the root directory while these
postcommands are executed. So any command specified in the
postsection must be available in the new RFS. This is where fixes, tweaks and modifications to the RFS are performed.
The sample Keystone Package included in the
fedora-rfsbuild-mini-glibc.rpmuses the conf script
10-fedora-rfsbuild-mini-glibc.conf. This Keystone Package was used to build the initrd supplied here for use with
rfsbuild. So, to recreate the RFS and initrd you would simply need to invoke
rfsbuild --repo=nfs10.0.0.105,file:///repo --repo=f8,http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/releases/8/Everything/arm/os/Packages --repo=f8u,http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/updates/8/arm --package=fedora-rfsbuild-mini-glibc --package=findutils --server=./startQEMU --rfspath=/newrfs --initrd=0 --verbosity=2
This assumes you have put fedora-rfsbuild-mini-glibc.rpm in your local NFS exported repository 10.0.0.105:/repo.
For those who like to live dangerously.... :-)
If you have an ARM host that is already running Linux and supports python and
yumthen you can simply install
rfsbuildon that machine and run it locally to build ARM RFSs. E.g.:
rfsbuild --repo=/repo --repo=c6,http://fedora-arm.wantstofly.org/pub/fedora/linux/core/6/arm/os --repo=c6u,http://fedora-arm.wantstofly.org/pub/fedora/linux/core/updates/6/arm --repo=c6e,http://fedora-arm.wantstofly.org/pub/fedora/linux/extras/6/arm --package=fedora-rfsbuild-mini-glibc --rfspath=/newrfs --initrd=0 --verbosity=2
/repodirectory is a local repository which contains the
/newrfsis where we want the new RFS to be built. We are using ARM packages from the fedora-arm repositories. Since the
serverparameter is absent the build will be performed locally.
X86 Host and ARM QEMU server
How to set up an x86 host and an ARM QEMU environment so that
rfsbuildcan be invoked on the host to initiate a build under QEMU.
rfsbuildon the X86 host if you haven't already done so.
This will create a directory /usr/share/rfsbuild containing the following:
- startQEMU -- support utility for starting QEMU
- qemu-ifup -- network configuration used by QEMU
- 10-fedora-rfsbuild-mini-glibc.conf -- sample conf script
- fedora-rfsbuild-mini-glibc.rpm -- sample keystone rpm
- fedora-rfsbuild-mini-glibc.spec -- sample spec file
- startrfsb -- this is installed in the /root directory of QEMU ARM linux. It starts a build when QEMU boots Linux.
- Copy startQEMU and qemu-ifup to a work directory where you can modify them and where you will invoke rfsbuild.
- Download the ARM kernel and initrd to the same work directory.
- zImage -- kernel used by QEMU
- initrd.gz -- initrd used by QEMU
- Install QEMU and get it working with startQEMU and the zImage and initrd.gz you downloaded. This includes setting up networking via the TUN/TAP interface. You can find some help at  and  .
AT this stage invoking
./startQEMUwith no parameters should start QEMU, boot Linux and automatically logon root and try to start an RFS build. This should fail harmlessly and leave you in QEMU Linux at the shell prompt.
To exit QEMU you can enter Ctl-a c to get to the QEMU monitor and then q to quit. If this fails you can always open another shell on the host and enter:
killall -9 qemu-system-arm
- Create the RFS directory:
- Export /newrfs via NFS. (
Edit /etc/exports and restart NFS daemons)
Check that it is accessible from QEMU.
Replace 10.0.0.105 with the IP address of your PC. This should behave the same as described above except you should see 10.0.0.105:/newrfs mounted on /newrfs when you check under QEMU:
df -a /
If NFS is not working it is likely that QEMU networking is not set up properly or NFSD on the host is not successfully exporting
Kill QEMU again.
At this point you should have
NFSworking. If not, you need to do some troubleshooting before continuing.
- Finally, invoke a test run of
rfsbuild --repo=f8,http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/releases/8/Everything/arm/os/Packages --repo=f8u,http://ftp.linux.org.uk/pub/linux/arm/fedora/pub/fedora/linux/updates/8/arm --package=setup --server=./startQEMU --rfspath=/newrfs --verbosity=2
This should create a skeleton RFS with only the
- --exclude is used to omit packages from package groups.
Yum, and consequently rfsbuild will not exclude a package required by dependencies.
- --cache specifies a
yumcache to use. It's not expected to be empty.
- --cacheonly tells
yumto use cache only i.e.
- --initramfs create an initramfs archive. Not working.
- --runscript the name of the script that
/newrfsfor QEMU to run. The default is
- --label the suffix of the RFS build directory. The default is constructed from the date. Not working correctly yet since QEMU is not initializing the date correctly.
For those of you (like me) who don't like repeatedly typing long command lines I've included a sample script in the RPM called
go. Simply invoke it as:
This will re-create the sample initrd.
By the way the samples are just that "samples" to show you how
rfsbuildworks. You will see some harmless error messages as you run the sample commands given above. The sample
confscript performs some very crude reductions on the RFS. Clean up and more structured pruning are left as an exercise for the reader. Useful revisions to the scripts and suggestions for improvement will be welcomed on the Fedora ARM mailing list.