at 16.09-beta 4.3 kB view raw
1# This module creates a bootable SD card image containing the given NixOS 2# configuration. The generated image is MBR partitioned, with a FAT /boot 3# partition, and ext4 root partition. The generated image is sized to fit 4# its contents, and a boot script automatically resizes the root partition 5# to fit the device on the first boot. 6# 7# The derivation for the SD image will be placed in 8# config.system.build.sdImage 9 10{ config, lib, pkgs, ... }: 11 12with lib; 13 14let 15 rootfsImage = import ../../../lib/make-ext4-fs.nix { 16 inherit pkgs; 17 inherit (config.sdImage) storePaths; 18 volumeLabel = "NIXOS_SD"; 19 }; 20in 21{ 22 options.sdImage = { 23 storePaths = mkOption { 24 type = with types; listOf package; 25 example = literalExample "[ pkgs.stdenv ]"; 26 description = '' 27 Derivations to be included in the Nix store in the generated SD image. 28 ''; 29 }; 30 31 bootSize = mkOption { 32 type = types.int; 33 default = 120; 34 description = '' 35 Size of the /boot partition, in megabytes. 36 ''; 37 }; 38 39 populateBootCommands = mkOption { 40 example = literalExample "'' cp \${pkgs.myBootLoader}/u-boot.bin boot/ ''"; 41 description = '' 42 Shell commands to populate the ./boot directory. 43 All files in that directory are copied to the 44 /boot partition on the SD image. 45 ''; 46 }; 47 }; 48 49 config = { 50 fileSystems = { 51 "/boot" = { 52 device = "/dev/disk/by-label/NIXOS_BOOT"; 53 fsType = "vfat"; 54 }; 55 "/" = { 56 device = "/dev/disk/by-label/NIXOS_SD"; 57 fsType = "ext4"; 58 }; 59 }; 60 61 sdImage.storePaths = [ config.system.build.toplevel ]; 62 63 system.build.sdImage = pkgs.stdenv.mkDerivation { 64 name = "sd-image-${pkgs.stdenv.system}.img"; 65 66 buildInputs = with pkgs; [ dosfstools e2fsprogs mtools libfaketime utillinux ]; 67 68 buildCommand = '' 69 # Create the image file sized to fit /boot and /, plus 20M of slack 70 rootSizeBlocks=$(du -B 512 --apparent-size ${rootfsImage} | awk '{ print $1 }') 71 bootSizeBlocks=$((${toString config.sdImage.bootSize} * 1024 * 1024 / 512)) 72 imageSize=$((rootSizeBlocks * 512 + bootSizeBlocks * 512 + 20 * 1024 * 1024)) 73 truncate -s $imageSize $out 74 75 # type=b is 'W95 FAT32', type=83 is 'Linux'. 76 sfdisk $out <<EOF 77 label: dos 78 label-id: 0x2178694e 79 80 start=8M, size=$bootSizeBlocks, type=b, bootable 81 start=${toString (8 + config.sdImage.bootSize)}M, type=83 82 EOF 83 84 # Copy the rootfs into the SD image 85 eval $(partx $out -o START,SECTORS --nr 2 --pairs) 86 dd conv=notrunc if=${rootfsImage} of=$out seek=$START count=$SECTORS 87 88 # Create a FAT32 /boot partition of suitable size into bootpart.img 89 eval $(partx $out -o START,SECTORS --nr 1 --pairs) 90 truncate -s $((SECTORS * 512)) bootpart.img 91 faketime "1970-01-01 00:00:00" mkfs.vfat -i 0x2178694e -n NIXOS_BOOT bootpart.img 92 93 # Populate the files intended for /boot 94 mkdir boot 95 ${config.sdImage.populateBootCommands} 96 97 # Copy the populated /boot into the SD image 98 (cd boot; mcopy -bpsvm -i ../bootpart.img ./* ::) 99 dd conv=notrunc if=bootpart.img of=$out seek=$START count=$SECTORS 100 ''; 101 }; 102 103 boot.postBootCommands = '' 104 # On the first boot do some maintenance tasks 105 if [ -f /nix-path-registration ]; then 106 # Figure out device names for the boot device and root filesystem. 107 rootPart=$(readlink -f /dev/disk/by-label/NIXOS_SD) 108 bootDevice=$(lsblk -npo PKNAME $rootPart) 109 110 # Resize the root partition and the filesystem to fit the disk 111 echo ",+," | sfdisk -N2 --no-reread $bootDevice 112 ${pkgs.parted}/bin/partprobe 113 ${pkgs.e2fsprogs}/bin/resize2fs $rootPart 114 115 # Register the contents of the initial Nix store 116 ${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration 117 118 # nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag. 119 touch /etc/NIXOS 120 ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system 121 122 # Prevents this from running on later boots. 123 rm -f /nix-path-registration 124 fi 125 ''; 126 }; 127}