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 # grafted in the file system at path `target'. 14 , contents ? [] 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 20 21 # Whether to invoke switch-to-configuration boot during image creation 22 , installBootLoader ? true ··· 37 format ? "raw" 38 }: 39 40 with lib; 41 42 let format' = format; in let ··· 51 raw = "img"; 52 }.${format}; 53 54 nixpkgs = cleanSource pkgs.path; 55 56 channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" {} '' ··· 79 targets = map (x: x.target) contents; 80 81 prepareImage = '' 82 - export PATH=${makeSearchPathOutput "bin" "bin" prepareImageInputs} 83 84 mkdir $out 85 diskImage=nixos.raw 86 truncate -s ${toString diskSize}M $diskImage 87 88 - ${if partitioned then '' 89 - parted --script $diskImage -- mklabel msdos mkpart primary ext4 1M -1s 90 - offset=$((2048*512)) 91 '' else '' 92 - offset=0 93 ''} 94 95 - mkfs.${fsType} -F -L nixos -E offset=$offset $diskImage 96 - 97 root="$PWD/root" 98 mkdir -p $root 99 ··· 133 find $root/nix/store -mindepth 1 -maxdepth 1 -type f -o -type d | xargs chmod -R a-w 134 135 echo "copying staging root to image..." 136 - cptofs ${optionalString partitioned "-P 1"} -t ${fsType} -i $diskImage $root/* / 137 ''; 138 in pkgs.vmTools.runInLinuxVM ( 139 pkgs.runCommand name 140 { preVM = prepareImage; 141 - buildInputs = with pkgs; [ utillinux e2fsprogs ]; 142 exportReferencesGraph = [ "closure" metaClosure ]; 143 postVM = '' 144 ${if format == "raw" then '' ··· 152 memSize = 1024; 153 } 154 '' 155 - ${if partitioned then '' 156 - rootDisk=/dev/vda1 157 - '' else '' 158 - rootDisk=/dev/vda 159 - ''} 160 161 # Some tools assume these exist 162 ln -s vda /dev/xvda ··· 165 mountPoint=/mnt 166 mkdir $mountPoint 167 mount $rootDisk $mountPoint 168 169 # Install a configuration.nix 170 mkdir -p /mnt/etc/nixos
··· 13 # grafted in the file system at path `target'. 14 , contents ? [] 15 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" 26 27 # Whether to invoke switch-to-configuration boot during image creation 28 , installBootLoader ? true ··· 43 format ? "raw" 44 }: 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 + 50 with lib; 51 52 let format' = format; in let ··· 61 raw = "img"; 62 }.${format}; 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 + 85 nixpkgs = cleanSource pkgs.path; 86 87 channelSources = pkgs.runCommand "nixos-${config.system.nixosVersion}" {} '' ··· 110 targets = map (x: x.target) contents; 111 112 prepareImage = '' 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 + } 123 124 mkdir $out 125 diskImage=nixos.raw 126 truncate -s ${toString diskSize}M $diskImage 127 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 135 '' else '' 136 + mkfs.${fsType} -F -L nixos $diskImage 137 ''} 138 139 root="$PWD/root" 140 mkdir -p $root 141 ··· 175 find $root/nix/store -mindepth 1 -maxdepth 1 -type f -o -type d | xargs chmod -R a-w 176 177 echo "copying staging root to image..." 178 + cptofs -p ${optionalString (partitionTableType != "none") "-P ${rootPartition}"} -t ${fsType} -i $diskImage $root/* / 179 ''; 180 in pkgs.vmTools.runInLinuxVM ( 181 pkgs.runCommand name 182 { preVM = prepareImage; 183 + buildInputs = with pkgs; [ utillinux e2fsprogs dosfstools ]; 184 exportReferencesGraph = [ "closure" metaClosure ]; 185 postVM = '' 186 ${if format == "raw" then '' ··· 194 memSize = 1024; 195 } 196 '' 197 + rootDisk=${if partitionTableType != "none" then "/dev/vda${rootPartition}" else "/dev/vda"} 198 199 # Some tools assume these exist 200 ln -s vda /dev/xvda ··· 203 mountPoint=/mnt 204 mkdir $mountPoint 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 + ''} 214 215 # Install a configuration.nix 216 mkdir -p /mnt/etc/nixos
+1 -1
nixos/maintainers/scripts/ec2/amazon-image.nix
··· 46 inherit lib config; 47 inherit (cfg) contents format name; 48 pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package 49 - partitioned = config.ec2.hvm; 50 diskSize = cfg.sizeMB; 51 configFile = pkgs.writeText "configuration.nix" 52 ''
··· 46 inherit lib config; 47 inherit (cfg) contents format name; 48 pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package 49 + partitionTableType = if config.ec2.hvm then "legacy" else "none"; 50 diskSize = cfg.sizeMB; 51 configFile = pkgs.writeText "configuration.nix" 52 ''
+1 -1
nixos/modules/virtualisation/virtualbox-image.nix
··· 25 name = "nixos-ova-${config.system.nixosLabel}-${pkgs.stdenv.system}"; 26 27 inherit pkgs lib config; 28 - partitioned = true; 29 diskSize = cfg.baseImageSize; 30 31 postVM =
··· 25 name = "nixos-ova-${config.system.nixosLabel}-${pkgs.stdenv.system}"; 26 27 inherit pkgs lib config; 28 + partitionTableType = "legacy"; 29 diskSize = cfg.baseImageSize; 30 31 postVM =