Linux – How to Generate Initramfs Image with Busybox Links

busyboxcpioinitramfskernellinux

Having been directed to initramfs by an answer to my earlier question (thanks!), I've been working on getting initramfs working. I can now boot the kernel and drop to a shell prompt, where I can execute busybox commands, which is awesome.

Here's where I'm stuck– there are (at least) two methods of generating initramfs images:

  1. By passing the kernel a path to a prebuilt directory hierarchy to be compressed
  2. By passing the kernel the name of a file that lists the files to be included.

The second method seemed a little cleaner, so I've been using that.

Just for reference, here's my file list so far:

dir /dev 755 0 0
nod /dev/console 644 0 0 c 5 1
nod /dev/loop0 644 0 0 b 7 0
dir /bin 755 1000 1000
slink /bin/sh busybox 777 0 0
file /bin/busybox /home/brandon/rascal-initramfs/bin/busybox 755 0 0
dir /proc 755 0 0
dir /sys 755 0 0
dir /mnt 755 0 0
file /init /home/brandon/rascal-initramfs/init.sh 755 0 0

Unfortunately, I have learned that busybox requires a long list of links to serve as aliases to all of its different commands. Is there a way to generate the list of all these commands so I can add it to my file list?

Alternatively, I could switch to method 1, using the prebuilt directory hierarchy, but I'm not sure how to make the /dev nodes in that case.

Both of these paths seem messy. Is there an elegant solution to this?

Best Answer

It's not the kernel that's generating the initramfs, it's cpio. So what you're really looking for is a way to build a cpio archive that contains devices, symbolic links, etc.

Your method 2 uses usr/gen_init_cpio in the kernel source tree to build the cpio archive during the kernel build. That's indeed a good way of building a cpio archive without having to populate the local filesystem first (which would require being root to create all the devices, or using fakeroot or a FUSE filesystem which I'm not sure has been written already).

All you're missing is generating the input file to gen_init_cpio as a build step. E.g. in shell:

INITRAMFS_SOURCE_DIR=/home/brandon/rascal-initramfs
exec >initramfs_source.txt
echo "dir /bin 755 0 0"
echo "file /bin/busybox $INITRAMFS_SOURCE_DIR/bin/busybox 755 0 0"
for x in sh ls cp …; do echo "slink /bin/$x busybox 777 0 0" done
# etc …

If you want to reflect the symbolic links to busybox that are present in your build tree, here's a way (I assume you're building on Linux):

( cd "$INITRAMFS_SOURCE_DIR/bin" &&
  for x in *; do
    if [ "$(readlink "$x")" = busybox ]; then
      echo "slink /bin/$x busybox 777 0 0"
    fi
  done )

Here's a way to copy all your symbolic links:

find "$INITRAMFS_SOURCE_DIR" -type l -printf 'slink %p %l 777 0 0\n'

For busybox, maybe your build tree doesn't have the symlinks, and instead you want to create one for every utility that you've compiled in. The simplest way I can think of is to look through your busybox build tree for .*.o.cmd files: there's one per generated command.

find /path/to/busybox/build/tree -name '.*.cmd' -exec sh -c '
    for x; do
      x=${x##*/.}
      echo "slink /bin/${x%%.*} busybox 777 0 0"
    done
' _ {} +
Related Question