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 == PackageManager::kOstreeDockerApp) {
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 LOG_ERROR <<
"\t\tInvalid custom data for docker-app: " << i.key().asString();
37 static int status_main(
LiteClient &client,
const bpo::variables_map &unused) {
39 auto target = client.primary->getCurrent();
41 if (target.MatchTarget(Uptane::Target::Unknown())) {
42 LOG_INFO <<
"No active deployment found";
44 auto name = target.filename();
45 if (target.custom_version().length() > 0) {
46 name = target.custom_version();
48 log_info_target(
"Active image is: ", client.config, target);
53 static int list_main(
LiteClient &client,
const bpo::variables_map &unused) {
57 LOG_INFO <<
"Refreshing target metadata";
58 if (!client.primary->updateImagesMeta()) {
59 LOG_WARNING <<
"Unable to update latest metadata, using local copy";
60 if (!client.primary->checkImagesMetaOffline()) {
61 LOG_ERROR <<
"Unable to use local copy of TUF data";
66 LOG_INFO <<
"Updates available to " << hwid <<
":";
67 for (
auto &t : client.primary->allTargets()) {
68 for (
auto const &it : t.hardwareIds()) {
70 log_info_target(
"", client.config, t);
78 static std::unique_ptr<Uptane::Target> find_target(
const std::shared_ptr<SotaUptaneClient> &client,
80 std::unique_ptr<Uptane::Target> rv;
81 if (!client->updateImagesMeta()) {
82 LOG_WARNING <<
"Unable to update latest metadata, using local copy";
83 if (!client->checkImagesMetaOffline()) {
84 LOG_ERROR <<
"Unable to use local copy of TUF data";
85 throw std::runtime_error(
"Unable to find update");
89 bool find_latest = (version ==
"latest");
90 std::unique_ptr<Uptane::Target> latest =
nullptr;
91 for (
auto &t : client->allTargets()) {
92 for (
auto const &it : t.hardwareIds()) {
95 if (latest ==
nullptr ||
Version(latest->custom_version()) <
Version(t.custom_version())) {
96 latest = std_::make_unique<Uptane::Target>(t);
98 }
else if (version == t.filename() || version == t.custom_version()) {
99 return std_::make_unique<Uptane::Target>(t);
104 if (find_latest && latest !=
nullptr) {
107 throw std::runtime_error(
"Unable to find update");
111 if (!client.primary->downloadImage(target).first) {
115 if (client.primary->VerifyTarget(target) != TargetStatus::kGood) {
116 LOG_ERROR <<
"Downloaded target is invalid";
120 auto iresult = client.primary->PackageInstall(target);
121 if (iresult.result_code.num_code == data::ResultCode::Numeric::kNeedCompletion) {
122 LOG_INFO <<
"Update complete. Please reboot the device to activate";
123 client.storage->savePrimaryInstalledVersion(target, InstalledVersionUpdateMode::kPending);
124 }
else if (iresult.result_code.num_code == data::ResultCode::Numeric::kOk) {
125 client.storage->savePrimaryInstalledVersion(target, InstalledVersionUpdateMode::kCurrent);
127 LOG_ERROR <<
"Unable to install update: " << iresult.description;
130 LOG_INFO << iresult.description;
134 static int update_main(
LiteClient &client,
const bpo::variables_map &variables_map) {
137 std::string version(
"latest");
138 if (variables_map.count(
"update-name") > 0) {
139 version = variables_map[
"update-name"].as<std::string>();
141 LOG_INFO <<
"Finding " << version <<
" to update to...";
142 auto target = find_target(client.primary, hwid, version);
143 LOG_INFO <<
"Updating to: " << *target;
144 return do_update(client, *target);
149 int (*main)(
LiteClient &,
const bpo::variables_map &);
152 {
"status", status_main},
154 {
"update", update_main},
157 void check_info_options(
const bpo::options_description &description,
const bpo::variables_map &vm) {
158 if (vm.count(
"help") != 0 || vm.count(
"command") == 0) {
159 std::cout << description <<
'\n';
162 if (vm.count(
"version") != 0) {
163 std::cout <<
"Current aktualizr version is: " << aktualizr_version() <<
"\n";
168 bpo::variables_map parse_options(
int argc,
char *argv[]) {
169 std::string subs(
"Command to execute: ");
170 for (
size_t i = 0; i <
sizeof(commands) /
sizeof(
SubCommand); i++) {
174 subs += commands[i].name;
176 bpo::options_description description(
"aktualizr-lite command line options");
180 description.add_options()
181 (
"help,h",
"print usage")
182 (
"version,v",
"Current aktualizr version")
183 (
"config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(),
"configuration file or directory")
184 (
"loglevel", bpo::value<int>(),
"set log level 0-5 (trace, debug, info, warning, error, fatal)")
185 (
"repo-server", bpo::value<std::string>(),
"url of the uptane repo repository")
186 (
"ostree-server", bpo::value<std::string>(),
"url of the ostree repository")
187 (
"primary-ecu-hardware-id", bpo::value<std::string>(),
"hardware ID of primary ecu")
188 (
"update-name", bpo::value<std::string>(),
"optional name of the update when running \"update\". default=latest")
189 (
"command", bpo::value<std::string>(), subs.c_str());
193 bpo::positional_options_description pos;
194 pos.add(
"command", 1);
196 bpo::variables_map vm;
197 std::vector<std::string> unregistered_options;
199 bpo::basic_parsed_options<char> parsed_options =
200 bpo::command_line_parser(argc, argv).options(description).positional(pos).allow_unregistered().run();
201 bpo::store(parsed_options, vm);
202 check_info_options(description, vm);
204 unregistered_options = bpo::collect_unrecognized(parsed_options.options, bpo::exclude_positional);
205 if (vm.count(
"help") == 0 && !unregistered_options.empty()) {
206 std::cout << description <<
"\n";
209 }
catch (
const bpo::required_option &ex) {
211 std::cout << ex.what() << std::endl << description;
213 }
catch (
const bpo::error &ex) {
214 check_info_options(description, vm);
217 LOG_ERROR <<
"boost command line option error: " << ex.what();
221 std::cout << ex.what() <<
'\n';
231 int main(
int argc,
char *argv[]) {
232 logger_init(isatty(1) == 1);
233 logger_set_threshold(boost::log::trivial::info);
235 bpo::variables_map commandline_map = parse_options(argc, argv);
237 int r = EXIT_FAILURE;
239 if (geteuid() != 0) {
240 LOG_WARNING <<
"\033[31mRunning as non-root and may not work as expected!\033[0m\n";
243 Config config(commandline_map);
244 config.storage.uptane_metadata_path =
BasedPath(config.storage.path /
"metadata");
245 LOG_DEBUG <<
"Current directory: " << boost::filesystem::current_path().string();
247 std::string cmd = commandline_map[
"command"].as<std::string>();
248 for (
size_t i = 0; i <
sizeof(commands) /
sizeof(
SubCommand); i++) {
249 if (cmd == commands[i].name) {
251 return commands[i].main(client, commandline_map);
254 throw bpo::invalid_option_value(cmd);
256 }
catch (
const std::exception &ex) {
257 LOG_ERROR << ex.what();