Files
William Douglas e999af5e5b Fixup gofmt errors
2022-11-03 09:14:37 -07:00

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
}