| /** |
| # Copyright 2024 NVIDIA CORPORATION |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| **/ |
| |
| package lookup |
| |
| import ( |
| "fmt" |
| "path/filepath" |
| "slices" |
| |
| "github.com/NVIDIA/nvidia-container-toolkit/internal/ldcache" |
| ) |
| |
| type ldcacheLocator struct { |
| *builder |
| resolvesTo map[string]string |
| } |
| |
| var _ Locator = (*ldcacheLocator)(nil) |
| |
| func NewLdcacheLocator(opts ...Option) Locator { |
| b := newBuilder(opts...) |
| |
| cache, err := ldcache.New(b.logger, b.root) |
| if err != nil { |
| b.logger.Warningf("Failed to load ldcache: %v", err) |
| if b.isOptional { |
| return &null{} |
| } |
| return ¬Found{} |
| } |
| |
| chain := NewSymlinkChainLocator(WithOptional(true)) |
| |
| resolvesTo := make(map[string]string) |
| _, libs64 := cache.List() |
| for _, library := range libs64 { |
| if _, processed := resolvesTo[library]; processed { |
| continue |
| } |
| candidates, err := chain.Locate(library) |
| if err != nil { |
| b.logger.Errorf("error processing library %s from ldcache: %v", library, err) |
| continue |
| } |
| |
| if len(candidates) == 0 { |
| resolvesTo[library] = library |
| continue |
| } |
| |
| // candidates represents a symlink chain. |
| // The first element represents the start of the chain and the last |
| // element the final target. |
| target := candidates[len(candidates)-1] |
| for _, candidate := range candidates { |
| resolvesTo[candidate] = target |
| } |
| } |
| |
| return &ldcacheLocator{ |
| builder: b, |
| resolvesTo: resolvesTo, |
| } |
| } |
| |
| // Locate finds the specified libraryname. |
| // If the input is a library name, the ldcache is searched otherwise the |
| // provided path is resolved as a symlink. |
| func (l ldcacheLocator) Locate(libname string) ([]string, error) { |
| var matcher func(string, string) bool |
| |
| if filepath.IsAbs(libname) { |
| matcher = func(p string, c string) bool { |
| m, _ := filepath.Match(filepath.Join(l.root, p), c) |
| return m |
| } |
| } else { |
| matcher = func(p string, c string) bool { |
| m, _ := filepath.Match(p, filepath.Base(c)) |
| return m |
| } |
| } |
| |
| var matches []string |
| seen := make(map[string]bool) |
| for name, target := range l.resolvesTo { |
| if !matcher(libname, name) { |
| continue |
| } |
| if seen[target] { |
| continue |
| } |
| seen[target] = true |
| matches = append(matches, target) |
| } |
| |
| slices.Sort(matches) |
| |
| if len(matches) == 0 && !l.isOptional { |
| return nil, fmt.Errorf("%s: %w", libname, ErrNotFound) |
| } |
| |
| return matches, nil |
| } |