# Provisioning initramfs for network boot

Alpine Linux-based initramfs that runs **provisioning-client.sh** after bringing up the network. Used with Raspberry Pi 4 / CM4 (reTerminal) when booting via TFTP from the provisioning LXC.

Includes Python 3 and `rpi-eeprom-config` so EEPROM configuration can be modified directly from the initramfs without chrooting into eMMC.

## What it does

1. Mounts `/proc`, `/sys`, `/dev`, `/dev/pts`.
2. Brings up eth0 and obtains a DHCP lease via `udhcpc`.
3. Runs the provisioning client with `PROVISIONING_SERVER` (default `http://10.20.50.1:5000`, overridable via kernel cmdline).
4. The client registers with the dashboard and polls for **Deploy** or **Backup**; on action it performs the dd + curl and reboots.

## Build

The build script uses Docker or Podman with `--platform linux/arm64` to create an Alpine aarch64 rootfs with Python 3, curl, and `rpi-eeprom-config`. Your host must support arm64 containers via QEMU emulation.

### Prerequisites

- **Docker** or **Podman** installed
- **arm64 emulation** (QEMU user-static):
  ```bash
  # Fedora
  sudo dnf install -y qemu-user-static

  # Debian/Ubuntu
  sudo apt install -y qemu-user-static
  ```

### Build the initramfs

```bash
cd emmc-provisioning/network-boot-initramfs
./build.sh
```

Optional: pass an output path:

```bash
./build.sh /path/to/initrd.img
```

The resulting `initrd.img` is approximately 25-35 MB compressed (Alpine base + Python + EEPROM firmware).

## Deploy to TFTP root

1. Copy **initrd.img** to the LXC TFTP root (e.g. `/srv/tftpboot`):

   ```bash
   scp initrd.img root@10.130.60.141:/srv/tftpboot/
   ```

2. In the TFTP root, ensure **config.txt** (Raspberry Pi boot config) includes the initramfs line. If you use the stock `config.txt` from the RPi firmware repo, add:

   ```
   initramfs initrd.img followkernel
   ```

   So the firmware loads the kernel and then the initrd that "follows" it. The Pi will boot the kernel and run `/init` from the initrd.

3. If your DHCP already points the Pi to this TFTP server and `start4cd.elf`, the Pi will load kernel + initrd from the same root. No NFS or extra server needed.

## Kernel cmdline (optional)

To override the provisioning server URL (e.g. if the dashboard is on another IP), add to **cmdline.txt** in the TFTP root (or append to the kernel command line):

```
provisioning_server=http://10.20.50.1:5000
```

The init script reads `provisioning_server=` from `/proc/cmdline` and exports `PROVISIONING_SERVER` for the client.

### Rescue mode (stuck in network-only boot)

If the device has **BOOT_ORDER=0x2** (network only), it never boots from eMMC. To fix the EEPROM config, add **provisioning_rescue=1** to the kernel cmdline (e.g. in the TFTP-served `cmdline.txt` for that device). The initramfs will start an interactive shell instead of the provisioning client.

Run **/rescue-eeprom.sh** to set `BOOT_ORDER=0xf21` directly from the initramfs. The script:

1. Reads the current EEPROM config using `rpi-eeprom-config` (included in the initramfs)
2. Creates a modified config with `BOOT_ORDER=0xf21` and tuned network timeouts
3. Embeds the config into a new EEPROM image using the bundled `pieeprom.bin` firmware
4. Copies the update (`pieeprom.upd` + `pieeprom.sig`) to the eMMC boot partition

No chroot, no EDITOR hack, no dependency on the eMMC OS.

After running the script, disable network boot on the LXC and reboot so the bootloader boots from eMMC and applies the update.

See **docs/NETWORK-BOOT-TROUBLESHOOTING.md** ("Stuck in network-only boot") for full steps.

## What's included in the initramfs

| Component | Purpose |
|-----------|---------|
| Alpine Linux base | Minimal rootfs with `apk` package manager |
| BusyBox | Core Unix utilities (sh, mount, ip, udhcpc, dd, etc.) |
| Python 3 | Required by `rpi-eeprom-config` |
| curl | HTTP client for provisioning dashboard API |
| rpi-eeprom-config | EEPROM configuration tool (from rpi-eeprom repo) |
| pieeprom.bin | EEPROM firmware image (for creating update files) |
| init | Boot script: mounts fs, DHCP, rescue or provision |
| provisioning-client.sh | Registers with dashboard, executes deploy/backup |
| rescue-eeprom.sh | Sets EEPROM boot order directly |
| udhcpc.script | Applies DHCP lease (IP, route, DNS) |

## Flow summary

1. Pi does DHCP -> gets IP and TFTP server (e.g. 10.20.50.1).
2. Pi loads via TFTP: start4cd.elf, fixup4cd.dat, config.txt, cmdline.txt, kernel8.img, **initrd.img**.
3. Kernel boots with initrd as root; runs `/init`.
4. Init mounts minimal fs, ensures network, runs `/provisioning-client.sh`.
5. Client registers and polls; you choose Deploy or Backup in the dashboard; client runs dd + curl and reboots.
6. After deploy, device boots from eMMC.

See **docs/NETWORK-BOOT-DEPLOYMENT-FLOW.md** for the full deployment flow.
