99#include " cmd.h"
1010#include " configure.h"
1111#include " linglong/common/error.h"
12+ #include " linglong/common/strings.h"
1213#include " linglong/utils/error/error.h"
1314#include " linglong/utils/log/log.h"
1415
1920#include < cstring>
2021#include < filesystem>
2122#include < fstream>
23+ #include < optional>
2224#include < sstream>
25+ #include < string_view>
26+ #include < utility>
2327#include < vector>
2428
2529#include < sys/wait.h>
@@ -34,6 +38,43 @@ constexpr std::string_view POST_UNINSTALL_ACTION_PREFIX = "ll-post-uninstall=";
3438
3539using CommandList = const std::vector<std::string> &;
3640
41+ namespace {
42+
43+ constexpr std::string_view WHITESPACE_CHARS = " \t\n\r\f\v " ;
44+
45+ } // namespace
46+
47+ utils::error::Result<std::optional<std::string>>
48+ details::parseInstallHookCommandLine (std::string_view line, std::string_view prefix)
49+ {
50+ LINGLONG_TRACE (" Parsing install hook command line" );
51+
52+ line = common::strings::trim_left (line, WHITESPACE_CHARS );
53+ if (!common::strings::starts_with (line, prefix)) {
54+ return std::optional<std::string>{};
55+ }
56+
57+ auto command = common::strings::trim_left (line.substr (prefix.size ()), WHITESPACE_CHARS );
58+ if (command.empty ()) {
59+ return std::optional<std::string>{ std::string{} };
60+ }
61+
62+ const auto quote = command.front ();
63+ if (quote != ' "' && quote != ' \' ' ) {
64+ return std::optional<std::string>{ std::string (command) };
65+ }
66+
67+ command.remove_prefix (1 );
68+
69+ auto suffix = common::strings::trim_right (command, WHITESPACE_CHARS );
70+ if (suffix.empty () || suffix.back () != quote) {
71+ return LINGLONG_ERR (" Invalid install hook command: unterminated quoted command" );
72+ }
73+
74+ suffix.remove_suffix (1 );
75+ return std::optional<std::string>{ std::string (suffix) };
76+ }
77+
3778utils::error::Result<void > executeHookCommands (
3879 CommandList commands, const std::vector<std::pair<std::string, std::string>> &envVars) noexcept
3980{
@@ -79,26 +120,31 @@ utils::error::Result<void> InstallHookManager::parseInstallHooks()
79120 return LINGLONG_ERR (fmt::format (" Couldn't open file: {}" , entry.path ()));
80121 }
81122
123+ const std::array<std::pair<std::string_view, std::vector<std::string> *>, 3 > hookRules = {
124+ { { PRE_INSTALL_ACTION_PREFIX , &preInstallCommands },
125+ { POST_INSTALL_ACTION_PREFIX , &postInstallCommands },
126+ { POST_UNINSTALL_ACTION_PREFIX , &postUninstallCommands } }
127+ };
128+
82129 std::string line;
130+ std::size_t lineNumber = 0 ;
83131 while (std::getline (file, line)) {
84- std::size_t pos = line.find (PRE_INSTALL_ACTION_PREFIX );
85- if (pos != std::string::npos) {
86- preInstallCommands.emplace_back (
87- line.substr (pos + PRE_INSTALL_ACTION_PREFIX .length ()));
88- break ;
89- }
90-
91- pos = line.find (POST_INSTALL_ACTION_PREFIX );
92- if (pos != std::string::npos) {
93- postInstallCommands.emplace_back (
94- line.substr (pos + POST_INSTALL_ACTION_PREFIX .length ()));
95- break ;
96- }
97-
98- pos = line.find (POST_UNINSTALL_ACTION_PREFIX );
99- if (pos != std::string::npos) {
100- postUninstallCommands.emplace_back (
101- line.substr (pos + POST_UNINSTALL_ACTION_PREFIX .length ()));
132+ ++lineNumber;
133+
134+ for (auto [prefix, commands] : hookRules) {
135+ auto command = details::parseInstallHookCommandLine (line, prefix);
136+ if (!command.has_value ()) {
137+ return LINGLONG_ERR (fmt::format (" Invalid install hook command in {}:{}" ,
138+ entry.path ().string (),
139+ lineNumber),
140+ command);
141+ }
142+
143+ if (!command->has_value ()) {
144+ continue ;
145+ }
146+
147+ commands->emplace_back (std::move (**command));
102148 break ;
103149 }
104150 }
0 commit comments