diff --git a/internal/osbuild2/device.go b/internal/osbuild2/device.go index a9090369b..150feae64 100644 --- a/internal/osbuild2/device.go +++ b/internal/osbuild2/device.go @@ -1,5 +1,12 @@ package osbuild2 +import ( + "fmt" + "strings" + + "github.com/osbuild/osbuild-composer/internal/disk" +) + type Devices map[string]Device type Device struct { @@ -11,3 +18,72 @@ type Device struct { type DeviceOptions interface { isDeviceOptions() } + +func deviceName(p disk.Entity) string { + if p == nil { + panic("device is nil; this is a programming error") + } + + switch payload := p.(type) { + case disk.Mountable: + return pathdot(payload.GetMountpoint()) + case *disk.LUKSContainer: + return "luks-" + payload.UUID[:4] + case *disk.LVMVolumeGroup: + return payload.Name + "vg" + case *disk.LVMLogicalVolume: + return payload.Name + } + panic(fmt.Sprintf("unsupported device type in deviceName: '%T'", p)) +} + +func getDevices(path []disk.Entity, filename string) (map[string]Device, string) { + var pt *disk.PartitionTable + + do := make(map[string]Device) + parent := "" + for _, elem := range path { + switch e := elem.(type) { + case *disk.PartitionTable: + pt = e + case *disk.Partition: + if pt == nil { + panic("path does not contain partition table; this is a programming error") + } + lbopt := LoopbackDeviceOptions{ + Filename: filename, + Start: pt.BytesToSectors(e.Start), + Size: pt.BytesToSectors(e.Size), + SectorSize: nil, + } + name := deviceName(e.Payload) + do[name] = *NewLoopbackDevice(&lbopt) + parent = name + case *disk.LUKSContainer: + lo := LUKS2DeviceOptions{ + Passphrase: e.Passphrase, + } + name := deviceName(e.Payload) + do[name] = *NewLUKS2Device(parent, &lo) + parent = name + case *disk.LVMLogicalVolume: + lo := LVM2LVDeviceOptions{ + Volume: e.Name, + } + name := deviceName(e.Payload) + do[name] = *NewLVM2LVDevice(parent, &lo) + parent = name + } + } + return do, parent +} + +func pathdot(path string) string { + if path == "/" { + return "root" + } + + path = strings.TrimLeft(path, "/") + + return strings.ReplaceAll(path, "/", ".") +} diff --git a/internal/osbuild2/luks2_device.go b/internal/osbuild2/luks2_device.go index 8c1defac0..8ade58797 100644 --- a/internal/osbuild2/luks2_device.go +++ b/internal/osbuild2/luks2_device.go @@ -8,9 +8,10 @@ type LUKS2DeviceOptions struct { func (LUKS2DeviceOptions) isDeviceOptions() {} -func NewLUKS2Device(options *LUKS2DeviceOptions) *Device { +func NewLUKS2Device(parent string, options *LUKS2DeviceOptions) *Device { return &Device{ Type: "org.osbuild.luks2", + Parent: parent, Options: options, } } diff --git a/internal/osbuild2/mkfs_btrfs_stage.go b/internal/osbuild2/mkfs_btrfs_stage.go index 6f116c31c..a7f64cceb 100644 --- a/internal/osbuild2/mkfs_btrfs_stage.go +++ b/internal/osbuild2/mkfs_btrfs_stage.go @@ -7,10 +7,10 @@ type MkfsBtrfsStageOptions struct { func (MkfsBtrfsStageOptions) isStageOptions() {} -func NewMkfsBtrfsStage(options *MkfsBtrfsStageOptions, device *Device) *Stage { +func NewMkfsBtrfsStage(options *MkfsBtrfsStageOptions, devices map[string]Device) *Stage { return &Stage{ Type: "org.osbuild.mkfs.btrfs", Options: options, - Devices: Devices{"device": *device}, + Devices: devices, } } diff --git a/internal/osbuild2/mkfs_ext4_stage.go b/internal/osbuild2/mkfs_ext4_stage.go index 2ee483664..bfa0be92f 100644 --- a/internal/osbuild2/mkfs_ext4_stage.go +++ b/internal/osbuild2/mkfs_ext4_stage.go @@ -7,10 +7,10 @@ type MkfsExt4StageOptions struct { func (MkfsExt4StageOptions) isStageOptions() {} -func NewMkfsExt4Stage(options *MkfsExt4StageOptions, device *Device) *Stage { +func NewMkfsExt4Stage(options *MkfsExt4StageOptions, devices map[string]Device) *Stage { return &Stage{ Type: "org.osbuild.mkfs.ext4", Options: options, - Devices: Devices{"device": *device}, + Devices: devices, } } diff --git a/internal/osbuild2/mkfs_fat_stage.go b/internal/osbuild2/mkfs_fat_stage.go index 6100656cb..ba8092c67 100644 --- a/internal/osbuild2/mkfs_fat_stage.go +++ b/internal/osbuild2/mkfs_fat_stage.go @@ -8,10 +8,10 @@ type MkfsFATStageOptions struct { func (MkfsFATStageOptions) isStageOptions() {} -func NewMkfsFATStage(options *MkfsFATStageOptions, device *Device) *Stage { +func NewMkfsFATStage(options *MkfsFATStageOptions, devices map[string]Device) *Stage { return &Stage{ Type: "org.osbuild.mkfs.fat", Options: options, - Devices: Devices{"device": *device}, + Devices: devices, } } diff --git a/internal/osbuild2/mkfs_stage.go b/internal/osbuild2/mkfs_stage.go index 38de5b794..54f9cc80f 100644 --- a/internal/osbuild2/mkfs_stage.go +++ b/internal/osbuild2/mkfs_stage.go @@ -18,47 +18,50 @@ func GenMkfsStages(pt *disk.PartitionTable, device *Device) []*Stage { panic("GenMkfsStages: failed to convert device options to loopback options") } - for _, p := range pt.Partitions { - if p.Payload == nil { - // no filesystem for partition (e.g., BIOS boot) - continue - } + genStage := func(mnt disk.Mountable, path []disk.Entity) error { + t := mnt.GetFSType() var stage *Stage - stageDevice := NewLoopbackDevice( - &LoopbackDeviceOptions{ - Filename: devOptions.Filename, - Start: pt.BytesToSectors(p.Start), - Size: pt.BytesToSectors(p.Size), - }, - ) - switch p.Payload.Type { + + stageDevices, lastName := getDevices(path, devOptions.Filename) + + // the last device on the PartitionTable must be named "device" + lastDevice := stageDevices[lastName] + delete(stageDevices, lastName) + stageDevices["device"] = lastDevice + + fsSpec := mnt.GetFSSpec() + switch t { case "xfs": options := &MkfsXfsStageOptions{ - UUID: p.Payload.UUID, - Label: p.Payload.Label, + UUID: fsSpec.UUID, + Label: fsSpec.Label, } - stage = NewMkfsXfsStage(options, stageDevice) + stage = NewMkfsXfsStage(options, stageDevices) case "vfat": options := &MkfsFATStageOptions{ - VolID: strings.Replace(p.Payload.UUID, "-", "", -1), + VolID: strings.Replace(fsSpec.UUID, "-", "", -1), } - stage = NewMkfsFATStage(options, stageDevice) + stage = NewMkfsFATStage(options, stageDevices) case "btrfs": options := &MkfsBtrfsStageOptions{ - UUID: p.Payload.UUID, - Label: p.Payload.Label, + UUID: fsSpec.UUID, + Label: fsSpec.Label, } - stage = NewMkfsBtrfsStage(options, stageDevice) + stage = NewMkfsBtrfsStage(options, stageDevices) case "ext4": options := &MkfsExt4StageOptions{ - UUID: p.Payload.UUID, - Label: p.Payload.Label, + UUID: fsSpec.UUID, + Label: fsSpec.Label, } - stage = NewMkfsExt4Stage(options, stageDevice) + stage = NewMkfsExt4Stage(options, stageDevices) default: - panic("unknown fs type " + p.Type) + panic("unknown fs type " + t) } stages = append(stages, stage) + + return nil } + + _ = pt.ForEachMountable(genStage) // genStage always returns nil return stages } diff --git a/internal/osbuild2/mkfs_stages_test.go b/internal/osbuild2/mkfs_stages_test.go index b47bdf564..f17e01e0c 100644 --- a/internal/osbuild2/mkfs_stages_test.go +++ b/internal/osbuild2/mkfs_stages_test.go @@ -17,11 +17,15 @@ func TestNewMkfsStage(t *testing.T) { } device := NewLoopbackDevice(&devOpts) + devices := map[string]Device{ + "device": *device, + } + btrfsOptions := &MkfsBtrfsStageOptions{ UUID: uuid.New().String(), Label: "test", } - mkbtrfs := NewMkfsBtrfsStage(btrfsOptions, device) + mkbtrfs := NewMkfsBtrfsStage(btrfsOptions, devices) mkbtrfsExpected := &Stage{ Type: "org.osbuild.mkfs.btrfs", Options: btrfsOptions, @@ -33,7 +37,7 @@ func TestNewMkfsStage(t *testing.T) { UUID: uuid.New().String(), Label: "test", } - mkext4 := NewMkfsExt4Stage(ext4Options, device) + mkext4 := NewMkfsExt4Stage(ext4Options, devices) mkext4Expected := &Stage{ Type: "org.osbuild.mkfs.ext4", Options: ext4Options, @@ -46,7 +50,7 @@ func TestNewMkfsStage(t *testing.T) { Label: "test", FATSize: common.IntToPtr(12), } - mkfat := NewMkfsFATStage(fatOptions, device) + mkfat := NewMkfsFATStage(fatOptions, devices) mkfatExpected := &Stage{ Type: "org.osbuild.mkfs.fat", Options: fatOptions, @@ -58,7 +62,7 @@ func TestNewMkfsStage(t *testing.T) { UUID: uuid.New().String(), Label: "test", } - mkxfs := NewMkfsXfsStage(xfsOptions, device) + mkxfs := NewMkfsXfsStage(xfsOptions, devices) mkxfsExpected := &Stage{ Type: "org.osbuild.mkfs.xfs", Options: xfsOptions, diff --git a/internal/osbuild2/mkfs_xfs_stage.go b/internal/osbuild2/mkfs_xfs_stage.go index 6f2b3aec7..14b5a2ac0 100644 --- a/internal/osbuild2/mkfs_xfs_stage.go +++ b/internal/osbuild2/mkfs_xfs_stage.go @@ -7,10 +7,10 @@ type MkfsXfsStageOptions struct { func (MkfsXfsStageOptions) isStageOptions() {} -func NewMkfsXfsStage(options *MkfsXfsStageOptions, device *Device) *Stage { +func NewMkfsXfsStage(options *MkfsXfsStageOptions, devices map[string]Device) *Stage { return &Stage{ Type: "org.osbuild.mkfs.xfs", Options: options, - Devices: Devices{"device": *device}, + Devices: devices, } }