NWR04B: How'd that happen?

After getting the CFLAGS fixed up, the last step before a working shell was getting init going -- either just saying something like init=/bin/sh in the kernel command line, or else getting init proper working. The first didn't work, so on to the second. First I looked at /etc/inittab on the filesystem. This message suggested that a very simple inittab should work just fine:

::askfirst:-/bin/sh

However, it wasn't working: the last message I got during the boot process was the BusyBox banner, and then nothing. I could ping it, but it wasn't responding to anything on the keyboard. I turned on debugging in init/init.c (#define DEBUG_INIT 1 up at the top), then started throwing in messageD(LOG|CONSOLE, "FIXME: Made it here") at various spots. I could see that init was running, and it was parsing /etc/inittab -- good. (Oh, should also mention that since the router is currently mounting its filesystem by NFS, running tcpdump host [ip address] | awk '/"/ {print $NF}' showed me the files it was trying to get -- which also showed inittab.) Okay, so move on to actually running the damn programs. That takes us through init_main() and run_actions()...yep, messageD shows we're getting there, too. From run_actions() we go to run()...and here's where we run into problems. run() basically blocks signals then runs fork()like so:

        if ((pid = fork()) == 0) {
               /* run the damn program */
        }
        return pid;

A few more messageDs showed we were reaching the other side of the if block w/o any problems, but didn't seem to be actually going inside. init kept trying, about once a second, to start up the programs in inittab but it was failing each time. And then I remembered: uClibc does not implement fork(); instead, it uses vfork(), which blocks the parent until the child exits, or calls execve(). (Here's a good explanation.) So what if we do:

        if ((pid = vfork()) == 0) {

Well, hot damn -- it works!