lol

nixos/make-disk-image.nix: Support EFI images

- Add a new parameter `imageType` that can specify either "efi" or
"legacy" (the default which should see no change in behaviour by
this patch).

- EFI images get a GPT partition table (instead of msdos) with a
mandatory ESP partition (so we add an assert that `partitioned`
is true).

- Use the partx tool from util-linux to determine exact start + size
of the root partition. This is required because GPT stores a secondary
partition table at the end of the disk, so we can't just have
mkfs.ext4 create the filesystem until the end of the disk.

- (Unrelated to any EFI changes) Since we're depending on the
`-E offset=X` option to mkfs which is only supported by e2fsprogs,
disallow any attempts of creating partitioned disk images where
the root filesystem is not ext4.

+66 -20
+64 -18
nixos/lib/make-disk-image.nix
··· 13 13 # grafted in the file system at path `target'. 14 14 , contents ? [] 15 15 16 - , # Whether the disk should be partitioned (with a single partition 17 - # containing the root filesystem) or contain the root filesystem 18 - # directly. 19 - partitioned ? true 16 + , # Type of partition table to use; either "legacy", "efi", or "none". 17 + # For "efi" images, the GPT partition table is used and a mandatory ESP 18 + # partition of reasonable size is created in addition to the root partition. 19 + # If `installBootLoader` is true, GRUB will be installed in EFI mode. 20 + # For "legacy", the msdos partition table is used and a single large root 21 + # partition is created. If `installBootLoader` is true, GRUB will be 22 + # installed in legacy mode. 23 + # For "none", no partition table is created. Enabling `installBootLoader` 24 + # most likely fails as GRUB will probably refuse to install. 25 + partitionTableType ? "legacy" 20 26 21 27 # Whether to invoke switch-to-configuration boot during image creation 22 28 , installBootLoader ? true ··· 37 43 format ? "raw" 38 44 }: 39 45 46 + assert partitionTableType == "legacy" || partitionTableType == "efi" || partitionTableType == "none"; 47 + # We use -E offset=X below, which is only supported by e2fsprogs 48 + assert partitionTableType != "none" -> fsType == "ext4"; 49 + 40 50 with lib; 41 51 42 52 let format' = format; in let ··· 51 61 raw = "img"; 52 62 }.${format}; 53 63 64 + rootPartition = { # switch-case 65 + legacy = "1"; 66 + efi = "2"; 67 + }.${partitionTableType}; 68 + 69 + partitionDiskScript = { # switch-case 70 + legacy = '' 71 + parted --script $diskImage -- \ 72 + mklabel msdos \ 73 + mkpart primary ext4 1MiB -1 74 + ''; 75 + efi = '' 76 + parted --script $diskImage -- \ 77 + mklabel gpt \ 78 + mkpart ESP fat32 8MiB 256MiB \ 79 + set 1 boot on \ 80 + mkpart primary ext4 256MiB -1 81 + ''; 82 + none = ""; 83 + }.${partitionTableType}; 84 + 54 85 nixpkgs = cleanSource pkgs.path; 55 86 56 87 channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" {} '' ··· 79 110 targets = map (x: x.target) contents; 80 111 81 112 prepareImage = '' 82 - export PATH=${makeSearchPathOutput "bin" "bin" prepareImageInputs} 113 + export PATH=${makeBinPath prepareImageInputs} 114 + 115 + # Yes, mkfs.ext4 takes different units in different contexts. Fun. 116 + sectorsToKilobytes() { 117 + echo $(( ( "$1" * 512 ) / 1024 )) 118 + } 119 + 120 + sectorsToBytes() { 121 + echo $(( "$1" * 512 )) 122 + } 83 123 84 124 mkdir $out 85 125 diskImage=nixos.raw 86 126 truncate -s ${toString diskSize}M $diskImage 87 127 88 - ${if partitioned then '' 89 - parted --script $diskImage -- mklabel msdos mkpart primary ext4 1M -1s 90 - offset=$((2048*512)) 128 + ${partitionDiskScript} 129 + 130 + ${if partitionTableType != "none" then '' 131 + # Get start & length of the root partition in sectors to $START and $SECTORS. 132 + eval $(partx $diskImage -o START,SECTORS --nr ${rootPartition} --pairs) 133 + 134 + mkfs.${fsType} -F -L nixos $diskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K 91 135 '' else '' 92 - offset=0 136 + mkfs.${fsType} -F -L nixos $diskImage 93 137 ''} 94 138 95 - mkfs.${fsType} -F -L nixos -E offset=$offset $diskImage 96 - 97 139 root="$PWD/root" 98 140 mkdir -p $root 99 141 ··· 133 175 find $root/nix/store -mindepth 1 -maxdepth 1 -type f -o -type d | xargs chmod -R a-w 134 176 135 177 echo "copying staging root to image..." 136 - cptofs ${optionalString partitioned "-P 1"} -t ${fsType} -i $diskImage $root/* / 178 + cptofs -p ${optionalString (partitionTableType != "none") "-P ${rootPartition}"} -t ${fsType} -i $diskImage $root/* / 137 179 ''; 138 180 in pkgs.vmTools.runInLinuxVM ( 139 181 pkgs.runCommand name 140 182 { preVM = prepareImage; 141 - buildInputs = with pkgs; [ utillinux e2fsprogs ]; 183 + buildInputs = with pkgs; [ utillinux e2fsprogs dosfstools ]; 142 184 exportReferencesGraph = [ "closure" metaClosure ]; 143 185 postVM = '' 144 186 ${if format == "raw" then '' ··· 152 194 memSize = 1024; 153 195 } 154 196 '' 155 - ${if partitioned then '' 156 - rootDisk=/dev/vda1 157 - '' else '' 158 - rootDisk=/dev/vda 159 - ''} 197 + rootDisk=${if partitionTableType != "none" then "/dev/vda${rootPartition}" else "/dev/vda"} 160 198 161 199 # Some tools assume these exist 162 200 ln -s vda /dev/xvda ··· 165 203 mountPoint=/mnt 166 204 mkdir $mountPoint 167 205 mount $rootDisk $mountPoint 206 + 207 + # Create the ESP and mount it. Unlike e2fsprogs, mkfs.vfat doesn't support an 208 + # '-E offset=X' option, so we can't do this outside the VM. 209 + ${optionalString (partitionTableType == "efi") '' 210 + mkdir -p /mnt/boot 211 + mkfs.vfat -n ESP /dev/vda1 212 + mount /dev/vda1 /mnt/boot 213 + ''} 168 214 169 215 # Install a configuration.nix 170 216 mkdir -p /mnt/etc/nixos
+1 -1
nixos/maintainers/scripts/ec2/amazon-image.nix
··· 46 46 inherit lib config; 47 47 inherit (cfg) contents format name; 48 48 pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package 49 - partitioned = config.ec2.hvm; 49 + partitionTableType = if config.ec2.hvm then "legacy" else "none"; 50 50 diskSize = cfg.sizeMB; 51 51 configFile = pkgs.writeText "configuration.nix" 52 52 ''
+1 -1
nixos/modules/virtualisation/virtualbox-image.nix
··· 25 25 name = "nixos-ova-${config.system.nixosLabel}-${pkgs.stdenv.system}"; 26 26 27 27 inherit pkgs lib config; 28 - partitioned = true; 28 + partitionTableType = "legacy"; 29 29 diskSize = cfg.baseImageSize; 30 30 31 31 postVM =