Request: Use an initramfs instead of an initrd. I'm sure an initrd will continue to work for a very long time, but the initramfs setup seems to be the way the kernel developers want everyone to move eventually.
Explanation and probably way too many details:
An initrd is a gzipped image of an ext2 filesystem (well, any particular filesystem that the kernel supports, but usually ext2 because it's tiny and simple). An initramfs is a gzipped CPIO archive of a group of files. When the kernel interprets an initrd, it gunzips it and treats it like a ramdisk (uses the ramdisk's own filesystem); when the kernel interprets an initramfs, it creates a tmpfs (basically), gunzips the initramfs image, and un-cpio-s its structure into the new tmpfs.
An initrd's "main" executable is /linuxrc. An initramfs's "main" executable is /init. (Simply renaming /linuxrc to /init should work for PING, with a few other changes to /init itself given below.)
When an initramfs hands control off to the real root filesystem, it's a single step instead of two. An initrd runs pivot_root and then executes the new shell, but an initramfs executes run-init (see klibc for the sources). run-init does a bunch of sanity checks to make sure it doesn't run when a non-initramfs is the root FS, then deletes all the files off the root FS (to free up RAM). Then it effectively does a "mount --move" on the new root directory (/tmpfs in the case of PING), moving it to /. Then it does a chroot to the new /, opens the new /dev/console device, and execs the new init with whatever arguments.
Syntax on run-init is:
run-init [ -c consolefile ] new-root init-file [ init-args ]
where consolefile is the new console file (defaults to /dev/console, shouldn't need to be changed), new-root is the /tmpfs directory in PING, init-file is /sbin/init in PING, and init-args are any arguments to pass to the new init. (I've been able to get away with skipping them, but most initramfs images pass "$@", to be sure everything gets through.)
What I used in my testing was the following:
- Code: Select all
exec /bin/run-init /tmpfs /sbin/init
wherever the initrd ran "pivot_root blah" then "exec /sbin/init blah".
which worked OK. But I built my own run-init using glibc (so I had to copy /lib/libc.so.6 and /lib/ld-linux.so.2 into the initramfs as well); rebuilding it using whatever crunchbox method will probably make a much smaller ISO. (In fact crunchbox may already have a run-init option? If not, klibc should provide usable sources; I used klibc-1.5.)
The one other thing to be careful of is that I believe the initramfs image file needs to have its pathnames start with a / character. I can't figure out any way to get the cpio command to do this, so I built a file and ran it through the kernel's usr/gen_init_cpio program to generate the cpio file instead. (gen_init_cpio can put any arbitrary file from the host at any arbitrary path in the cpio image.) This also requires a bit of a hack to fix an issue with the stat program (it won't print the decimal major/minor number of device nodes); the script to do that is named ~/replace_0x, and is given below:
- Code: Select all
#!/bin/bash
while read line ; do
set -- $line
for i in "$@" ; do
case "$i" in
0x*)
echo -n "$(($i)) "
;;
*)
echo -n "$i "
esac
done
echo ""
done
Apart from that, the commands to actually generate an initramfs image are below (of course the kernel needs to be built first, to generate the gen_init_cpio binary):
- Code: Select all
( find . -type d -not -name . -printf "dir /%P %m %U %G\n"
find . -type f -printf "file /%P %p %m %U %G\n"
find . -type l -printf "slink /%P %l 0777 0 0\n"
find . -type c -exec stat --format="nod %n %a %u %g c 0x%t 0x%T" {} \;
find . -type b -exec stat --format="nod %n %a %u %g b 0x%t 0x%T" {} \;
) | sed -e 's/^nod \./nod /' | ~/replace_0x >../file_list
<kernel_source_path>/usr/gen_init_cpio ../file_list | gzip -c >../initramfs.cpio.gz
The first find generates commands to create the directory tree in the cpio archive. The second generates commands to copy all the files into the cpio archive. The third generates commands to create all the symbolic links (critical given the crunchbox architecture in the initramfs). The fourth and fifth generate commands to create the character and block devices, respectively. The sed is needed to get rid of the "." at the start of the device-node command paths; the pipe through replace_0x changes the 0x%t and 0x%T items (from stat) from hex into decimal. This all gets dumped into ../file_list for gen_init_cpio to work on.
Then gen_init_cpio is called, which dumps the cpio archive to stdout; this is piped through gzip and written to the cpio.gz file. It's critical that gen_init_cpio be called from the same directory as was current when the ../file_list was generated (otherwise the relative paths from find won't be correct in ../file_list).
Of course the initramfs image can be called anything; initrd.gz would work fine if you don't want to change the syslinux.cfg file. However, I was able to remove all of the following from the kernel command line in syslinux.cfg:
ramdisk_size=33000
load_ramdisk=1
init=/linuxrc
prompt_ramdisk=0
and the image still worked fine. I'm not sure if these are kernel options or syslinux options, but if they're kernel options, then they can go away, and the system will still at least boot and be able to run partimage.
Thanks!