/** # Copyright (c) 2024, HCUOpt CORPORATION. All rights reserved. **/ package discover import ( "dcu-container-toolkit/internal/logger" "dcu-container-toolkit/internal/lookup" "fmt" "os" "path/filepath" "strings" "sync" ) type pciMounts struct { None logger logger.Interface lookup lookup.Locator root string required []string sync.Mutex cache []Mount } var _ Discover = (*pciMounts)(nil) // NewPciMounts creates a discoverer for the required pci mounts using the specified locator. func NewPciMounts(logger logger.Interface, lookup lookup.Locator, root string, required []string) Discover { return &pciMounts{ logger: logger, lookup: lookup, root: root, required: required, } } func (d *pciMounts) Mounts() ([]Mount, error) { if d.lookup == nil { return nil, fmt.Errorf("no lookup defined") } if d.cache != nil { d.logger.Debugf("returning cached mounts") return d.cache, nil } d.Lock() defer d.Unlock() d.logger.Infof("Locating %v in %v", d.required, d.root) uniqueMounts := make(map[string]Mount) for _, candidate := range d.required { d.logger.Infof("Locating %v", candidate) located, err := d.lookup.Locate(candidate) if err != nil { d.logger.Warningf("Could not locate %v: %v", candidate, err) continue } if len(located) == 0 { d.logger.Warningf("Missing %v", candidate) continue } d.logger.Debugf("Located %v as %v", candidate, located) for _, p := range located { node, err := os.Readlink(p) if err != nil { d.logger.Warningf("Failed to evaluate symlink %v; ignoring", p) continue } if !filepath.IsAbs(node) { node = filepath.Join(filepath.Dir(p), node) } if _, ok := uniqueMounts[node]; ok { d.logger.Debugf("Skipping duplicate mount %v", node) continue } r := d.relativeTo(node) if r == "" { r = node } d.logger.Infof("Selecting %v as %v", node, r) uniqueMounts[node] = Mount{ HostPath: node, Path: r, Options: []string{ "rbind", "rprivate", }, } } } var mounts []Mount for _, m := range uniqueMounts { mounts = append(mounts, m) } d.cache = mounts return d.cache, nil } // relativeTo returns the path relative to the root for the file locator func (d *pciMounts) relativeTo(path string) string { if d.root == "/" { return path } return strings.TrimPrefix(path, d.root) }