Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions libs/utils/src/linglong/utils/hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
#include "hooks.h"

#include "cmd.h"
#include "configure.h"

Check warning on line 10 in libs/utils/src/linglong/utils/hooks.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "configure.h" not found.
#include "linglong/common/error.h"

Check warning on line 11 in libs/utils/src/linglong/utils/hooks.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/common/error.h" not found.
#include "linglong/common/strings.h"

Check warning on line 12 in libs/utils/src/linglong/utils/hooks.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/error/error.h" not found.
#include "linglong/utils/error/error.h"

Check warning on line 13 in libs/utils/src/linglong/utils/hooks.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "linglong/utils/log/log.h" not found.
#include "linglong/utils/log/log.h"

Check warning on line 15 in libs/utils/src/linglong/utils/hooks.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: <fmt/format.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.
#include <fmt/format.h>

#include <array>
Expand Down Expand Up @@ -46,7 +47,8 @@
cmd.setEnv(name, value);
}

auto result = cmd.exec({ "-c", command });
cmd.toStdin(command);
auto result = cmd.exec({});
if (!result.has_value()) {
return LINGLONG_ERR(
fmt::format("Hook command '{}' failed: {}.", command, result.error()));
Expand All @@ -59,6 +61,17 @@
{
LINGLONG_TRACE("Parsing install hooks");

auto extractValue = [](const std::string &line, std::size_t prefixLen) -> std::string {
auto trimmed = linglong::common::strings::trim(std::string_view(line).substr(prefixLen));
if (trimmed.size() >= 2
&& ((trimmed.front() == '"' && trimmed.back() == '"')
|| (trimmed.front() == '\'' && trimmed.back() == '\''))) {
trimmed.remove_prefix(1);
trimmed.remove_suffix(1);
}
return std::string(trimmed);
};
Comment on lines +64 to +73

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If the hook command contains leading or trailing whitespace inside the surrounding quotes (e.g., ll-pre-install=" echo hello "), stripping the quotes will leave the leading/trailing whitespace intact. Additionally, if the command only contains spaces inside the quotes (e.g., ll-pre-install=" "), it will result in a whitespace-only command. Trimming the string view again after stripping the quotes ensures that any such whitespace is cleaned up and empty commands are correctly identified.

Suggested change
auto extractValue = [](const std::string &line, std::size_t prefixLen) -> std::string {
auto trimmed = linglong::common::strings::trim(std::string_view(line).substr(prefixLen));
if (trimmed.size() >= 2
&& ((trimmed.front() == '"' && trimmed.back() == '"')
|| (trimmed.front() == '\'' && trimmed.back() == '\''))) {
trimmed.remove_prefix(1);
trimmed.remove_suffix(1);
}
return std::string(trimmed);
};
auto extractValue = [](const std::string &line, std::size_t prefixLen) -> std::string {
auto trimmed = linglong::common::strings::trim(std::string_view(line).substr(prefixLen));
if (trimmed.size() >= 2
&& ((trimmed.front() == '"' && trimmed.back() == '"')
|| (trimmed.front() == '\'' && trimmed.back() == '\''))) {
trimmed.remove_prefix(1);
trimmed.remove_suffix(1);
trimmed = linglong::common::strings::trim(trimmed);
}
return std::string(trimmed);
};


std::error_code ec;
for (const auto &entry : std::filesystem::directory_iterator(LINGLONG_INSTALL_HOOKS_DIR, ec)) {
if (ec) {
Expand All @@ -84,21 +97,21 @@
std::size_t pos = line.find(PRE_INSTALL_ACTION_PREFIX);
if (pos != std::string::npos) {
preInstallCommands.emplace_back(
line.substr(pos + PRE_INSTALL_ACTION_PREFIX.length()));
extractValue(line, pos + PRE_INSTALL_ACTION_PREFIX.length()));
break;
}

pos = line.find(POST_INSTALL_ACTION_PREFIX);
if (pos != std::string::npos) {
postInstallCommands.emplace_back(
line.substr(pos + POST_INSTALL_ACTION_PREFIX.length()));
extractValue(line, pos + POST_INSTALL_ACTION_PREFIX.length()));
break;
}

Check warning on line 110 in libs/utils/src/linglong/utils/hooks.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'executeInstallHooks' is never used.
pos = line.find(POST_UNINSTALL_ACTION_PREFIX);
if (pos != std::string::npos) {
postUninstallCommands.emplace_back(
line.substr(pos + POST_UNINSTALL_ACTION_PREFIX.length()));
extractValue(line, pos + POST_UNINSTALL_ACTION_PREFIX.length()));
break;
}
Comment on lines 97 to 116

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If a hook command is empty (e.g., ll-pre-install="" or ll-pre-install=), it is still added to the commands list. This causes executeInstallHooks to perform unnecessary operations (such as reading proc fd links) and ultimately spawns a shell process (sh) just to execute an empty command. Filtering out empty commands during parsing avoids this overhead entirely.

            std::size_t pos = line.find(PRE_INSTALL_ACTION_PREFIX);
            if (pos != std::string::npos) {
                if (auto val = extractValue(line, pos + PRE_INSTALL_ACTION_PREFIX.length()); !val.empty()) {
                    preInstallCommands.emplace_back(std::move(val));
                }
                break;
            }

            pos = line.find(POST_INSTALL_ACTION_PREFIX);
            if (pos != std::string::npos) {
                if (auto val = extractValue(line, pos + POST_INSTALL_ACTION_PREFIX.length()); !val.empty()) {
                    postInstallCommands.emplace_back(std::move(val));
                }
                break;
            }

            pos = line.find(POST_UNINSTALL_ACTION_PREFIX);
            if (pos != std::string::npos) {
                if (auto val = extractValue(line, pos + POST_UNINSTALL_ACTION_PREFIX.length()); !val.empty()) {
                    postUninstallCommands.emplace_back(std::move(val));
                }
                break;
            }

}
Expand Down
Loading