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";
60 client.primary->updateImageMeta();
61 }
catch (
const std::exception &e) {
62 LOG_WARNING <<
"Unable to update latest metadata, using local copy";
64 client.primary->checkImageMetaOffline();
65 }
catch (
const std::exception &e2) {
66 LOG_ERROR <<
"Unable to use local copy of TUF data";
71 LOG_INFO <<
"Updates available to " << hwid <<
":";
72 for (
auto &t : client.primary->allTargets()) {
73 for (
auto const &it : t.hardwareIds()) {
75 log_info_target(
"", client.config, t);
83 static std::unique_ptr<Uptane::Target> find_target(
const std::shared_ptr<SotaUptaneClient> &client,
85 std::unique_ptr<Uptane::Target> rv;
87 client->updateImageMeta();
88 }
catch (
const std::exception &e) {
89 LOG_WARNING <<
"Unable to update latest metadata, using local copy";
91 client->checkImageMetaOffline();
92 }
catch (
const std::exception &e2) {
93 throw std::runtime_error(
"Unable to find update");
97 bool find_latest = (version ==
"latest");
98 std::unique_ptr<Uptane::Target> latest =
nullptr;
99 for (
auto &t : client->allTargets()) {
100 for (
auto const &it : t.hardwareIds()) {
103 if (latest ==
nullptr ||
Version(latest->custom_version()) <
Version(t.custom_version())) {
104 latest = std_::make_unique<Uptane::Target>(t);
106 }
else if (version == t.filename() || version == t.custom_version()) {
107 return std_::make_unique<Uptane::Target>(t);
112 if (find_latest && latest !=
nullptr) {
115 throw std::runtime_error(
"Unable to find update");
119 target.InsertEcu(client.primary_ecu);
120 if (!client.primary->downloadImage(target).first) {
124 if (client.primary->VerifyTarget(target) != TargetStatus::kGood) {
125 LOG_ERROR <<
"Downloaded target is invalid";
129 auto iresult = client.primary->PackageInstall(target);
130 if (iresult.result_code.num_code == data::ResultCode::Numeric::kNeedCompletion) {
131 LOG_INFO <<
"Update complete. Please reboot the device to activate";
132 client.storage->savePrimaryInstalledVersion(target, InstalledVersionUpdateMode::kPending);
133 }
else if (iresult.result_code.num_code == data::ResultCode::Numeric::kOk) {
134 client.storage->savePrimaryInstalledVersion(target, InstalledVersionUpdateMode::kCurrent);
136 LOG_ERROR <<
"Unable to install update: " << iresult.description;
139 LOG_INFO << iresult.description;
143 static int update_main(
LiteClient &client,
const bpo::variables_map &variables_map) {
146 std::string version(
"latest");
147 if (variables_map.count(
"update-name") > 0) {
148 version = variables_map[
"update-name"].as<std::string>();
150 LOG_INFO <<
"Finding " << version <<
" to update to...";
151 auto target = find_target(client.primary, hwid, version);
152 LOG_INFO <<
"Updating to: " << *target;
153 return do_update(client, *target);
158 int (*main)(
LiteClient &,
const bpo::variables_map &);
161 {
"status", status_main},
163 {
"update", update_main},
166 void check_info_options(
const bpo::options_description &description,
const bpo::variables_map &vm) {
167 if (vm.count(
"help") != 0 || (vm.count(
"command") == 0 && vm.count(
"version") == 0)) {
168 std::cout << description <<
'\n';
171 if (vm.count(
"version") != 0) {
172 std::cout <<
"Current aktualizr version is: " << aktualizr_version() <<
"\n";
177 bpo::variables_map parse_options(
int argc,
char *argv[]) {
178 std::string subs(
"Command to execute: ");
179 for (
size_t i = 0; i <
sizeof(commands) /
sizeof(
SubCommand); i++) {
183 subs += commands[i].name;
185 bpo::options_description description(
"aktualizr-lite command line options");
189 description.add_options()
190 (
"help,h",
"print usage")
191 (
"version,v",
"Current aktualizr version")
192 (
"config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(),
"configuration file or directory")
193 (
"loglevel", bpo::value<int>(),
"set log level 0-5 (trace, debug, info, warning, error, fatal)")
194 (
"repo-server", bpo::value<std::string>(),
"URL of the Uptane Image repository")
195 (
"primary-ecu-hardware-id", bpo::value<std::string>(),
"hardware ID of Primary ecu")
196 (
"update-name", bpo::value<std::string>(),
"optional name of the update when running \"update\". default=latest")
197 (
"command", bpo::value<std::string>(), subs.c_str());
201 bpo::positional_options_description pos;
202 pos.add(
"command", 1);
204 bpo::variables_map vm;
205 std::vector<std::string> unregistered_options;
207 bpo::basic_parsed_options<char> parsed_options =
208 bpo::command_line_parser(argc, argv).options(description).positional(pos).allow_unregistered().run();
209 bpo::store(parsed_options, vm);
210 check_info_options(description, vm);
212 unregistered_options = bpo::collect_unrecognized(parsed_options.options, bpo::exclude_positional);
213 if (vm.count(
"help") == 0 && !unregistered_options.empty()) {
214 std::cout << description <<
"\n";
217 }
catch (
const bpo::required_option &ex) {
219 std::cout << ex.what() << std::endl << description;
221 }
catch (
const bpo::error &ex) {
222 check_info_options(description, vm);
225 LOG_ERROR <<
"boost command line option error: " << ex.what();
229 std::cout << ex.what() <<
'\n';
239 int main(
int argc,
char *argv[]) {
240 logger_init(isatty(1) == 1);
241 logger_set_threshold(boost::log::trivial::info);
243 bpo::variables_map commandline_map = parse_options(argc, argv);
245 int r = EXIT_FAILURE;
247 if (geteuid() != 0) {
248 LOG_WARNING <<
"\033[31mRunning as non-root and may not work as expected!\033[0m\n";
251 Config config(commandline_map);
252 config.storage.uptane_metadata_path =
BasedPath(config.storage.path /
"metadata");
253 LOG_DEBUG <<
"Current directory: " << boost::filesystem::current_path().string();
255 std::string cmd = commandline_map[
"command"].as<std::string>();
256 for (
size_t i = 0; i <
sizeof(commands) /
sizeof(
SubCommand); i++) {
257 if (cmd == commands[i].name) {
259 return commands[i].main(client, commandline_map);
262 throw bpo::invalid_option_value(cmd);
264 }
catch (
const std::exception &ex) {
265 LOG_ERROR << ex.what();