summary refs log tree commit diff
path: root/nixos/lib/make-disk-image.nix
diff options
context:
space:
mode:
authorSamuel Dionne-Riel <samuel@dionne-riel.com>2021-04-23 04:15:14 -0400
committerSamuel Dionne-Riel <samuel@dionne-riel.com>2021-04-24 14:49:04 -0400
commit05c13a03e2fb27186d8d1f2825807bf156512111 (patch)
tree9ecba23759ade2f003f66b807119f6b9312d2cd9 /nixos/lib/make-disk-image.nix
parent0ca4f6b7395ffcfd0153791f9623a4844650b023 (diff)
downloadnixpkgs-05c13a03e2fb27186d8d1f2825807bf156512111.tar
nixpkgs-05c13a03e2fb27186d8d1f2825807bf156512111.tar.gz
nixpkgs-05c13a03e2fb27186d8d1f2825807bf156512111.tar.bz2
nixpkgs-05c13a03e2fb27186d8d1f2825807bf156512111.tar.lz
nixpkgs-05c13a03e2fb27186d8d1f2825807bf156512111.tar.xz
nixpkgs-05c13a03e2fb27186d8d1f2825807bf156512111.tar.zst
nixpkgs-05c13a03e2fb27186d8d1f2825807bf156512111.zip
make-disk-image: Get proper size for automatic size
On some filesystems, `du` without `--apparent-size` will not give the
actual size for a file. Using `--apparent-size` will give us the actual
file size.

Though, this is not actually correct still. 1000 × 1 bytes is not 1000
bytes. It is 1000 × ceil(filesize/blockSize)*blockSize.

So instead of adding up the actual file sizes. We are adding up the
block sizes.

Note that this also changes the builder to work with *bytes*, rather
than with any other units. Doing maths on bytes is less likely to go
awry than doing it on other units.
Diffstat (limited to 'nixos/lib/make-disk-image.nix')
-rw-r--r--nixos/lib/make-disk-image.nix34
1 files changed, 28 insertions, 6 deletions
diff --git a/nixos/lib/make-disk-image.nix b/nixos/lib/make-disk-image.nix
index 023d0791a5c..164f2f0f0be 100644
--- a/nixos/lib/make-disk-image.nix
+++ b/nixos/lib/make-disk-image.nix
@@ -163,6 +163,8 @@ let format' = format; in let
 
   closureInfo = pkgs.closureInfo { rootPaths = [ config.system.build.toplevel channelSources ]; };
 
+  blockSize = toString (4 * 1024); # ext4fs block size (not block device sector size)
+
   prepareImage = ''
     export PATH=${binPath}
 
@@ -175,6 +177,15 @@ let format' = format; in let
       echo $(( "$1" * 512  ))
     }
 
+    # Given lines of numbers, adds them together
+    sum_lines() {
+      local acc=0
+      while read -r number; do
+        acc=$((acc+number))
+      done
+      echo "$acc"
+    }
+
     mkdir $out
 
     root="$PWD/root"
@@ -235,12 +246,23 @@ let format' = format; in let
 
     ${if diskSize == "auto" then ''
       ${if partitionTableType == "efi" || partitionTableType == "hybrid" then ''
-        additionalSpace=$(( ($(numfmt --from=iec '${additionalSpace}') + $(numfmt --from=iec '${bootSize}')) / 1000 ))
+        additionalSpace=$(( ($(numfmt --from=iec '${additionalSpace}') + $(numfmt --from=iec '${bootSize}')) ))
       '' else ''
-        additionalSpace=$(( $(numfmt --from=iec '${additionalSpace}') / 1000 ))
+        additionalSpace=$(( $(numfmt --from=iec '${additionalSpace}') ))
       ''}
-      diskSize=$(( $(set -- $(du -d0 $root); echo "$1") + $additionalSpace ))
-      truncate -s "$diskSize"K $diskImage
+
+      # Compute required space in filesystem blocks
+      requiredSpace=$(find . ! -type d -exec 'du' '--apparent-size' '--block-size' "${blockSize}" '{}' ';' | cut -f1 | sum_lines)
+      # Convert to bytes
+      requiredSpace=$(( requiredSpace * ${blockSize} ))
+
+      diskSize=$(( requiredSpace  + additionalSpace ))
+      truncate -s "$diskSize" $diskImage
+
+      printf "Automatic disk size...\n"
+      printf "  Space needed: %d bytes\n" $requiredSpace
+      printf "  Additional space: %d bytes\n" $additionalSpace
+      printf "  Disk image size: %d bytes\n" $diskSize
     '' else ''
       truncate -s ${toString diskSize}M $diskImage
     ''}
@@ -251,9 +273,9 @@ let format' = format; in let
       # Get start & length of the root partition in sectors to $START and $SECTORS.
       eval $(partx $diskImage -o START,SECTORS --nr ${rootPartition} --pairs)
 
-      mkfs.${fsType} -F -L ${label} $diskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K
+      mkfs.${fsType} -b ${blockSize} -F -L ${label} $diskImage -E offset=$(sectorsToBytes $START) $(sectorsToKilobytes $SECTORS)K
     '' else ''
-      mkfs.${fsType} -F -L ${label} $diskImage
+      mkfs.${fsType} -b ${blockSize} -F -L ${label} $diskImage
     ''}
 
     echo "copying staging root to image..."