Skip to content

Commit

Permalink
Refactor ResolvePossibleSymlinkToHostPath to common directory
Browse files Browse the repository at this point in the history
Signed-off-by: Dom Del Nano <[email protected]>
  • Loading branch information
ddelnano committed Dec 2, 2024
1 parent 8540621 commit f817a59
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 45 deletions.
78 changes: 78 additions & 0 deletions src/common/system/linux_headers_utils.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright 2018- The Pixie 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
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "src/common/system/linux_headers_utils.h"

#include <fstream>
#include <limits>
#include <memory>
#include <string>

#include "src/common/base/file.h"
#include "src/common/fs/fs_wrapper.h"
#include "src/common/system/config.h"

namespace px {
namespace system {

StatusOr<std::filesystem::path> ResolvePossibleSymlinkToHostPath(const std::filesystem::path p) {
// Check if "p" is a symlink.
std::error_code ec;
const bool is_symlink = std::filesystem::is_symlink(p, ec);
if (ec) {
return error::NotFound(absl::Substitute("Did not find the host headers at path: $0, $1.",
p.string(), ec.message()));
}

if (!is_symlink) {
// Not a symlink, we are good now.
return p;
}

// Resolve the symlink, and re-convert to a host path..
const std::filesystem::path resolved = std::filesystem::read_symlink(p, ec);
if (ec) {
return error::Internal(ec.message());
}

// Relative paths containing "../" can result in an invalid host mount path when using
// ToHostPath. Therefore, we need to treat the absolute and relative cases differently.
std::filesystem::path resolved_host_path;
if (resolved.is_absolute()) {
resolved_host_path = system::Config::GetInstance().ToHostPath(resolved);
VLOG(1) << absl::Substitute(
"Symlink target is an absolute path. Converting that to host path: $0 -> $1.",
resolved.string(), resolved_host_path.string());
} else {
resolved_host_path = p.parent_path();
resolved_host_path /= resolved.string();
VLOG(1) << absl::Substitute(
"Symlink target is a relative path. Concatenating it to parent directory: $0",
resolved_host_path.string());
}

// Downstream won't be ok unless the resolved host path exists; return an error if needed.
if (!fs::Exists(resolved_host_path)) {
return error::NotFound(absl::Substitute("Did not find host headers at resolved path: $0.",
resolved_host_path.string()));
}
return resolved_host_path;
}

} // namespace system
} // namespace px
44 changes: 44 additions & 0 deletions src/common/system/linux_headers_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright 2018- The Pixie 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
*
* 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.
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <filesystem>

#include "src/common/base/base.h"

namespace px {
namespace system {

/**
* Resolves a possible symlink path to its corresponding host filesystem path.
*
* This function takes a filesystem path and checks if it is a symbolic link. If it is,
* the symlink is resolved to its target path. Depending on whether the target is an absolute
* or relative path, it is further processed to convert it into a valid host path (as in
* Config::ToHostPath(...) path).
*
* If the input path is not a symlink, it is returned as-is. The function ensures that
* the final resolved path exists in the host filesystem before returning it. Errors are
* returned when the path does not exist, the resolution fails, or when there is an issue
* accessing the filesystem.
*/
StatusOr<std::filesystem::path> ResolvePossibleSymlinkToHostPath(const std::filesystem::path p);

} // namespace system
} // namespace px
47 changes: 2 additions & 45 deletions src/stirling/utils/linux_headers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "src/common/fs/temp_file.h"
#include "src/common/minitar/minitar.h"
#include "src/common/system/config.h"
#include "src/common/system/linux_headers_utils.h"
#include "src/common/system/proc_pid_path.h"
#include "src/common/zlib/zlib_wrapper.h"

Expand Down Expand Up @@ -209,55 +210,11 @@ Status FindLinuxHeadersDirectory(const std::filesystem::path& lib_modules_dir) {
return error::NotFound("Could not find 'source' or 'build' under $0.", lib_modules_dir.string());
}

StatusOr<std::filesystem::path> ResolvePossibleSymlinkToHostPath(const std::filesystem::path p) {
// Check if "p" is a symlink.
std::error_code ec;
const bool is_symlink = std::filesystem::is_symlink(p, ec);
if (ec) {
return error::NotFound(absl::Substitute("Did not find the host headers at path: $0, $1.",
p.string(), ec.message()));
}

if (!is_symlink) {
// Not a symlink, we are good now.
return p;
}

// Resolve the symlink, and re-convert to a host path..
const std::filesystem::path resolved = std::filesystem::read_symlink(p, ec);
if (ec) {
return error::Internal(ec.message());
}

// Relative paths containing "../" can result in an invalid host mount path when using
// ToHostPath. Therefore, we need to treat the absolute and relative cases differently.
std::filesystem::path resolved_host_path;
if (resolved.is_absolute()) {
resolved_host_path = system::Config::GetInstance().ToHostPath(resolved);
VLOG(1) << absl::Substitute(
"Symlink target is an absolute path. Converting that to host path: $0 -> $1.",
resolved.string(), resolved_host_path.string());
} else {
resolved_host_path = p.parent_path();
resolved_host_path /= resolved.string();
VLOG(1) << absl::Substitute(
"Symlink target is a relative path. Concatenating it to parent directory: $0",
resolved_host_path.string());
}

// Downstream won't be ok unless the resolved host path exists; return an error if needed.
if (!fs::Exists(resolved_host_path)) {
return error::NotFound(absl::Substitute("Did not find host headers at resolved path: $0.",
resolved_host_path.string()));
}
return resolved_host_path;
}

Status LinkHostLinuxHeadersKernel(const std::filesystem::path& lib_modules_dir) {
const auto host_path = system::Config::GetInstance().ToHostPath(lib_modules_dir);
LOG(INFO) << absl::Substitute("Looking for host Linux headers at $0.", host_path.string());

PX_ASSIGN_OR_RETURN(const auto resolved_host_path, ResolvePossibleSymlinkToHostPath(host_path));
PX_ASSIGN_OR_RETURN(const auto resolved_host_path, system::ResolvePossibleSymlinkToHostPath(host_path));
PX_RETURN_IF_ERROR(fs::CreateSymlinkIfNotExists(resolved_host_path, lib_modules_dir));
LOG(INFO) << absl::Substitute("Linked host headers at $0 to symlink in pem namespace at $1.",
resolved_host_path.string(), lib_modules_dir.string());
Expand Down

0 comments on commit f817a59

Please sign in to comment.