go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/connection/snapshot/blockdevices.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package snapshot 5 6 import ( 7 "errors" 8 "strings" 9 10 "github.com/rs/zerolog/log" 11 ) 12 13 type blockDevices struct { 14 BlockDevices []blockDevice `json:"blockDevices,omitempty"` 15 } 16 17 type blockDevice struct { 18 Name string `json:"name,omitempty"` 19 FsType string `json:"fstype,omitempty"` 20 Label string `json:"label,omitempty"` 21 Uuid string `json:"uuid,omitempty"` 22 MountPoint string `json:"mountpoint,omitempty"` 23 Children []blockDevice `json:"children,omitempty"` 24 } 25 26 type fsInfo struct { 27 name string 28 fstype string 29 } 30 31 func (blockEntries blockDevices) GetRootBlockEntry() (*fsInfo, error) { 32 log.Debug().Msg("get root block entry") 33 for i := range blockEntries.BlockDevices { 34 d := blockEntries.BlockDevices[i] 35 log.Debug().Str("name", d.Name).Interface("children", d.Children).Interface("mountpoint", d.MountPoint).Msg("found block device") 36 for i := range d.Children { 37 entry := d.Children[i] 38 if entry.IsNoBootVolume() { 39 devFsName := "/dev/" + entry.Name 40 return &fsInfo{name: devFsName, fstype: entry.FsType}, nil 41 } 42 } 43 } 44 return nil, errors.New("target volume not found on instance") 45 } 46 47 func (blockEntries blockDevices) GetBlockEntryByName(name string) (*fsInfo, error) { 48 log.Debug().Str("name", name).Msg("get matching block entry") 49 var secondName string 50 if strings.HasPrefix(name, "/dev/sd") { 51 // sdh and xvdh are interchangeable 52 end := strings.TrimPrefix(name, "/dev/sd") 53 secondName = "/dev/xvd" + end 54 } 55 for i := range blockEntries.BlockDevices { 56 d := blockEntries.BlockDevices[i] 57 log.Debug().Str("name", d.Name).Interface("children", d.Children).Interface("mountpoint", d.MountPoint).Msg("found block device") 58 fullDeviceName := "/dev/" + d.Name 59 if name != fullDeviceName { // check if the device name matches 60 if secondName == "" { 61 continue 62 } 63 if secondName != fullDeviceName { // check if the device name matches the second name option (sdh and xvdh are interchangeable) 64 continue 65 } 66 } 67 log.Debug().Msg("found match") 68 for i := range d.Children { 69 entry := d.Children[i] 70 if entry.IsNoBootVolumeAndUnmounted() { 71 devFsName := "/dev/" + entry.Name 72 return &fsInfo{name: devFsName, fstype: entry.FsType}, nil 73 } 74 } 75 } 76 return nil, errors.New("target volume not found on instance") 77 } 78 79 func (blockEntries blockDevices) GetUnnamedBlockEntry() (*fsInfo, error) { 80 fsInfo, err := blockEntries.GetUnmountedBlockEntry() 81 if err == nil && fsInfo != nil { 82 return fsInfo, nil 83 } else { 84 // if we get here, there was no non-root, non-mounted volume on the instance 85 // this is expected in the "no setup" case where we start an instance with the target 86 // volume attached and only that volume attached 87 fsInfo, err = blockEntries.GetRootBlockEntry() 88 if err == nil && fsInfo != nil { 89 return fsInfo, nil 90 } 91 } 92 return nil, errors.New("target volume not found on instance") 93 } 94 95 func (blockEntries blockDevices) GetUnmountedBlockEntry() (*fsInfo, error) { 96 log.Debug().Msg("get unmounted block entry") 97 for i := range blockEntries.BlockDevices { 98 d := blockEntries.BlockDevices[i] 99 log.Debug().Str("name", d.Name).Interface("children", d.Children).Interface("mountpoint", d.MountPoint).Msg("found block device") 100 if d.MountPoint != "" { // empty string means it is not mounted 101 continue 102 } 103 for i := range d.Children { 104 entry := d.Children[i] 105 if entry.IsNoBootVolumeAndUnmounted() { 106 devFsName := "/dev/" + entry.Name 107 return &fsInfo{name: devFsName, fstype: entry.FsType}, nil 108 } 109 } 110 } 111 return nil, errors.New("target volume not found on instance") 112 } 113 114 func (entry blockDevice) IsNoBootVolume() bool { 115 return entry.Uuid != "" && entry.FsType != "" && entry.FsType != "vfat" && entry.Label != "EFI" 116 } 117 118 func (entry blockDevice) IsNoBootVolumeAndUnmounted() bool { 119 return entry.IsNoBootVolume() && entry.MountPoint == "" 120 }