change initramfs by hand?

What's the correct way to change the initramfs file that's used during boot?
I know that it's a gzipped cpio archive, but when I gunzip, extract, re-archive (without changing any files), and gzip, then the result is that the system does not boot any more. And I even set the cpio archive type.

Do I need special tools for the initramfs? There are progs like update-initramfs but the point is that I need to put in files that were *not* put in by the tools that originally created the initramfs.

Not special tools, per se... First you gunzip it, like you said. What method did you use to extract/archive? Usually, one would do:

mkdir /tmp/initrd
cd /tmp/initrd
gunzip -c Initrd.img.gz | cpio -id 

# make changes to /tmp/initrd directory
find . | cpio -o | gzip -c >/boot/initrd.new.img

Thanks otheus! I tried that (without making changes to the files in the /tmp/initrd directory), and I changed the link in /boot to point to initrd.new.img.
Now I get the following error during boot:

RAMDISK: Compressed image found at block 0
RAMDISK: incomplete write (-28 != 32768) 8388608
List of all partitions:
No filesystem could mount root, tried:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

And there the computer hangs. Not even Ctrl-Alt-Del reboots it. Poweroff is needed.

The method I described works as of Linux 2.6.13 (or before FC3) If you are using an older version (uname -k) perhaps you have to create a filesystem. See "Manually building a custom initial RAM disk" at Linux initial RAM disk (initrd) overview.

$ mkdir /tmp/initrd.tmp ; cd /tmp/initrd.tmp
$ <extract>
$ du -sk . 
$ # use size reported above for: $blocks
$ dd if=/dev/zero of=/tmp/initrd.img bs=1024 count=$blocks
$ /sbin/mke2fs -F -m 0 -b 1024 /tmp/initrd.img $blocks
$ mount /tmp/initrd.img /mnt/initrd -t ext2 -o loop=/dev/loop0

If that works, copy the files from /tmp/initrd.tmp into /mnt/initrd. Afterwards:

$ umount /mnt/initrd
$ gzip /tmp/initrd.img

Now move it to /boot. Good luck!

Thanks for the help otheus. I appreciate.

I have kernel 2.6.26.

The ibm web page (initrd overview) is really well made, but it's partially obsolete (as they say themselves: "up to FC3"; it's also 2.5 years old).

I tried the code you suggested anyway; every step of the initrd creation process works well, but the system won't boot. With both methods (this and the one you suggested earlier) I get the following error during boot:

RAMDISK: Compressed image found at block 0
RAMDISK: incomplete write (-28 != 32768) 8388608
List of all partitions:
No filesystem could mount root, tried:
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)

Which is probably an improvement over the previous error message which I got before posting here for the first time:

Failed to execute /init
Kernel panic - not syncing: No init found. Try passing init= option to kernel.

So I guess I'm closer, but not there yet...

OK, so a modern kernel, so the first method should be enough.

Could you post your grub.conf file please?

Sure, but I don't think the grub.conf matters too much; it boots the original initrd just fine, and I don't modify any grub files when trying the new initrd.

BTW where is grub.conf? The only grub files I see are in /boot/grub, and the only human-readable ones are "default", "device.map" and "menu.lst". The first is empty except comments, the second only contains the lines

(hd0) /dev/hda
(hd1) /dev/sda

but seems to be unimportant as the unmodified initrd boots just the same when switching this to

(hd0) /dev/sda
(hd1) /dev/hda

and the third contains the usual kernel and initrd config, but it boots the unmodified initrd fine and I never modify it. Instead I change the link initrd.img in /boot to point to the modified initrd. There's still a grub entry using an initrd called initrd.img-2.6.26-1-686 which I never modify, and that always boots. Given that initrd.img-2.6.26-1-686 and the unmodified initrd.img are binary equal, the file menu.lst probably isn't the problem either.

Something else occured to me: do I need to specify the --format option in cpio? E.g. change from "bin" to "newc" format? Because when I look at the (gunzipped) initrd in boot with "file", it says:

"ASCII cpio archive (SVR4 with no CRC)".

But this is not the default which cpio creates.

Ohhhh. that might be a problem. Is there a /etc/grub.conf or is it just a soft-link to /etc/grub/grub.conf??

Neither. There's no file grub.conf anywhere in the /etc or /boot trees.
That's probably OK since it's true for all my machines, and most of them work fine. The web site Debian - GRUB Wiki tells me that for Debian (which I use) the files is called /boot/grub/menu.lst . Makes sense to me, since as far as I understand everything outside /boot is invisible during the boot process.

Are you sure that's where the error is? As I said grub does its job (I can see the line "initrd /initrd.img" ), and the boot process hangs about 10 seconds later.

To my knowledge, the grub file MUST specify the initrd and root options to the kernel. Otherwise, things fail. Let me poll some others on this.

I am sure it must. It does, too. What I said is that I set up the names on symbolic links in the /boot filesystem so that the old filenames will point to the new files. Hence the old grub file can load the new initrd without me changing grubs config.

What we mean is that the CONTENTS of the grub configuration file MUST have a line like:

  kernel /vmlinuz-xxxx-xxx.xx root=/dev/sda3
  initrd=/someinitrd.img.gz 

The REAL someinitrd.img.gz MUST exist IN the same partition as grub. Softlinks will work IF the real file is still in the same partition.

menu.lst is correct, that should contain what otheus was requesting...

I would be interested in seeing that file myself.

Your previous post...

seems to say that your menu.lst points to an incorrect imitrd.img.

For instance my menu.lst says:

default=1
timeout=5
splashimage=(hd0,0)/grub/splash.xpm.gz
hiddenmenu
title Red Hat Enterprise Linux ES (2.6.9-5.0.3.EL)
        root (hd0,0)
        kernel /vmlinuz-2.6.9-5.0.3.EL ro root=LABEL=/ rhgb quiet
        initrd /initrd-2.6.9-5.0.3.EL.img
title Red Hat Enterprise Linux ES (2.6.9-5.0.3.ELsmp)
        root (hd0,0)
        kernel /vmlinuz-2.6.9-5.0.3.ELsmp ro root=LABEL=/
        initrd /initrd-2.6.9-5.0.3.ELsmp.img
title Red Hat Enterprise Linux ES (2.6.9-5.ELsmp)
        root (hd0,0)
        kernel /vmlinuz-2.6.9-5.ELsmp ro root=LABEL=/ rhgb quiet
        initrd /initrd-2.6.9-5.ELsmp.img
title Red Hat Enterprise Linux ES-up (2.6.9-5.EL)
        root (hd0,0)
        kernel /vmlinuz-2.6.9-5.EL ro root=LABEL=/ rhgb quiet
        initrd /initrd-2.6.9-5.EL.img

notice that the last line (for reading sake) says "initrd /initrd-2.6.9-5.EL.img" and my "initrd-2.6.9-5.EL.img" file is located in "/boot/initrd-2.6.9-5.EL.img".

# ls -l /boot/initrd-2.6.9-5.EL.img
-rw-rw-r--  1 root root 489486 Mar  9  2005 /boot/initrd-2.6.9-5.EL.img

Yes it does. See below.

Yes, that's the case.

Here's the menu.lst (without comments):

default         0
timeout         5

title           Debian GNU/Linux, kernel 2.6.26-1-686 Default
root            (hd0,0)
kernel          /vmlinuz root=/dev/mapper/rootfs ro\n")
initrd          /initrd.img

title           Debian GNU/Linux, kernel 2.6.26-1-686 Default (single-user mode)
root            (hd0,0)
kernel          /vmlinuz root=/dev/mapper/rootfs ro\n") single
initrd          /initrd.img

title           Debian GNU/Linux, kernel 2.6.26-1-686
root            (hd0,0)
kernel          /vmlinuz-2.6.26-1-686 root=/dev/mapper/rootfs ro\n")
initrd          /initrd.img-2.6.26-1-686

title           Debian GNU/Linux, kernel 2.6.26-1-686 (single-user mode)
root            (hd0,0)
kernel          /vmlinuz-2.6.26-1-686 root=/dev/mapper/rootfs ro\n") single
initrd          /initrd.img-2.6.26-1-686

The relevant lines are:

default         0

and the first boot option as the default is "0"

title           Debian GNU/Linux, kernel 2.6.26-1-686 Default
root            (hd0,0)
kernel          /vmlinuz root=/dev/mapper/rootfs ro\n")
initrd          /initrd.img

so can you send us the output from:

# ls -l /boot/initrd.img

and if that is a symbolic link (/boot/initrd.img -> /boot/some_other-file.img) please send the output from an "ls -l" against that file as well.

wait.... look at this:

kernel          /vmlinuz root=/dev/mapper/rootfs ro\n")

see that "\n)" at the end...

Are you sure that is correct?

I have never seen that in any menu.lst I have seen and it looks like extra text from a grub menu builder that accidently got inserted.

The "\n" is a newline character and the trailing double quote and closing parenthesis almost certainly says that this was inserted as part of a string wrapped in quotes and inside a matching set of parenthesis.

I may be wrong but...

The \n") looks wrong but I also think it's relatively harmless. It will botch the "ro" argument so the kernel will not see it, but IIUC that's the only harm it does.

In fact, I think the tangent into Grub is wrong. I'd like to suggest you trace back a few steps and explain what exactly you are trying to accomplish. Have you looked at update-initramfs and the initramfs-tools? My understanding of these is limited, but it looks to me like it's what you should be using. But of course, if you know better, perhaps you could at least expand a bit on this topic.

(I was summoned here by otheus for some reason. I'm afraid I won't be able to follow this thread regularly.)

Yes I tried update-initramfs and it works fine in general. There are some important reasons for also trying to understand/modify the initrd directly:

  1. to modify the scripts that update-initramfs installs but don't work correctly. E.g. the part that mounts the / filesystem fails if that disk is not ready immediately (but e.g. via USB); it is recognized 5 seconds later, but by then it's too late.

  2. to modify the initrd on a different computer, or via a different operating system on the same computer. This is necessary if the initrd does not boot. The update-initramfs cannot help here since it assumes that things in the initrd should be as under the currently running OS.

I see you're trying to use a device mapper. Could you provide the initramfs scripts in /etc directory that create the device mapper rootfs? I use device mapper with cryptsetup/luks to encrypt my rootfs. The problem is probably that you don't have the appropriate scripts to create /dev/mapper/rootfs before init calls pivot_root.