Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Mar 1999 16:30:45 -0800
From:      Patrick Powell <papowell@astart2.astart.com>
To:        freebsd-small@freebsd.org
Subject:   How2Build Update
Message-ID:  <36E9B1B5.3AD7E06C@astart.com>

next in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------EBAC1F2D12499441013FE952
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

This is a modified version of the how2build.html page in
/usr/src/release/picobsd/doc/src/how2build.html

I have added some corrections and additions,  including a section on how

FreeBSD 3.1-RELEASE sets up a two floppy boot system.

Patrick Powell



--------------EBAC1F2D12499441013FE952
Content-Type: text/html; charset=us-ascii; name="00049D62.html"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="00049D62.html"
Content-Base: "file:///C|/WINDOWS/TEMP/00049D62.html"

<html>
<! $Id: how2build.html,v 1.4 1998/11/01 20:01:40 abial Exp $ >
<head>
<title><center>PicoBSD Development Kit</center></title>
</head>
<body>
<h1><center>How to Build Your Own Version of PicoBSD </center></h1>
<h2><center> Andrzej Bialecki <tt>&lt;abial@freebsd.org&gt;</tt></center></h2>
<h2><center>Updated and Extended by Patrick Powell <tt>&lt;papowell@astart.com&gt;</tt> </center></H2>
<A HREF=#build><h2>1. Introduction</h2></A>
<UL>
<LI><A HREF="#bugs">1.1 Errata for FreeBSD 3.1-RELEASE </A>
</UL>
<A HREF=#build><h2>2. Using the PicoBSD build Procedures</h2></A>
<A HREF=#buildoptions><h2>3. Build Options and Extensions</h2></A>
<A HREF=#details><h2>4. The Details</h2></A>
<UL>
<LI><A HREF=#kernel>4.1 Kernel, MFS, and Root File System</A>
<LI><A HREF=#bsd>4.2 BSD Kernel Organization</A>
<LI><A HREF=#memory>4.3 Memory File Systems</A>
<LI><A HREF=#vnode>4.4 VNODE Devices and File Systems</A>
<LI><A HREF=#init>4.5 Initializing MFS Root File Systems</A>
<LI><A HREF=#compress>4.6 Compressing The Kernel</A>
<LI><A HREF=#build_kernel>4.7 Build_kernel, State1, Populate, and Stage2 Scripts</A>
<LI><A HREF=#bootseq>4.8 Building the Boot Floppy with Stage3 Script</A>
<LI><A HREF=#startup>4.9 Startup and Floppy Files</A>
</UL>
<A HREF="#multi"><h2>5. Multiple Boot Floppies </h2></A>
<UL>
<LI><A HREF="#multi_mfs">5.1 Boot and MFS Using Loader</A>
<LI><A HREF="#multi_comp">5.2 Boot and Compressed MFS</A>
<LI><A HREF="#multi_cdrom">5.3 Boot and CDROM</A>
</UL>
<A HREF="intro"><h2>1. Introduction</h2></A>
<p> 
The
<A HREF=#build>Using the PicoBSD build Procedures</A>
section is a guide to using the PicoBSD build facilities.
<A HREF=#buildoptions>Build Options and Extensions</A>
describes the options used by the <tt>build</tt> script,
and the other scripts of the PicoBSD package.
The
<A HREF=intrinsics.html>Intrinsics</A>
document provides an expert level guide to the various scripts and their actions.
<A HREF=#details>The Details</A> is a more an expanded form of the
<A HREF=intrinsics.html>Intrinsics</A> notes,
together with explanations of some of the underlying technology used to make the
various PicoBSD components.

<A NAME="bugs"><h2>1.1 Errata for FreeBSD 3.1-RELEASE </h2></A>
<p>
The following errata have been found in the FreeBSD 3.1-RELEASE.
<ol>
<li> Missing kzip /usr/lib/aout files on FreeBSD 3.1-RELEASE.
<p>
   The necessary library files for the kzip utility are missing on the
   FreeBSD 3.1-RELEASE.  Do the following steps to create and install them:
<pre>
   cd /usr/src/sys/i386/boot/kzipboot
   make all install
</pre>

<li> Crunchgen, ppp, and  -DRELEASE_CRUNCH
<p>
   Some of the binaries such as ppp will not build correctly unless
   the RELEASE_CRUNCH environment variable is set to 1.  You must
   also set the -DRELEASE_CRUNCH flag in the ${TYPE}/crunch1/Makfile:
<pre>
*** net/crunch1/Makefile        Sat May  1 16:13:50 1999
--- net/crunch1/Makefile.orig   Wed Apr 28 09:22:50 1999
***************
*** 12,18 ****
        fi
        @cat crunch.conf|sed -e "s@/usr/src@${SRC}@" >crunch1.conf
        @crunchgen ./crunch1.conf
!       @${MAKE} -f crunch1.mk -DRELEASE_CRUNCH -DNOPAM all \
            "CFLAGS=${CFLAGS} -DCRUNCHED_BINARY -DNOSECURE -DNOCRYPT" #2>&1 >/dev/null

  clean:
--- 12,18 ---- 
        fi
        @cat crunch.conf|sed -e "s@/usr/src@${SRC}@" >crunch1.conf
        @crunchgen ./crunch1.conf
!       @${MAKE} -f crunch1.mk -DNOPAM all \
            "CFLAGS=${CFLAGS} -DCRUNCHED_BINARY -DNOSECURE -DNOCRYPT" #2>&1 >/dev/null
    
  clean:
</pre>
</ol>
   
   

<A NAME="build"><h2>2. Using the PicoBSD build Procedures</h2></A>

<ol>
<li>
	Get the file <code>picobsd.tgz</code>. It contains the scripts
	you'll need.  Also, I assume you run quite -current system with
	full sources installed.

<p>	NOTE1: beginning with version 0.4, PicoBSD sources are maintained as
	part of official FreeBSD CVS repository, so if you have recent
	source tree you can find them in /src/release/picobsd.</p>

<p>	NOTE2: there were some mysterious interactions between vn(4) driver and
	'disklabel auto' in versions earlier than 3.0. There is another set
	of scripts prepared by <A HREF="mailto:dinesh@alphaque.com">Dinesh Nair
	</a> which allows to build PicoBSD floppies on a earlier systems.</p>

<p>	NOTE3: this document reflects the modified build procedures that were
	developed by Patrick Powell <papowell@astart.com>.  These are based on
	the FreeBSD 3.1-RELEASE distribution.

<p>	Unpack the archive into your <code>src/release/picobsd</code>.
	You'll need at least 5MB of free space.</p>
</li>
<li>	Change working directory (<code>cd build</code>) and run the
	<code>./build</code> script. Select target language, size of MFS and
	one of pre-canned setups (personal dialup, dialin server or
	router-like). Details of each setup are contained in dial/,
	router/, isp/ and net/ directories respectively. You should at least
	check <code>${TYPE}/config/PICOBSD</code> file to make sure it contains
	the drivers you want.

<p>	You can also choose a special type called 'custom'. You'll need to
	supply the full path to your own custom config tree constructed
	exactly like one of the standard config directories. Also, you'll
	probably want to adjust the number of inodes on MFS - see the
	<code>stage1</code> script and look for <code>INODES=</code>.</p>

<p>	You can create your own configuration.  The recommended method is to
	start with an existing configuration, such as <code>net</code>,
	and to copy the files to a your new configuration.  For example,
	to create <code>small</code>,  you would do:
<pre>
cd /usr/src/release/picobsd
cp -r net small
</pre>
</li>
<li>	There are several directories which contain some sources and config
	files:
<pre>
	build/			main build directory; you MUST cd here!
	dial/			config files for dialup setup
		conf/		kernel config file
		crunch1/	crunch of system programs
		mfs.tree/	contains the MFS configuration
		lang/		contains language-dependent files
		floppy.tree/	contains the startup floppy hierarchy

	isp/			config files for dialin server setup
		...		(as above)
	net/			config files for router-like setup
		...		(as above)
	tinyware/		collection of small system utilities
	tools/			additional tools them needed during build
</pre>
<p>	There are no <code>/etc/passwd</code> nor <code>/etc/pwd.db</code>
	files on the "dial" floppy - in case of other types, they are
	reconstructed from <code>/etc/master.passwd</code> on each startup
	(and then put on MFS with the rest of <code>/etc</code>).
	In case of "dial" type floppy, you don't need them at all.</p>

<p>	NOTE: thanks to the above, the floppy is needed only during startup,
	and then only if you want to synchronize (possibly changed) MFS /etc
	with the one on the floppy. It means that you can pull off the floppy
	from the drive as soon as <code>login:</code> prompt appears. 
	In other words, it is almost equal to read-only floppy.</p>
</li>
<li>	Edit the set of installed programs.
<ul>
<li>		Go to <code>${TYPE}/crunch1</code> directory, and edit it
		to suit your needs. Keep in mind that floppies aren't made
		of rubber... :-)
</li>
<li>		There are some patches included in these directories, which
		are applied during build process to some of the Makefiles in
		your <code>/usr/src</code>. These patches attempt to decrease
		the size of some programs by cutting off rarely/unlikely used
		parts. The patches are reversed when you do a
		<code>make clean</code> (or <code>build/clean</code>
		for that matter).
<p>		NOTE: patches may fail to apply, if your sources are too
		different from the ones I used. Don't worry: they are so
		straightforward that you can apply them by hand.</p>
</li>
<li>		In order to have a functioning system you MUST include at
		least one of <code>init</code>, or <code>oinit</code>,
		or <code>sysinstall</code> in
		your <code>crunch.conf</code>. Of course these can be your
		own programs... But if you install the stock
		<code>init</code>, you
		also have to install sh, getty, login etc... to provide for
		the standard login support.
<p>		This release of PicoBSD contains a small replacement for
		init(8), called 'oinit'. You can find it in TinyWare
		collection.
</li>
</ul>
</li>
<li>	Make sure that the system you're running has /dev/[r]vn0* entries in
	/dev directory (if not, you can make them with 'MAKEDEV vn0'), AND
	that your running kernel has built-in vnode driver (there should be a
	line in your kernel config file stating 'pseudo-device vn').
</li>
<li>	You'll need at least 9MB of free disk space, and free /mnt directory.
</li>
<li>	Do a <code>cd build/</code> and fire off the <code>./build</code>
	script. Select the build parameters or 'n' for 'no change'. If all
	is well, after some time (like 10-30m) you end up with a
	'picobsd.bin' file in this directory.

<p>	The build script accepts the following options:
<pre>
build [-v] [-n] [config]
  -v   verbose operation
  -n   do not write floppy
  config  - configuration, must be directory ../config
</pre>
	The -v option will show the execution steps in detail.  The -n
        suppresses writing a floppy.  This can be done at a later time by
	using <code>dd</code> to copy the output <code>picobsd.bin</code> file
	to the floppy.
<pre>
dd if=picobsd.bin of=/dev/rfd0
</pre>

<p>	If there were any errors, please execute the build script using the -v
        option and try
	to find what causes this error. Most often this will be one of the
	following reasons:</p>
<ul>
<li>		<code>crunchgen</code> can't find the source directory for a
		program 'proggy':
<ul>
<li>		make sure that the source directory for 'proggy' is called
		  'proggy', otherwise the crunchgen won't find it
</li>
<li>		make sure that the Makefile allows crunchgen to deduce the
		  set of objects to build. You can manually add an OBJS= ...
		  to the program's Makefile.
</li>
</ul>
</li>
<li>		crunch fails to build.
<ul>
<li>		check your system source tree for stale .depend files and/or
		  objects (*.o)
</li>
<li>		see if the individual programs can be built using original
		  Makefiles. If not, cvsup the correct sources.
</li>
<li>            crunch fails to include all of the object files for a program.
                See the crunch(8) man page on how to explicitly specify the object
                files needed.  You might also want to try to fix the Makefile for the
                program if it is a standard system utility.
</ul>
</li>
<li>		/: write failed - file system is full
<ul>
<li>		this one is obvious - you wanted to put too many programs on
		the MFS and/or the target floppy. Or, you really don't have
		any space left on the root partition.. :-)
</li>
<li>		also, you can check if the
		MFS size is correctly reported while it's still mounted (right
		after <code>stage1</code> script ends).
</li>
</ul>
</ul>

	You can also remove <code>2>&amp;1</code> redirections from Makefiles
	to see the stderr.
</li>
</ol>

<p>That's all. You're welcome to change and improve these scripts. If you
 stumble upon something which looks like a good idea to have it here, let me
 know.</p>

<p>If, for some reason, the scripts don't work for you at all, also let me
 know.</p>

<A NAME="buildoptions"><h2>3. Build Options and Extensions</h2></A>
<p> The build command is invoked with:
<pre>
build [-v] [-n] [config]
  -v   verbose operation
  -n   do not write floppy
  config  - configuration, must be directory ../config
</pre>
<p>
	The -v option will show the execution steps in detail.  The -n
        suppresses writing a floppy.  This can be done at a later time by
	using <code>dd</code> to copy the output <code>picobsd.bin</code> file
	to the floppy.

<p>
The build script's purpose is to set the following environment variables,
and then invoke the <code>build_kernel, stage1, populate, stage2, stage3,</code>
and optionally <code>install</code> scripts.
See 
<A HREF=intrinsics.html>Intrinsics</A> or the sections below
for details about each of these scripts.
<ul>
<li><code>TYPE</code>=config
<br>
This is the name of the configuration that will be built.
By default,  the configuration files will be in <code>../$TYPE</code>,
relative to the build directory.
The when the <code>custom</code> configuration is used,
<code>build</code> will create a symbolic link from <code>../custom</code>
to the specified location of the files.
<li><code>SRC</code>=path to source files
<br>This is the location of the source files for the system configuration.
The default is <code>/usr/src</code>
<li><code>SIZE</code>=N
<br>
The number of Kbytes of memory to be used at run time for the MFS (Memory File System).
This should be large enough to contain all of the executables files to be placed in MFS.
See the discussion later about the Kernel and MFS Generation.
<li><code>LANGUAGE</code>en or pl
<br>
Some of the files put in the MFS during creation have English and Polish versions.
The default is <code>en</code> (English). 
<li><code>INODES</code>=1024
<br>The number of inodes for the MFS.
If you want to put a large number of files into the MFS, then you will
need to increase the number of inodes.
<li><code>PREBUILD_PASSWD</code>=no
<br>
You can prebuild the /etc/passwd file and put it into the MFS.  However,
this will take up quite a bit of space.
The default is to put a small <code>/etc/master.passwd</code> file into the
MFS,  and during system initialization to create the <code>/etc/passwd</code>
file using the <code>pw_dbgen</code>.
This method allows you to store a modified password file on the floppy disk
and be able to edit it using normal tools.
This is discussed in later sections.
</ul>
<p>
The <tt>build_kernel</tt> script will configure and build a kernel
using the files in the <tt>../${TYPE}/conf</tt> directory.
The kernel will be in the <tt>/usr/src/sys/i386/compile/PICOBSD-${TYPE}</tt>
directory.
<p>
The <tt>stage1</tt> script will create an MSF file system of <tt>$SIZE</tt> Kbytes
and mount it on <tt>/mnt</tt>.
The <tt>populate</tt> script will copy files from <tt>../${TYPE}/lang</tt>
and generate a <tt>crunch</tt> file using the <tt>../${TYPE}/crunch1</tt>
directory and files.  These are all put into the MFS generated by <tt>stage1</tt>.
<tt>stage2</tt> will put the MFS into the kernel,  and finally <tt>stage3</tt>
will generate a floppy disk image.
The <tt>install</tt> script may then be used to copy the image to an actual floppy disk.

<A NAME=kernel><h2>4. The Details</h2></A>
<p>
This section is a discussion of the various techniques and background
technology needed to build a FreeBSD PICOBSD release.
It assumes that the reader is familiar with building a FreeBSD system,
and has had some experience with system installation as well.
<p>
For technical details,  I recommend studying the reading list available in the FreeBSD FAQ.
There are many excellent books and articles there,
but it is difficult to know where to start.
<A NAME=kernel><h2>4.1 Kernel, MFS, and Root File System</h2></A>
<p>
One of the more interesting aspects of the picobsd system is how you
embed a Memory File System image into a kernel,
and how the entire system gets packaged and started.
These notes will explain the underlying methods,
and will hopefully provide a guideline to persons wanting to use picobsd for
some radically different situtations.
<p>
First,  we will review the BSD Kernel boot process,
then we will discuss the root file system and how the kernel finds and mounts the
root file system.
Next we will briefly cover how the Memory File System is implemented in the kernel,
and then how you can specify that the root file system is a MFS.
Finally,  we will explain how the contents of the MFS are initialized at system
generation,  and how we can then compress a kernel to make it even smaller.

<A NAME=bsd><h2>4.2 BSD Kernel Organization</h2></A>
<p>
Briefly,  the BSD kernel image is organized as a series of blocks of
bytes in a file.
Depending on the type of kernel object format,
the location and order differ,
but the following blocks are present:
<ul>
<li>header - tells the size, location, and order of the other blocks in the executable.
Also tells the size and location of <code>unitialized</code> data areas,
and the <em>staring location</em> or entry point of the code.
<li>code - the executable code
<li>preinitializaed data - strings and other values that have been statically initialized
during system compilation.
<li>relocation information - used to update kernel address locations
</ul>
<p>
During system boot,
the kernel executable code is loaded into memory,  the initialized memory is set up,
the uninitialized memory area is zeroed, and the relocation information is scanned
and locations in the kernel are set to actual locations of strings or other data
structures in memory.
The loader will then jump to (or call) the kernel entry point.
<p>
At this point the kernel is now in charge,  and will proceede to execute
code to initialize various modules or data structures and hardware devices.
This initialization is <em>not</em> the device probing,
but a much more low level initialization of devices such as the floating point unit,
memory management, and other essential devices.
<p>
One of the most essential devices is the
<em>root file system device</em>.
In fact,  this is so essential that it is actually specified in the kernel
config file used to build the kernel:
<pre>
config          kernel  root on fd0a
</pre>
For details on this,
see the 
<it/Building 4.4BSD Kernels with Config/,
part of the FreeBSD system documentation
in <tt>/usr/share/doc/smm/04.config</tt>.
If you really want to suffer, you can also look at
<tt> /usr/src/sys/kern/init_main.c</tt> for some really gory details.
<p>
By explicitly specifying the root file system device
early in the booting process the kernel will be
able to read (and write) files from the root device.
This allows the kernel to read a kernel configuration file from the root file system
which can be used to modify device probing operations.
<p>
After probing and initializing devices,
the kernel will then start scheduling processes for execution.
One of the very first processes is the so called
<tt>init</tt> process.
In FreeBSD 3.1-RELEASE,
the kernel will sequentially search for
<tt>
/sbin/init,
/sbin/oinit, 
/sbin/init.bak,
</tt>
or
<tt>
/stand/sysinstall, 
</tt>
and execute the first one it finds.
It is the responsibility of this process to carry out the necessary system initialization
and set up user logins.
By convention,
the init process will run the
<tt>/etc/rc</tt> script to do initialization,
wait for users to log on.
See <tt>man init</tt>, or the
<tt>/usr/src/sbin/init/init.c</tt> file for the graphic details.
<p>
You should be aware that init will record login
and other information in the following files:
<pre>
/var/run/utmp     The utmp file.
/var/log/wtmp     The wtmp file.
/var/log/lastlog  The lastlog file.
</pre>
The good news is that <tt>init</tt> will not create the files.
The bad news is that the files will continue to grow,  and may fill up
the file system.
On very small file system this can be a problem,
and you should not create these files or arrange for them to be truncated
at appropriate intervals.

<A NAME=memory><h2>4.3 Memory File Systems</h2></A>
<p>
A Unix file system consists of a <em>device</em>
corresponding to hardware where the information is stored,
a <em>device driver</em> which provides the necessary kernel level operations
to read and write data from the device,
and a
<tt>mount service</tt>
which provides the interface between the kernel's file system primitives
(read, write, open, etc) and the device driver.
The mount service can also translate one file system format such as MSDOS
into sensible UNIX files.
<p>
The Memory File System has a rather simple device and device driver:
the device is a block of memory.
The device driver simply copies information to and from these memory areas.
<p>
This memory area can in two places:
<ol>
<li>
Process image, which can be swapped out, size limited by swap space
<li>
Kernel memory, size limited by physical memory
</ol>
<p>
At this point,  I suggest you look at the MFS man page (<tt>man mfs</tt>)
and <em>A Pageable Memory Based Filesystem</em> in
<tt> /usr/share/doc/papers/memfs.ascii.gz</tt> for details of how this is implemented.
Effectively,
you run the <tt>mfs_mount</tt> command
all that happens is a process will do a <tt/malloc/ of the amount of memory requested,
and the device driver then does reads and writes to the process image. 
<p>
The MFS which uses Kernel Memory is the one which we are interested in.
We first need to generate a kernel which will support MFS and allow us to use
the MFS as a root device.
We do this with the  configuration options:
<pre>
options         MFS                     #Memory File System
options         MFS_ROOT                #MFS usable as root device
options         MFS_ROOT_SIZE=10        #Size in Kbytes
</pre>
<p>
The first option, MFS,  simply adds the MFS kernel modules to the kernel.
The second option will define a
<em>initialized</em> <tt>mfs_root</tt> character array of size
<tt>MFS_ROOT_SIZE</tt> K bytes,
and force the kernel to use this array as the root file system.
<p>
Here is the declaration of the <tt>mfs_root</tt> variable in
<tt>/usr/src/sys/ufs/mfs/mfs_vfsops.c</tt>:
<pre>
static u_char mfs_root[MFS_ROOT_SIZE*1024] = "MFS Filesystem goes here";
static u_char end_mfs_root[] __unused = "MFS Filesystem had better STOP here";
</pre>
<p>
During the system initialization,
the kernel will look at the <tt>mfs_root</tt>
variable,
and expect it to have the same format as a UFS file system.
If it does,
then it will treat this device as the root device,
and ignore any root device specified by the <tt>config</tt> specification.
<p>
We will explore how we can construct a file system and place it in the
<tt>mfs_root</tt> array in the next couple of sections.

<A NAME=vnode><h2>4.4 VNODE Devices and File Systems</h2></A>
<p>
In a previous section,
we discussed how the MFS file system allows
blocks of memory (even in a user process) to be used as a file system.
Well,  files are simply blocks of memory in some sense.
Can we create a device that will allow us to access a file as a
<em>device</em>?
<p>
The <em>vnode</em> device driver does exactly this.
When we run the <em>vnodeconfig</em> program,
this establishes a link between a file and a vnode device.
The vnode device driver then tranlates low level kernel block io
reads and writes in file lseeks and file read and write operations.
Lets see how we can construct a file that we can uses as a device:
<pre>
dd of=fs.PICOBSD if=/dev/zero count=2500 bs=1k 2> /dev/null
vnconfig -s labels -c /dev/rvn0 fs.PICOBSD 2>/dev/null
</pre>
<p>
The dd command will create a 2500 Kbyte file of all zeros,
and then the <tt>vnconfig</tt> command will link the file to the
<tt>/dev/rvn0</tt> and <tt>/dev/vn0</tt> devices.
You can use <tt>/dev/rnv0</tt> to access the file contents:
<pre>
dd if=/dev/rnv0 bs=1 count=4 seek=32
</pre>
But we can also
<em>format</em> the device ...  I mean file so that its contents
have the structure of a hard drive.
In the FreeBSD environment
we use the
<em>disk label</em> utility to write a block of data at a specific offset from the
start of the disk... I mean file,
that provides information about the number of sectors, tracks,
and cylinders on the device, and installs any boot blocks if requred.
This is done using the <tt>disklabel</tt> command as follows:
<pre>
disklabel -rw vn0 auto
</pre>
<p>
The <tt>auto</tt> option will simply query the VNODE driver code
for the disk information and will copy this to the label area.
See <tt>man disklabel</tt> for details about this operation.
<p>
The file contents now are an image of a generic disk drive,
and we can now create a file system on it using the
<tt>newfs</tt> command:
<pre>
INODES=4096
newfs -i $INODES -m 0 -p 0 -o space /dev/rvn0c 2>&1 >/dev/null
mount /dev/vn0c /mnt
</pre>
<p>
The number of <tt>inodes</tt> that are created on the disk determines
the maximum number of files that can be stored on the disk.
The <tt>-i 4096</tt> parameter specifies that we create one inode for each 32K bytes.
One a 2048Kbyte file system,  this would be 512 inodes, or a maximum of 512 files.
<A NAME=init><h2>4.5 Initializing MFS Root File Systems</h2></A>
<p>
By using
<tt>
dd,
vnconfig,
disklabel,
</tt>
and <tt>newfs</tt>,
we can create a file <tt>fs.PICOBSD</tt> whose contents are exactly the same
as a copy of a real disk system.
We can mount this device and then
copy files to it:
<pre>
mkdir /mnt/etc
cp /etc/rc /mnt/etc/rc
cp /etc/init /mnt/etc/rc
...
umount /mnt
fsck -p /dev/rvn0c
vnconfig -u /dev/rvn0
</pre>
<p>
At this point,  we will have a file,
<tt>fs.PICOBSD</tt>,
whose contents are exactly the same a disk based file system,
and which we could use as a root file system if it was on a physical device.
<p>
Now we do a really tricky thing:
we are going to copy this file system image into the
MFS area in the kernel.
We find the string
<tt>"MFS Filesystem goes here"</tt> in the kernel image,
and we brutally copy the
<tt>fs.PICOBSD</tt> file over top of it.
<p>
The <tt>write_mfs_in_kernel</tt> utility will do exactly this;
see <tt>/usr/src/release/picobsd/tools/write_mfs_in_kernel </tt> for details.
We use:
<pre>
write_mfs_in_kernel kernel fs.PICOBSD
</pre>
<p>
If we were to load this kernel into memory  and start it executing,
it would examine the contents of the
<tt>mfs_root</tt>,
discover that it is a file system image,
and then the MFS file system image as its root disk.
<A NAME=compress><h2>4.6 Compressing The Kernel</h2></A>
<p>
In the previous steps we outline how we would make a kernel with a MFS
root file system,
and how we would initialize the file system.
However,  there is a small problem with this kernel - it is extremely large.
We have a least 2500 K bytes of initialized data (the MFS image).
<p>
We can get around this by compressing the kernel using (say) gzip (Lempel-Ziv algorithm),
or the even more efficient bzip (block-sorting algorithm).
One of the more pleasant things about these algorithms is that they compress long strings of
zeros (0) with excellent efficiency.  Here are some sample numbers
<pre>
Filesystem  1K-blocks     Used    Avail Capacity iused   ifree  %iused
/dev/vn0c        2387     1300     1087    54%     285     353    45%
                      Raw     Stripped    Compressed
Kernel (2500K MFS)  4102K     3840K       1258K
Kernel (3500K MFS)  5126K     4864K       1260K
</pre>
As you can see, there is approximately a 2k increase in compressed
kernel size for a 1000K increase in MFS size.

<A NAME=build_kernel><h2>4.7 Build_kernel, Stage1, Populate, and Stage2 Scripts</h2></A>
<p>
The <tt>build</tt> script will first call the
<tt>build_kernel</tt> script to build a kernel with the MFS and
MFS_ROOT options and MFS_ROOT_SIZE set to the MFS file system size.
<p>
Next,  the
<tt>stage1</tt> script generates the <tt>fs.PICOBSD</tt> file which will be used
for the Memory File System.
This is done using the commands:
<pre>
umount /dev/vn0 2> /dev/null || true
umount /mnt 2> /dev/null || true
vnconfig -u /dev/rvn0 2> /dev/null || true
#  generate a file of $SIZE K of zeros
dd of=fs.PICOBSD if=/dev/zero count=${SIZE} bs=1k 2> /dev/null
vnconfig -s labels -c /dev/rvn0 fs.PICOBSD 2>/dev/null
#  we autolabel this
disklabel -rw vn0 auto
n=
if [ -n "$INODES" ] ; then
        n="-i $INODES";
fi
newfs $n -m 0 -p 0 -o space /dev/rvn0c 2>&1 >/dev/null
mount /dev/vn0c /mnt
</pre>
<p>
We now have a file system mounted on <tt>/tmp</tt> which we will now
fill with the files for the MFS.
The <tt>populate</tt> will effectively generate a root file system
by creating the <tt>
/dev,
/etc,
/usr,
/sbin,
</tt>
and other directories,
creating the device files in <tt>/dev</tt>,
and copying other files in place.
<p>
The <tt>populate</tt> script also generates a <em>crunch</em> executable,
which is a single file that has the executables for a large number of commands.
This reduces the number of duplicate statically linked executables that are needed
for a small file system.
<p>
After the MFS is created and populated, the <tt>stage2</tt> script will embed
the MFS into the kernel, and strip and compress the kernel.
<pre>
umount /mnt 2>&1 >/dev/null
fsck -p /dev/rvn0c
vnconfig -u /dev/rvn0 2>&1 >/dev/null
if [ ! -f ../tools/write_mfs_in_kernel/wmik ]; then
        (cd ../tools/write_mfs_in_kernel; make)
fi
../tools/write_mfs_in_kernel/wmik kernel fs.PICOBSD
strip kernel
strip --remove-section=.note --remove-section=.comment kernel
gzip -9 -n -f kernel
</pre>
<p>
First, we unmount the <tt>fs.PICOBSD</tt> file,
and run <tt>fsck</tt> to ensure that it is in a consistent state
and mark the file system as <em>clean</em> so the kernel will not try to run
<tt>fsck</tt> during system startup.
We also strip the kernel to remove symbol tables and contents.
This reduces the kernel size substantially,
but means that we will be unable to use some utilities that require a symbol table.
We then use the <tt>write_mfs_in_kernel</tt> command to copy the MFS
to the kernel,  and then use gzip to compress the kernel.
<p>
We are now ready to put all of this onto a floppy disk.
But first, let us review how we boot from a floppy disk.
<A NAME=bootseq><h2> 4.8 Building the Boot Floppy with Stage3 Script</h2></A>
<p>
The <tt>stage3</tt> we creates a floppy image file and then
mounts it on /mnt using the following
<tt>
dd, vnconfig, newfs,
</tt>
and
<tt>
mount
</tt>
commands:
<pre>
umount /dev/vn0 2> /dev/null || true
umount /mnt 2> /dev/null || true
vnconfig -u /dev/rvn0 2> /dev/null || true
dd of=picobsd.bin if=/dev/zero count=1440 bs=1k 2> /dev/null
vnconfig -c /dev/rvn0 picobsd.bin 2>/dev/null
disklabel -Brw /dev/rvn0 fd1440 2>&1 >/dev/null
newfs -i 4096 -m 0 -p 0 -o space /dev/rvn0c 2>&1 >/dev/null
mount /dev/vn0c /mnt 
</pre>
<p>
The <tt>dd</tt> command creates a 1440Kbyte file which will be our floppy disk image.
The <tt>vnconfig</tt> then attaches it to the <tt>/dev/rvn0</tt>
and <tt>/dev/vn0</tt> VNODE device.
<p>
The <tt>disklabel</tt> command is where a lot of subtle things happen
that are not explicity visible.
The <tt>-B</tt> option causes the
<tt>/boot/boot1</tt>
and
<tt>/boot/boot2</tt>
files to be written to the floppy disk,
and installed as boot blocks for the device.
The <tt>fd1440</tt> will cause the disk image to be labelled as a 1440K floppy disk.
Finally,  we mount the floppy image onto <tt>/mnt</tt> in preparation
for copying files to it.
<p>
The inquisitive readers who examine the <tt>/boot</tt> directory will discover there
is also a <tt>/boot/boot0</tt> file.
The <tt>/boot/boot0</tt> is the boot file used
on <it>multi-system</it> hard drives,  and allows users to select which
of multiple systems they wish to boot.
This boot file is installed in the Master Boot Record (MBR) which is only
available on drives that support a MSDOS partition structure,
such as hard drives and some removable media (Zip) drives.
Since we are using a floppy disk,  we do not need to worry about <tt>boot0</tt>.
<p>
We copy the compressed kernel to the floppy image:
<pre>
cp kernel.gz /mnt/kernel.gz
</pre>
<p>
At this point,  you can copy the floppy image to an actual floppy disk
and then mount the floppy using the following commands:
<pre>
# for writes to all devices including VNODE devices
sync
dd if=fs.PICOBSD of=/dev/rfd0
mkdir /tmp/mnt
mount /dev/fd0 /tmp/mnt
ls /tmp/mnt
</pre>
The <tt>ls</tt> command will show that the floppy disk has the <tt>kernel.gz</tt>.
If you feel adventurous,  you can try to boot the floppy.
If you do,  you will be suprised to find that the boot code
reports that it cannot find a <tt>/kernel</tt> file.
Even if you <em>rename</em> the <tt>kernel.gz</tt> to <tt>kernel</tt>,
then the boot code will still give an error.
<p>
What is happening?
The <tt>boot1</tt> and <tt>boot2</tt>
loaders expect to load reqular, non-compressed kernels into memory and execute them.
They do not have any uncompression facilities as they are very small and simple.
<p>
One way to handle this is to use the
<tt>kzip</tt>
utility,  which compresses a kernel,
then adds code to uncompress the kernel and then jump to the kernel entry point.
<p>
Rather than use this,
we will add a <em>level3</em> bootstrap loader
that not only is smart enough to not only uncompress the kernel,  but also
can pass in user specified configuration values and perform
other configuration functions.
<p>
Here is the final boot sequence we will use:
<ol>
<li>
boot1 on floppy sector 0/0/1 loaded into memory and executed by BIOS
<li>
boot2 on UNIX partition loaded into memory and executed by boot1
(uses /boot.config for information)
<li>
/boot/loader loaded memory and executed by boot2
(uses /boot/loader.rc for information)
<li>
/kernel.kz decompressed and loaded into memory, modified by /boot/loader, and executed.
(uses /kernel.config for information)
</ol>
<p>
The <tt>boot1</tt>
code (<tt>/boot/boot1</tt>) was placed on the first
sector of the floppy by the
<tt>disklabel</tt> program.
It also labelled the disk and wrote the
<tt>boot2</tt> code (<tt>/boot/boot2</tt>) into a standard sector location.
Boot1 has just enough code to load Boot2 using the PC BIOS facilities,
and is limited to loading it from a standard location in a file
system partition.
Boot1 finds UNIX partition,
copies boot2, to memory and then jumps to the boot2 entry point.
<p>
Boot2 is about 8Kbytes of code and data,
and can read a Unix UFS file systems using BIOS calls. 
For details on its capabilities, see <tt>man boot</tt> for details.
There are several hardwired files and configuration
entries in boot4.
Boot2 will examine the partition that it was loaded from
and make sure it has a UNIX UFS file system or a file system it can manage.
It will then try to open <tt>/boot.config</tt>,
read
<em>a single line from the file</em>,
and interpret it in the same way as a user specified boot optons.
It will then pause for a few seconds to allow a user to entry new or modified
values by pressing a key during the boot process and entering them
at the prompt.
<p>
The PICOBSD setup
uses its capabilities by
creating a <tt>/boot.config</tt> on the floppy disk image
and initialing it with:
<pre>
/boot/loader
</pre>
This will cause <tt>boot2</tt> to find and load file <tt>/boot/loader</tt> into memory
and execute it as a kernel.
<p>
What is this all about?  The answer is simple:  we want to be able to
configure the devices and we need a loader that is smart enough
to uncompress our kernel.
The boot3 loader (just called <tt>loader</tt> now)
has these and a tremendouse number of other capabilities,
and it just a trifle large (131Kbytes).
We use the <tt>kzip</tt> (kernel zip) facility
to compress it and attach a bit of code to decompress and then run
the compressed code,
and then copy the compressed file to the <tt>/boot/loader</tt> file on the floppy:
<pre>
# we make a compressed loader mkdir /mnt/boot cp /boot/loader .
mkdir /mnt/boot
cp /boot/loader loader
kzip -v loader
mv loader.kz /mnt/boot/loader
rm -f loader loader.o
echo "/boot/loader" >/mnt/boot.config
</pre>
<p>
The boot2 loader copies the file <tt>/boot/loader</tt>
into memory now executes it.
The <tt>/boot/loader</tt>will now uncompress itself and can read commands from
the console or the following file (whose location is not very well documented in the man pages):
<pre>
/boot/loader.rc
</pre>
<p>
(Aside: <tt>/boot/loader.rc</tt> used to be <tt>/boot/boot.conf</tt> in earlier FreeBSD
releases, and this name is is pretty close to boot.config (see above).
I wonder how many people this has confused?.)
<p>
If there is not file or there are no commands in the file 
then the <tt>/boot/loader</tt> will try to locate
<tt>/kernel,
/kernel.gz,
/kernel.old,
/kernel.gz.old,
</tt> in turn and will load the first one found into memory and execute it.
<p>
The PICOBSD <tt>stage3</tt> script initializes
<tt>/boot/loader.rc</tt> on the floppy disk with the following commands:
<pre>
load /kernel
load -t userconfig_script /kernel.config
boot -P
</pre>
<p>
If you are interested in the capabilities of <tt>loader</tt>,
see <tt>/usr/src/boot/common/help.common</tt> or 
<tt>/boot/loader.help</tt> for a command summary.
<p>
Now let us see what happens when <tt>/boot/loader</tt> carries out the
above commands.
The <tt>load /kernel</tt> causes it to search for
<tt>/kernel</tt>
and
<tt>/kernel.gz</tt>;
it will find
<tt>/kernel.gz</tt> and uncompress it as it is loaded
into memory.
<p>
The
<tt>load -t userconfig_script /kernel.config</tt> will cause the loader
to copy the contents of
<tt>/kernel.config</tt> into memory,
and label it as the <tt>userconfig_script</tt> module.
When the kernel is started,
the <tt>userconfig</tt> module in the kernel (see
<tt>/usr/src/sys/i386/i386/userconfig.c</tt> for the nastier details) will
check to see if the <tt>userconfig_script</tt> module has been loaded,
and will then read device configuration settings from it.
The commands can have the form:
<pre>
  cmd     usage              example
  di      disable dev        di de0
  dr      drq dev #          dr 4
  ei      eisa # (EISA slots)ei 4
  en      enable dev         en ep0
  ex      exit (quit)        ex
  f       flags dev mask     f  de0 0xff
  h       help               h
  intro   intro screen       intro
  iom     iomem  dev addr    iom ed0 0xdf0000
  ios     iosize dev size    iosize ed0 0x1000
  ir      irq dev #          irq ed0 5
  l       ls, list           l
  pn      pnp (scan)         pnp
  po      port dev addr      port ed0 0x300
  res     reset CPU          res
  q       quit               q
  v       visual mode        v
</pre>
<p>If you generate a stock kernel for a large number of systems,
you may discover that some systems have different hardware IO addresses than
those in the kernel.
The need for port (io) address and interrupt modification is used only with ISA
and not with PCI bus cards.
<p>
The <tt>boot -P</tt> causes the
<tt>/boot/loader</tt> to jump to the loaded kernel entry point,
and pass it a <tt>-P</tt> (use serial
console if no keyboard) flag.  See <tt>man boot</tt> for details of the
flags and their actions.
<p>
Finally, kernel execution is started.  The kernel
does its initialization, and the kernel <tt>userconfig</tt> kernel module is
initialized.  The <tt>userconfig_script</tt>
value set by <tt>/boot/loader</tt>
causes it to reads the <tt>/kernel.config</tt>
file, and if we have generated
our kernel with the INTRO_USERCONFIG option, the kernel will go
into VISUAL <tt>userconfig</tt> operation.
<p>
To stop the loader from going into VISUAL <tt>userconfig</tt> operation,
you must to modify the
PICOBSD kernel configuration file.  Comment out the following line:
<pre>
options         INTRO_USERCONFIG        #imply -c and parse
</pre>
and regenerate the kernel.
<p>
Pleae be aware that the MFS in the kernel is not used until <em>after</em>
the devices have been probed.
Thus,  the
<tt>boot.config</tt>
and
<tt>kernel.config</tt>
files will be read from the floppy disk file system.
<p>
Here are the commands from <tt>script3</tt> used to set up the floppy disk for booting:
<pre>
mkdir /mnt/boot
cp /boot/loader .
kzip -v loader mv loader.kz /mnt/boot/loader rm -f loader loader.o
# set up the /boot.config file to cause boot2 to load /boot/loader
echo "/boot/loader" >/mnt/boot.config
# set up the /boot/loader.rc to cause the /boot/loader to
# load in the kernel and set options
cat  >/mnt/boot/loader.rc &lt;&lt;EOF
load /kernel
load -t userconfig_script /kernel.config
boot -P
EOF
</pre>
<A NAME=startup><h2>4.9 Startup and Floppy Files</h2></A>
<p>
Once the kernel has been loaded into memory,
and execution has started,
it will run the first of
<tt>
/sbin/init,
/sbin/oinit, 
/sbin/init.bak,
/sbin/init.bak,
</tt>
or
<tt>
/stand/sysinstall
</tt>
that it finds <em>on the root file system</em> which is actually the MFS,
due to the <tt>MFS_ROOT</tt> kernel configuration option.
If the MFS file system contained all of the files that we would ever need,
or we would not need to modify any configuration options,
then we are finished with setting up our system.
<p>
On the other hand,
we might discover that there are some configuration settings such as
network IP addresses,
hard drives to be mounted,
or a <tt>/var</tt> MFS file system to be created and mounted.
To allow our system to be easily configured,
we will put a set of files on the floppy disk which are then copied
to the MFS file system as part of the boot procedure.
This is managed by following items in the
PICOBSD installation.
<ol>
<li><tt>${TYPE}/floppy.tree/*</tt>
<br>
These files are copied to floppy disk during the PICOBSD installation process.
The default is a
<tt>boot.config</tt>
and
<tt>kernel.config</tt> to be used during the boot process,
and a <tt>/etc</tt> directory containing files which will overwrite
the MFS <tt>/etc</tt> files.
<li>
<tt>${TYPE}/lang/mfs.rc.${LANG}</tt>
<br>This file is copied to the MFS <tt>/etc/rc</tt> file,
and will be executed as part of the system startup procedure.
</ol>
Here is the contents of the <tt>net/lang/mfs.rc.en</tt> file:
<pre>
mount -o rdonly /dev/fd0a /start_floppy
cd /start_floppy/etc
cp -Rp . /etc/
cd /etc
pwd_mkdb -p ./master.passwd
umount /start_floppy
echo "Ok. (Now you may remove floppy if you like)"
echo ""
. rc
exit 0
</pre>
<p>Let us see what this does.
First,
it mounts the floppy disk on the <tt>/start_floppy</tt>
directory,  and then copies all the files in the floppy
<tt>/etc</tt> directory to the MFS <tt>/etc</tt> directory.
Then it unmounts the floppy and proceeds to execute the
<tt>/etc/rc</tt> file again.
This may appear to be an endless loop,
but if we have an <tt>/etc/rc</tt> file on the floppy,
this will overwrite the MFS <tt>/etc/rc</tt> file,
and we will execute it instead of the MFS file.
<p>
The
<tt>${TYPE}/lang/rc.en</tt> file is copied to the floppy <tt>/etc/rc</tt>
file during setup.
Here is a sample to show the various things that can be done.
<pre>
#!/bin/sh
############################################
### Special setup for one floppy PICOBSD ###
### THIS IS NOT THE NORMAL /etc/rc !!!!! ###
############################################
if [ -f /etc/rc.conf ]; then
    . /etc/rc.conf
fi
mount -a -t nonfs
swapon -a
if [ "x$swapfile" != "xNO" -a -w "$swapfile" -a -b /dev/vn0b ]; then
        echo "Adding $swapfile as additional swap."
        vnconfig /dev/vn0b $swapfile && swapon /dev/vn0b
fi
rm -f /var/run/*
# configure serial devices
if [ -f /etc/rc.serial ]; then
        . /etc/rc.serial
fi
# start up the initial network configuration.
if [ -f /etc/rc.network ]; then
        . /etc/rc.network
        network_pass1
fi
mount -a -t nfs
chmod 666 /dev/tty[pqrsPQRS]*
#(cd /var/run && { cp /dev/null utmp; chmod 644 utmp; })
if [ -n "$network_pass1_done" ]; then
    network_pass2
fi
if [ -n "$network_pass2_done" ]; then
    network_pass3
fi
if [ "X${inetd_enable}" = X"YES" ]; then
        echo "Starting inetd."; inetd ${inetd_flags}
fi

#  make device database
dev_mkdb
exit 0
</pre>
<p>
This looks a lot more like a regular <tt>rc</tt> startup file.
However,
this is very stripped down,  and makes a lot of assumptions about the environment
it is running in.
First,
the <tt>/etc/rc.conf</tt> file is read,
and is used to set various options that are used in the script. 
The
<tt>mount -a -t nonfs</tt> will mount all of the non-NFS files that are
listed in the <tt>/etc/fstab</tt> file.
If you have a CDROM or hard drive that you want to mount,
you can add this the the <tt>/etc/fstab</tt> file.
The <tt>swapon -a</tt> command will set any swap that is
specified in <tt>/etc/fstab</tt>.
<p>
The next entry shows how you can set up a swap file using the
VNODE file system.   This is useful if the drive that you are mounting
is a single partition and you do not want to have a swap partition.
One example of this is when you have a MSDOS file system that you mount
but still want to have a swap file.
This is rather ugly and nasty, but in small systems which need to boot
on multiple platforms can prove to be very useful.
<p>The
<tt> rm -f /var/run/*</tt> command is very standard and makes sure that there
are no entries in the <tt>/var/run</tt> directory.
If this is MFS,  then there will not be any,  but you might have mounted
<tt>/var</tt> in a previous step,  and this will clean it out.
<p>
After setting up swap,
we proceed to start up networking and then mount any NFS file systems
specified in <tt>/etc/fstab</tt>.
Finally,  we start up the various servers that we want to run on our system.
<A NAME="multi"><h2>5. Multiple Boot Floppies </h2></A>
<p>
One of the problems that you will sooner or later encounter is that you
simply cannot get all of your code onto a single floppy disk.
The following sections outline some procedures you can use to
solve this problem.
<A NAME="multi_mfs"><h2>5.1 Boot and MFS Using Loader</h2></A>
<p>One of the most common solutions is to have two or more floppies.
The first one contains the kernel and a very small amount
of <em>glue</em> files,
while the other contains the actual MFS file system.
If you check the <tt>/boot/loader.help</tt> file in the FreeBSD 3.1-RELEASE,
you will discover the following interesting commands:
<pre>
echo [-n] [&lt;message&gt;]

  Emits &lt;message&gt;, with no trailing newline if -n is specified.  This
  is most useful in conjunction with scripts and the '@' line prefix.
  Variables are substituted by prefixing them with $, eg.
    echo Current device is $currdev
  will print the current device.

read [-t &lt;value&gt;] [-p &lt;prompt&gt;] [&lt;variable name&gt;]
  The read command reads a line of input from the terminal.  If the
  -t argument is specified, it will return nothing if no input has
  been received after &lt;value&gt; seconds.  (Any keypress will cancel
  the timeout).
  
  If -p is specified, &lt;prompt&gt; is printed before reading input. No
  newline is emitted after the prompt.
  
  If a variable name is supplied, the variable is set to the value
  read, less any terminating newline.

load [-t &lt;type&gt;] &lt;filename&gt;
  Loads the module contained in &lt;filename&gt; into memory.  If no other
  modules are loaded, &lt;filename&gt; must be a kernel or the command will
  fail.
  
  If -t is specified, the module is loaded as raw data of &lt;type&gt;, for
  later use by the kernel or other modules.  &lt;type&gt; may be any string.
</pre>
<p>
Now suppose that we were to place the following commands into the
<tt>/boot/loader.rc</tt> file:
<pre>
load /kernel
echo Please insert MFS root floppy and press enter:
read
load -t mfs_root /mfsroot
boot
</pre>
<p>
The <tt>load</tt> command will cause the loader to load (and uncompress)
the <tt>/kernel</tt> or <tt>/kernel.gz</tt> file.
The <tt>echo</tt> and <tt>read</tt> print a line on the console and then
wait for the user to put a new floppy in the floppy drive.
The <tt>load -t mfs_root /mfsroot</tt> command is very interesting.
It will cause the loader to copy the contents of the file <tt>/mfsroot</tt>
into the kernel module <tt>mfs_root</tt>.
The <tt>mfs_root</tt> is where the kernel expects to find the
MFS image.
<p>
Thus,  we can simply put our MFS file system onto a floppy disk in the
file <tt>/mfsroot</tt> and we can now load this.
<p>A basic limitation of this method is that your MFS must fit in a single file,
and cannot be compressed.
However,
as we will see in the next section,
we can easily get around this problem.
<A NAME="multi_comp"><h2>5.2 Boot and Compressed MFS</h2></A>
<p>As we saw in previous sections,
the root file system must contain an <tt>init</tt> program
which is the first process started by the kernel.
We can use the <init>process to perform the following actions:
<ol>
<li>start a shell script which will
<ol>
<li>
ask the user to mount a floppy NNN
<li>
mount the floppy
<li>
check to see that there is a file, say FNNN, on the floppy.
This will contain compressed files.
<li>
Uncompress the file FNNN from the floppy
<li>
After all the files have been extracted from the floppy,
runs a <it>cleanup</it> script that would change permissions,
create database files,  or concatenate files that needed
to be split to put them on a floppy.
</ol>
<li>
runs the <tt>/etc/rc</tt> script
</ol>
<p>
This is simply an adaptation of a common method used to distributes software
on floppy disk media.
<A NAME="multi_cdrom"><h2>5.3 Boot and CDROM</h2></A>
<p>
If you have a CDROM reader on your system,
then it is possible to simply mount a CDROM and extract the files
from the CDROM.
However,  these files are still placed in memory and on systems with
limited amounts of memory and large numbers of files needed
this may not be desireable.
<p>
The <b>union</b> file system mount facility can be used to solve this
problem.
A union mount allows you to overlay two directory structures.
For example,
suppose that I had directory <tt>/my/usr</tt> which contained a set of
files that I wanted to use in place of the standard <tt>/usr</tt> files.
Due to hardwired paths in various systems utilities,  I could simply
not change a PATH environment variable.  I would normally be forced to
copy all of the files from <tt>/my/usr</tt> to <tt>/usr</tt>,
and then copy the originals back in place.  This can be very
time consuming and is fraught with danger,  especially if extra files
are left in place.
The <tt>mount -b </tt> option will invert the search order,
so that the original file system is search first,
then the union mount.
<p>
Consider the following mount command:
<pre>
mount -t union /my/usr /usr
</pre>
The <tt>/usr</tt> is the common or <it>uniondir</tt>.
The mount command causes the <tt>/my/usr</tt> directory to appear at <tt>/usr</tt>;
when a file is searched for,  the <tt>/my/usr</tt> directory contents are searched
first,  and if the file is not found then the original <tt>/usr</tt> is searched.
<p>
Now suppose that we have a CDROM that has all of the files that we would like to use.
We can mount the cdrom and then union mount it as follows:
<pre>
mount -t cd9660 /dev/wcd0a /mnt_cd
mount -t union /mnt_cd /
</pre>
Now when we access a file,  we will get the file from the CDROM first.
<p>
One of the problems with this method is that every time we search for a directory,
then a shadow directory is created in the original MFS file system as well.
We can rapidly run out of INODES unless we are careful,  as our MFS file system
is usually pretty small due to space limitations of the kernel.
A way around this is to simply create a true Memory File System and
mount this.  We then can mount and copy files to this MFS file system.
This is most effectively done during the <tt>/etc/rc</tt> initialization.
<pre>
# /etc/rc
mount -t cd9660 /dev/wcd0 /cdrom
# allow 1024 blocks of 512 bytes or 512K, lots of inodes for shadowing
mount_mfs -i 2048 -s 1024 -T /dev/null /usr
# allow 102400 blocks of 512 bytes or 51200K
mount_mfs -s 102400 -T /dev/null /var
# want to have /usr writable so we reverse order
mount -b -t union /cdrom/usr /usr
</pre>
<p>
The good news is that this is an <b>excellent</b> way to provide small
MFS based systesm.
The bad news is that as of FreeBSD 3.1-RELEASE,  the union file system
has severe problems and is not yet fully supported.
<hr>
<i>Last modified: Fri Apr 30 18:14:55 PDT 1999 by Patrick Powell <papowell@astart.com>
<br>
<i>Generated: @DATE@
<p><A HREF="mailto:papowell@astart.com">&lt;papowell@astart.com&gt;</a></i></p>
<p><A HREF="mailto:abial@freebsd.org">&lt;abial@freebsd.org&gt;</a></i></p>
</body>
</html>

--------------EBAC1F2D12499441013FE952--



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-small" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?36E9B1B5.3AD7E06C>