Skip to content

Commit b598826

Browse files
committed
[no-relnote] Move root to separate file
Signed-off-by: Evan Lezar <[email protected]>
1 parent 6b037a0 commit b598826

File tree

2 files changed

+86
-37
lines changed

2 files changed

+86
-37
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
**/
16+
17+
package ldcache
18+
19+
import (
20+
"os"
21+
"path/filepath"
22+
23+
"github.com/moby/sys/symlink"
24+
)
25+
26+
// A containerRoot represents the root filesystem of a container.
27+
type containerRoot string
28+
29+
// hasPath checks whether the specified path exists in the root.
30+
func (r containerRoot) hasPath(path string) bool {
31+
resolved, err := r.resolve(path)
32+
if err != nil {
33+
return false
34+
}
35+
if _, err := os.Stat(resolved); err != nil && os.IsNotExist(err) {
36+
return false
37+
}
38+
return true
39+
}
40+
41+
// resolve returns the absolute path including root path.
42+
// Symlinks are resolved, but are guaranteed to resolve in the root.
43+
func (r containerRoot) resolve(path string) (string, error) {
44+
absolute := filepath.Clean(filepath.Join(string(r), path))
45+
return symlink.FollowSymlinkInScope(absolute, string(r))
46+
}

cmd/nvidia-cdi-hook/update-ldcache/update-ldcache.go

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ import (
3131
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
3232
)
3333

34+
const (
35+
// ldsoconfdFilenamePattern specifies the pattern for the filename
36+
// in ld.so.conf.d that includes references to the specified directories.
37+
// The 00-nvcr prefix is chosen to ensure that these libraries have a
38+
// higher precedence than other libraries on the system, but lower than
39+
// the 00-cuda-compat that is included in some containers.
40+
ldsoconfdFilenamePattern = "00-nvcr-*.conf"
41+
)
42+
3443
type command struct {
3544
logger logger.Interface
3645
}
@@ -100,27 +109,29 @@ func (m command) run(c *cli.Context, cfg *options) error {
100109
return fmt.Errorf("failed to load container state: %v", err)
101110
}
102111

103-
containerRoot, err := s.GetContainerRoot()
112+
containerRootDir, err := s.GetContainerRoot()
104113
if err != nil {
105114
return fmt.Errorf("failed to determined container root: %v", err)
106115
}
107116

108117
ldconfigPath := m.resolveLDConfigPath(cfg.ldconfigPath)
109118
args := []string{filepath.Base(ldconfigPath)}
110-
if containerRoot != "" {
111-
args = append(args, "-r", containerRoot)
119+
if containerRootDir != "" {
120+
args = append(args, "-r", containerRootDir)
112121
}
113122

114-
if root(containerRoot).hasPath("/etc/ld.so.cache") {
123+
containerRoot := containerRoot(containerRootDir)
124+
125+
if containerRoot.hasPath("/etc/ld.so.cache") {
115126
args = append(args, "-C", "/etc/ld.so.cache")
116127
} else {
117128
m.logger.Debugf("No ld.so.cache found, skipping update")
118129
args = append(args, "-N")
119130
}
120131

121132
folders := cfg.folders.Value()
122-
if root(containerRoot).hasPath("/etc/ld.so.conf.d") {
123-
err := m.createConfig(containerRoot, folders)
133+
if containerRoot.hasPath("/etc/ld.so.conf.d") {
134+
err := m.createLdsoconfdFile(containerRoot, ldsoconfdFilenamePattern, folders...)
124135
if err != nil {
125136
return fmt.Errorf("failed to update ld.so.conf.d: %v", err)
126137
}
@@ -136,61 +147,53 @@ func (m command) run(c *cli.Context, cfg *options) error {
136147
return syscall.Exec(ldconfigPath, args, nil)
137148
}
138149

139-
type root string
140-
141-
func (r root) hasPath(path string) bool {
142-
_, err := os.Stat(filepath.Join(string(r), path))
143-
if err != nil && os.IsNotExist(err) {
144-
return false
145-
}
146-
return true
147-
}
148-
149150
// resolveLDConfigPath determines the LDConfig path to use for the system.
150151
// On systems such as Ubuntu where `/sbin/ldconfig` is a wrapper around
151152
// /sbin/ldconfig.real, the latter is returned.
152153
func (m command) resolveLDConfigPath(path string) string {
153154
return strings.TrimPrefix(config.NormalizeLDConfigPath("@"+path), "@")
154155
}
155156

156-
// createConfig creates (or updates) /etc/ld.so.conf.d/00-nvcr-<RANDOM_STRING>.conf in the container
157-
// to include the required paths.
158-
// Note that the 00-nvcr prefix is chosen to ensure that these libraries have
159-
// a higher precedence than other libraries on the system but are applied AFTER
160-
// 00-cuda-compat.conf.
161-
func (m command) createConfig(root string, folders []string) error {
162-
if len(folders) == 0 {
163-
m.logger.Debugf("No folders to add to /etc/ld.so.conf")
157+
// createLdsoconfdFile creates a file at /etc/ld.so.conf.d/ in the specified root.
158+
// The file is created at /etc/ld.so.conf.d/{{ .pattern }} using `CreateTemp` and
159+
// contains the specified directories on each line.
160+
func (m command) createLdsoconfdFile(in containerRoot, pattern string, dirs ...string) error {
161+
if len(dirs) == 0 {
162+
m.logger.Debugf("No directories to add to /etc/ld.so.conf")
164163
return nil
165164
}
166165

167-
if err := os.MkdirAll(filepath.Join(root, "/etc/ld.so.conf.d"), 0755); err != nil {
168-
return fmt.Errorf("failed to create ld.so.conf.d: %v", err)
166+
ldsoconfdDir, err := in.resolve("/etc/ld.so.conf.d")
167+
if err != nil {
168+
return err
169+
}
170+
if err := os.MkdirAll(ldsoconfdDir, 0755); err != nil {
171+
return fmt.Errorf("failed to create ld.so.conf.d: %w", err)
169172
}
170173

171-
configFile, err := os.CreateTemp(filepath.Join(root, "/etc/ld.so.conf.d"), "00-nvcr-*.conf")
174+
configFile, err := os.CreateTemp(ldsoconfdDir, pattern)
172175
if err != nil {
173-
return fmt.Errorf("failed to create config file: %v", err)
176+
return fmt.Errorf("failed to create config file: %w", err)
174177
}
175178
defer configFile.Close()
176179

177-
m.logger.Debugf("Adding folders %v to %v", folders, configFile.Name())
180+
m.logger.Debugf("Adding directories %v to %v", dirs, configFile.Name())
178181

179-
configured := make(map[string]bool)
180-
for _, folder := range folders {
181-
if configured[folder] {
182+
added := make(map[string]bool)
183+
for _, dir := range dirs {
184+
if added[dir] {
182185
continue
183186
}
184-
_, err = configFile.WriteString(fmt.Sprintf("%s\n", folder))
187+
_, err = configFile.WriteString(fmt.Sprintf("%s\n", dir))
185188
if err != nil {
186-
return fmt.Errorf("failed to update ld.so.conf.d: %v", err)
189+
return fmt.Errorf("failed to update config file: %w", err)
187190
}
188-
configured[folder] = true
191+
added[dir] = true
189192
}
190193

191194
// The created file needs to be world readable for the cases where the container is run as a non-root user.
192-
if err := os.Chmod(configFile.Name(), 0644); err != nil {
193-
return fmt.Errorf("failed to chmod config file: %v", err)
195+
if err := configFile.Chmod(0644); err != nil {
196+
return fmt.Errorf("failed to chmod config file: %w", err)
194197
}
195198

196199
return nil

0 commit comments

Comments
 (0)