Octave --- My octuple boot laptop

As I promised in several threads, here are some notes on how I installed several Operating Systems on my laptap. I will give links to the tools that I obtained from various third parties. And I will include the source code for a few scripts that I wrote.

Introduction
A few months ago the disk drive on my Inspiron 8200 fried out. I decided to customize it with new peripherals. I got a 100 GB Seagate drive and a DVD burner. That 100 GB drive is mounted in a carrier. It is a big deal to mount the drive in a carrier, but remove one screw and the carrier can just be pulled out. I bought a second carrier and a second 100 GB drive. This allows me to switch my hard drive and so I can try experiments with little risk. I can remove one of my batteries and install another drive in the battery slot. I have a floppy drive to install there. My BIOS supports booting from any ATA device so I can boot from the hard disk, the CD/DVD drive or the floppy.

I decided to install as many OS's as I could on the new setup. The problem is that, except for Linux, everything demands a primary partition and there are only 4 primary partitions. If one is used as a chain of logical partitions, that leaves 3 non-linux OS's. I decided to live with that. There are some extreme solutions that would allow more non-linux OS's, but they are too extreme. I wanted NETbsd, Desktop BSD, and Solaris 8 in addition to what I did install. But those 3 OS's did not seem worth very extreme measures. So I wound up with:

  • Windows XP
  • Redhat
  • Fedora
  • SuSE
  • Debian
  • Scientific
  • FreeBSD
  • Solaris 10

Tools

I used several software tools to help me with this project.

GRUB
First, I need a really good bootloader that I understand completely. GRUB is really the only game in town. There are some very powerful bootloader products, but without access to the source code, there is a limit to how well I can understand them. GRUB is actually very easy to understand, but it has been documented poorly. Until I understood GRUB, various disasters rendered my system unbootable. In each case I was able to eventually track down exactly what happened. It really is no longer possible to render my system unbootable.

Disk Director/True Image
I needed a Partition Manager and I have used Partition Magic in the past. But PowerQuest sold the product to another company and it doesn't seem to be well supported now. I decided to try Acronis Disk Director which is less expensive. It isn't perfect, but it worked well enough. I also bought Acronis True Image. Again not perfect, but it can completely restore the system on to a brand new drive from DVD backup. You can create a bootable cd that has both products on it. This allows backups and restores from a quiescent disk. Disk Director comes with a GUI sector editor that is arguably better that dskprobe.

Disk Wizard/Seatools
Seagate has these utilities available for download from their site. These are bootable CD's that can run diagnostics and write zeros over an entire drive among various other tasks. I like to zero out a drive before I do a re-install (9 hours for 100 GB!). And it can do non-destructive tests on the drive. Other manufacturers have similiar utilities.

System Rescue CD
When I did have trouble during the project, this is the tool that got me out of the woods. It is basicly a "Live CD" with a lot of useful tools available.

Sector Inspector
This is an XP comand line based physical sector utility. It can do a lot of stuff that the GUi based sector editors cannot do. This is a Microsoft program and it is free.

grub
Acronis Disk Director Suite 10.0
Acronis True Image 9.0 Home
Disk Wizard
Seatools
SystemRescueCd
sector inspector

I have switched from dskprobe to the Acronis Sector Editor. But dskprobe is free and it comes in the support tools package on the XP installation CD. Or you can download the Support Tools here. dskprobe comes with a doc file called dskprtrb.doc which I thought was very helpful. Also dskprobe is a stand-alone utility while the Acronis sector editor is a sub-tool of Disk Director.

Installation Notes

Here are some notes on what I did to install the os'es. I did not just gather a collection of OS's and jump straight into the mass installation. I did test installations first to gain experience with each installer. In every case, I used the "custom" options to maximize my flexibility during the install. This means that I had to understand each installer rather well. Remember that the Master Boot Record has a table for 4 partition entries.

Windows XP
I installed XP first on the first primary partition which I formatted with an NTFS filesystem. I installed the recovery console and I added an option to boot into safe mode. This means that the NT bootloader presents a menu not unlike the grub menu. I created an E: partition which used FAT32. This is my first logical partition. The second entry in the partition table is now consumed to support my string of logical partitions. This partition will contain data files and Linux will mount it as /driveE. This allows me move files between Linux and XP. At bootup time, the NT loader looks for a file called hiberfil.sys. If found, it is loaded into memory and execution resumes. This is how hibernation is implemented. Upon awakening from hibernation, it is critical that nothing has changed since hibernation began. Even docking or undocking a laptop is enough is cause problems. I will be booting via grub and I can't guarantee that another OS might not get started. Since I am sharing partitions among OS's this would be a recipe for disaster. So I have disabled hibernation.

Each of the other OS installation procedures is prepared to co-exist with a pre-existing XP instance in the first primary partition. Most of them would install a bootloader that could boot XP or themself. See the "failsafe boot" article below to see why this is not a problem.

Linux Distros
I used LVM for each Linux distro. Even / is under LVM, but Linux cannot boot from LVM, so I created a temporary /boot partition during the install. Let's take RedHat as am example...it was the first distro I installed. I copied /boot to /mastergrub/RedHat. Then I moved /mastergrub/RedHat/grub to /mastergrub/grub. /mastergrub/RedHat/grub became a symlink to /mastergrub/grub. And /boot becomes a symlink to /mastergrub/RedHat. Each distro gets its own subdirectory under /mastergrub and each of these subdirectories gets a grub symlink pointing to /mastergrub/grub. So all of the distros wind up using the same grub instance. That /boot partition is then just discarded.

I used a separate /tmp partition and swap partition putside of LVM. The swap area is 2 GB and /tmp is 1 GB. Each Linux distro uses the same partitions. So, in total, I use 3 GB for /tmp and swap rather than 15 GB. I am in the process of modifying the start up scripts to rebuild /tmp at boot time. This will mean that any OS can use the swap or /tmp area for any purpose. It also explains why /tmp in ext2 rather than ext3. There is no point in a log if I rebuild the filesystem upon each boot.

RedHat is rather old and it is out of step with the other distros. But I still encounter RedHat deployed by companies so I wanted a version on my laptop. RedHat is using LVM version 1 and the other distros use LVM version 2. I picked Fedora, and did a "vgscan --makenodes". This gave me device files for all of the other distros' logical volumes. I can mount the other distros when I need to. I will use this to develop a file level backup for the Linux distros. I have also used this to correct a problem with boot up scripts.

Every Linux partition is a logical partition. This includes the Grub partitions and the LVM partitions. I have a /userdata partition formatted as ext3 which all of the Linux distros mount. I do have a small /home (under LVM) in each distro so that each can have its own start up files, etc. But most of my stuff will go in /userdata. So each distro has its own LVM partition. But then there is swap, /tmp, /userdata, and /mastergrub (each in a separate logical partition) used by all distros in common. And there is /driveE which they mount as well.

FreeBSD
FreeBSD goes into primary partition 3. I used Acronis to pre-allocate the partition before the installation. FreeBSD carves up the partition intp pieces that it confusingly also calls partitions. In theory, Grub can boot FreeBSD directly, but I could not get that to work. So I had FreeBSD install it's own bootloader into the partition, thus leaving the MBR alone. Then I modified grub.conf to chainloader into it. I would like to get a direct Grub boot working and I plan to work on this. For now, it is good enough.

Solaris
I have one primary partition left and I installed Solaris 10 in it. Much like FreeBSD, Solaris carves the partition up. It uses "slices" so describe the pieces. Again, I preallocated the partition before doing the install. At the last minute I noticed that Sun had a new version of Solaris 10 on their site. I don't usually instantly jump to each new version, but Sun had switched from their own bootloader to using grub. So I downloaded the latest Solaris 10. Well, none of my versions of Grub can read the Solaris slices...I even downloaded the latest Grub from the Grub home page and still no go. Sun must have modified Grub. I may switch to Sun's version at some point. But for now, my Grub is chainloadering Sun's Grub.

My Final Grub Configuration
With each OS that used Grub, I took a look at its grub.conf. Many times I saw a new technique; and, if I liked it, I added it to my bag of tricks. SuSE heavily modified Grub and I could not find much info on their mods. There are warnings that SuSE's mods introduced a security problem. So I will not use the SuSE version of Grub. But even with SuSE, I found some things to use. My grub.conf:

#
#  This configuration file is maintained by a series of scripts that support the concept of this
#  partition being moved or copied.  Statements like "    r00t (xxxx) " where there is exactly one
#  space between the word "root" and the opening parenthesis will be replaced with a grub device
#  that corresponds to the current partition.  Put extra spaces after "root" to protect a root entry
#  from this automatic replacement.
default=1
timeout=60
color red/black black/green
	title Boot Octave from grub.conf on mastergrub
	root
title 1) Windows XP Pro
	root		(hd0,0)
	makeactive
	chainloader	+1
title 2) RedHat
	root (hd0,6)
	kernel /Redhat/vmlinuz-2.4.18-14 ro root=/dev/RedHat00/LogVol00 hdb=ide-scsi
	initrd /Redhat/initrd-2.4.18-14.img
title 3) Fedora Core
	root (hd0,6)
	kernel /Fedora/vmlinuz-2.6.15-1.2054_FC5 ro root=/dev/Fedora00/LogVol00 rhgb quiet
	initrd /Fedora/initrd-2.6.15-1.2054_FC5.img
title 4) SuSE
	root (hd0,6)
	kernel /SuSE/vmlinuz root=/dev/SuSE00/lvol0 vga=0x31a    resume=/dev/hda8  splash=silent showopts
	initrd /SuSE/initrd
title 5) Debian 
	root (hd0,6)
	kernel	/Debian/vmlinuz-2.4.27-2-386 root=/dev/mapper/Debian00-lvol0 ro 
	initrd	/Debian/initrd.img-2.4.27-2-386
title 6) Scientific 
	root (hd0,6)
	kernel /Scientific/vmlinuz-2.6.9-34.EL ro root=/dev/Scientific00/LogVol00 rhgb quiet
	initrd /Scientific/initrd-2.6.9-34.EL.img
title 7) FreeBSD
	rootnoverify (hd0,2)
	makeactive
	chainloader	+1
title 8) Solaris
	rootnoverify (hd0,3)
	makeactive
	chainloader +1
title ----UTILITIES----
	root
title ______reboot
	reboot
title ______off
	halt
title ______halt
	halt --no-apm
title ______floppy
	chainloader (fd0)+1

One of the secrets of success in a complex installation like this is to completely understand exactly where everything is on disk. Acronis disk director could list some of the info, but I needed more. I wrote a tool to take the info that Acronis displayed and produce a table for my notes...

   ===== Device Name ====                                     ========== Start ========== ========== End ============== ====== Length ========
P#   Grub   Linux FreeBSD      Description    Partition Type     LBA     Cyl--Head--Sectr    LBA     Cyl--Head--Sector   Sectors    MB    Cyls
-- -------- ----- ------- ------------------- --------------- ---------- ---------------- ---------- ------------------ --------- ------ -----
   (hd0)    hda           the whole disk                               0 (0---0---1)       195371568 (12161---81---1)     5371569   2622   334
                          first full cylinder                          0 (0---0---1)           16064 (0---254---63)         16065      7     1
                          usable space                                 0 (0---0---1)       195366464 (12160---254---63)   5366465   2620   334
                          unusable space                       195366465 (12161---0---1)   195371568 (12161---81---1)        5104      2
                          MBR                                          0 (0---0---1)               0 (0---0---1)                1
                          the hidden sectors                           1 (0---0---2)              62 (0---0---63)              62
1  (hd0,0)  hda1  ad0s1   XP                  NTFS       0x07         63 (0---1---1)        31519529 (1961---254---63)    1519467    741    94
                          EBR                                   31519530 (1962---0---1)     31519592 (1962---0---63)           63
5  (hd0,4)  hda5  ad0s4   driveE              FAT32      0x0B   31519593 (1962---1---1)     52500419 (3267---254---63)    0980827    478    61
                          EBR                                   52500420 (3268---0---1)     52500482 (3268---0---63)           63
6  (hd0,5)  hda6  ad0s5   /userdata           EXT3       0x83   52500483 (3268---1---1)     62990864 (3920---254---63)    0490382    239    30
                          EBR                                   62990865 (3921---0---1)     62990934 (3921---1---7)            70
7  (hd0,6)  hda7  ad0s7   /mastergrub         EXT3       0x83   62990935 (3921---1---8)     63263969 (3937---254---63)     273035    133    16
                          EBR                                   63263970 (3938---0---1)     63264032 (3938---0---63)           63
8  (hd0,7)  hda8  ad0s8                       Linux swap 0x82   63264033 (3938---1---1)     67472999 (4199---254---63)    4208967   2055   262
                          EBR                                   67473000 (4200---0---1)     67473062 (4200---0---63)           63
9  (hd0,8)  hda9  ad0s9   /tmp                EXT3       0x8E   67473063 (4200---1---1)     69577514 (4330---254---63)    2104452   1027   131
                          EBR                                   69577515 (4331---0---1)     69577577 (4331---0---63)           63
10 (hd0,9)  hda10 ad0s10  Redhat00            Linux LVM  0x8E   69577578 (4331---1---1)     77979509 (4853---254---63)    8401932   4102   523
                          EBR                                   77979510 (4854---0---1)     77979572 (4854---0---63)           63
11 (hd0,10) hda11 ad0s11  Fedora00            Linux LVM  0x8E   77979573 (4854---1---1)     88469954 (5506---254---63)    0490382    239    30
                          EBR                                   88469955 (5507---0---1)     88470017 (5507---0---63)           63
12 (hd0,11) hda12 ad0s12  SuSE00              Linux LVM  0x8E   88470018 (5507---1---1)    101064914 (6290---254---63)    2594897   1267   161
                          EBR                                  101064915 (6291---0---1)    101064977 (6291---0---63)           63
13 (hd0,12) hda13 ad0s13  Debian00            Linux LVM  0x8E  101064978 (6291---1---1)    117852839 (7335---254---63)    6787862   3314   422
                          EBR                                  117852840 (7336---0---1)    117852902 (7336---0---63)           63
14 (hd0,13) hda14 ad0s14  Scientific00        Linux LVM  0x8E  117852903 (7336---1---1)    130447799 (8119---254---63)    2594897   1267   161
                          EBR                                  130447800 (8120---0---1)    130447862 (8120---0---63)           63
15 (hd0,14) hda15 ad0s15  /backupgrub         EXT3       0x83  130447863 (8120---1---1)    130720904 (8136---254---63)     273042    133    17
                          EBR                                  130720905 (8137---0---1)    130720967 (8137---0---63)           63
16 (hd0,15) hda16 ad0s16  /testgrub           EXT3       0x83  130720968 (8137---1---1)    130994009 (8153---254---63)     273042    133    17
                          Free Space                           130994010 (8154---0---1)    158256314 (9850---254---63)    7262305   3546   452
2  (hd0,2)  hda2  ad0s2                       FreeBSD    0xA5  158256315 (9851---0---1)    172939724 (10764---254---63)   4683410   2286   291
3  (hd0,3)  hda3  ad0s3                       Solaris    0xBF  172939725 (10765---0---1)   195366464 (12160---254---63)   2426740   1184   151

Some notes on this...

MBR, the hidden sectors, and the EBR's
The Master Boot Record (MBR) is the first sector of the disk. It has the boot code and the partition table in it. The rest of the first track is called "the hidden sectors". In my case, Grub stage 1.5 is in the hidden sectors. The structure of this first track is duplicated for each logical partition. Each logical partition has a structure like a MBR as it first sector. Then the rest of the first track is ignored. This first track immediately precedes the logical partition that it describes. Microsoft uses the term "logical drive" which almost means the same thing as "logical partition". But looking carefully at the definitions it seems to me that "logical drive" = EBR + "wasted sectors" + "logical partition". In any case, you need the MBR and the EBR's to define the partition layout of a drive. I see programs to backup the MBR but they always ignore the EBR's. I will fix that by writing a utility to backup the MBR plus the EBR's. Strickly speaking the EBR is one sector and it is followed by some wasted sectors. In my chart I have cheated a little bit and redefined the EBR to be all overhead sectors between partitions. I feel that the chart is "busy enough" and would be even harder to read with two lines between each partition.

Cylinder Alignment
Notice how the partitions are generally aligned on cylinder boundaries. The exception is /mastergrub and this is due to a bug in Acronis Disk Director. I originally had /mastergrub at .5 MB which is too big. I shrunk it, but I made the free space appear before the partition rather then after it. (This let me shuffle the free space down and add it to my XP partition.) When I produced this chart, I noted that /mastergrub was not aligned properly. This wastes a few more cylinders, but it seems to have few consequences. The only potential problems that I can think of... Some programs try to guess the disk geometry....with amazing success. They might do this by looking at the alignment of the partitions. Some programs (like Acronis itself) can locate and restore deleted partitions. This might fail if the partition was misaligned to begin with. I notice that Acronis has a "fast" and "slow" search for deleted partitions (with the "slow" option being more robust) and this might push you into the "slow" option.

This encouraged me to experiment with partitions that were truly logical but also had an entry in the fourth MBR slot as a primary partition. My idea was to switch one of several logicals into the primary slot, install an OS, destroy the primary entry, and boot from the logical partition. This did not work very well. A smart bootloader could switch a partition from logical to primary and then boot it, but I did not want to write a bootloader.

I notice that each logical partition is wasting most of a full track. I am considering misaligning all of the partitions to recover that space. There is not a lot of space to be recovered and this may not be worth the effort. Also Acronis does not have enough control to allow me to try. I believe that qtparted can do this though.

Solaris Changed Types
Solaris 10 is using BF as its partition type and the Solasis 10 installer does not recognize partition with a type of 82 anymore.

I did not want to enter the starting and ending LBA's for the EBR's. The script should be able to calculate them from the preceding and following entries. This increased the complexity of the script but in the long run it saved effort. And here is the source code...

#! /usr/bin/ksh

typeset -L3 opartn
typeset -L9 ogrubdev
typeset -L6 olinuxdev
typeset -L8 ofbsddev
typeset -L20 odesc
typeset -L11 otype
typeset -L5 ohextype
typeset -R9 ofirst
typeset -L17 ofirstchs
typeset -R9 olast
typeset -L20 olastchs
typeset -R7 olong
typeset -R6 omegs
typeset -R5 ocyls
function chs
{
        ((s=$1%63))
        ((rest=$1/63))
        ((h=rest%255))
        ((c=rest/255))
        ((c=rest/255))
        ((s=s+1))
        echo "(${c}---${h}---${s})"
        return 0
}
some_data_left=1
saved_record=0

echo '   ===== Device Name ====                                     ========== Start ========== ========== End ============== ====== Length ========'
echo 'P#   Grub   Linux FreeBSD      Description    Partition Type     LBA     Cyl--Head--Sectr    LBA     Cyl--Head--Sector   Sectors    MB    Cyls'
echo '-- -------- ----- ------- ------------------- --------------- ---------- ---------------- ---------- ------------------ --------- ------ -----'

echo ';(hd0)   ;hda       ;            ;the whole disk     ;          ;    ;        0;195371568
      ;        ;          ;            ;first full cylinder;          ;    ;        0;    16064
      ;        ;          ;            ;usable space       ;          ;    ;        0;195366464
      ;        ;          ;            ;unusable space     ;          ;    ;195366465;195371568
      ;        ;          ;            ;MBR                ;          ;    ;        0;        0
      ;        ;          ;            ;the hidden sectors ;          ;    ;        1;       62
     1;(hd0,0) ;hda1      ;ad0s1       ;XP                 ;NTFS      ;0x07;       63; 31519529
      ;        ;          ;            ;EBR                ;          ;    ;         ;
     5;(hd0,4) ;hda5      ;ad0s4       ;driveE             ;FAT32     ;0x0B; 31519593; 52500419
      ;        ;          ;            ;EBR                ;          ;    ;         ;
     6;(hd0,5) ;hda6      ;ad0s5       ;/userdata          ;EXT3      ;0x83; 52500483; 62990864
      ;        ;          ;            ;EBR                ;          ;    ;         ;
     7;(hd0,6) ;hda7      ;ad0s7       ;/mastergrub        ;EXT3      ;0x83; 62990935; 63263969
      ;        ;          ;            ;EBR                ;          ;    ;         ;
     8;(hd0,7) ;hda8      ;ad0s8       ;                   ;Linux swap;0x82; 63264033; 67472999
      ;        ;          ;            ;EBR                ;          ;    ;         ;
     9;(hd0,8) ;hda9      ;ad0s9       ;/tmp               ;EXT3      ;0x8E; 67473063; 69577514
      ;        ;          ;            ;EBR                ;          ;    ;         ;
    10;(hd0,9) ;hda10     ;ad0s10      ;Redhat00           ;Linux LVM ;0x8E; 69577578; 77979509
      ;        ;          ;            ;EBR                ;          ;    ;         ;
    11;(hd0,10);hda11     ;ad0s11      ;Fedora00           ;Linux LVM ;0x8E; 77979573; 88469954
      ;        ;          ;            ;EBR                ;          ;    ;         ;
    12;(hd0,11);hda12     ;ad0s12      ;SuSE00             ;Linux LVM ;0x8E; 88470018;101064914
      ;        ;          ;            ;EBR                ;          ;    ;         ;
    13;(hd0,12);hda13     ;ad0s13      ;Debian00           ;Linux LVM ;0x8E;101064978;117852839
      ;        ;          ;            ;EBR                ;          ;    ;         ;
    14;(hd0,13);hda14     ;ad0s14      ;Scientific00       ;Linux LVM ;0x8E;117852903;130447799
      ;        ;          ;            ;EBR                ;          ;    ;         ;
    15;(hd0,14);hda15     ;ad0s15      ;/backupgrub        ;EXT3      ;0x83;130447863;130720904
      ;        ;          ;            ;EBR                ;          ;    ;         ;
    16;(hd0,15);hda16     ;ad0s16      ;/testgrub          ;EXT3      ;0x83;130720968;130994009
      ;        ;          ;            ;Free Space         ;          ;    ;130994010;158256314
     2;(hd0,2) ;hda2      ;ad0s2       ;                   ;FreeBSD   ;0xA5;158256315;172939724
     3;(hd0,3) ;hda3      ;ad0s3       ;                   ;Solaris   ;0xBF;172939725;195366464'|\
while ((some_data_left)) ; do
        if ((saved_record)) ; then
                saved_record=0
                partn=$saved_partn
                grubdev=$saved_grubdev
                linuxdev=$saved_linuxdev
                fbsddev=$saved_fbsddev
                desc=$saved_desc
                type=$saved_type
                hextype=$saved_hextype
                first=$saved_first
                last=$saved_last
        else
                if IFS=";" read partn grubdev linuxdev fbsddev desc type hextype first last ; then
                        if [[ "$desc" = EBR* ]] ; then
                                if IFS=";" read partn grubdev linuxdev fbsddev desc type hextype fir
                                        saved_record=1
                                        saved_partn=$partn
                                        saved_grubdev=$grubdev
                                        saved_linuxdev=$linuxdev
                                        saved_fbsddev=$fbsddev
                                        saved_desc=$desc
                                        saved_type=$type
                                        saved_hextype=$hextype
                                        saved_first=$first
                                        saved_last=$last
                                        partn=""
                                        grubdev=""
                                        linuxdev=""
                                        fbsddev=""
                                        type=""
                                        hextype=""
                                        desc="EBR"
                                        ((first=old_last+1))
                                        ((last=saved_first-1))
                                else
                                        echo error EBR is last record >&2
                                        exit 1
                                fi
                        fi
                else
                        some_data_left=0
                fi
        fi

        if ((some_data_left)) ; then
                opartn=$partn
                ogrubdev=$grubdev
                olinuxdev=$linuxdev
                ofbsddev=$fbsddev
                odesc=$desc
                otype=$type
                ohextype=$hextype
                ofirst=$first
                ofirstchs=$(chs $first)
                olast=$last
                olastchs=$(chs $last)
                ((olong=last-first+1))
                if ((olong>2048)) ; then
                        ((omegs=olong/2048))
                else
                        omegs=""
                fi
                if ((olong>16064)) ; then
                        ((ocyls=(olong+64)/16065))
                else
                        ocyls=""
                fi
                echo "${opartn}${ogrubdev}${olinuxdev}${ofbsddev}${odesc}${otype}${ohextype}" \
                        "${ofirst} ${ofirstchs} ${olast} ${olastchs} ${olong} ${omegs} ${ocyls}"

                old_partn=$partn
                old_grubdev=$grubdev
                old_linuxdev=$linuxdev
                old_fbsddev=$fbsddev
                old_desc=$desc
                old_type=$type
                old_hextype=$hextype
                old_first=$first
                old_last=$last
        fi
done
exit 0

The /mastergrub partition has the grub software and the kernels for each installed Linux distro. Grub stage 1 resides in the Master Boot Record (MBR) which is the first sector of the disk. More often than not, each OS install would rewrite the MBR to point to it's own copy of grub or other bootloader. Sometimes I would fiddle around the grub software in /mastergrub and break it. In addition to installing grub stage 1 in the MBR, stage 1 can be installed in the first sector of that partition. And then some other bootloader can chainloader into it. I wrote my own installation scripts. They are:

mbrinstall
This script simply installs grub stage 1 in the MBR.

localinstall
This script installs grub stage 1 in the local partition. (/mastergrub for now.) Then is uses dd to obtain a copy of the first sector of the local partition. This is put in a file in the /driveE filesystem. Recall that /diveE is a FAT32 filesystem used to pass files between linux and XP. Windows XP will obtain the sector and incorporate it into the XP bootup sequence. In XP my boot.ini file is something like:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Pro" /fastdetect /NoExecute=OptIn
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Pro (Safe Mode)" /fastdetect /NoExecute=OptIn /safeboot:minimal /sos /bootlog
C:\bootsector.mastergrub="MasterGrub Menu"
C:\CMDCONS\BOOTSECT.DAT="Microsoft Windows Recovery Console" /cmdcons

So now, if I can boot XP, I can use XP to transfer control to grub in /mastergrub. This is a big help since most OS install scripts install a boot loader with an option to boot Windows. So I can use that option, start to boot XP, but select the menu option to boot /mastergrub. Then I boot a distro, and run the mbrinstall script mentioned above.

floppyinstall
Booting from XP will not work if I have damaged the grub software in /mastergrub. I don't have room on a floppy for those kernels, but I have never broken my kernels. I easily have room on a floppy for grub, including the grub.conf file. This script creates such a floppy. Then I can boot the floppy and start the system that way.

cdinstall
What if I completely lose /mastergrub? cdinstall creates a CD which is a complete backup of /mastergrub. Additionally, it is a bootable CD which can boot any of the distros without using /mastergrub at all. This script needed a piece of Grub called stage2_eltorito which was not supplied with any version of Grub that I had. So I downloaded and compiled the source code from the Grub home page.

/backupgrub and /testgrub
Actually all of the above scripts have benn extended to support /backupgrub. This is simply another partition which is a copy of /mastergrub. Every now and then, I use rsync to copy the files over. Then I cd into /backupgrub and run the localinstall script. Whenever one of these scripts runs, it figures out what partition it is running in. The grub.conf file is adjusted to reflect the current partition (or in the case of cdinstall, adjusted to boot from cd). I also created a /testgrub partition so that I would stop running dangerous experiments in a critical partition.

supermbrbackup
A number of utilities exist to backup and restore the MBR. This includes the boot code and the partition table. The thing is though, that of my partitions are described in Extended Boot Records scattered all over my disk. I wanted a utility that would recreate all of my partitions (empty of course) on a brand new disk. And while I was at it, I had it scan the unused sectors after the MBR which is where GRUB stage 1.5 resides. So this backs up everything except the contents of partitions. The backup are written to a floppy along with a script to restore them. This script can be run after booting the System Rescue CD. My intent was that this would be the first step in a bare metal restore. But it turns out that I didn't need it.

Bare Metal Restore
This is what happen if I lose the entire hard disk. This is the ultimate in ensuring that I can boot. I used Acronis True Image to do a complete backup of my drive. It does not support Linux LVM nor FreeBSD and Solaris slices. But it can do a sector-by-sector backup of those partitions. After the backup finished, I replaced my hard drive and used my bootable Seatools disk to zero it out (9 hours with a 100 GB disk). Then I booted my Acronis boot disk and fed it the backup DVD's. It recreated my entire system.

I used a Seagate utility to write zeros to the entire disk before I started. That means that the Linux LVM and FreeBSD/Solaris partitions probably had a lot of zeroed sectors in the unused space. This helps the compression routine in the Acronis sector-by-sector backup do a good job.

I still need a file level backup for Linux/FreeBSD/Solaris. I will work on that.

Here is the source code for the scripts mentioned above.

#! /bin/bash

#
#  mbrinstall --- install grub from this partition on to the MBR of the
#  current disk.  When the BIOS subsequently boots this disk, it will run
#  grub from this partition.

if [[ $(pwd) != */scripts  || $0 != ./* ]]  ; then
	echo error you must cd to the scripts directory and invoke this script with "./name"
	exit 1
fi
#
#  Extract device file name and mount point from the output of "df" command
set $(df -k . | awk  'NR == 2 { print $0}')
devicefile=$1
mountpoint=$6
name=${mountpoint#/}

#
#  Build grub style device name

devicefile=$(df -k . | awk  'NR == 2 { print $1}')
string=${devicefile#/dev/}
partition=${string#???}
drive=${string%$partition}
case "$drive" in
	hda) grubdrive="hd0" ;;
	hdb) grubdrive="hd1" ;;
	hdc) grubdrive="hd2" ;;
	hdd) grubdrive="hd3" ;;
	*)
		echo localinstall cannot handle device $drive
		exit 1
		;;
esac
((partition=partition-1))
grubdevice="(${grubdrive},${partition})"
echo devicefile=$devicefile
echo mountpoint=$mountpoint
echo name=$name
echo partition = $partition
echo drive = $drive
echo grubdrive = $grubdrive
echo grubdevice = $grubdevice

#
# rewrite grub.conf to reflect the local partition

cp ../grub/grub.conf ../grub/grub.conf.old
sed < ../grub/grub.conf.old > ../grub/grub.conf \
's/.*root (.*/	root '${grubdevice}'/
s/.*title Boot Octave from.*/	title Boot Octave from '${name}'/'

#  
#  Use grub to install itself on the drive

set -x
${mountpoint}/bin/grub --batch --verbose --device-map=${mountpoint}/grub/device.map << End
root  $grubdevice
setup  (${grubdrive})
End
set +x
exit 0
#! /bin/bash

#
#  localinstall --  install grub in the first sector of the current partition. 
#  This will make the current partition bootable.

dir=$(pwd)

if [[ $dir != */scripts  || $0 != ./* ]]  ; then
	echo error you must cd to the scripts directory and invoke this script with "./name"
	exit 1
fi
exit 0
#
#  Extract device file name and mount point from the output of "df" command
set $(df -k . | awk  'NR == 2 { print $0}')
devicefile=$1
mountpoint=$6
name=${mountpoint#/}

#
#  Build grub style device name

string=${devicefile#/dev/}
partition=${string#???}
drive=${string%$partition}
case "$drive" in
	hda) grubdrive="hd0" ;;
	hdb) grubdrive="hd1" ;;
	hdc) grubdrive="hd2" ;;
	hdd) grubdrive="hd3" ;;
	*)
		echo localinstall cannot handle device $drive
		exit 1
		;;
esac
((partition=partition-1))
grubdevice="(${grubdrive},${partition})"
echo devicefile=$devicefile
echo mountpoint=$mountpoint
echo name=$name
echo partition = $partition
echo drive = $drive
echo grubdrive = $grubdrive
echo grubdevice = $grubdevice


#
# rewrite grub.conf to reflect the local partition

cp ../grub/grub.conf ../grub/grub.conf.old
sed < ../grub/grub.conf.old > ../grub/grub.conf \
's/.*root (.*/	root '${grubdevice}'/
s/.*title Boot Octave from.*/	title Boot Octave from '${name}'/'

set -x


# 
#  We are going to write on the raw device so
#  make sure that the filesystem does not also
#  do any writing.

mount -o remount -o ro $mountpoint
sync

#  
#  Use grub to install itself on the device

${mountpoint}/bin/grub --batch --verbose --device-map=${mountpoint}/grub/device.map << End
root  $grubdevice
setup  $grubdevice
End

#
#  Now we need a new copy of bootsector to give to XP
[[ ! -d /driveE/bootsectors ]] && mkdir /driveE/bootsectors
dd if=${fulldevice} bs=512 count=1 of=/driveE/bootsectors/bootsector.$name

set +x

#
#  Restore read-write access to mountpoint
mount -o remount -o rw $mountpoint
exit 0
#! /bin/bash

#
#  floppyinstall -- install the grub software including the configuration file 
#  from this partition on to a floppy. This will create a bootable floppy that 
#  will boot the kernels from this partition.
#
if [[ $(pwd) != */scripts  || $0 != ./* ]]  ; then
	echo error you must cd to the scripts directory and invoke this script with "./name"
	exit 1
fi
#
#  Extract device file name and mount point from the output of "df" command
set $(df -k . | awk  'NR == 2 { print $0}')
devicefile=$1
mountpoint=$6
name=${mountpoint#/}

#
#  Build grub style device name

string=${devicefile#/dev/}
partition=${string#???}
drive=${string%$partition}
case "$drive" in
	hda) grubdrive="hd0" ;;
	hdb) grubdrive="hd1" ;;
	hdc) grubdrive="hd2" ;;
	hdd) grubdrive="hd3" ;;
	*)
		echo localinstall cannot handle device $drive
		exit 1
		;;
esac
((partition=partition-1))
grubdevice="(${grubdrive},${partition})"
echo devicefile=$devicefile
echo mountpoint=$mountpoint
echo name=$name
echo partition = $partition
echo drive = $drive
echo grubdrive = $grubdrive
echo grubdevice = $grubdevice

#
#  set up the floppy

set -x
mkdosfs -F 32 -c /dev/fd0
[[ ! -d /media/floppy ]]  && mkdir -p /media/floppy
mount -t vfat -o shortname=winnt /dev/fd0 /media/floppy

mkdir -p /media/floppy/boot/grub
cd /media/floppy/boot/grub
cp ${mountpoint}/grub/stage1 .
cp ${mountpoint}/grub/stage2 .
cd ${mountpoint}

#
# rewrite grub.conf to reflect the local partition

sed < ${mountpoint}/grub/grub.conf > /media/floppy/boot/grub/grub.conf \
's/.*root (.*/	root '${grubdevice}'/
s/.*title Boot Octave from.*/	title Boot Octave from '${name}' via floppy built '"$(date +'%B %e, %Y')"'/'

umount /dev/fd0

#  
#  Use grub to install itself on floppy

set -x
${mountpoint}/bin/grub --batch --verbose --device-map=${mountpoint}/grub/device.map << End
root  (fd0)
setup  (fd0)
End
exit 0
#! /bin/bash


#
#  cdinstall -- install the grub software including the configuration file 
#  from this partition on to a cd. This will create a bootable cd that 
#  can boot the kernels from the cd itself.
#
if [[ $(pwd) != */scripts  || $0 != ./* ]]  ; then
	echo error you must cd to the scripts directory and invoke this script with "./name"
	exit 1
fi
#
#  Extract device file name and mount point from the output of "df" command
set $(df -k . | awk  'NR == 2 { print $0}')
devicefile=$1
mountpoint=$6
name=${mountpoint#/}

#
#  Build grub style device name

string=${devicefile#/dev/}
partition=${string#???}
drive=${string%$partition}
case "$drive" in
	hda) grubdrive="hd0" ;;
	hdb) grubdrive="hd1" ;;
	hdc) grubdrive="hd2" ;;
	hdd) grubdrive="hd3" ;;
	*)
		echo localinstall cannot handle device $drive
		exit 1
		;;
esac
((partition=partition-1))
grubdevice="(${grubdrive},${partition})"
grubdevice="(cd)"
echo devicefile=$devicefile
echo mountpoint=$mountpoint
echo name=$name
echo partition = $partition
echo drive = $drive
echo grubdrive = $grubdrive
echo grubdevice = $grubdevice


set -x
mkdir /tmp/iso
mkdir /tmp/iso/backup
cp -R $mountpoint /tmp/iso/backup
mkdir -p /tmp/iso/boot/grub

cp /mastergrub/src/grub-0.97/stage2/stage2_eltorito /tmp/iso/boot/grub
#cp /mastergrub/grub/grub.conf /tmp/iso/boot/grub
# rewrite grub.conf to reflect the local partition

sed < ${mountpoint}/grub/grub.conf > /tmp/iso/boot/grub/menu.lst \
's/.*root (.*/	root '${grubdevice}'/
s/.*title Boot Octave from.*/	title Boot Octave from cd built '"$(date +'%B %e, %Y')"'/'
#cp /mastergrub/grub/grub.conf /tmp/iso/boot/grub/menu.lst
cp -R /mastergrub/Redhat /tmp/iso
cp -R /mastergrub/Fedora /tmp/iso
cp -R /mastergrub/SuSE /tmp/iso
cp -R /mastergrub/Debian /tmp/iso
cp -R /mastergrub/Scientific /tmp/iso
mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o /driveE/grub.iso /tmp/iso
exit 0
#! /bin/bash
#
#  supermbrbackup --  save disk infrastructure
#  This script backs up the partition structure on hd0.  It also scans the hidden sectors and backs up any
#  non-zero data.  In my case, this is grub stage 1.5.  And naturally, the boot code in the mbr is included.
#  Without this stuff, the disk won't be bootable.   The data is saved on a floppy disk.  Also a shell script
#  to restore the data is included on the floppy.  That script can be run from a bootable cd such as the
#  System Rescue CD.  So this is intended as the first step of a bare metal restore.
# 

#
#  We need some info about the disk (psuedo) geometry
SECT_NUM=63 #### Sectors per cylinder
SECT_LNG=512 ### Bytes per sector

#
#  This was originally a ksh script which was converted to bash.  The original ksh code is still here,
#  prefixed with "##".  
##integer bytes
##set -A bytes abytes
declare -a bytes abytes
typeset -i bytes

#
#  Build a filesystem on the floppy

mkfs -t ext2 -b 1024 -i 1024 -O sparse_super /dev/fd0 2>/dev/null
mkdir -p /media/fd0
mount -t ext2 /dev/fd0 /media/fd0

#
#  The variable called "restore" will contain the entire restore script.  The script will be written out
#  once it is complete.  I wanted to prevent excess i/o on the floppy drive and I expect the script to 
#  be short... so I decided to build it in-core.

total_saved=0
restore="#! /bin/bash"

#
#  Read a specified sector and set up the arrays abytes and bytes with the contents of each byte

function read_sector 
{
	skip=$1
	## dd if=/dev/hda bs=$SECT_LNG skip=$skip count=1 2>/dev/null| od -An -t x1  -w32 -v
	abytes=( $(dd if=/dev/hda bs=$SECT_LNG skip=$skip count=1 2>/dev/null| od -An -t x1  -w32 -v ))
	for((ibyte=0; ibyte < ${#abytes[*]}; ibyte++)) ; do
		bytes[ibyte]="16#${abytes[ibyte]}"
	done
	return 0
}

#
#  Write the sector onto the floppy disk (also update the restore script)

function save_sector
{
	((total_saved++))
	dd if=/dev/hda bs=$SECT_LNG skip=$1 count=1 2>/dev/null of=/media/fd0/sec${1}
	restore="$restore
	dd if=sec${1} bs=$SECT_LNG seek=$1 count=1 of=/dev/hda"
	return 0
}

#
#  Nothing to check.... sector zero is always saved.

echo sector 0 is the MBR
save_sector 0

#
#  Now scan the hidden sectors.  Back them up only if the sectors contains some non-zero data

for((sec=1; sec < $SECT_NUM; sec++)) ; do
	read_sector $sec
	nonzero=0
	for((ibyte=0; ibyte < ${#bytes[*]}; ibyte++)) ; do
		((${bytes[ibyte]})) && nonzero=1
	done
	if ((nonzero)) ; then
		echo sector $sec has non-zero data
		save_sector $sec
	fi
done

##typeset -R2 partition
##typeset -i bytes
##typeset -R11 next
read_sector 0
exstart=0

#
#  Scan the partition table looking for an extended partition.

for ((partition=1; partition < 5; partition++))  ; do
	((s=430 + (partition * 16)))
	status=${abytes}
	type=${abytes[s+4]}
	(( fval=(( (${bytes[s+11]}*256+${bytes[s+10]})*256 + ${bytes[s+9]})*256)+${bytes[s+8]} ))
	(( length=(((${bytes[s+15]}*256+${bytes[s+14]})*256+${bytes[s+13]})*256)+${bytes[s+12]} ))
	((lval=fval+length-1))
	((lval == -1)) && ((lval=0))
	if [[ $type = 0f ]] ; then
		exstart=$fval
	fi
done

#
#  If we found an extended partition, step though the logical's and back up each MBR of each logical
#  drive.
if ((exstart)) ; then
	next=$exstart
	while ((next)) ; do
		read_sector $next
		((s=430 + (1 * 16)))
		type=${abytes[s+4]}
		(( fval=(( (${bytes[s+11]}*256+${bytes[s+10]})*256 + ${bytes[s+9]})*256)+${bytes[s+8]} ))
		(( length=(((${bytes[s+15]}*256+${bytes[s+14]})*256+${bytes[s+13]})*256)+${bytes[s+12]} ))
		((lval=fval+length-1))
		((lval == -1)) && ((lval=0))
		((pstart=fval + next))
		((pstop=lval + next))
		((s=430 + (2 * 16)))
		type=${abytes[s+4]}
		(( fval=(( (${bytes[s+11]}*256+${bytes[s+10]})*256 + ${bytes[s+9]})*256)+${bytes[s+8]} ))
		(( length=(((${bytes[s+15]}*256+${bytes[s+14]})*256+${bytes[s+13]})*256)+${bytes[s+12]} ))
		((lval=fval+length-1))
		((lval == -1)) && ((lval=0))
		if ((length)) ; then
			((nextnext=fval+exstart))
		else
			((nextnext=0))
		fi
		echo "sector $next describes logical partition $partition ($pstart - $pstop)"
		save_sector $next
		((partition=partition+1))
		((next=nextnext))
	done
fi

#
#  Write out the restore script and finish up

echo "$restore" > /media/fd0/restore
chmod 755 /media/fd0/restore
umount /dev/fd0
exit 0