diff --git a/providers/os/connection/device/device_connection.go b/providers/os/connection/device/device_connection.go index 0d217da59..f8e034f64 100644 --- a/providers/os/connection/device/device_connection.go +++ b/providers/os/connection/device/device_connection.go @@ -5,6 +5,7 @@ package device import ( "errors" + "path" "runtime" "strings" @@ -185,10 +186,16 @@ 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, conf *inventory.Config, asset *inventory.Asset) (*fs.FileSystemConnection, error) { + fsPath := partition.MountPoint + if partition.Bind != "" { + fsPath = path.Join(fsPath, partition.Bind) + } + // create and initialize fs provider - conf.Options["path"] = partition.MountPoint + log.Debug().Str("path", fsPath).Msg("device connection> trying to detect asset") + conf.Options["path"] = fsPath fsConn, err := fs.NewConnection(connId, &inventory.Config{ - Path: partition.MountPoint, + Path: fsPath, PlatformId: conf.PlatformId, Options: conf.Options, Type: "fs", diff --git a/providers/os/connection/device/linux/device_manager.go b/providers/os/connection/device/linux/device_manager.go index ae41b638e..f478ce249 100644 --- a/providers/os/connection/device/linux/device_manager.go +++ b/providers/os/connection/device/linux/device_manager.go @@ -5,8 +5,10 @@ package linux import ( "bytes" + "os" "os/exec" "path" + "path/filepath" "strconv" "strings" @@ -91,7 +93,7 @@ func (d *LinuxDeviceManager) IdentifyMountTargets(opts map[string]string) ([]*sn return partitions, nil } - fstabEntries, err := d.AttemptFindFstab(partitions) + fstabEntries, err := d.HintFSTypes(partitions) if err != nil { log.Warn().Err(err).Msg("could not find fstab") return partitions, nil @@ -107,8 +109,10 @@ func (d *LinuxDeviceManager) IdentifyMountTargets(opts map[string]string) ([]*sn return partitions, nil } -func (d *LinuxDeviceManager) AttemptFindFstab(partitions []*snapshot.PartitionInfo) ([]resources.FstabEntry, error) { - for _, partition := range partitions { +func (d *LinuxDeviceManager) HintFSTypes(partitions []*snapshot.PartitionInfo) ([]resources.FstabEntry, error) { + for i := range partitions { + partition := partitions[i] + dir, err := d.volumeMounter.MountP(&snapshot.MountPartitionDto{PartitionInfo: partition}) if err != nil { continue @@ -119,33 +123,85 @@ func (d *LinuxDeviceManager) AttemptFindFstab(partitions []*snapshot.PartitionIn } }() - cmd := exec.Command("find", dir, "-type", "f", "-wholename", `*/etc/fstab`) - out, err := cmd.CombinedOutput() + entries, err := d.AttemptFindFstab(dir) if err != nil { - log.Error().Err(err).Msg("error finding fstab") - continue + return nil, err } - - if len(strings.Split(string(out), "\n")) != 2 { - log.Debug().Bytes("find", out).Msg("fstab not found, too many results") - continue + if entries != nil { + return entries, nil } - mnt, fstab := path.Split(strings.TrimSpace(string(out))) - fstabFile, err := afero.ReadFile( - fs.NewMountedFs(mnt), - path.Base(fstab)) - if err != nil { - log.Error().Err(err).Msg("error reading fstab") - continue + if ok := d.AttemptFindOSTree(dir, partition); ok { + return nil, nil } - return resources.ParseFstab(bytes.NewReader(fstabFile)) } return nil, errors.New("fstab not found") } +func (d *LinuxDeviceManager) AttemptFindFstab(dir string) ([]resources.FstabEntry, error) { + cmd := exec.Command("find", dir, "-type", "f", "-wholename", `*/etc/fstab`) + out, err := cmd.CombinedOutput() + if err != nil { + log.Error().Err(err).Msg("error searching for fstab") + return nil, nil + } + + if len(strings.Split(string(out), "\n")) != 2 { + log.Debug().Bytes("find", out).Msg("fstab not found, too many results") + return nil, nil + } + + mnt, fstab := path.Split(strings.TrimSpace(string(out))) + fstabFile, err := afero.ReadFile( + fs.NewMountedFs(mnt), + path.Base(fstab)) + if err != nil { + log.Error().Err(err).Msg("error reading fstab") + return nil, nil + } + + return resources.ParseFstab(bytes.NewReader(fstabFile)) +} + +func (d *LinuxDeviceManager) AttemptFindOSTree(dir string, partition *snapshot.PartitionInfo) bool { + info, err := os.Stat(path.Join(dir, "ostree")) + if err != nil { + if os.IsNotExist(err) { + return false + } + + log.Error().Err(err).Str("device", partition.Name).Msg("unable to stat ostree") + return false + } + + if !info.IsDir() { + return false + } + + boot1, err := os.Readlink(path.Join(dir, "ostree", "boot.1")) + if err != nil { + log.Error().Err(err).Str("device", partition.Name).Msg("unable to readlink boot.1") + return false + } + + matches, err := filepath.Glob(path.Join(dir, "ostree", boot1, "*", "*", "0")) + if err != nil { + log.Error().Err(err).Str("device", partition.Name).Msg("unable to glob ostree") + return false + } + + if len(matches) == 0 { + return false + } else if len(matches) > 1 { + log.Warn().Str("device", partition.Name).Msg("multiple ostree matches") + } + + partition.Bind = strings.TrimPrefix(matches[0], dir) + return true +} + // MountWithFstab mounts partitions adjusting the mountpoint and mount options according to the discovered fstab entries func (d *LinuxDeviceManager) MountWithFstab(partitions []*snapshot.PartitionInfo, entries []resources.FstabEntry) ([]*snapshot.PartitionInfo, error) { for _, entry := range entries { diff --git a/providers/os/connection/snapshot/partition.go b/providers/os/connection/snapshot/partition.go index a21abddb1..33163fbd7 100644 --- a/providers/os/connection/snapshot/partition.go +++ b/providers/os/connection/snapshot/partition.go @@ -24,6 +24,8 @@ type PartitionInfo struct { // (optional) MountOptions are the mount options MountOptions []string + // (optional) Bind adjusts the root for FS connection + Bind string } type MountPartitionDto struct {