<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html 
     PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Creating a Bootable Solaris Recovery CD</title>
<meta name="title" content="Creating a Bootable Solaris Recovery CD" />
<meta name="author" content="mah@everybody.org" />
<style type="text/css">
@import "/mah.css";
<!-- Old browsers can't touch this -->
</style>
</head>
<body>
<div id="header">
<p><a href="/">top</a>::<a href="/docs/">docs</a>
</p>
<h1>Creating a Bootable Solaris Recovery CD</h1>
by <a href="http://mah.everybody.org/">Mark A. Hershberger</a> (<a href="http://mah.everybody.org/weblog/">weblog</a>)
</div>
<div id="googlead">
<script type="text/javascript"><!--
google_ad_client = "pub-3932658445533817";
google_ad_width = 120;
google_ad_height = 600;
google_ad_format = "120x600_as";
google_ad_type = "text";
google_ad_channel ="";
google_color_border = "E0FFE3";
google_color_bg = "E0FFE3";
google_color_link = "0000CC";
google_color_url = "008000";
google_color_text = "000000";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<div id="main">

<p>
Solaris, unlike some other Operating Systems, does not ship with
a method for creating bootable recovery media.  The following
procedure is one that I've been able to devise after searching
for more help on the matter.</p><p>

In documenting this process, I will first show you how to create
a bootable recovery disk.  Once that is successful, I'll describe
how to create a bootable CDROM.</p><p>

<h2>Slice 1 &mdash; the driver for the recovery</h2><p>

The partition we are going to build is a bit large &mdash;
200MB.  You could make it smaller by squeezing stuff out, but it
is fine for our purposes since the recovery image is generally
quite small (less than 100MB for the core install).</p><p>

I did this with a SCSI disk attached to an UltraSPARC 5.  Using
format, I created two partitions, a 200MB slice 1 (c1t1d0s1) and
a 450MB (c1t1d0s0, to emulate the room remaing on the CD) slice
0.  After partitioning the disk with format and with the Solaris
8 Software CD (Disk 1 of 2, 2/02 edition) at c0t2d0, I went
through the following steps:</p><ol>

<li>Create a filesystem on slice 1 of the partitioned disk:
<pre>
    # newfs /dev/rdsk/c1t1d0s1
</pre></li>

<li>Mount slice 1 of the disk:
<pre>
    # mount /dev/dsk/c1t1d0s1 /mnt
</pre></li>

<li>Mount slice 1 of the install CD:
<pre>
    # mount -o ro /dev/dsk/c0t2d0s1 /cdrom
</pre></li>

<li>Copy the contents of slice 1 on the CD to the disk:
<pre>
    # cd /cdrom; tar cf - .tmp_proto . | (cd /mnt; tar xf -)
</pre></li>

<li>Unmount the slice 1 of the CD and mount slice 0:
<pre>
    # umount /cdrom; mount -F hsfs /dev/dsk/c0t2d0s0 /cdrom
</pre></li>

<li>Copy the filesystem from Solaris*/Tools/Boot to slice 1 of
the disk, taking care not to copy over openwindows:
<pre>
    # cd /cdrom/Solaris*/Tools/Boot
    # tar cf - a bin a cdrom devices kernel mnt       platform reconfigure  tmp var bin dev etc lib opt          proc sbin usr/bin usr/ccs usr/kernel usr/kvm usr/lib       usr/old usr/perl5 usr/platform usr/preserve usr/proc       usr/pub usr/sadm usr/sbin usr/share usr/snadm              usr/spool usr/src usr/tmp usr/usr usr/xpg4 | (cd /mnt;
      tar xf -)
</pre>
You probably don't have to copy all of that stuff, but the
important thing is to avoid copying usr/dt and usr/openwin.</li>

<li>Remove <tt>/mnt/etc/sysidcfg</tt> and replace it with a symlink
to <tt>../cdrom/sysidcfg</tt>:
<pre>
    # rm /mnt/etc/sysidcfg
    # ln -s ../cdrom/sysidcfg /mnt/etc/sysidcfg
</pre></li>

<li>Patch
<tt>/mnt/sbin/rcS</tt> so that it will look at the CD
for boot information rather than trying to get the information
from the network.  To do this, replace these lines:
<pre>
if [ $USING_DHCP -eq 1 ] ; then
	echo "Using DHCP for network configuration information."
	dhcp_find_and_mount_cdrom
    else
	echo "Using RPC Bootparams for network configuration information."
	bootparams_find_and_mount_cdrom
fi
</pre>
with these:
<pre>
if [ ! -f /cdrom/sysidcfg ]; then
  cdrom=CdRoMmOuNtPoInTgOeShErE
  mount -F hsfs $cdrom /cdrom
  if [ ! -f /cdrom/sysidcfg ]; then
    echo Rescue CD
    if [ ! -z "${dial_pid}" ]; then
        kill $dial_pid >/dev/null 2>&1
    fi
    /usr/bin/bash
    reboot
  fi
fi
</pre>
</p><b><i>Note</i></b>: we have "CdRoMmOuNtPoInTgOeShErE" intead of an actual
mount point.  This is so that we can replace the string later
when it is embedded in a binary.  If you are testing this with a
disk before you burn a CD, you should put your
slice 0 mount point in place of this string.  Also, note that if
the script doesn't find a sysidcfg file, it will run bash (which
you will need to copy over with the libraries it needs
seperately) and then reboot.  This means that if you have a CD
with just this slice 1 and no slice 0, you can use the CD as a
rescue disk.</p>
<p>Also, you will need to change <tt>/mnt/sbin/suninstall</tt> to
add the line <tt>touch ${PREINSTALL}</tt> just before the
following statements:
<pre>
if [ -f ${PREINSTALL} -o -f ${INSTALLBOOT} ]; then
        if [ -f ${JSLOCKFILE} ]; then
                gettext "You must reboot the system to restart a JumpStart install."
</pre></p></li>

<li>Install the boot block onto slice 1:
<pre>
    # installboot /usr/platform/`uname -i`/lib/fs/ufs/bootblk
</pre></li></ol><p>

Slice 1 is now bootable and will launch into jumpstart if <tt>/cdrom</tt>
contains the Jumpstart setup.  We will exploit this and the new
(in later versions of Solaris 8) Flash installation to create a
CD that can recover the core OS with all the configuration intact.</p>

<h2>Creating a flash archive</h2>

*** FIXME the script needs to ensure that root_password isn't blank.

<p>Here is my <a href="mksysidcfg.txt">mksysidcfg</a> script.  Using
it takes a little preparation on your part. The script uses
<tt>flarcreate</tt> from the Solaris 8 CDROM to create the Flash
Archive.  The script expects the file to be in /usr/sbin/flarcreate.
</p><p>

You should create a file named <tt>/etc/flar_exclude</tt> listing
everything on the rootdisk that you <b>don't</b> want in the archive.
For example, on our virus scanner, I have the following in
<tt>/etc/flar_create</tt>:</p>

<pre>
/opt/trend/Plug-Ins/EM/tempdir/
/var/adm/
/var/log/
/var/tmp/
/var/iscan/
/var/iscan/log.
/var/iscan/Archive/
/var/iscan/Quarantine/
/var/iscan/tmp/
/var/iscan/virus/
/var/spool/mqueue/
/var/spool/mqueue-delivery/
/var/spool/clientmqueue/
/home/mah/cdrom
</pre><p>

<tt>/home/mah/cdrom</tt> is where I put the build images.  I
exclude that because I don't want the build image to contain a
copy of itself.  In cases where you want the directory, but not
the files in the directory, you need to put the pathname with a
trailing <tt>/</tt> as I did in this file.  Also, it is a good
idea to not copy over log files.  Note that I've avoided the log
files in the <tt>/var/iscan/</tt> directory with
<tt>/var/iscan/log.</tt> and I have just the top of the
<tt>/var/log</tt> and <tt>/var/adm</tt> path.  The logfiles there
are touched in a postinstall script.</p><p>

Mount the 450Mb partition and then run:</p>
<pre>
    # ./mksysidcfg -b -f /,/var,/usr -m /mnt
</pre>

<ul><li><tt>-b</tt> tells it you already have a bootable image
and don't need the script to attempt to make one.</li>

<li><tt>-f /,/var,/usr</tt> tells the script which filesystems to put
into the archive.  Everything on the root disk should go here.
I've not finished the script to figure out which is the root disk
and where stuff goes yet.</li>

<li><tt>-m /mnt</tt> tells the script where to put the
image.</li></ul><p>

When running the script, you may get errors like 
<pre>
    WARNING: computehash not found; cannot generate checksums
    cpio: Error with lstat() of "", errno 2, No such file or directory
</pre>
which you may safely ignore.</p><p>

The above command creates a directory, <tt>/mnt/cdrom</tt>
containing a jumpstart setup ready to do a Flash install of the
machine you just ran it on.  The contents of this directory need
to be mounted as <tt>/cdrom</tt> when slice 1 (created above)
boots up.  This means that you probably need to move the contents
of the subdirectory to the root of the disk.</p><p>

In this case, I've mounted my disk at <tt>/mnt</tt>, so to have
the disk set up properly, I run:<pre>
    # mv /mnt/cdrom/.install_config /mnt/cdrom/* /mnt
    # rmdir /mnt/cdrom
</pre>

<p>Now, to boot from the slice 1 on the disk, it is very handy to
use devalias in the boot prom.  My scsi disk is set up as c1t1d0 on a
UltraSPARC 5, so the devalias command is:
<pre>
    ok devalias scsi /pci@1f,0/pci@1/pci@1/SUNW,isptwo@4/sd@1,0
</pre>
With this alias, I can boot off of the prepped slice (b) using 
<pre>
    ok boot scsi:b
</pre>
(<tt>scsi:b</tt> here translates to
<tt>/pci@1f,0/pci@1/pci@1/SUNW,isptwo@4/sd@1,0:b</tt>)
</p><p>

Assuming you've set the <tt>cdrom</tt> variable in the
<tt>rcS</tt> script correctly, you should see it coming up,
rebuilding the system from the flash archive, and rebooting as
the restored system.</p>

<h2>Creating the CD</h2>

The first step to building the recovery CD is to capture slice 1.
Sun hardware looks at slice 1 on the CD to boot (that's a
gloss-over &mdash; it looks at a different slice depending on the
architecture, but, for our purposes, it looks at slice 1).  This
slice contains a complete UFS partition for booting.</p><p>

In the previous steps, we created a bootable recovery disk; now
we will use the slice 1 image to burn CDs for multiple
machines.</p><p>

<ol><li>

Copy the slice 1 image to a file:
<pre>
    # dd if=/dev/rdsk/c1t1d0s1 of=s1.img
</pre>
Make sure that your <tt>sbin/rcS</tt> script has the string
"cdrom=CdRoMmOuNtPoInTgOeShErE" in it.<p>

This image file can be used for different machines of the same
architecture, so keep it around.  The only thing you need to do
is replace the "cdrom=CdRoMmOuNtPoInTgOeShErE" bit with
"cdrom=/dev/dsk/???".  Make sure to use a string of the same
length when editing a binary file.  Pad with spaces if you must.</p></li><li>

Determine the proper <tt>/dev/dsk</tt> file for the cdrom.
Substitute this for the magic string in the <tt>s1.img</tt> file
above:
<pre>
    # sed 's/cdrom=CdRoMmOuNtPoInTgOeShErE/cdrom=\/dev\/dsk\/c0t2d0s0/' &lt; s1.img &gt; host.img
</pre></li><li>

Using the JumpStart image <tt>mksysidcfg</tt> created, the slice
1 image modified in the previous step, and a
recent copy of <a
href="http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/mkisofs.html">mkisofs</a>
(the version of mkisofs available with Solaris 8 won't work),
make an ISO image to burn to CD:
<pre>
    # mkisofs -B host.img,... -o host.iso cdrom
</pre>
The above command assumes that you are sitting in the parent
directory of the cdrom subdirectory that <tt>mksysidcfg</tt>
created.</li><li>

Burn the ISO image to disk:
<pre>
    # cdrecord dev=1,1 host.iso
</pre></li><p>

That's It!
</p></p>

If you find this procedure useful, please <a
href="mailto:mah@everybody.org">email me and let me know</a>.

<h2>References</h2>
<a
href="http://www.sun.com/blueprints/0301/BuildBoot.pdf">Building
a Bootable JumpStart Installation CD-ROM</a>

<!--

$ dd if=/dev/zero of=/var/tmp/cdrom.img bs=1048576 count=650
$ lofiadm -a /var/tmp/cdrom.img
</div>
<hr />
<div id="footer">
<table width="100%"><tr><td>
<address>
<a href="mailto:mah@everybody.org">mah@everybody.org</a>
</address>
<span class="modified">Last Modified: Sat Jul  9 21:22:05 2005</span>
</td><td align="right">

<a href="http://jigsaw.w3.org/css-validator/check/referer">
<img src="http://jigsaw.w3.org/css-validator/images/vcss.gif"
     alt="Valid CSS!" height="31" width="88" /></a>

<a href="http://validator.w3.org/check/referer">
<img src="http://validator.w3.org/images/vxhtml10"
     alt="Valid XHTML 1.0!" height="31" width="88" /></a>

</td></tr></table>
</div>
</body></html>

