#!/bin/sh -eu # # SPDX-FileCopyrightText: 2021-2023, 2025 Alyssa Ross # SPDX-FileCopyrightText: 2022 Unikie # SPDX-License-Identifier: EUPL-1.2+ # # usage: make-gpt.sh GPT_PATH PATH:PARTTYPE[:PARTUUID[:PARTLABEL[:PARTMiB]]]... ONE_MiB=1048576 # Prints the number of 1MiB blocks required to store the file named # $1. We use 1MiB blocks because that's what sfdisk uses for # alignment. It would be possible to get a slightly smaller image # using actual normal-sized 512-byte blocks, but it's probably not # worth it to configure sfdisk to do that. sizeMiB() { wc -c "$1" | awk -v ONE_MiB=$ONE_MiB \ '{printf "%d\n", ($1 + ONE_MiB - 1) / ONE_MiB}' } # Copies from path $3 into partition number $2 in partition table $1. fillPartition() { start="$(sfdisk -J "$1" | jq -r --argjson index "$2" \ '.partitiontable.partitions[$index].start * 512')" # GNU cat will use copy_file_range(2) if possible, whereas dd # will always do a userspace copy, which is significantly slower. lseek -S 1 "$start" cat "$3" 1<>"$1" } scriptsDir="$(dirname "$0")" out="$1" shift table=$(for partition; do awk -f "$scriptsDir/sfdisk-field.awk" \ -v partition="$partition" \ -v size="$(sizeMiB "${partition%%:*}")" done) # Keep 1MiB free at the start, and 1MiB free at the end. gptMiB=2 while read -r partition; do # Here we rely on sfdisk-field.awk always putting size last. : $((gptMiB += ${partition##*=})) done <