debian-forge-composer/internal/disk/customizations.go
Christian Kellner fb7f92aa95 disk: clone partition table before modifying it
The partition table is modified `CreatePartitionTable`, which is
not a problem for the table itself since it is currently passed
by value. However, all shallow copies share the same file system
pointers and `CreatePartitionTable` will modify those as well.
As there is a data race where two concurrent thread modify the
content of the Fileystem object at the same time before writing
the uuids out to the manifest via the stage options and thus the
resulting manifest would be broken.
Therefore we use the new `Clone` methods to make a dee@ copy of
the `PartitionTable` object in the `CreatePartitionTable` method;
This will allow us to pass the `basePartitionTable` object by val
and also return the resulting `PartitionTable` as a pointer.
2022-02-22 19:23:41 +00:00

111 lines
3 KiB
Go

package disk
import (
"encoding/hex"
"io"
"math/rand"
"github.com/google/uuid"
"github.com/osbuild/osbuild-composer/internal/blueprint"
)
const (
sectorSize = 512
BIOSBootPartitionGUID = "21686148-6449-6E6F-744E-656564454649"
BIOSBootPartitionUUID = "FAC7F1FB-3E8D-4137-A512-961DE09A5549"
FilesystemDataGUID = "0FC63DAF-8483-4772-8E79-3D69D8477DE4"
FilesystemDataUUID = "CB07C243-BC44-4717-853E-28852021225B"
EFISystemPartitionGUID = "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"
EFISystemPartitionUUID = "68B2905B-DF3E-4FB3-80FA-49D1E773AA33"
EFIFilesystemUUID = "7B77-95E7"
RootPartitionUUID = "6264D520-3FB9-423F-8AB8-7A0A8E3D3562"
)
func CreatePartitionTable(
mountpoints []blueprint.FilesystemCustomization,
imageSize uint64,
basePartitionTable PartitionTable,
rng *rand.Rand,
) PartitionTable {
// we are modifying the contents of the base partition table,
// including the file systems, which are shared among shallow
// copies of the partition table, so make a copy first
table := basePartitionTable.Clone()
if bootPartition := table.BootPartition(); bootPartition != nil {
// the boot partition UUID needs to be set since this
// needs to be randomly generated
bootPartition.Filesystem.UUID = uuid.Must(newRandomUUIDFromReader(rng)).String()
}
for _, m := range mountpoints {
if m.Mountpoint != "/" {
partitionSize := m.MinSize / sectorSize
table.createFilesystem(m.Mountpoint, partitionSize, rng)
}
}
if tableSize := table.getPartitionTableSize(); imageSize < tableSize {
imageSize = tableSize
}
table.Size = imageSize
// start point for all of the arches is
// 2048 sectors.
var start uint64 = table.updatePartitionStartPointOffsets(2048)
// treat the root partition as a special case
// by setting the size dynamically
rootPartition := table.RootPartition()
rootPartition.Size = ((imageSize / sectorSize) - start - 100)
rootPartition.Filesystem.UUID = uuid.Must(newRandomUUIDFromReader(rng)).String()
return *table
}
func (pt *PartitionTable) createFilesystem(mountpoint string, size uint64, rng *rand.Rand) {
filesystem := Filesystem{
Type: "xfs",
UUID: uuid.Must(newRandomUUIDFromReader(rng)).String(),
Mountpoint: mountpoint,
FSTabOptions: "defaults",
FSTabFreq: 0,
FSTabPassNo: 0,
}
partition := Partition{
Size: size,
Filesystem: &filesystem,
}
if pt.Type == "gpt" {
partition.Type = FilesystemDataGUID
partition.UUID = uuid.Must(newRandomUUIDFromReader(rng)).String()
}
pt.Partitions = append(pt.Partitions, partition)
}
func newRandomUUIDFromReader(r io.Reader) (uuid.UUID, error) {
var id uuid.UUID
_, err := io.ReadFull(r, id[:])
if err != nil {
return uuid.Nil, err
}
id[6] = (id[6] & 0x0f) | 0x40 // Version 4
id[8] = (id[8] & 0x3f) | 0x80 // Variant is 10
return id, nil
}
// NewRandomVolIDFromReader creates a random 32 bit hex string to use as a
// volume ID for FAT filesystems
func NewRandomVolIDFromReader(r io.Reader) (string, error) {
volid := make([]byte, 4)
_, err := r.Read(volid)
return hex.EncodeToString(volid), err
}