Skip to content

Commit

Permalink
Load protected packages from installroot
Browse files Browse the repository at this point in the history
The set of protected packages might differ between systems therefore it
would be good to use a relevant set for the current location.
  • Loading branch information
j-mracek authored and evan-goode committed Jan 18, 2024
1 parent 9b484b8 commit 0b57dd0
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 75 deletions.
2 changes: 1 addition & 1 deletion doc/dnf5.conf.5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,7 @@ repository configuration file should aside from repo ID consists of baseurl, met
``protected_packages``
:ref:`list <list-label>`

List of packages that DNF5 should never completely remove.
This append list option contains names of packages that DNF5 should never completely remove.

They are protected via Obsoletes as well as user/plugin removals.

Expand Down
3 changes: 2 additions & 1 deletion include/libdnf5/base/base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ class Base {
repo::RepoSackWeakPtr get_repo_sack() { return repo_sack.get_weak_ptr(); }
rpm::PackageSackWeakPtr get_rpm_package_sack() { return rpm_package_sack.get_weak_ptr(); }

/// Loads libdnf plugins, vars from environment, varsdirs and installroot (releasever, arch).
/// Loads libdnf plugins, vars from environment, varsdirs and installroot (releasever, arch) and resolves
/// configuration of protected_packages (glob:).
/// To prevent differences between configuration and internal Base settings, following configurations
/// will be locked: installroot, varsdir.
/// The method is supposed to be called after configuration is updated, application plugins applied
Expand Down
8 changes: 8 additions & 0 deletions libdnf5/base/base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

#include "libdnf5/base/base.hpp"

#include "../conf/config_utils.hpp"
#include "base_impl.hpp"
#include "conf/config.h"
#include "module/module_sack_impl.hpp"
Expand Down Expand Up @@ -183,6 +184,13 @@ void Base::setup() {
config.get_system_cachedir_option().set(Option::Priority::INSTALLROOT, full_path.string());
}

// Add protected packages from files from installroot
{
auto & protected_option = config.get_protected_packages_option();
auto resolved_protected_packages = resolve_path_globs(protected_option.get_value_string(), installroot_path);
protected_option.set(protected_option.get_priority(), resolved_protected_packages);
}

load_plugins();
p_impl->plugins.init();

Expand Down
75 changes: 2 additions & 73 deletions libdnf5/conf/config_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,75 +84,6 @@ static int str_to_bytes(const std::string & str) {
return static_cast<int>(res);
}

static void add_from_file(std::ostream & out, const std::string & file_path) {
utils::fs::File file(file_path, "r");

std::string line;
while (file.read_line(line)) {
auto start = line.find_first_not_of(" \t\r");
if (start == std::string::npos) {
continue;
}
if (line[start] == '#') {
continue;
}
auto end = line.find_last_not_of(" \t\r");

out.write(line.c_str() + start, static_cast<int>(end - start + 1));
out.put(' ');
}
}

static void add_from_files(std::ostream & out, const std::string & glob_path) {
glob_t glob_buf;
glob(glob_path.c_str(), GLOB_MARK | GLOB_NOSORT, nullptr, &glob_buf);
for (size_t i = 0; i < glob_buf.gl_pathc; ++i) {
auto path = glob_buf.gl_pathv[i];
if (path[strlen(path) - 1] != '/') {
add_from_file(out, path);
}
}
globfree(&glob_buf);
}

/// @brief Replaces globs (like /etc/foo.d/\\*.foo) by content of matching files.
///
/// Ignores comment lines (start with '#') and blank lines in files.
/// Result:
/// Words delimited by spaces. Characters ',' and '\n' are replaced by spaces.
/// Extra spaces are removed.
/// @param strWithGlobs Input string with globs
/// @return Words delimited by space
static std::string resolve_globs(const std::string & str_with_globs) {
std::ostringstream res;
std::string::size_type start{0};
while (start < str_with_globs.length()) {
auto end = str_with_globs.find_first_of(" ,\n", start);
if (str_with_globs.compare(start, 5, "glob:") == 0) {
start += 5;
if (start >= str_with_globs.length()) {
break;
}
if (end == std::string::npos) {
add_from_files(res, str_with_globs.substr(start));
break;
}
if ((end - start) != 0) {
add_from_files(res, str_with_globs.substr(start, end - start));
}
} else {
if (end == std::string::npos) {
res << str_with_globs.substr(start);
break;
}
if ((end - start) != 0) {
res << str_with_globs.substr(start, end - start) << " ";
}
}
start = end + 1;
}
return res.str();
}

class ConfigMain::Impl {
friend class ConfigMain;
Expand Down Expand Up @@ -293,7 +224,7 @@ class ConfigMain::Impl {
OptionString proxy_username{nullptr};
OptionString proxy_password{nullptr};
OptionStringSet proxy_auth_method{"any", "any|none|basic|digest|negotiate|ntlm|digest_ie|ntlm_wb", false};
OptionStringList protected_packages{resolve_globs("dnf5 glob:/etc/dnf/protected.d/*.conf")};
OptionStringList protected_packages{std::vector<std::string>{"dnf5", "glob:/etc/dnf/protected.d/*.conf"}};
OptionString username{""};
OptionString password{""};
OptionBool gpgcheck{false};
Expand Down Expand Up @@ -534,9 +465,7 @@ ConfigMain::Impl::Impl(Config & owner) : owner(owner) {
"protected_packages",
protected_packages,
[&](Option::Priority priority, const std::string & value) {
if (priority >= protected_packages.get_priority()) {
option_T_list_append(protected_packages, priority, resolve_globs(value));
}
option_T_list_append(protected_packages, priority, value);
},
nullptr,
false);
Expand Down
98 changes: 98 additions & 0 deletions libdnf5/conf/config_utils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
Copyright Contributors to the libdnf project.
This file is part of libdnf: https://github.com/rpm-software-management/libdnf/
Libdnf is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
Libdnf is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with libdnf. If not, see <https://www.gnu.org/licenses/>.
*/

#include "config_utils.hpp"

#include "libdnf5/utils/fs/file.hpp"

#include <glob.h>


namespace libdnf5 {


static void add_from_file(std::ostream & out, const std::string & file_path) {
utils::fs::File file(file_path, "r");

std::string line;
while (file.read_line(line)) {
auto start = line.find_first_not_of(" \t\r");
if (start == std::string::npos) {
continue;
}
if (line[start] == '#') {
continue;
}
auto end = line.find_last_not_of(" \t\r");

out.write(line.c_str() + start, static_cast<int>(end - start + 1));
out.put(' ');
}
}


static void add_from_files(
std::ostream & out, const std::string & glob_path, const std::filesystem::path & installroot) {
// Extend path by installroot
const auto full_path = (installroot / std::filesystem::path(glob_path).relative_path()).string();
glob_t glob_buf;
glob(full_path.c_str(), GLOB_MARK | GLOB_NOSORT, nullptr, &glob_buf);
for (size_t i = 0; i < glob_buf.gl_pathc; ++i) {
auto path = glob_buf.gl_pathv[i];
if (path[strlen(path) - 1] != '/') {
add_from_file(out, path);
}
}
globfree(&glob_buf);
}


std::string resolve_path_globs(const std::string & str_with_globs, const std::filesystem::path & installroot) {
std::ostringstream res;
std::string::size_type start{0};
while (start < str_with_globs.length()) {
auto end = str_with_globs.find_first_of(" ,\n", start);
if (str_with_globs.compare(start, 5, "glob:") == 0) {
start += 5;
if (start >= str_with_globs.length()) {
break;
}
if (end == std::string::npos) {
add_from_files(res, str_with_globs.substr(start), installroot);
break;
}
if ((end - start) != 0) {
add_from_files(res, str_with_globs.substr(start, end - start), installroot);
}
} else {
if (end == std::string::npos) {
res << str_with_globs.substr(start);
break;
}
if ((end - start) != 0) {
res << str_with_globs.substr(start, end - start) << " ";
}
}
start = end + 1;
}
return res.str();
}


} // namespace libdnf5
14 changes: 14 additions & 0 deletions libdnf5/conf/config_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ along with libdnf. If not, see <https://www.gnu.org/licenses/>.

#include "libdnf5/conf/option.hpp"


namespace libdnf5 {


template <typename T>
static void option_T_list_append(T & option, Option::Priority priority, const std::string & value) {
if (value.empty()) {
Expand All @@ -47,6 +49,18 @@ static void option_T_list_append(T & option, Option::Priority priority, const st
}
}


/// @brief Replaces globs (like /etc/foo.d/\\*.foo) by content of matching files.
///
/// Ignores comment lines (start with '#') and blank lines in files.
/// Result:
/// Words delimited by spaces. Characters ',' and '\n' are replaced by spaces.
/// Extra spaces are removed.
/// @param strWithGlobs Input string with globs
/// @return Words delimited by space
std::string resolve_path_globs(const std::string & str_with_globs, const std::filesystem::path & installroot);


} // namespace libdnf5

#endif

0 comments on commit 0b57dd0

Please sign in to comment.