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.
grub(8)
source code
downloaded. You can get it here.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.
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
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.
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
.
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.
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.