#include "simulation.hpp" #include namespace ota::installation { const std::string &expected_contents() { static const std::string contents = "release-2:kernel+device-tree+rootfs"; return contents; } const char *name(RecoveryAction action) { switch (action) { case RecoveryAction::RestartPreparation: return "restart preparation; keep A"; case RecoveryAction::ReadyToActivate: return "B verified again; wait for activation policy"; case RecoveryAction::PreserveTrial: return "preserve saved B trial and attempts"; case RecoveryAction::SeparateRecovery: return "stop; separate recovery required"; } throw std::logic_error("Unknown recovery action"); } const char *boot_choice(BootRecord record) { switch (record) { case BootRecord::ASelected: return "A"; case BootRecord::BTrial: return "B trial (attempt handling is outside this model)"; case BootRecord::Invalid: return "separate recovery"; } throw std::logic_error("Unknown boot record"); } void Installer::require_writable() const { if (storage_.boot != BootRecord::ASelected) { throw std::logic_error("B is selected or boot state is invalid"); } } void Installer::begin() { require_writable(); verified_ = false; storage_.release = "release-2"; storage_.progress = Progress::Writing; } void Installer::write_partial() { require_writable(); if (storage_.progress != Progress::Writing || storage_.release != "release-2") { throw std::logic_error("Save matching intent before writing"); } verified_ = false; storage_.b_contents = expected_contents().substr(0, 8); } void Installer::finish_write() { require_writable(); if (storage_.progress != Progress::Writing || storage_.release != "release-2") { throw std::logic_error("Save matching intent before writing"); } verified_ = false; storage_.b_contents = expected_contents(); } void Installer::verify() { require_writable(); verified_ = false; if (storage_.release != "release-2" || storage_.b_contents != expected_contents()) { throw std::runtime_error("Installed release does not match expected contents"); } verified_ = true; } void Installer::save_prepared() { require_writable(); if (!verified_) throw std::logic_error("Verify B before saving prepared state"); storage_.progress = Progress::Prepared; } void Installer::request_trial(WriteResult result) { require_writable(); if (!verified_ || storage_.progress != Progress::Prepared) { throw std::logic_error("Verify B and save prepared state before activation"); } // Supplied outcomes stand for the storage contract of boot control. // OldRecord leaves all fields intact; NewRecord saves one complete record. if (result == WriteResult::OldRecord) { throw std::runtime_error("Interrupted request; old record remains"); } if (result == WriteResult::InvalidRecord) { storage_.boot = BootRecord::Invalid; throw std::runtime_error("Interrupted request; no valid record remains"); } storage_.boot = BootRecord::BTrial; storage_.attempts_left = 2; } void Installer::save_requested() { if (storage_.boot != BootRecord::BTrial) { throw std::logic_error("No saved B trial request"); } storage_.progress = Progress::TrialRequested; } RecoveryAction Installer::recover() { verified_ = false; // Boot state takes priority over progress. Never write B or renew attempts // when a trial is already selected. Invalid boot state is not confirmation. if (storage_.boot == BootRecord::Invalid) return RecoveryAction::SeparateRecovery; if (storage_.boot == BootRecord::BTrial) { save_requested(); return RecoveryAction::PreserveTrial; } if (storage_.release != "release-2" || storage_.b_contents != expected_contents()) { return RecoveryAction::RestartPreparation; } verify(); save_prepared(); return RecoveryAction::ReadyToActivate; } void perform_step(Installer &installer, int step) { switch (step) { case 0: installer.begin(); break; case 1: installer.write_partial(); break; case 2: installer.finish_write(); break; case 3: installer.verify(); break; case 4: installer.save_prepared(); break; case 5: installer.request_trial(); break; case 6: installer.save_requested(); break; default: throw std::logic_error("Unknown installation step"); } } }// namespace ota::installation