Skip to content

Commit 3e249b2

Browse files
corneliusclaussenhikinggrass
authored andcommitted
Add system module using D-Bus and RAUC
Signed-off-by: Cornelius Claussen <[email protected]> Adding sdbus-c++ dependecy in cmake for module Linux_Systemd_Rauc (uncomment) Signed-off-by: Florin Mihut <[email protected]> * Reboot and mark-good * removed mark good script. Cleanup. mark good is handled in init() via Systemd Signed-off-by: Cornelius Claussen <[email protected]> * Extension of API for OTA update Signed-off-by: Jan Christoph Habig <[email protected]> Linux_systemd_rauc: Add compatibility with sdbus-c++ 2.x API (#186) Signed-off-by: Cornelius Claussen <[email protected]> feat: added new interface rauc_status that provides percentage (#246) completion during a RAUC install fix: added sdbus-c++ to build Signed-off-by: James Chapman <[email protected]> Cc 13 react to new req system restart messages new (#267) * refactor: extract mechanism for safely calling system commands into companion lib * Add C++ interface to safe_system mechanism * Use safe_system mechanism to implement different types of reset * Address minor issues from PR discussion * Made errno->string conversion thread-safe again. * Use safer mechanism to call external executable in Rauc module * Improve interfaces of companion functions for safe calling of system functions * Make safe_system_c an internal function * Add function to print commands for logging * Handle timeout in safe_system commands and add verbose return type * Fix clang-format * Fix namespace formatting Signed-off-by: Christoph Burandt <[email protected]> feat: add event queue so that modules can request actions from feat: RAUC updates now via event queue fix: SIGCHILD handler not correctly configured fix: updated reboot command OCPP OTA uses the RAUC primary to determine when an OTA was successfully booted - in testing this was not always reliable. The boot slot is more reliable and if it changes after a reboot then that is a good indication that the OTA worked. The updates mean that the OCPP OTA could have a different approach if needed. This implementation supports a migration from using primary slot to using boot slot. feat: save boot and promary slot for OTA checking fix: fixes during testing The System module has code that performs OTA via RAUC's dbus interface. The code has been updated so that a base class performs most operations and the EVerest module specific requirements are now in a derived class. fix: libev now working with sdbus-c++ for RAUC feat: building code + tests with updated companion library feat: factor out common dbus functions feat: implement systemd dbus capability feat: updated sdbus-c++ to support Aync calls for version 1.6 and 2.1.0 Signed-off-by: James Chapman <[email protected]> Move into modules/Misc/Linux_Systemd_Rauc Added system lib to lib/everest Linking Linux_Systemd_Rauc against everest::system Removed provides of rauc interface Removed rauc status types dependency and changed to system types. ADjusted signal_firwmare_update_status signal Added VerifyUpdateScriptPath config parameter and James Chapman as module author Using VerifyUpdateScriptPath config param to decide if an update can be marked as good fixed typo and updated documentation about sdbus version Signed-off-by: Piet Gömpel <[email protected]> Install sdbus-c++ v2.1.0 from source in EDM mode Run apt update before installing libsystemd-dev dependency Fix linkage to sdbus-c++ Use run_application() wrapper for boost process This fixes build on opensuse Include N01.FR.20 fix in Linux_Systemd_Rauc module Signed-off-by: Kai-Uwe Hermann <[email protected]>
1 parent c54d1b9 commit 3e249b2

31 files changed

+2654
-7
lines changed

.ci/build-kit/docker/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,6 @@ FROM ghcr.io/everest/everest-ci/build-kit-base:${BASE_IMAGE_TAG}
1010
# && cd ${EVEREST_CMAKE_PATH} \
1111
# && git checkout ${EVEREST_CMAKE_VERSION} \
1212
# && rm -r .git
13+
14+
# FIXME(kai): Install libsystemd-dev as a dependency of sdbus-c++
15+
RUN apt-get update && apt-get -y install libsystemd-dev

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ if(NOT DISABLE_EDM)
9797

9898
# FIXME (aw): we need to set this by hand due to edm
9999
set(EVEREST_SCHEMA_DIR ${everest-framework_SOURCE_DIR}/schemas)
100+
101+
if(NOT TARGET SDBusCpp::sdbus-c++)
102+
add_library(SDBusCpp::sdbus-c++ ALIAS sdbus-c++)
103+
endif()
100104
else()
101105
find_package(everest-framework REQUIRED)
102106
find_package(everest-ocpp REQUIRED)
@@ -115,6 +119,8 @@ else()
115119
find_package(nlohmann_json REQUIRED)
116120

117121
find_package(ftxui 5 QUIET) # optional, if not available BringUp module will not be built
122+
123+
find_package(sdbus-c++ REQUIRED)
118124
endif()
119125

120126

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,18 @@ minimum requirements:
3636
* PLC GreenPhy
3737
* RFID
3838

39-
### Ubuntu 22.04
39+
### Ubuntu 24.04
4040

4141
> [!WARNING]
42-
> Ubuntu 20.04 is not supported anymore. Please use Ubuntu 22.04 or newer.
42+
> Ubuntu 20.04 and Ubuntu 22.04 are not supported anymore. Please use Ubuntu 24.04 or newer.
4343
4444
```bash
4545
sudo apt update
4646
sudo apt install -y python3-pip python3-venv git rsync wget cmake doxygen \
47-
graphviz build-essential clang-tidy cppcheck openjdk-17-jdk npm docker \
47+
graphviz build-essential clang-tidy cppcheck openjdk-17-jdk npm docker.io \
4848
docker-compose libboost-all-dev nodejs libssl-dev libsqlite3-dev \
49-
clang-format curl rfkill libpcap-dev libevent-dev pkg-config libcap-dev
49+
clang-format curl rfkill libpcap-dev libevent-dev pkg-config libcap-dev \
50+
libsystemd-dev
5051
```
5152

5253
### OpenSuse
@@ -59,18 +60,18 @@ zypper install -y git rsync wget cmake doxygen graphviz clang-tools cppcheck \
5960
libboost_program_options-devel libboost_system-devel libboost_thread-devel \
6061
java-17-openjdk java-17-openjdk-devel nodejs nodejs-devel npm python3-pip \
6162
gcc-c++ libopenssl-devel sqlite3-devel libpcap-devel libevent-devel \
62-
libcap-devel
63+
libcap-devel systemd-devel
6364
```
6465

65-
### Fedora 40, 41 & 42
66+
### Fedora 41 & 42
6667

6768
```bash
6869
sudo dnf update
6970
sudo dnf install make automake gcc gcc-c++ kernel-devel python3-pip \
7071
python3-devel git rsync wget cmake doxygen graphviz clang-tools-extra \
7172
cppcheck java-21-openjdk java-21-openjdk-devel boost-devel nodejs \
7273
nodejs-devel npm openssl openssl-devel libsqlite3x-devel curl rfkill \
73-
libpcap-devel libevent-devel libcap-devel
74+
libpcap-devel libevent-devel libcap-devel systemd-devel
7475
```
7576

7677
## Build & Install

dependencies.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ mqttc:
105105
git: https://github.com/LiamBindle/MQTT-C.git
106106
git_tag: v1.1.6
107107
options: ["MQTT_C_EXAMPLES OFF", "CMAKE_POSITION_INDEPENDENT_CODE ON"]
108+
# Linux_Systemd_Rauc module
109+
sdbus-cpp:
110+
git: https://github.com/Kistler-Group/sdbus-cpp.git
111+
git_tag: v2.1.0
112+
cmake_condition: "EVEREST_DEPENDENCY_ENABLED_SDBUS_CPP"
108113
# unit testing
109114
gtest:
110115
# GoogleTest now follows the Abseil Live at Head philosophy. We recommend updating to the latest commit in the main branch as often as possible.

lib/everest/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ add_subdirectory(everest_api_types)
55
add_subdirectory(external_energy_limits)
66
add_subdirectory(helpers)
77
add_subdirectory(run_application)
8+
add_subdirectory(system)
89
add_subdirectory(tls)
910
add_subdirectory(util)
1011
add_subdirectory(io)

lib/everest/system/CMakeLists.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
if(NOT DEFINED sdbus-c++_VERSION_MAJOR AND NOT DISABLE_EDM)
2+
string(REPLACE "." ";" SDBUS_CPP_VERSION_SPLIT ${CPM_PACKAGE_sdbus-cpp_VERSION})
3+
list(GET SDBUS_CPP_VERSION_SPLIT 0 sdbus-c++_VERSION_MAJOR)
4+
endif()
5+
message("Found sdbus-c++ major version: " ${sdbus-c++_VERSION_MAJOR})
6+
7+
add_library(everest_system STATIC)
8+
add_library(everest::system ALIAS everest_system)
9+
ev_register_library_target(everest_system)
10+
11+
target_sources(everest_system
12+
PRIVATE
13+
src/dbus_base.cpp
14+
src/rauc_dbus_base.cpp
15+
src/safe_system.cpp
16+
)
17+
18+
target_include_directories(everest_system
19+
PUBLIC
20+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
21+
$<INSTALL_INTERFACE:include>
22+
)
23+
24+
target_link_libraries(everest_system
25+
PRIVATE
26+
everest::log
27+
PUBLIC
28+
SDBusCpp::sdbus-c++
29+
)
30+
31+
target_compile_definitions(everest_system
32+
PRIVATE
33+
SDBUSCPP_MAJOR_VERSION=${sdbus-c++_VERSION_MAJOR}
34+
)
35+
36+
if (BUILD_TESTING)
37+
target_compile_definitions(everest_system PUBLIC EVEREST_COVERAGE_ENABLED)
38+
add_subdirectory(tests)
39+
endif()
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright Pionix GmbH and Contributors to EVerest
3+
4+
/**
5+
* \file sdbus-c++ version independent interfaces
6+
*
7+
* The sdbus-c++ library is used to provide a C++ interface to DBus.
8+
* The functions defined here enable code to compile and run against
9+
* version 1.4 or higher of sdbus-c++.
10+
*/
11+
12+
#pragma once
13+
14+
#include <sdbus-c++/sdbus-c++.h>
15+
16+
namespace everest::lib::system::dbus {
17+
18+
using async_method_callback = std::function<void(sdbus::MethodReply reply, std::optional<sdbus::Error> error)>;
19+
using async_property_callback = std::function<void(std::optional<sdbus::Error> error, sdbus::Variant value)>;
20+
21+
// library version independent functions
22+
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy(const char* destination, const char* objectPath);
23+
[[nodiscard]] std::unique_ptr<sdbus::IProxy> createProxy(const char* destination, const char* objectPath,
24+
sdbus::dont_run_event_loop_thread_t);
25+
[[nodiscard]] sdbus::MethodCall createMethodCall(const std::unique_ptr<sdbus::IProxy>& proxy, const char* interfaceName,
26+
const char* methodName);
27+
sdbus::PendingAsyncCall callMethodAsync(const std::unique_ptr<sdbus::IProxy>& proxy, sdbus::MethodCall& method,
28+
async_method_callback handler, uint64_t timeout_us);
29+
sdbus::PendingAsyncCall getPropertyAsync(const std::unique_ptr<sdbus::IProxy>& proxy, async_property_callback handler,
30+
const char* property, const char* interface);
31+
void registerSignalHandler(std::unique_ptr<sdbus::IProxy>& proxy, const char* interfaceName, const char* signalName,
32+
sdbus::signal_handler signalHandler);
33+
34+
void initialise_handlers(const std::unique_ptr<sdbus::IProxy>& proxy, std::function<void(void)> init);
35+
void process_pending(sdbus::IConnection& connection);
36+
37+
} // namespace everest::lib::system::dbus
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright Pionix GmbH and Contributors to EVerest
3+
4+
#pragma once
5+
6+
#include <sdbus-c++/sdbus-c++.h>
7+
8+
#include <everest/system/dbus_base.hpp>
9+
10+
#include <cstdint>
11+
#include <string>
12+
#include <string_view>
13+
14+
namespace everest::lib::system::rauc_dbus {
15+
16+
namespace defaults {
17+
constexpr const char* service_domain = "de.pengutronix.rauc";
18+
constexpr const char* object_path = "/";
19+
} // namespace defaults
20+
21+
namespace interface {
22+
constexpr const char* Installer = "de.pengutronix.rauc.Installer";
23+
constexpr const char* DBus_Properties = "org.freedesktop.DBus.Properties";
24+
} // namespace interface
25+
26+
namespace property {
27+
constexpr const char* Progress = "Progress";
28+
constexpr const char* Operation = "Operation";
29+
constexpr const char* LastError = "LastError";
30+
constexpr const char* BootSlot = "BootSlot";
31+
} // namespace property
32+
33+
namespace signal {
34+
constexpr const char* PropertiesChanged = "PropertiesChanged";
35+
constexpr const char* Completed = "Completed";
36+
} // namespace signal
37+
38+
namespace method {
39+
constexpr const char* InstallBundle = "InstallBundle";
40+
constexpr const char* InspectBundle = "InspectBundle";
41+
constexpr const char* Mark = "Mark";
42+
constexpr const char* GetSlotStatus = "GetSlotStatus";
43+
constexpr const char* GetPrimary = "GetPrimary";
44+
} // namespace method
45+
46+
namespace rauc_messages {
47+
struct Progress {
48+
int percent;
49+
std::string description;
50+
int level;
51+
};
52+
53+
struct CmdResult {
54+
bool success;
55+
std::string error_msg;
56+
};
57+
58+
enum class Operation {
59+
Unknown,
60+
Idle,
61+
Installing
62+
};
63+
64+
struct UpdateTransaction {
65+
std::int32_t request_id;
66+
std::string boot_slot;
67+
std::string primary_slot;
68+
};
69+
70+
enum class HealthCheckStatus {
71+
ScriptExitedWithError,
72+
ScriptNotExecutable,
73+
ScriptNotSet,
74+
ScriptTerminatedBySignal,
75+
SetupFailed,
76+
Success,
77+
UnknownError
78+
};
79+
80+
Operation string_to_operation(const std::string_view& s);
81+
// Stream operators are needed for type conversion in sdbus
82+
sdbus::Message& operator<<(sdbus::Message& msg, const Progress& items);
83+
sdbus::Message& operator>>(sdbus::Message& msg, Progress& items);
84+
85+
} // namespace rauc_messages
86+
87+
// ----------------------------------------------------------------------------
88+
// Base class
89+
90+
class RaucBase {
91+
public:
92+
using property_cb = dbus::async_property_callback;
93+
using method_cb = dbus::async_method_callback;
94+
using slot_info_t = std::map<std::string, std::map<std::string, std::string>>;
95+
96+
struct CurrentState {
97+
rauc_messages::HealthCheckStatus system_health_rc;
98+
std::string boot_slot;
99+
std::string primary_slot;
100+
};
101+
102+
RaucBase();
103+
RaucBase(sdbus::dont_run_event_loop_thread_t);
104+
105+
void configure(const std::string& verify_update_script_path = "");
106+
bool check_previous_transaction(const CurrentState& current, const rauc_messages::UpdateTransaction& saved);
107+
108+
// methods
109+
sdbus::PendingAsyncCall install_bundle(method_cb handler, const std::string& filename, uint64_t timeout_us);
110+
sdbus::PendingAsyncCall mark(method_cb handler, const std::string& mark, const std::string& slot,
111+
uint64_t timeout_us);
112+
113+
// properties
114+
sdbus::PendingAsyncCall get_boot_slot(property_cb handler) const;
115+
116+
protected:
117+
std::unique_ptr<sdbus::IProxy> proxy;
118+
119+
using slots_t = std::vector<sdbus::Struct<std::string, std::map<std::string, sdbus::Variant>>>;
120+
static slot_info_t convert(slots_t& slots);
121+
122+
rauc_messages::HealthCheckStatus check_system_health();
123+
124+
// methods
125+
sdbus::PendingAsyncCall get_primary_slot(method_cb handler, uint64_t timeout_us);
126+
sdbus::PendingAsyncCall get_slot_status(method_cb handler, uint64_t timeout_us);
127+
128+
// properties
129+
sdbus::PendingAsyncCall get_last_error(property_cb handler) const;
130+
sdbus::PendingAsyncCall get_operation(property_cb handler) const;
131+
sdbus::PendingAsyncCall get_progress(property_cb handler) const;
132+
133+
virtual bool decide_if_good(const rauc_messages::UpdateTransaction& saved, const CurrentState& current);
134+
virtual void configure_handlers() = 0;
135+
136+
private:
137+
std::string verify_update_script_path;
138+
};
139+
140+
// ----------------------------------------------------------------------------
141+
// Synchronous base class
142+
143+
class RaucBaseSync : public RaucBase {
144+
public:
145+
using RaucBase::RaucBase;
146+
147+
rauc_messages::UpdateTransaction create_transaction(std::int32_t request_id, uint64_t timeout_us);
148+
bool check_previous_transaction(const rauc_messages::UpdateTransaction& saved, uint64_t timeout_us);
149+
150+
// methods
151+
rauc_messages::CmdResult install_bundle(const std::string& filename, uint64_t timeout_us);
152+
void mark(const std::string& mark, const std::string& slot, uint64_t timeout_us);
153+
154+
// properties
155+
std::string get_boot_slot() const;
156+
157+
protected:
158+
// methods
159+
std::string get_primary_slot(uint64_t timeout_us);
160+
slot_info_t get_slot_status(uint64_t timeout_us);
161+
162+
// properties
163+
std::string get_last_error() const;
164+
rauc_messages::Operation get_operation() const;
165+
rauc_messages::Progress get_progress() const;
166+
};
167+
168+
// ----------------------------------------------------------------------------
169+
// Asynchronous base class
170+
171+
class RaucBaseAsync : public RaucBase {
172+
public:
173+
using RaucBase::RaucBase;
174+
175+
// methods
176+
bool install_bundle(const std::string& filename, uint64_t timeout_us);
177+
bool mark(const std::string& mark, const std::string& slot, uint64_t timeout_us);
178+
179+
// properties
180+
bool get_boot_slot();
181+
182+
protected:
183+
sdbus::PendingAsyncCall active_request;
184+
185+
// methods
186+
bool get_primary_slot(uint64_t timeout_us);
187+
bool get_slot_status(uint64_t timeout_us);
188+
189+
// properties
190+
bool get_last_error();
191+
bool get_operation();
192+
bool get_progress();
193+
194+
// callbacks
195+
enum class error_t : std::uint8_t {
196+
install_bundle,
197+
mark,
198+
boot_slot,
199+
primary_slot,
200+
slot_status,
201+
last_error,
202+
operation,
203+
progress
204+
};
205+
206+
virtual void cb_install_bundle() = 0;
207+
virtual void cb_mark() = 0;
208+
virtual void cb_boot_slot(const std::string_view& value) = 0;
209+
virtual void cb_primary_slot(const std::string_view& value) = 0;
210+
virtual void cb_slot_status(const slot_info_t& value) = 0;
211+
virtual void cb_last_error(const std::string_view& value) = 0;
212+
virtual void cb_operation(rauc_messages::Operation value) = 0;
213+
virtual void cb_progress(const rauc_messages::Progress& value) = 0;
214+
virtual void cb_error(error_t fn, const std::string_view& error) = 0;
215+
};
216+
217+
} // namespace everest::lib::system::rauc_dbus
218+
219+
namespace sdbus {
220+
template <>
221+
struct signature_of<everest::lib::system::rauc_dbus::rauc_messages::Progress>
222+
: signature_of<Struct<int, std::string, int>> {};
223+
} // namespace sdbus

0 commit comments

Comments
 (0)