4 #include <boost/filesystem.hpp>
5 #include <boost/program_options.hpp>
7 #include "config/config.h"
10 #include "utilities/aktualizr_version.h"
12 namespace bpo = boost::program_options;
14 static void log_info_target(
const std::string &prefix,
const Config &config,
const Uptane::Target &t) {
15 auto name = t.filename();
16 if (t.custom_version().length() > 0) {
17 name = t.custom_version();
19 LOG_INFO << prefix + name <<
"\tsha256:" << t.sha256Hash();
20 if (config.pacman.type == PACKAGE_MANAGER_OSTREEDOCKERAPP) {
22 auto apps = t.custom_data()[
"docker_apps"];
23 for (Json::ValueIterator i = apps.begin(); i != apps.end(); ++i) {
26 LOG_INFO <<
"\tDocker Apps:";
28 if ((*i).isObject() && (*i).isMember(
"filename")) {
29 LOG_INFO <<
"\t\t" << i.key().asString() <<
" -> " << (*i)[
"filename"].asString();
31 if ((*i).isObject() && (*i).isMember(
"uri")) {
32 LOG_INFO <<
"\t\t" << i.key().asString() <<
" -> " << (*i)[
"uri"].asString();
38 static int status_main(
LiteClient &client,
const bpo::variables_map &unused) {
40 auto target = client.primary->getCurrent();
42 if (target.MatchTarget(Uptane::Target::Unknown())) {
43 LOG_INFO <<
"No active deployment found";
45 auto name = target.filename();
46 if (target.custom_version().length() > 0) {
47 name = target.custom_version();
49 log_info_target(
"Active image is: ", client.config, target);
54 static int list_main(
LiteClient &client,
const bpo::variables_map &unused) {
58 LOG_INFO <<
"Refreshing Targets metadata";
59 if (!client.primary->updateImageMeta()) {
60 LOG_WARNING <<
"Unable to update latest metadata, using local copy";
61 if (!client.primary->checkImageMetaOffline()) {
62 LOG_ERROR <<
"Unable to use local copy of TUF data";
67 LOG_INFO <<
"Updates available to " << hwid <<
":";
68 for (
auto &t : client.primary->allTargets()) {
69 for (
auto const &it : t.hardwareIds()) {
71 log_info_target(
"", client.config, t);
79 static std::unique_ptr<Uptane::Target> find_target(
const std::shared_ptr<SotaUptaneClient> &client,
81 std::unique_ptr<Uptane::Target> rv;
82 if (!client->updateImageMeta()) {
83 LOG_WARNING <<
"Unable to update latest metadata, using local copy";
84 if (!client->checkImageMetaOffline()) {
85 LOG_ERROR <<
"Unable to use local copy of TUF data";
86 throw std::runtime_error(
"Unable to find update");
90 bool find_latest = (version ==
"latest");
91 std::unique_ptr<Uptane::Target> latest =
nullptr;
92 for (
auto &t : client->allTargets()) {
93 for (
auto const &it : t.hardwareIds()) {
96 if (latest ==
nullptr ||
Version(latest->custom_version()) <
Version(t.custom_version())) {
97 latest = std_::make_unique<Uptane::Target>(t);
99 }
else if (version == t.filename() || version == t.custom_version()) {
100 return std_::make_unique<Uptane::Target>(t);
105 if (find_latest && latest !=
nullptr) {
108 throw std::runtime_error(
"Unable to find update");
112 target.InsertEcu(client.primary_ecu);
113 if (!client.primary->downloadImage(target).first) {
117 if (client.primary->VerifyTarget(target) != TargetStatus::kGood) {
118 LOG_ERROR <<
"Downloaded target is invalid";
122 auto iresult = client.primary->PackageInstall(target);
123 if (iresult.result_code.num_code == data::ResultCode::Numeric::kNeedCompletion) {
124 LOG_INFO <<
"Update complete. Please reboot the device to activate";
125 client.storage->savePrimaryInstalledVersion(target, InstalledVersionUpdateMode::kPending);
126 }
else if (iresult.result_code.num_code == data::ResultCode::Numeric::kOk) {
127 client.storage->savePrimaryInstalledVersion(target, InstalledVersionUpdateMode::kCurrent);
129 LOG_ERROR <<
"Unable to install update: " << iresult.description;
132 LOG_INFO << iresult.description;
136 static int update_main(
LiteClient &client,
const bpo::variables_map &variables_map) {
139 std::string version(
"latest");
140 if (variables_map.count(
"update-name") > 0) {
141 version = variables_map[
"update-name"].as<std::string>();
143 LOG_INFO <<
"Finding " << version <<
" to update to...";
144 auto target = find_target(client.primary, hwid, version);
145 LOG_INFO <<
"Updating to: " << *target;
146 return do_update(client, *target);
151 int (*main)(
LiteClient &,
const bpo::variables_map &);
154 {
"status", status_main},
156 {
"update", update_main},
159 void check_info_options(
const bpo::options_description &description,
const bpo::variables_map &vm) {
160 if (vm.count(
"help") != 0 || (vm.count(
"command") == 0 && vm.count(
"version") == 0)) {
161 std::cout << description <<
'\n';
164 if (vm.count(
"version") != 0) {
165 std::cout <<
"Current aktualizr version is: " << aktualizr_version() <<
"\n";
170 bpo::variables_map parse_options(
int argc,
char *argv[]) {
171 std::string subs(
"Command to execute: ");
172 for (
size_t i = 0; i <
sizeof(commands) /
sizeof(
SubCommand); i++) {
176 subs += commands[i].name;
178 bpo::options_description description(
"aktualizr-lite command line options");
182 description.add_options()
183 (
"help,h",
"print usage")
184 (
"version,v",
"Current aktualizr version")
185 (
"config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(),
"configuration file or directory")
186 (
"loglevel", bpo::value<int>(),
"set log level 0-5 (trace, debug, info, warning, error, fatal)")
187 (
"repo-server", bpo::value<std::string>(),
"URL of the Uptane Image repository")
188 (
"primary-ecu-hardware-id", bpo::value<std::string>(),
"hardware ID of primary ecu")
189 (
"update-name", bpo::value<std::string>(),
"optional name of the update when running \"update\". default=latest")
190 (
"command", bpo::value<std::string>(), subs.c_str());
194 bpo::positional_options_description pos;
195 pos.add(
"command", 1);
197 bpo::variables_map vm;
198 std::vector<std::string> unregistered_options;
200 bpo::basic_parsed_options<char> parsed_options =
201 bpo::command_line_parser(argc, argv).options(description).positional(pos).allow_unregistered().run();
202 bpo::store(parsed_options, vm);
203 check_info_options(description, vm);
205 unregistered_options = bpo::collect_unrecognized(parsed_options.options, bpo::exclude_positional);
206 if (vm.count(
"help") == 0 && !unregistered_options.empty()) {
207 std::cout << description <<
"\n";
210 }
catch (
const bpo::required_option &ex) {
212 std::cout << ex.what() << std::endl << description;
214 }
catch (
const bpo::error &ex) {
215 check_info_options(description, vm);
218 LOG_ERROR <<
"boost command line option error: " << ex.what();
222 std::cout << ex.what() <<
'\n';
232 int main(
int argc,
char *argv[]) {
233 logger_init(isatty(1) == 1);
234 logger_set_threshold(boost::log::trivial::info);
236 bpo::variables_map commandline_map = parse_options(argc, argv);
238 int r = EXIT_FAILURE;
240 if (geteuid() != 0) {
241 LOG_WARNING <<
"\033[31mRunning as non-root and may not work as expected!\033[0m\n";
244 Config config(commandline_map);
245 config.storage.uptane_metadata_path =
BasedPath(config.storage.path /
"metadata");
246 LOG_DEBUG <<
"Current directory: " << boost::filesystem::current_path().string();
248 std::string cmd = commandline_map[
"command"].as<std::string>();
249 for (
size_t i = 0; i <
sizeof(commands) /
sizeof(
SubCommand); i++) {
250 if (cmd == commands[i].name) {
252 return commands[i].main(client, commandline_map);
255 throw bpo::invalid_option_value(cmd);
257 }
catch (
const std::exception &ex) {
258 LOG_ERROR << ex.what();