Upgrading RasPi3 from 23.05 -> 23.11 says "cp not found"?

Hello there!

First, the issue:

$ systemd-run -E LOCALE_ARCHIVE -E NIXOS_INSTALL_BOOTLOADER --collect --no-ask-password --pty --quiet --same-dir --service-type=exec --unit=nixos-rebuild-switch-to-configuration --wait /nix/store/7dapv6kjs90d9s1b8caibrm7md864qp0-nixos-system-POTLI-ND-MTAG01-23.11.2962.b8dd8be3c790/bin/switch-to-configuration switch
/nix/store/9dlhf35czyybbri2gy05jh8y2fivi6dh-uboot-builder.sh: line 15: cp: command not found

Looking at the generated script:

# cat /nix/store/9dlhf35czyybbri2gy05jh8y2fivi6dh-uboot-builder.sh
#! /nix/store/lm10ywzflq9qfhr4fl0zqxrhiksf28ks-bash-5.2-p15/bin/sh -e

target=/boot # Target directory

while getopts "t:c:d:g:" opt; do
    case "$opt" in
        d) target="$OPTARG" ;;
        *) ;;
    esac
done

copyForced() {
    local src="$1"
    local dst="$2"
    cp $src $dst.tmp
    mv $dst.tmp $dst
}

# Call the extlinux builder
"/nix/store/8nvq1bziwx8qvj27gx6kjqhqbvpim6jn-extlinux-conf-builder.sh" "$@"

# Add the firmware files
fwdir=/nix/store/8a86w8yykxbg4wzkpwvg41j6ysrvvwxi-raspberrypi-firmware-1.20230405/share/raspberrypi/boot/
copyForced $fwdir/bootcode.bin  $target/bootcode.bin
copyForced $fwdir/fixup.dat     $target/fixup.dat
copyForced $fwdir/fixup_cd.dat  $target/fixup_cd.dat
copyForced $fwdir/fixup_db.dat  $target/fixup_db.dat
copyForced $fwdir/fixup_x.dat   $target/fixup_x.dat
copyForced $fwdir/start.elf     $target/start.elf
copyForced $fwdir/start_cd.elf  $target/start_cd.elf
copyForced $fwdir/start_db.elf  $target/start_db.elf
copyForced $fwdir/start_x.elf   $target/start_x.elf

# Add the uboot file
copyForced /nix/store/i2nwzxvxvqws2a3yj7jwvvn6j4g386c3-uboot-rpi_3_defconfig-2023.07.02/u-boot.bin $target/u-boot-rpi.bin

# Add the config.txt
copyForced /nix/store/p6lfhnk2hplhv0cy94rbl6i87l83rxqk-config.txt $target/config.txt

It uses normal, standard sh, which doesn’t have a built-in cp but should still have access to it through $PATH. That said, this is part of the Rasberry Pi configuration; which is marked deprecated. So I took a look at the configuration in this system:

  boot.loader = {
    grub.enable = false;
    raspberryPi = {
      enable = true;
      version = 3;
      uboot.enable = true;
    };
  };

Now for some context: Our company deploys Raspberry Pis as monitoring agents to run Telegraf to send data to an InfluxDB - so we can do with a small Pi like that (although we do allocate swapspace to ensure the Nix commands don’t OOM or take forever due to memory allocation issues).

I also verified if /boot is available, and it is…although, it is not mounted?

# lsblk
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
mmcblk0     179:0    0 59.5G  0 disk
├─mmcblk0p1 179:1    0   30M  0 part
└─mmcblk0p2 179:2    0 59.4G  0 part /nix/store
                                     /
# mount | grep boot
(no output)

…So I suppose something has gone wrong a long time ago as it is.

Question is, why is cp not available? Do I need to explicitly state it in the environment packages? These look as such right now:

  environment.systemPackages = with pkgs; [
    curl git mib-library netavark wget
  ];

Questions would be:

  1. It appears that /boot needs to be migrated from a folder on the rootfs to the actual partition. How do I organize that?
  2. Why is cp missing and how do I add it back?

By the way, this is the hardware-configuration:

# cat hardware-configuration.nix
# Do not modify this file!  It was generated by ‘nixos-generate-config’
# and may be overwritten by future invocations.  Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:

{
  imports =
    [ (modulesPath + "/installer/scan/not-detected.nix")
    ];

  boot.initrd.availableKernelModules = [ ];
  boot.initrd.kernelModules = [ ];
  boot.kernelModules = [ ];
  boot.extraModulePackages = [ ];

  fileSystems."/" =
    { device = "/dev/disk/by-uuid/44444444-4444-4444-8888-888888888888";
      fsType = "ext4";
    };

  swapDevices = [ ];

  # Enables DHCP on each ethernet and wireless interface. In case of scripted networking
  # (the default) this is the recommended approach. When using systemd-networkd it's
  # still possible to use this option, but it's recommended to use it in conjunction
  # with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
  networking.useDHCP = lib.mkDefault true;
  # networking.interfaces.enu1u1.useDHCP = lib.mkDefault true;
  # networking.interfaces.wlan0.useDHCP = lib.mkDefault true;

  nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux";
  powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand";
}

The Pis were initialized quite a while ago at this point; chances are, that the default hardware config has changed since, as it does not mount /boot.

Thank you in advance and kind regards!

I found the solution myself and it took FOREVER. xD

Blog post: Installing NixOS on a Raspberry Pi 3B | Eisfunke

TL;DR: There is u-boot in the /boot partition by default and it reads rootfs’ /boot/extlinux/... configuration. So! There is no need to use any of the boot.loader.raspberryPi option, if you have that already copied into /boot.

This, however, raises aother question: SD card images usually have that included… but, does it? I would rather there be an option to at least check for updates or install u-boot there if not already done so for one reason or another.

Sadly, I don’t know where to put in a PR to get this information to more people possibly stuck at the same thing or confused at the rather short-handed deprecation notice… So if you could tell me how I could improve that situation, please do let me know! :slight_smile:

Kind regards!