Files
container/Sources/ContainerizationOS/Path.swift
T
Kathryn Baldauf e283e023ab Use container's environment when starting the init process (#329)
Fixes an issue first described in
https://github.com/apple/container/issues/740.

Previously the initial process of the container was using vminitd's
environment variables to find the target executable. This PR updates the
code to use the container's configured environment for the initial
process instead. The behavior of an exec in a container should be the
same as before.

Signed-off-by: Kathryn Baldauf <k_baldauf@apple.com>
2025-10-13 21:33:18 -07:00

87 lines
3.0 KiB
Swift

//===----------------------------------------------------------------------===//
// Copyright © 2025 Apple Inc. and the Containerization project authors.
//
// 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
//
// https://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.
//===----------------------------------------------------------------------===//
import Foundation
/// `Path` provides utilities to look for binaries in the current PATH,
/// or to return the current PATH.
public struct Path {
/// lookPath looks up an executable's path from $PATH
public static func lookPath(_ name: String) -> URL? {
lookup(name, path: getCurrentPath())
}
public static func lookPath(_ name: String, path: String) -> URL? {
lookup(name, path: path)
}
// getEnv returns the default environment of the process
// with the default $PATH added for the context of a macOS application bundle
public static func getEnv() -> [String: String] {
var env = ProcessInfo.processInfo.environment
env["PATH"] = getCurrentPath()
return env
}
private static func lookup(_ name: String, path: String) -> URL? {
// Return nil for empty names
if name.isEmpty {
return nil
}
if name.contains("/") {
if findExec(name) {
return URL(fileURLWithPath: name)
}
return nil
}
for var lookdir in path.split(separator: ":") {
if lookdir.isEmpty {
lookdir = "."
}
let file = URL(fileURLWithPath: String(lookdir)).appendingPathComponent(name)
if findExec(file.path) {
return file
}
}
return nil
}
/// getPath returns $PATH for the current process
public static func getCurrentPath() -> String {
let env = ProcessInfo.processInfo.environment
return env["PATH"] ?? "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
}
// findPath returns a string containing the 'PATH' environment variable
public static func findPath(_ env: [String]?) -> String? {
guard let env = env else {
return nil
}
return env.first(where: { path in
let split = path.split(separator: "=")
return split.count == 2 && split[0] == "PATH"
})
}
// findExec returns true if the provided path is an executable
private static func findExec(_ path: String) -> Bool {
let fm = FileManager.default
return fm.isExecutableFile(atPath: path)
}
}