mirror of
https://github.com/clearlinux/clr-installer.git
synced 2026-08-19 05:47:09 +00:00
372 lines
8.1 KiB
Go
372 lines
8.1 KiB
Go
// Copyright © 2020 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
package storage
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/clearlinux/clr-installer/errors"
|
|
)
|
|
|
|
// Version used for reading and writing YAML
|
|
type blockDeviceYAMLMarshal struct {
|
|
Name string `yaml:"name,omitempty"`
|
|
Path string `yaml:"path,omitempty"`
|
|
Model string `yaml:"model,omitempty"`
|
|
MajorMinor string `yaml:"majMin,omitempty"`
|
|
FsType string `yaml:"fstype,omitempty"`
|
|
UUID string `yaml:"uuid,omitempty"`
|
|
Serial string `yaml:"serial,omitempty"`
|
|
MountPoint string `yaml:"mountpoint,omitempty"`
|
|
Label string `yaml:"label,omitempty"`
|
|
Size string `yaml:"size,omitempty"`
|
|
ReadOnly string `yaml:"ro,omitempty"`
|
|
RemovableDevice string `yaml:"rm,omitempty"`
|
|
Type string `yaml:"type,omitempty"`
|
|
State string `yaml:"state,omitempty"`
|
|
Children []*BlockDevice `yaml:"children,omitempty"`
|
|
Options string `yaml:"options,omitempty"`
|
|
}
|
|
|
|
// UnmarshalJSON decodes a BlockDevice, targeted to integrate with json
|
|
// decoding framework
|
|
// nolint: gocyclo // TODO: Refactor this
|
|
func (bd *BlockDevice) UnmarshalJSON(b []byte) error {
|
|
dec := json.NewDecoder(bytes.NewReader(b))
|
|
|
|
for {
|
|
t, err := dec.Token()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
|
|
str, valid := t.(string)
|
|
if !valid {
|
|
continue
|
|
}
|
|
|
|
switch str {
|
|
case "name":
|
|
var name string
|
|
|
|
if name, err = getNextStrToken(dec, "name"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.Name = name
|
|
case "path":
|
|
var path string
|
|
|
|
if path, err = getNextStrToken(dec, "path"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.Path = path
|
|
case "model":
|
|
var model string
|
|
|
|
if model, err = getNextStrToken(dec, "model"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.Model = model
|
|
case "maj:min":
|
|
var majMin string
|
|
|
|
if majMin, err = getNextStrToken(dec, "maj:min"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.MajorMinor = majMin
|
|
case "size":
|
|
var size uint64
|
|
|
|
if size, err = getNextByteToken(dec, "size"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.Size = size
|
|
case "pttype":
|
|
var pttype string
|
|
|
|
if pttype, err = getNextStrToken(dec, "pttype"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.PtType = pttype
|
|
case "fstype":
|
|
var fstype string
|
|
|
|
if fstype, err = getNextStrToken(dec, "fstype"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.FsType = fstype
|
|
case "uuid":
|
|
var uuid string
|
|
|
|
if uuid, err = getNextStrToken(dec, "uuid"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.UUID = uuid
|
|
case "serial":
|
|
var serial string
|
|
|
|
if serial, err = getNextStrToken(dec, "serial"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.Serial = serial
|
|
case "type":
|
|
var tp string
|
|
|
|
tp, err = getNextStrToken(dec, "type")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.Type, err = parseBlockDeviceType(tp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "state":
|
|
var state string
|
|
|
|
state, err = getNextStrToken(dec, "state")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.State, err = parseBlockDeviceState(state)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
case "mountpoint":
|
|
var mpoint string
|
|
|
|
if mpoint, err = getNextStrToken(dec, "mountpoint"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.MountPoint = mpoint
|
|
case "label":
|
|
var label string
|
|
|
|
if label, err = getNextStrToken(dec, "label"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.Label = label
|
|
case "partlabel":
|
|
var label string
|
|
|
|
if label, err = getNextStrToken(dec, "partlabel"); err != nil {
|
|
return err
|
|
}
|
|
|
|
bd.PartitionLabel = label
|
|
case "ro":
|
|
if bd.ReadOnly, err = getNextBoolToken(dec, "ro"); err != nil {
|
|
return err
|
|
}
|
|
case "rm":
|
|
if bd.RemovableDevice, err = getNextBoolToken(dec, "rm"); err != nil {
|
|
return err
|
|
}
|
|
case "children":
|
|
bd.Children = []*BlockDevice{}
|
|
if err := dec.Decode(&bd.Children); err != nil {
|
|
return errors.Errorf("Invalid \"children\" token: %s", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getNextStrToken(dec *json.Decoder, name string) (string, error) {
|
|
t, _ := dec.Token()
|
|
if t == nil {
|
|
return "", nil
|
|
}
|
|
|
|
str, valid := t.(string)
|
|
if !valid {
|
|
return "", errors.Errorf("\"%s\" token should have a string value", name)
|
|
}
|
|
|
|
return str, nil
|
|
}
|
|
|
|
func getNextByteToken(dec *json.Decoder, name string) (uint64, error) {
|
|
var byteSize uint64
|
|
var err error
|
|
|
|
dec.UseNumber()
|
|
token, _ := dec.Token()
|
|
if token == nil {
|
|
return 0, nil
|
|
}
|
|
|
|
switch t := token.(type) {
|
|
case json.Number:
|
|
// Is it an unsigned int value (lsblk >= 2.33)
|
|
var n int64
|
|
|
|
n, err = t.Int64()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
byteSize = uint64(n)
|
|
|
|
case string:
|
|
// Is it a string value (lsblk < 2.33)
|
|
|
|
str, sValid := token.(string)
|
|
if !sValid {
|
|
return 0, errors.Errorf("\"%s\" token is neither an uint64 nor a string value", name)
|
|
}
|
|
|
|
byteSize, err = ParseVolumeSize(str)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
return byteSize, nil
|
|
}
|
|
|
|
func getNextBoolToken(dec *json.Decoder, name string) (bool, error) {
|
|
t, _ := dec.Token()
|
|
if t == nil {
|
|
return false, nil
|
|
}
|
|
|
|
// Is it a boolean value (lsblk >= 2.33)
|
|
b, bValid := t.(bool)
|
|
if bValid {
|
|
return b, nil
|
|
}
|
|
|
|
// Is it a string value (lsblk < 2.33)
|
|
str, sValid := t.(string)
|
|
if !sValid {
|
|
return false, errors.Errorf("\"%s\" token is neither a boolean nor a string value", name)
|
|
}
|
|
|
|
if str == "0" {
|
|
return false, nil
|
|
} else if str == "1" {
|
|
return true, nil
|
|
} else if str == "" {
|
|
return false, nil
|
|
}
|
|
|
|
return false, errors.Errorf("Unknown ro value: %s", str)
|
|
}
|
|
|
|
// MarshalYAML is the yaml Marshaller implementation
|
|
func (bd *BlockDevice) MarshalYAML() (interface{}, error) {
|
|
var bdm blockDeviceYAMLMarshal
|
|
|
|
bdm.Name = bd.Name
|
|
bdm.Path = bd.Path
|
|
bdm.Model = bd.Model
|
|
bdm.MajorMinor = bd.MajorMinor
|
|
bdm.FsType = bd.FsType
|
|
bdm.UUID = bd.UUID
|
|
bdm.Serial = bd.Serial
|
|
bdm.MountPoint = bd.MountPoint
|
|
bdm.Label = bd.Label
|
|
bdm.Size = strconv.FormatUint(bd.Size, 10)
|
|
bdm.ReadOnly = strconv.FormatBool(bd.ReadOnly)
|
|
bdm.RemovableDevice = strconv.FormatBool(bd.RemovableDevice)
|
|
bdm.Type = bd.Type.String()
|
|
bdm.State = bd.State.String()
|
|
bdm.Children = bd.Children
|
|
bdm.Options = bd.Options
|
|
|
|
return bdm, nil
|
|
}
|
|
|
|
// UnmarshalYAML is the yaml Unmarshaller implementation
|
|
func (bd *BlockDevice) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
|
var unmarshBlockDevice blockDeviceYAMLMarshal
|
|
|
|
if err := unmarshal(&unmarshBlockDevice); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Copy the unmarshaled data
|
|
bd.Name = unmarshBlockDevice.Name
|
|
bd.Path = unmarshBlockDevice.Path
|
|
bd.Model = unmarshBlockDevice.Model
|
|
bd.MajorMinor = unmarshBlockDevice.MajorMinor
|
|
bd.FsType = unmarshBlockDevice.FsType
|
|
bd.UUID = unmarshBlockDevice.UUID
|
|
bd.Serial = unmarshBlockDevice.Serial
|
|
bd.MountPoint = unmarshBlockDevice.MountPoint
|
|
bd.Label = unmarshBlockDevice.Label
|
|
bd.Children = unmarshBlockDevice.Children
|
|
bd.Options = unmarshBlockDevice.Options
|
|
// Convert String to Uint64
|
|
if unmarshBlockDevice.Size != "" {
|
|
uSize, err := ParseVolumeSize(unmarshBlockDevice.Size)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bd.Size = uSize
|
|
}
|
|
|
|
// Map the BlockDeviceType
|
|
if unmarshBlockDevice.Type != "" {
|
|
iType, err := parseBlockDeviceType(unmarshBlockDevice.Type)
|
|
if err != nil {
|
|
return errors.Errorf("Device: %s: %v", unmarshBlockDevice.Name, err)
|
|
}
|
|
if iType < 0 || iType > BlockDeviceTypeUnknown {
|
|
}
|
|
bd.Type = iType
|
|
if iType != BlockDeviceTypeDisk {
|
|
bd.MakePartition = true
|
|
bd.FormatPartition = true
|
|
}
|
|
}
|
|
|
|
// Map the BlockDeviceState
|
|
if unmarshBlockDevice.State != "" {
|
|
iState, err := parseBlockDeviceState(unmarshBlockDevice.State)
|
|
if err != nil {
|
|
return errors.Errorf("Device: %s: %v", unmarshBlockDevice.Name, err)
|
|
}
|
|
bd.State = iState
|
|
}
|
|
|
|
// Map the ReanOnly bool
|
|
if unmarshBlockDevice.ReadOnly != "" {
|
|
bReadOnly, err := strconv.ParseBool(unmarshBlockDevice.ReadOnly)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bd.ReadOnly = bReadOnly
|
|
}
|
|
|
|
// Map the RemovableDevice bool
|
|
if unmarshBlockDevice.RemovableDevice != "" {
|
|
bRemovableDevice, err := strconv.ParseBool(unmarshBlockDevice.RemovableDevice)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
bd.RemovableDevice = bRemovableDevice
|
|
}
|
|
|
|
return nil
|
|
}
|