Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gadget: emmc syntax support #14533

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 95 additions & 35 deletions gadget/gadget.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ const (
schemaMBR = "mbr"
// schemaGPT identifies a GUID Partition Table partitioning schema
schemaGPT = "gpt"
// schemaEMMC identifies a schema for eMMC
schemaEMMC = "emmc"

SystemBoot = "system-boot"
SystemData = "system-data"
Expand Down Expand Up @@ -1088,6 +1090,24 @@ func asOffsetPtr(offs quantity.Offset) *quantity.Offset {
return &offs
}

func setVolumeStructureOffset(vs *VolumeStructure, startPtr *quantity.Offset) (next *quantity.Offset) {
if vs.Offset == nil && startPtr != nil {
var start quantity.Offset
if vs.Role != schemaMBR && *startPtr < NonMBRStartOffset {
start = NonMBRStartOffset
} else {
start = *startPtr
}
vs.Offset = &start
}
// We know the end of the structure only if we could define an offset
// and the size is fixed.
if vs.Offset != nil && vs.isFixedSize() {
return asOffsetPtr(*vs.Offset + quantity.Offset(vs.Size))
}
return nil
}

func setImplicitForVolume(vol *Volume, model Model) error {
rs := whichVolRuleset(model)
if vol.HasPartial(PartialSchema) {
Expand All @@ -1112,42 +1132,34 @@ func setImplicitForVolume(vol *Volume, model Model) error {

previousEnd := asOffsetPtr(0)
for i := range vol.Structure {
vs := &vol.Structure[i]

// set the VolumeName for the structure from the volume itself
vol.Structure[i].VolumeName = vol.Name
vs.VolumeName = vol.Name
// Store index as we will reorder later
vol.Structure[i].YamlIndex = i
vs.YamlIndex = i
// MinSize is Size if not explicitly set
if vol.Structure[i].MinSize == 0 {
vol.Structure[i].MinSize = vol.Structure[i].Size
if vs.MinSize == 0 {
vs.MinSize = vs.Size
}
// Set the pointer to the volume
vol.Structure[i].EnclosingVolume = vol
vs.EnclosingVolume = vol

// set other implicit data for the structure
if err := setImplicitForVolumeStructure(&vol.Structure[i], rs, knownFsLabels, knownVfatFsLabels); err != nil {
if err := setImplicitForVolumeStructure(vs, rs, knownFsLabels, knownVfatFsLabels); err != nil {
return err
}

// Set offset if it was not set (must be after setImplicitForVolumeStructure
// so roles are good). This is possible only if the previous structure had
// a well-defined end.
if vol.Structure[i].Offset == nil && previousEnd != nil {
var start quantity.Offset
if vol.Structure[i].Role != schemaMBR && *previousEnd < NonMBRStartOffset {
start = NonMBRStartOffset
} else {
start = *previousEnd
}
vol.Structure[i].Offset = &start
}
// We know the end of the structure only if we could define an offset
// and the size is fixed.
if vol.Structure[i].Offset != nil && vol.Structure[i].isFixedSize() {
previousEnd = asOffsetPtr(*vol.Structure[i].Offset +
quantity.Offset(vol.Structure[i].Size))
} else {
previousEnd = nil
if vol.Schema == schemaEMMC {
// For eMMC, we do not support partition offsets. The partitions
// are hardware partitions that act more like traditional disks.
vs.Offset = asOffsetPtr(0)
continue
}
previousEnd = setVolumeStructureOffset(vs, previousEnd)
}

return nil
Expand Down Expand Up @@ -1267,11 +1279,17 @@ func fmtIndexAndName(idx int, name string) string {
return fmt.Sprintf("#%v", idx)
}

var validSchemaNames = []string{schemaMBR, schemaGPT, schemaEMMC}

func isValidSchema(schema string) bool {
return strutil.ListContains(validSchemaNames, schema)
}

func validateVolume(vol *Volume) error {
if !validVolumeName.MatchString(vol.Name) {
return errors.New("invalid name")
}
if !vol.HasPartial(PartialSchema) && vol.Schema != schemaGPT && vol.Schema != schemaMBR {
if !vol.HasPartial(PartialSchema) && !isValidSchema(vol.Schema) {
return fmt.Errorf("invalid schema %q", vol.Schema)
}

Expand Down Expand Up @@ -1338,6 +1356,12 @@ func isMBR(vs *VolumeStructure) bool {
}

func validateCrossVolumeStructure(vol *Volume) error {
// emmc have no traditional volumes, instead emmc has the concept
// of hardware partitions that act like separate disks.
if vol.Schema == schemaEMMC {
return nil
}

previousEnd := quantity.Offset(0)
// cross structure validation:
// - relative offsets that reference other structures by name
Expand Down Expand Up @@ -1393,6 +1417,20 @@ func validateOffsetWrite(s, firstStruct *VolumeStructure, volSize quantity.Size)
return nil
}

func contentCheckerCreate(vs *VolumeStructure, vol *Volume) func(string, *VolumeContent) error {
if vol.Schema == schemaEMMC {
return validateEMMCContent
}

if vs.HasFilesystem() {
return validateFilesystemContent
}

// default to bare content checker if no filesystem
// is present
return validateBareContent
}

func validateVolumeStructure(vs *VolumeStructure, vol *Volume) error {
if !vs.hasPartialSize() {
if vs.Size == 0 {
Expand All @@ -1419,20 +1457,14 @@ func validateVolumeStructure(vs *VolumeStructure, vol *Volume) error {
return fmt.Errorf("invalid filesystem %q", vs.Filesystem)
}

var contentChecker func(*VolumeContent) error

if vs.HasFilesystem() {
contentChecker = validateFilesystemContent
} else {
contentChecker = validateBareContent
}
contentChecker := contentCheckerCreate(vs, vol)
for i, c := range vs.Content {
if err := contentChecker(&c); err != nil {
if err := contentChecker(vs.Name, &c); err != nil {
return fmt.Errorf("invalid content #%v: %v", i, err)
}
}

if err := validateStructureUpdate(vs, vol); err != nil {
if err := validateStructureUpdate(vs); err != nil {
return err
}

Expand All @@ -1442,6 +1474,14 @@ func validateVolumeStructure(vs *VolumeStructure, vol *Volume) error {
return nil
}

func validateStructureTypeEMMC(s string) error {
// for eMMC we don't support the type being set
if s != "" {
return errors.New(`type is not supported for "emmc" schema`)
}
return nil
}

func validateStructureType(s string, vol *Volume) error {
// Type can be one of:
// - "mbr" (backwards compatible)
Expand All @@ -1453,6 +1493,11 @@ func validateStructureType(s string, vol *Volume) error {
// Hybrid ID is 2 hex digits of MBR type, followed by 36 GUUID
// example: EF,C12A7328-F81F-11D2-BA4B-00A0C93EC93B

// eMMC volumes we treat differently
if vol.Schema == schemaEMMC {
return validateStructureTypeEMMC(s)
}

if s == "" {
return errors.New(`type is not specified`)
}
Expand Down Expand Up @@ -1552,7 +1597,7 @@ func validateRole(vs *VolumeStructure) error {
return nil
}

func validateBareContent(vc *VolumeContent) error {
func validateBareContent(_ string, vc *VolumeContent) error {
if vc.UnresolvedSource != "" || vc.Target != "" {
return fmt.Errorf("cannot use non-image content for bare file system")
}
Expand All @@ -1562,7 +1607,22 @@ func validateBareContent(vc *VolumeContent) error {
return nil
}

func validateFilesystemContent(vc *VolumeContent) error {
func validateEMMCContent(name string, vc *VolumeContent) error {
// We only allow offset and size for the rpmb block
if (vc.Offset != nil || vc.Size != 0) && name != "rpmb" {
return fmt.Errorf("cannot specify size or offset for content in %q", name)
}

if vc.UnresolvedSource != "" || vc.Target != "" {
return fmt.Errorf("cannot use non-image content for hardware partitions")
}
if vc.Image == "" {
return fmt.Errorf("missing image file name")
}
return nil
}

func validateFilesystemContent(_ string, vc *VolumeContent) error {
if vc.Image != "" || vc.Offset != nil || vc.Size != 0 {
return fmt.Errorf("cannot use image content for non-bare file system")
}
Expand All @@ -1575,7 +1635,7 @@ func validateFilesystemContent(vc *VolumeContent) error {
return nil
}

func validateStructureUpdate(vs *VolumeStructure, v *Volume) error {
func validateStructureUpdate(vs *VolumeStructure) error {
if !vs.HasFilesystem() && len(vs.Update.Preserve) > 0 {
return errors.New("preserving files during update is not supported for non-filesystem structures")
}
Expand Down
Loading
Loading