From 4259d2ca441463cf81bbf68ee57e0a45e77233e6 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Wed, 7 Aug 2024 17:26:17 +0200 Subject: [PATCH 1/3] state: Catch all errors during system state load There are multiple exceptions that can occur during loading the system state from toml files. Now they are caught and wrapped in StateLoadError. --- libdnf5/system/state.cpp | 34 ++++++++++++++++++++++++++-------- libdnf5/system/state.hpp | 8 ++++++++ 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/libdnf5/system/state.cpp b/libdnf5/system/state.cpp index 7cff97e0b..210d32076 100644 --- a/libdnf5/system/state.cpp +++ b/libdnf5/system/state.cpp @@ -297,6 +297,10 @@ StateNotFoundError::StateNotFoundError(const std::string & type, const std::stri : libdnf5::Error(M_("{} state for \"{}\" not found."), type, key) {} +StateLoadError::StateLoadError(const std::string & path, const std::string & error) + : libdnf5::Error(M_("Loading system state TOML file {} failed (see dnf5-system-state(7)): {}"), path, error) {} + + State::State(const std::filesystem::path & path) : path(path) { load(); } @@ -600,7 +604,7 @@ static T load_toml_data(const std::string & path, const std::string & key) { return {}; } - auto toml_value = toml::parse(path); + const auto toml_value = toml::parse(path); auto version_string = toml::find(toml_value, "version"); auto version_parsed = parse_version(version_string); @@ -616,15 +620,29 @@ static T load_toml_data(const std::string & path, const std::string & key) { void State::load() { - package_states = load_toml_data>(get_package_state_path(), "packages"); - nevra_states = load_toml_data>(get_nevra_state_path(), "nevras"); - group_states = load_toml_data>(get_group_state_path(), "groups"); - environment_states = - load_toml_data>(get_environment_state_path(), "environments"); + std::string path; + try { + path = get_package_state_path(); + package_states = load_toml_data>(path, "packages"); + path = get_nevra_state_path(); + nevra_states = load_toml_data>(path, "nevras"); + path = get_group_state_path(); + group_states = load_toml_data>(path, "groups"); + path = get_environment_state_path(); + environment_states = load_toml_data>(path, "environments"); #ifdef WITH_MODULEMD - module_states = load_toml_data>(get_module_state_path(), "modules"); + path = get_module_state_path(); + module_states = load_toml_data>(path, "modules"); #endif - system_state = load_toml_data(get_system_state_path(), "system"); + path = get_system_state_path(); + system_state = load_toml_data(path, "system"); + } catch (const InvalidVersionError & ex) { + throw; + } catch (const UnsupportedVersionError & ex) { + throw; + } catch (const std::exception & ex) { + throw StateLoadError(path, ex.what()); + } package_groups_cache.reset(); } diff --git a/libdnf5/system/state.hpp b/libdnf5/system/state.hpp index 8730e4c10..f410342b9 100644 --- a/libdnf5/system/state.hpp +++ b/libdnf5/system/state.hpp @@ -101,6 +101,14 @@ class UnsupportedVersionError : public libdnf5::Error { const char * get_name() const noexcept override { return "UnsupportedVersionError"; } }; +class StateLoadError : public libdnf5::Error { +public: + StateLoadError(const std::string & path, const std::string & error); + + const char * get_domain_name() const noexcept override { return "libdnf5::system"; } + const char * get_name() const noexcept override { return "StateLoadError"; } +}; + /// A class providing information and allowing modification of the DNF system /// state. The state consists of a list of userinstalled packages, installed From 7221317f76b34dc30fc9c71d4d75a5435fb60b97 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Wed, 7 Aug 2024 17:29:11 +0200 Subject: [PATCH 2/3] doc: Add man page describing the system state The page also contains information how to recover from corrupted system state files. --- dnf5.spec | 1 + doc/CMakeLists.txt | 1 + doc/conf.py.in | 1 + doc/dnf5.conf.5.rst | 11 +++++++--- doc/misc/index.rst | 1 + doc/misc/system-state.7.rst | 44 +++++++++++++++++++++++++++++++++++++ 6 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 doc/misc/system-state.7.rst diff --git a/dnf5.spec b/dnf5.spec index 06423f02b..52f23b0b9 100644 --- a/dnf5.spec +++ b/dnf5.spec @@ -335,6 +335,7 @@ It supports RPM packages, modulemd modules, and comps groups & environments. %{_mandir}/man7/dnf*-installroot.7.* %{_mandir}/man7/dnf*-modularity.7.* %{_mandir}/man7/dnf*-specs.7.* +%{_mandir}/man7/dnf*-system-state.7.* %{_mandir}/man5/dnf*.conf.5.* %{_mandir}/man5/dnf*.conf-todo.5.* %{_mandir}/man5/dnf*.conf-deprecated.5.* diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 90d728654..19a1855a6 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -93,6 +93,7 @@ if(WITH_MAN) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-installroot.7 DESTINATION share/man/man7) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-modularity.7 DESTINATION share/man/man7) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-specs.7 DESTINATION share/man/man7) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-system-state.7 DESTINATION share/man/man7) # plugin commands install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/dnf5-automatic.8 DESTINATION share/man/man8) diff --git a/doc/conf.py.in b/doc/conf.py.in index 7d97ff599..eb3e7c508 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -158,6 +158,7 @@ man_pages = [ ('misc/installroot.7', 'dnf5-installroot', 'Installroot Parameter', AUTHORS, 7), ('misc/modularity.7', 'dnf5-modularity', 'Modularity Overview', AUTHORS, 7), ('misc/specs.7', 'dnf5-specs', 'Patterns Specification', AUTHORS, 7), + ('misc/system-state.7', 'dnf5-system-state', 'System state', AUTHORS, 7), ('dnf_daemon/dnf5daemon_client.8', 'dnf5daemon-client', 'Command-line interface for Dnf5daemon', AUTHORS, 8), ('dnf_daemon/dnf5daemon_server.8', 'dnf5daemon-server', 'Package management service with a DBus interface', AUTHORS, 8), ('dnf_daemon/dnf5daemon_dbus_api.8', 'dnf5daemon-dbus-api', 'DBus API Reference for Dnf5daemon', AUTHORS, 8), diff --git a/doc/dnf5.conf.5.rst b/doc/dnf5.conf.5.rst index 3b95f7080..fdd5c9e07 100644 --- a/doc/dnf5.conf.5.rst +++ b/doc/dnf5.conf.5.rst @@ -431,15 +431,20 @@ repository configuration file should aside from repo ID consists of baseurl, met :ref:`string ` - For superuser overwrites the :ref:`cachedir <_cachedir_options-label>` option value. + For superuser overwrites the :ref:`cachedir ` option value. Allows to differentiate user and superuser cachedir. Default: ``/var/cache/libdnf5``. -.. _system_state_options-label: +.. _system_state_dir_options-label: -``system_state`` +``system_state_dir`` + :ref:`string ` + + System state files location. See :manpage:`dnf5-system-state(7)`, :ref:`system state ` for details. + + Default: ``/usr/lib/sysimage/libdnf5``. .. _tsflags_options-label: diff --git a/doc/misc/index.rst b/doc/misc/index.rst index 90daf25bb..3d8b617c9 100644 --- a/doc/misc/index.rst +++ b/doc/misc/index.rst @@ -14,3 +14,4 @@ Miscellaneous installroot.7 modularity.7 specs.7 + system-state.7 diff --git a/doc/misc/system-state.7.rst b/doc/misc/system-state.7.rst new file mode 100644 index 000000000..7e9421cb5 --- /dev/null +++ b/doc/misc/system-state.7.rst @@ -0,0 +1,44 @@ +.. + 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 General Public License as published by + the Free Software Foundation, either version 2 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with libdnf. If not, see . + +.. _systemstate_misc_ref-label: + +############## + System state +############## + +Description +=========== + +The DNF5 system state consists of several TOML files with their location determined by the `system_state_dir` configuration option (:manpage:`dnf5-conf(5)`, :ref:`system_state_dir `). DNF5 uses the system state to: + + 1. Store the reasons why each installed package was added to the system. The reasons can be "user" for packages that the user explicitly asked DNF5 to install, "dependency" and "weak dependency" for packages pulled in as dependencies of another package, "group" for packages installed by a group, or "external" for packages installed by another tool (e.g. rpm). + + 2. Track installed groups and packages installed by these groups. + + 3. Track installed environmental groups. + + +The way of storing the DNF5 system state is an internal implementation detail and may change at any time. To modify the state, always use the DNF5 command-line interface or DNF5 API. + + +Recovering from a corrupted system state +======================================== + +If the system state files become corrupted, simply back up and remove the corrupted TOML file mentioned in the error message. It will be regenerated during the next successful DNF5 transaction. +The regenerated files may lack some data, such as the reasons why packages were installed or the repositories from which they were installed. From e147626918f768e7d1a47464d2b35ffe2caf3416 Mon Sep 17 00:00:00 2001 From: Marek Blaha Date: Tue, 20 Aug 2024 08:57:32 +0200 Subject: [PATCH 3/3] doc: Add references from dnf5(8) to new man pages --- doc/dnf5.8.rst | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/doc/dnf5.8.rst b/doc/dnf5.8.rst index 19edb7f66..7064957b3 100644 --- a/doc/dnf5.8.rst +++ b/doc/dnf5.8.rst @@ -456,16 +456,12 @@ Miscellaneous: | :manpage:`dnf5-aliases(7)`, :ref:`Aliases for command line arguments ` | :manpage:`dnf5-caching(7)`, :ref:`Caching ` | :manpage:`dnf5-comps(7)`, :ref:`Comps groups and environments ` + | :manpage:`dnf5-filtering(7)`, :ref:`Packages filtering, ` | :manpage:`dnf5-forcearch(7)`, :ref:`Forcearch parameter ` | :manpage:`dnf5-installroot(7)`, :ref:`Installroot parameter ` - | :manpage:`dnf5-specs(7)`, :ref:`Patterns specification ` - -.. - # TODO(jkolarik): Filtering is not ready yet - | :manpage:`dnf5-filtering(7)`, :ref:`Packages filtering, ` - - # TODO(jkolarik): Modularity is not ready yet | :manpage:`dnf5-modularity(7)`, :ref:`Modularity overview, ` + | :manpage:`dnf5-specs(7)`, :ref:`Patterns specification ` + | :manpage:`dnf5-system-state(7)`, :ref:`System state ` Project homepage: | https://github.com/rpm-software-management/dnf5