MIGRATING YOUR SYSTEM TO ANOTHER HARDDRIVE

by Ted Walther <ted@reactor-core.org>

Sun Oct 29 15:31:39 PST 2000

INTRODUCTION

Since GNU/Linux and the free BSDs made their appearance in the i386 world, what is considered a "small" hard drive has gotten larger, from 500M in 1992, to 15G now, 8 years later.

As everyone knows, all harddrives get filled up eventually. Then we go out and find newer, bigger ones :-) Most of us have probably gone through several hard drives in the last 8 years, each a binary order of magnitude larger than the last.

Whether a GNU/Linux, BSD, or Windows user, for most people this has involved doing a fresh install of your OS of choice on the newer, bigger harddrive, trying to recall exactly what tricks you needed to use 2 years ago the last time you did this, to configure the system as close to that carefully customized environment you already had on your previous drive. And then you carefully copy over anything you think you might need or want from the old drive to the new. The first pass usually misses things; you don't realize you left something on the old drive until months have passed and its a matter of life and death and you've already reformatted the drive for other purposes :-) One can never seem to recreate ones former system by doing a reinstall.

In gardening, the "move by reinstalling" method would be like carefully buying new pots and soil, preparing them in the location you want, then ripping your old plants out of their comfy homes and sticking them in the new pots. The plants MAY survive… but they'll take a long time to recover, if they ever do. The correct method is to carefully slip the plant together with the soil out of the old pot, gently put it in the new pot, and put new soil around the roots to give it the stability and nutrition to grow some more.

Today I hope to show the equivalent of that gentle transplant for your personal systems. This weekend I went through the process myself, having finally filled up my 4G drive; I transplanted my system to a 15G drive.

The now defunct Signal Ground website wrote an excellent article on how they used a couple Unix commands to duplicate their Windows systems. I have a couple warnings about Signal Grounds approach. They work in a test environment; probably they have a large number of identical disks; even if they don't, for them the important thing is to have a functioning Windows system for testing purposes, not necessarily to take advantage of increased size of bigger disks. Although I haven't tested it, I believe their approach doesn't take advantage of extra space if the target install drive is larger than the original. It would also fail disastrously if for some reason your target drive is *smaller* than the original.

Today I present a way which gets around the potential problems in Signal Grounds approach. I did additional research and show how to complete the process without any extraneous reboots, or need for floppy or cdrom drives to boot from.

PREPARATION

Thats it. No need for a floppy or cdrom drive during the whole process, so if you don't have enough room to put the new drive in, take the cdrom drive out and plug the harddrive in its place.

FORMATTING AND PARTITIONING

Under GNU/Linux, one must use the fdisk(8) and mke2fs(8) programs; under BSD one uses disklabel(8) and newfs(8).

When I plugged in my new 15G drive this weekend, it showed up as /dev/hdc. Under Open or Net BSD it might have shown up as /dev/wd2; under newer versions of FreeBSD it would have looked like /dev/ad2.

The important thing here is to make sure you make a corresponding partition on the new drive for every one on the old drive; be careful about making the new partitions smaller; by all means make them larger.

Now for a word about BSD's partitioning scheme and why Linux would do well to copy it; The root partition mounted as "/" should be 64M in size. How you partition the rest is up to you; but following this little rule means you never have to worry about cylinder limits and such like when setting up boot loaders to boot your OS. It means all your other partitions (especially /usr) can be as large as you wish, because no other partition has to stay below the 1024 cylinder limit.

Anyhow, I did this under GNU/Linux:

$ fdisk /dev/hdc
... created the partitions ...
$ mke2fs /dev/hdc1
$ mkswap /dev/hdc2
$ mke2fs /dev/hdc3
$ mke2fs /dev/hdc4

Under BSD I would have done this:

$ disklabel -w -B wd2
$ disklabel -e wd2
... it pops you into vi; you need to get out your
... hand calculator to calculate starting offsets
... and partition sizes in 512 byte sectors, but
... other than that its very easy and straightforward
$ newfs /dev/wd0a
$ newfs /dev/wd0e
$ newfs /dev/wd0f

COPYING THE DATA

Any POSIX shell of the Bourne family should work; I have tested the following commands with the ash and bash shells. korn and C shells not guaranteed.

The version of GNU Tar that comes with the BSD's and any recent GNU/Linux will work; other tars may, but I have not tested them. GNU/Linux afficionados will note that some of the zoomier features of GNU tar are not used here; that is because the free BSD's use an older version of GNU tar.

Now, mount your new drive somewhere with the same hierarchy you have on your current drive. For instance, my current drive looks like this:

$ df
Filesystem           1k-blocks      Used Available Use% Mounted on
/dev/hda1               254244     65549    175568  28% /
/dev/hda3               508052    173928    307891  37% /var
/dev/hda4             13535176   5427564   7420056  43% /usr

After I've mounted my new drive, things should look like this:

$ df
Filesystem           1k-blocks      Used Available Use% Mounted on
/dev/hda1               254244     65549    175568  28% /
/dev/hda3               508052    173928    307891  37% /var
/dev/hda4             13535176   5427564   7420056  43% /usr
/dev/hdc1               254244         2    241531   0% /mnt
/dev/hdc3               508052         2    482649   0% /mnt/var
/dev/hdc4             13535176         2  12858417   0% /mnt/usr

Normally, given the task of copying a directory hierarchy, one would think of using cp -Rp. Well, that doesn't quite work. Next, one might think to use cpio(1). Cpio has some bugs which make it unsuitable too. ar(1)? Please, give me a break. No, tar(1), with all its warts, wins the contest here.

Before actually beginning to copy, one needs to decide what shouldn't be copied. If your new drive is mounted on /mnt, you definately don't want to copy it to itself; that way lies recursion madness.

$ echo mnt     > /excludes

Next, its not usually a good idea to try to copy /proc:

$ echo proc   >> /excludes

On a typical system, whether BSD or GNU/Linux, one probably wants to X out other external media mount points, such as /cdrom and /floppy

$ echo cdrom  >> /excludes
$ echo floppy >> /excludes

On a BSD system, one definately wants to X out the kernfs mount point as well:

$ echo kern   >> /excludes

Once finished setting up the file listing the directories to not copy over, one should at least create those mount points on the new harddrive and make sure they have the same ownership and permissions on the new drive as on the original. On my Debian system I ended up doing the following:

$ cd /
$ ls -ld $(cat excludes)
drwxr-xr-x    2 root     root         1024 Oct 28 13:03 cdrom
drwxr-xr-x    2 root     root         1024 Oct 28 13:03 floppy
drwxr-xr-x    2 root     root         1024 Oct 28 13:03 mnt
dr-xr-xr-x   81 root     root            0 Oct 28 15:50 proc
$ mkdir -m 755 /mnt/cdrom
$ mkdir -m 755 /mnt/floppy
$ mkdir -m 755 /mnt/mnt
$ mkdir -m 555 /mnt/proc

Lets see if that did the trick:

$ cd /mnt
$ ls -ld $(cat /excludes)
drwxr-xr-x    2 root     root         1024 Oct 28 13:03 cdrom
drwxr-xr-x    2 root     root         1024 Oct 28 13:03 floppy
drwxr-xr-x    2 root     root         1024 Oct 28 13:03 mnt
dr-xr-xr-x   81 root     root            0 Oct 28 15:50 proc

Yup, that did it. Now we are finally ready to duplicate the contents of our drive.

$ cd /
$ tar cf - * -X excludes | (cd /mnt; tar xpf -)

Depending how much data you have to move, this could take more than 1/2 an hour. In the extreme case, this could take several hours, so to put your mind at ease, replace tar xpf in the script above with tar xvpf. Adding the -v option will display each file as it is successfully copied.

MAKING IT BOOTABLE

Under BSD, when we ran disklabel(8) with the "-w -B" options, we already made the drive bootable. Nothing more need be done.

Under GNU/Linux, things are quite different. Horrifyingly messy in fact. The default bootloader, lilo(8), has options to install boot code to arbitrary drives; but it has no capability of letting one set up a drive to boot when that drives physical device number will change, such as when I move my new drive from being /dev/hdc to /dev/hda. What *is* possible with lilo(8) is to shutdown, plug your new drive into its final destination, then boot from a cdrom or floppy disk that has lilo(8) installed, tell the kernel the root device is the partition you plan to be your root partition, and run lilo from your booted box. That is fine; but I promised you wouldn't need to do any extraneous reboots, nor need an extra floppy or cdrom drive.

Enter grub(8). You should have the source code downloaded before you powered down to single user mode; now:

$ cd grub-source-directory
$ ./configure; make; make install
$ mkdir -p /boot/grub
$ cp $(find /usr -type d -name i386-pc)/* /boot/grub
$ grub
 
    GRUB  version 0.5.96.1  (640K lower / 3072K upper memory)
 
 [ Minimal BASH-like line editing is supported.  For the first word, TAB
   lists possible command completions.  Anywhere else TAB lists the possible
   completions of a device/filename. ]
 
grub> device (hd0)   /dev/hdc
grub> root   (hd0,0)
grub> setup  (hd0)
grub> quit
$ 

Now grub(8) is installed on your target drive; you could reboot at this point if you are comfortable with issuing commands to the bootloader at bootup time. The info(5) pages have in recent times become an excellent introduction to grub, and I really recommend you read them.

We do want to add the final bit of convenience though; we want to automate the bootup. grub(8) has the nice feature that you don't have to tell it ahead of time which files you might want to boot as kernels. It has filesystem tab completion. Also, you can edit /boot/grub/menu.lst to create a menu of possibilities to boot from. Here is what mine looks like; you should be able to alter it to your own taste after reading the info(5) pages.

$ cat /boot/grub/menu.lst
default 0
timeout 10
 
title Masterful Debian I686 of Doom
root (hd0,0)
kernel /boot/vmlinuz
$

After editing menu.lst, there is no need to run any program to let grub know it changed; it finds it when it boots up.

In brief summary, grub(8) designates drives as (hd0) where GNU/Linux would use /dev/hda or BSD would use /dev/wd0. The first partition of the first drive in grub would become (hd0,0), compared to GNU/Linux's /dev/hda1, OpenBSD's /dev/wd0a and FreeBSD's /dev/ad0s1. Floppy disks become (fd0) instead of /dev/fd0.

CONCLUSION

Voila! Your system now has more room to grow. I hope this information is helpful. If you have any suggestions, corrections, or additions for this howto, I can be contacted at 604-582-9308, or at ted@reactor-core.org.

STANDARD DISCLAIMER OF LIABILITY

I hereby disclaim all liability for any use to which the information in this document may be put. I warrant that I have made this document as accurate as I can, and make no claim to its accuracy beyond that.

Kopyright (k) 2000, Nemo. All rights reversed. Copying encouraged.

[Back to the Reactor Core]