diff --git a/providers/os/config/config.go b/providers/os/config/config.go index 86edc17aa..9d0e9fec2 100644 --- a/providers/os/config/config.go +++ b/providers/os/config/config.go @@ -300,6 +300,12 @@ var Config = plugin.Provider{ Desc: "Mount all partitions of the block device", Option: plugin.FlagOption_Hidden, }, + { + Long: "include-mounted", + Type: plugin.FlagType_Bool, + Desc: "Include mounted block devices in the scan", + Option: plugin.FlagOption_Hidden, + }, { Long: "platform-ids", Type: plugin.FlagType_List, diff --git a/providers/os/connection/device/device_connection.go b/providers/os/connection/device/device_connection.go index 2ab89d6fb..0834121ba 100644 --- a/providers/os/connection/device/device_connection.go +++ b/providers/os/connection/device/device_connection.go @@ -174,10 +174,15 @@ func (p *DeviceConnection) Partitions() map[string]*snapshot.PartitionInfo { // tryDetectAsset tries to detect the OS on a given block device func tryDetectAsset(connId uint32, partition *snapshot.PartitionInfo, manager DeviceManager, conf *inventory.Config, asset *inventory.Asset) (*fs.FileSystemConnection, string, error) { log.Debug().Str("name", partition.Name).Str("type", partition.FsType).Msg("mounting partition") - scanDir, err := manager.Mount(partition) - if err != nil { - log.Error().Err(err).Msg("unable to complete mount step") - return nil, "", err + + scanDir := partition.MountPoint + var err error + if scanDir == "" { + scanDir, err = manager.Mount(partition) + if err != nil { + log.Error().Err(err).Msg("unable to complete mount step") + return nil, "", err + } } // create and initialize fs provider diff --git a/providers/os/connection/device/linux/device_manager.go b/providers/os/connection/device/linux/device_manager.go index c59cffecc..646591876 100644 --- a/providers/os/connection/device/linux/device_manager.go +++ b/providers/os/connection/device/linux/device_manager.go @@ -17,6 +17,7 @@ const ( DeviceName = "device-name" DeviceNames = "device-names" MountAllPartitions = "mount-all-partitions" + IncludeMounted = "include-mounted" ) type LinuxDeviceManager struct { @@ -66,7 +67,7 @@ func (d *LinuxDeviceManager) IdentifyMountTargets(opts map[string]string) ([]*sn var partitions []*snapshot.PartitionInfo var errs []error for _, deviceName := range deviceNames { - partitionsForDevice, err := d.identifyViaDeviceName(deviceName, opts[MountAllPartitions] == "true") + partitionsForDevice, err := d.identifyViaDeviceName(deviceName, opts[MountAllPartitions] == "true", opts[IncludeMounted] == "true") if err != nil { errs = append(errs, err) continue @@ -153,7 +154,7 @@ func (c *LinuxDeviceManager) identifyViaLun(lun int) (*snapshot.PartitionInfo, e return device.GetMountablePartition() } -func (c *LinuxDeviceManager) identifyViaDeviceName(deviceName string, mountAll bool) ([]*snapshot.PartitionInfo, error) { +func (c *LinuxDeviceManager) identifyViaDeviceName(deviceName string, mountAll bool, includeMounted bool) ([]*snapshot.PartitionInfo, error) { blockDevices, err := c.volumeMounter.CmdRunner.GetBlockDevices() if err != nil { return nil, err @@ -166,7 +167,7 @@ func (c *LinuxDeviceManager) identifyViaDeviceName(deviceName string, mountAll b if mountAll { log.Debug().Str("device", device.Name).Msg("mounting all partitions") - return device.GetMountablePartitions(true) + return device.GetPartitions(true, includeMounted) } pi, err := device.GetMountablePartition() diff --git a/providers/os/connection/snapshot/blockdevices.go b/providers/os/connection/snapshot/blockdevices.go index 8f6b05c1e..7f6a45580 100644 --- a/providers/os/connection/snapshot/blockdevices.go +++ b/providers/os/connection/snapshot/blockdevices.go @@ -163,7 +163,7 @@ func (blockEntries BlockDevices) FindDevice(requested string) (BlockDevice, erro } // Searches all the partitions in the device and finds one that can be mounted. It must be unmounted, non-boot partition -func (device BlockDevice) GetMountablePartitions(includeAll bool) ([]*PartitionInfo, error) { +func (device BlockDevice) GetPartitions(includeBoot bool, includeMounted bool) ([]*PartitionInfo, error) { log.Debug().Str("device", device.Name).Msg("get partitions for device") blockDevices := &BlockDevices{ @@ -182,11 +182,19 @@ func (device BlockDevice) GetMountablePartitions(includeAll bool) ([]*PartitionI log.Debug().Str("name", partition.Name).Msg("skipping partition without filesystem type") return false } - if includeAll { - return !partition.isMounted() + + // skip boot partitions unless includeBoot is true + if !partition.isNoBootVolume() && !includeBoot { + log.Debug().Str("name", partition.Name).Msg("skipping boot partition") + return false + } + + // skip mounted partitions unless includeMounted is true + if partition.isMounted() && !includeMounted { + return false } - return partition.isNoBootVolumeAndUnmounted() + return true } partitions := []*PartitionInfo{} @@ -198,7 +206,8 @@ func (device BlockDevice) GetMountablePartitions(includeAll bool) ([]*PartitionI partitions = append(partitions, &PartitionInfo{ Name: devFsName, FsType: partition.FsType, Label: partition.Label, Uuid: partition.Uuid, - Aliases: partition.Aliases, + Aliases: partition.Aliases, + MountPoint: partition.MountPoint, }) } else { log.Debug(). @@ -219,7 +228,7 @@ func (device BlockDevice) GetMountablePartitions(includeAll bool) ([]*PartitionI // If multiple partitions meet this criteria, the largest one is returned. func (device BlockDevice) GetMountablePartition() (*PartitionInfo, error) { // return the largest partition. we can extend this to be a parameter in the future - partitions, err := device.GetMountablePartitions(false) + partitions, err := device.GetPartitions(false, false) if err != nil { return nil, err } diff --git a/providers/os/connection/snapshot/blockdevices_test.go b/providers/os/connection/snapshot/blockdevices_test.go index a42dd2a4f..de5a9b75c 100644 --- a/providers/os/connection/snapshot/blockdevices_test.go +++ b/providers/os/connection/snapshot/blockdevices_test.go @@ -264,7 +264,7 @@ func TestGetMountablePartition(t *testing.T) { }) } -func TestGetMountablePartitions(t *testing.T) { +func TestGetPartitions(t *testing.T) { t.Run("get all non-mounted partitions", func(t *testing.T) { block := BlockDevice{ Name: "sda", @@ -277,7 +277,7 @@ func TestGetMountablePartitions(t *testing.T) { {Uuid: "12347", FsType: "", Label: "ROOT", Name: "sda4", MountPoint: ""}, }, } - parts, err := block.GetMountablePartitions(true) + parts, err := block.GetPartitions(true, false) require.NoError(t, err) expected := []*PartitionInfo{ {Name: "/dev/sda2", FsType: "xfs", Uuid: "12345", Label: "ROOT"}, @@ -293,13 +293,35 @@ func TestGetMountablePartitions(t *testing.T) { Label: "ROOT", Uuid: "1234", } - parts, err := block.GetMountablePartitions(true) + parts, err := block.GetPartitions(true, false) require.NoError(t, err) expected := []*PartitionInfo{ {Name: "/dev/sda", FsType: "xfs", Uuid: "1234", Label: "ROOT"}, } require.ElementsMatch(t, expected, parts) }) + + t.Run("get all partitions (include mounted)", func(t *testing.T) { + block := BlockDevice{ + Name: "sda", + Children: []BlockDevice{ + // already mounted + {Uuid: "1234", FsType: "xfs", Label: "ROOT", Name: "sda1", MountPoint: "/"}, + {Uuid: "12345", FsType: "xfs", Label: "ROOT", Name: "sda2", MountPoint: ""}, + {Uuid: "12346", FsType: "xfs", Label: "ROOT", Name: "sda3", MountPoint: ""}, + // no fs type + {Uuid: "12347", FsType: "", Label: "ROOT", Name: "sda4", MountPoint: ""}, + }, + } + parts, err := block.GetPartitions(true, true) + require.NoError(t, err) + expected := []*PartitionInfo{ + {Name: "/dev/sda1", FsType: "xfs", Uuid: "1234", Label: "ROOT", MountPoint: "/"}, + {Name: "/dev/sda2", FsType: "xfs", Uuid: "12345", Label: "ROOT"}, + {Name: "/dev/sda3", FsType: "xfs", Uuid: "12346", Label: "ROOT"}, + } + require.ElementsMatch(t, expected, parts) + }) } func TestLongestMatchingSuffix(t *testing.T) { diff --git a/providers/os/connection/snapshot/partition.go b/providers/os/connection/snapshot/partition.go index 532868829..075da1fe5 100644 --- a/providers/os/connection/snapshot/partition.go +++ b/providers/os/connection/snapshot/partition.go @@ -19,6 +19,8 @@ type PartitionInfo struct { Label string // (optional) UUID is the partition UUID Uuid string + // (optional) MountPoint is the partition mount point + MountPoint string } func (entry BlockDevice) isNoBootVolume() bool { diff --git a/providers/os/provider/provider.go b/providers/os/provider/provider.go index 7bcfeb22c..628f3f409 100644 --- a/providers/os/provider/provider.go +++ b/providers/os/provider/provider.go @@ -246,6 +246,9 @@ func (s *Service) ParseCLI(req *plugin.ParseCLIReq) (*plugin.ParseCLIRes, error) if mountAll, ok := flags["mount-all-partitions"]; ok { conf.Options["mount-all-partitions"] = strconv.FormatBool(mountAll.RawData().Value.(bool)) } + if includeMounted, ok := flags["include-mounted"]; ok { + conf.Options["include-mounted"] = strconv.FormatBool(includeMounted.RawData().Value.(bool)) + } if platformIDs, ok := flags["platform-ids"]; ok { platformIDs := platformIDs.Array