Files
cariflex/tools/EVerest-main/modules/Misc/Linux_Systemd_Rauc/main/systemImpl.cpp
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

192 lines
8.5 KiB
C++

// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
#include "systemImpl.hpp"
#include "diagnostics_handler.hpp"
#include <fstream>
#include <everest/run_application/run_application.hpp>
using namespace everest::run_application;
namespace module {
namespace main {
const std::string CONSTANTS = "constants.env";
const std::string DIAGNOSTICS_UPLOADER = "diagnostics_uploader.sh";
namespace fs = std::filesystem;
// FIXME (aw): this function needs to be refactored into some kind of utility library
fs::path create_temp_file(const fs::path& dir, const std::string& prefix) {
const std::string fn_template = (dir / prefix).string() + "XXXXXX" + std::string(1, '\0');
std::vector<char> fn_template_buffer{fn_template.begin(), fn_template.end()};
// mkstemp needs to have at least 6 XXXXXX at the end and it will replace these
// with a valid file name
auto fd = mkstemp(fn_template_buffer.data());
if (fd == -1) {
EVLOG_AND_THROW(Everest::EverestBaseRuntimeError("Failed to create temporary file at: " + fn_template));
}
// close the file descriptor
close(fd);
return fn_template_buffer.data();
}
void systemImpl::init() {
this->scripts_path = mod->info.paths.libexec;
}
void systemImpl::ready() {
}
types::system::UpdateFirmwareResponse
systemImpl::handle_update_firmware(types::system::FirmwareUpdateRequest& firmware_update_request) {
// FIXME: implement planned updates at a specific time
// FIXME: we don't care about the certificate and signature provided as an argument for now.
// RAUC will not use them anyhow and updates will be equally secure whether they are launched by OCPP secure update
// mechanism or the old non-secure mechanism.
if (mod->rauc.is_idle()) {
EVLOG_info << "Installing bundle from URL: " << firmware_update_request.location;
this->mod->install_firmware_bundle(firmware_update_request.location, firmware_update_request.request_id);
return types::system::UpdateFirmwareResponse::Accepted;
} else {
return types::system::UpdateFirmwareResponse::Rejected;
}
}
types::system::UploadLogsResponse
systemImpl::handle_upload_logs(types::system::UploadLogsRequest& upload_logs_request) {
types::system::UploadLogsResponse response;
if (this->log_upload_running) {
response.upload_logs_status = types::system::UploadLogsStatus::AcceptedCanceled;
} else {
response.upload_logs_status = types::system::UploadLogsStatus::Accepted;
}
const auto date_time = Everest::Date::to_rfc3339(date::utc_clock::now());
const auto diagnostics_file_path = create_temp_file(fs::temp_directory_path(), "diagnostics-" + date_time);
const auto diagnostics_file_name = diagnostics_file_path.filename().string();
response.upload_logs_status = types::system::UploadLogsStatus::Accepted;
response.file_name = diagnostics_file_name;
// populate file with available logs within the specified time window
DiagnosticsHandler diag(mod->info.paths.libexec, mod->config.OCPPLogPath, mod->config.SessionLogPath);
const auto create_result = diag.create_log(diagnostics_file_path.c_str(), upload_logs_request.oldest_timestamp,
upload_logs_request.latest_timestamp);
this->upload_logs_thread =
std::thread([this, create_result, upload_logs_request, diagnostics_file_name, diagnostics_file_path]() {
if (this->log_upload_running) {
EVLOG_info << "Received Log upload request and log upload already running - cancelling current upload";
this->interrupt_log_upload.exchange(true);
EVLOG_info << "Waiting for other log upload to finish...";
std::unique_lock<std::mutex> lk(this->log_upload_mutex);
this->log_upload_cv.wait(lk, [this]() { return !this->log_upload_running; });
EVLOG_info << "Previous Log upload finished!";
}
std::lock_guard<std::mutex> lg(this->log_upload_mutex);
EVLOG_info << "Starting upload of log file";
this->interrupt_log_upload.exchange(false);
this->log_upload_running = true;
const auto diagnostics_uploader = this->scripts_path / DIAGNOSTICS_UPLOADER;
const auto constants = this->scripts_path / CONSTANTS;
std::vector<std::string> args = {constants.string(), upload_logs_request.location, diagnostics_file_name,
diagnostics_file_path.string()};
bool uploaded = false;
int32_t retries = 0;
const auto total_retries = upload_logs_request.retries.value_or(this->mod->config.DefaultRetries);
const auto retry_interval =
upload_logs_request.retry_interval_s.value_or(this->mod->config.DefaultRetryInterval);
types::system::LogStatus log_status;
if (create_result == DiagnosticsHandler::log_result_t::error_file) {
// problem creating the file - nothing to upload
log_status.log_status = types::system::LogStatusEnum::UploadFailure;
this->publish_log_status(log_status);
} else {
while (!uploaded && retries <= total_retries && !this->interrupt_log_upload) {
retries += 1;
log_status.request_id = upload_logs_request.request_id.value_or(-1);
run_application(
diagnostics_uploader.string(), args, [this, &log_status](const std::string& output_line) {
if (output_line == "Uploaded") {
log_status.log_status = types::system::string_to_log_status_enum(output_line);
} else if (output_line == "UploadFailure" || output_line == "PermissionDenied" ||
output_line == "BadMessage" || output_line == "NotSupportedOperation") {
log_status.log_status = types::system::LogStatusEnum::UploadFailure;
} else {
log_status.log_status = types::system::LogStatusEnum::Uploading;
}
this->publish_log_status(log_status);
if (this->interrupt_log_upload) {
return CmdControl::Terminate;
}
return CmdControl::Continue;
});
if (this->interrupt_log_upload) {
EVLOG_info << "Uploading Logs was interrupted, terminating upload script, requestId: "
<< log_status.request_id;
// N01.FR.20
log_status.log_status = types::system::LogStatusEnum::AcceptedCanceled;
this->publish_log_status(log_status);
} else if (log_status.log_status != types::system::LogStatusEnum::Uploaded &&
retries <= total_retries) {
std::this_thread::sleep_for(std::chrono::seconds(retry_interval));
} else {
uploaded = true;
}
}
}
this->log_upload_running = false;
this->log_upload_cv.notify_one();
EVLOG_info << "Log upload thread finished";
});
this->upload_logs_thread.detach();
return response;
}
bool systemImpl::handle_is_reset_allowed(types::system::ResetType& type) {
// Allow resets at any time for now
return true;
}
void systemImpl::handle_reset(types::system::ResetType& type, bool& scheduled) {
if (type == types::system::ResetType::Soft) {
EVLOG_info << "Performing soft reset";
// This will effectivly stop everest and make it restart via systemd
exit(255);
} else {
EVLOG_info << "Performing hard reset";
// this reboots the whole linux system
system("/sbin/reboot");
}
}
bool systemImpl::handle_set_system_time(std::string& timestamp) {
// currently not supported, system runs on network time
return true;
}
types::system::BootReason systemImpl::handle_get_boot_reason() {
return types::system::BootReason::Unknown;
}
void systemImpl::handle_allow_firmware_installation() {
EVLOG_info << "Received allow_firmware_installation command - allow firmware update to proceed with reboot.";
this->mod->firmware_update_may_proceed_with_reboot_callback();
}
} // namespace main
} // namespace module