You CAN cause code to be executed by messing with the kernel command line. The most obvious method is to replace init with something else. The most common application of this is to launch a shell very early in the boot process, usually because you need to fix something or because everything else is very badly broken, eg:
init=/bin/bash
Keep in mind that at this point in the boot process, the filesystems are all still mounted read-only. In addition, there is a whole bunch of things that just won't work correctly. Because you don't have a real init running, shutdown and reboot won't work. You have to manually remount the root filesystem read-only and call reboot -f
to reboot, for example.
I have no idea if you can pass arguments to bash in this manner. I have never tried. In theory, if you can pass -c
to bash, you can tell that bash process to do anything. But it might turn into a fairly long argument, and I don't know if the kernel would allow such things.
Second thing you can do. You can copy an initial ramfs (initramfs) to the filesystem, and configure the bootloader to use it in config.txt
. There are several ways to get scripts into an initramfs to do special things. You'll have to prepare a special initramfs for this purpose though (see initramfs-tools(8)), so I am not sure if this is a better solution than a custom image.
You could include the script in /boot (I laughed at your suggestion about "regular" machines, but this would be the bit you can access from those machines) and attempt to launch that using the kernel init line, but files on dos filesystems aren't executable unless you make it so for the entire filesystem.
If it was me, I'd make a custom image that uses dhcp to configure the network, and that contains a custom script that runs at boot. This script checks for a specific file which acts as a flag. If the file exists, do nothing. If not, configure things, then create the flag file.
Your config script could even pull the real thing from an http server. This means you don't have to make a new image if you have to tweak something.
That should be the least stressful solution.
One final possibility, but you'll have to do this on a "non-regular" machine :-) You can mount the ext4 filesystem to a loop device and copy files to it without writing it to sdcard first. For a standard Raspbian Jessie image, it would be something like this:
sudo losetup /dev/loop0 /tmp/gw.img -o 62914560
sudo mount /dev/loop0 /mnt
sudo cp /my/superduper/script.sh /mnt
sudo umount /dev/loop0
sudo fsck -f /dev/loop0 # This is optional
sudo losetup -d /dev/loop0
I like to do a forced fsck on my filesystems before making images. Sets the mount count to zero on first boot :-)
EDIT: After many months and more experience. You want to look at u-boot. Replace the boot-loader with u-boot. This can be done from a "regular machine". Once you have u-boot in place, you can either network-boot a distribution from which you can easily flash the sd-card, or you could in theory flash the card directly, though I have no idea how hard that would be.
Essentially u-boot brings network-boot to the Raspberry Pi, something it does not support on its own.