Update a driver in an initrd file
Recently I found myself wanting to put SUSE Linux Enterprise Desktop 11 SP1 on to machine with a Sandybridge chipset. This was a problem as the e1000e driver in SLED 11 SP1 isn't new enough to support the network card in the machine. Having found an updated driver I still had the problem that I wanted to be able to do installations over the network with AutoYaST and PXE boot. That didn't work because the initrd file being used for PXE boot didn't have the new e1000e driver in. So the install failed almost immediately due to the absence of a network connection.
The solution is to make a new initrd file containing the new e1000e driver. It's far from obvious how to do this but I found the solution at http://www.sharms.org/blog/2007/11/howto-add-updated-e1000-driver-to-sled-10-sp1/ This post is basically just me duplicating the information because you can never have such information in too many places. Also I've expanded it a little bit to include instructions on how to do some bits that I had to work out. You can of course adapt the following for whatever module you might find the need to update.
First of all, make a new directory and unpack the current initrd in to it
$ mkdir -p updated_initrd/initrd_unpack
$ cd updated_initrd/initrd_unpack
$ gunzip -dc /path/to/initrd | cpio
Now get the new version of the e1000e module. I found this in an rpm on Novell's website which I needed to download and unpack to get the driver out of it.
$ cd ..
$ wget http://drivers.suse.com/driver-process/pub/update/Intel/sle11sp1/common/i586/intel-e1000e-kmp-pae-1.2.20_126.96.36.199_0.7-1.i586.rpm
$ mkdir rpmcontents
$ cd rpmcontents
$ rpm2cpio ../intel-e1000e-kmp-pae-1.2.20_188.8.131.52_0.7-1.i586.rpm | cpio -idv
Next copy the new driver over in to where you unpacked the initrd
$ cp lib/modules/184.108.40.206-0.7-pae/updates/e1000e.ko ../initrd_unpack/modules/
cp: overwrite `../initrd/modules/e1000e.ko'? y
Now you need to update files called modules.alias and modules.pcimap using information that you get from the depmod command. You can get the information to put in modules.alias with
$ /sbin/depmod -n $(pwd)/lib/modules/220.127.116.11-0.7-pae/updates/e1000e.ko | grep ^alias > /tmp/newaliases
Then I made a copy of the modules.alias file with the information for e1000e removed from it
$ grep -v ' e1000e$' ../initrd_unpack/lib/modules/18.104.22.168-0.7-default/modules.alias > /tmp/modules.alias
Add the new information to that file
$ cat /tmp/newaliases >> /tmp/modules.alias
And then replace the original file
$ cp /tmp/modules.alias ../initrd_unpack/lib/modules/22.214.171.124-0.7-default/modules.alias
cp: overwrite `../initrd_unpack/lib/modules/126.96.36.199-0.7-default/modules.alias'? y
The process is the same for the modules.pcimap file
$ /sbin/depmod -n $(pwd)/lib/modules/188.8.131.52-0.7-pae/updates/e1000e.ko | grep '^e1000e ' > /tmp/newpcimap
$ grep -v '^e1000e ' ../initrd_unpack/lib/modules/184.108.40.206-0.7-default/modules.pcimap > /tmp/modules.pcimap
$ cat /tmp/newpcimap >> /tmp/modules.pcimap
$ cp /tmp/modules.pcimap ../initrd_unpack/lib/modules/220.127.116.11-0.7-default/modules.pcimap
cp: overwrite `../initrd_unpack/lib/modules/18.104.22.168-0.7-default/modules.pcimap'? y
Finally, make the new initrd file
$ cd ../initrd_unpack
$ find . | cpio --quiet -o -H newc > ../initrd
$ cd ..
$ gzip -v9c initrd > initrd.gz
$ mv initrd.gz initrd
mv: overwrite `initrd'? y
$ file initrd
initrd: gzip compressed data, was "initrd", from Unix, last modified: Wed Jun 29 12:31:49 2011, max compression