Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
main.cc
1 #include <iostream>
2 
3 #include <boost/filesystem.hpp>
4 #include <boost/program_options.hpp>
5 #include <boost/property_tree/ini_parser.hpp>
6 #include <boost/signals2.hpp>
7 
8 #include "config/config.h"
9 #include "logging/logging.h"
10 #include "primary/aktualizr.h"
11 #include "primary/aktualizr_helpers.h"
12 #include "secondary.h"
13 #include "utilities/aktualizr_version.h"
14 #include "utilities/sig_handler.h"
15 #include "utilities/utils.h"
16 
17 namespace bpo = boost::program_options;
18 
19 void checkInfoOptions(const bpo::options_description &description, const bpo::variables_map &vm) {
20  if (vm.count("help") != 0) {
21  std::cout << description << '\n';
22  exit(EXIT_SUCCESS);
23  }
24  if (vm.count("version") != 0) {
25  std::cout << "Current aktualizr version is: " << aktualizr_version() << "\n";
26  exit(EXIT_SUCCESS);
27  }
28 }
29 
30 bpo::variables_map parseOptions(int argc, char *argv[]) {
31  bpo::options_description description("aktualizr command line options");
32  // clang-format off
33  // Try to keep these options in the same order as Config::updateFromCommandLine().
34  // The first three are commandline only.
35  description.add_options()
36  ("help,h", "print usage")
37  ("version,v", "Current aktualizr version")
38  ("config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(), "configuration file or directory")
39  ("loglevel", bpo::value<int>(), "set log level 0-5 (trace, debug, info, warning, error, fatal)")
40  ("run-mode", bpo::value<std::string>(), "run mode of aktualizr: full, once, campaign_check, campaign_accept, campaign_decline, campaign_postpone, check, download, or install")
41  ("tls-server", bpo::value<std::string>(), "URL of device gateway")
42  ("repo-server", bpo::value<std::string>(), "URL of the Uptane Image repository")
43  ("director-server", bpo::value<std::string>(), "URL of the Uptane Director repository")
44  ("primary-ecu-serial", bpo::value<std::string>(), "serial number of Primary ECU")
45  ("primary-ecu-hardware-id", bpo::value<std::string>(), "hardware ID of Primary ECU")
46  ("secondary-config-file", bpo::value<boost::filesystem::path>(), "Secondary ECUs configuration file")
47  ("campaign-id", bpo::value<std::string>(), "ID of the campaign to act on")
48  ("hwinfo-file", bpo::value<boost::filesystem::path>(), "custom hardware information JSON file");
49  // clang-format on
50 
51  // consider the first positional argument as the aktualizr run mode
52  bpo::positional_options_description pos;
53  pos.add("run-mode", 1);
54 
55  bpo::variables_map vm;
56  std::vector<std::string> unregistered_options;
57  try {
58  bpo::basic_parsed_options<char> parsed_options =
59  bpo::command_line_parser(argc, argv).options(description).positional(pos).allow_unregistered().run();
60  bpo::store(parsed_options, vm);
61  checkInfoOptions(description, vm);
62  bpo::notify(vm);
63  unregistered_options = bpo::collect_unrecognized(parsed_options.options, bpo::exclude_positional);
64  if (vm.count("help") == 0 && !unregistered_options.empty()) {
65  std::cout << description << "\n";
66  exit(EXIT_FAILURE);
67  }
68  } catch (const bpo::required_option &ex) {
69  // print the error and append the default commandline option description
70  std::cout << ex.what() << std::endl << description;
71  exit(EXIT_FAILURE);
72  } catch (const bpo::error &ex) {
73  checkInfoOptions(description, vm);
74 
75  // log boost error
76  LOG_ERROR << "boost command line option error: " << ex.what();
77 
78  // print the error message to the standard output too, as the user provided
79  // a non-supported commandline option
80  std::cout << ex.what() << '\n';
81 
82  // set the returnValue, thereby ctest will recognize
83  // that something went wrong
84  exit(EXIT_FAILURE);
85  }
86 
87  return vm;
88 }
89 
90 void processEvent(const std::shared_ptr<event::BaseEvent> &event) {
91  if (event->isTypeOf<event::DownloadProgressReport>()) {
92  // Do nothing; libaktualizr already logs it.
93  } else if (event->variant == "UpdateCheckComplete") {
94  // Do nothing; libaktualizr already logs it.
95  } else if (event->variant == "AllDownloadsComplete") {
96  const auto downloads_complete = dynamic_cast<event::AllDownloadsComplete *>(event.get());
97  LOG_INFO << "got " << event->variant << " event with status: " << downloads_complete->result.status;
98  } else if (event->variant == "AllInstallsComplete") {
99  const auto installs_complete = dynamic_cast<event::AllInstallsComplete *>(event.get());
100  LOG_INFO << "got " << event->variant << " event with status: " << installs_complete->result.dev_report.result_code;
101  } else {
102  LOG_INFO << "got " << event->variant << " event";
103  }
104 }
105 
106 int main(int argc, char *argv[]) {
107  logger_init();
108  logger_set_threshold(boost::log::trivial::info);
109 
110  bpo::variables_map commandline_map = parseOptions(argc, argv);
111 
112  LOG_INFO << "Aktualizr version " << aktualizr_version() << " starting";
113 
114  int r = EXIT_FAILURE;
115 
116  try {
117  if (geteuid() != 0) {
118  LOG_WARNING << "\033[31mAktualizr is currently running as non-root and may not work as expected! Aktualizr "
119  "should be run as root for proper functionality.\033[0m\n";
120  }
121  Config config(commandline_map);
122  LOG_DEBUG << "Current directory: " << boost::filesystem::current_path().string();
123 
124  Aktualizr aktualizr(config);
125  std::function<void(std::shared_ptr<event::BaseEvent> event)> f_cb = processEvent;
126  boost::signals2::scoped_connection conn;
127 
128  conn = aktualizr.SetSignalHandler(f_cb);
129 
130  if (!config.uptane.secondary_config_file.empty()) {
131  try {
132  Primary::initSecondaries(aktualizr, config.uptane.secondary_config_file);
133  } catch (const std::exception &e) {
134  LOG_ERROR << "Failed to initialize Secondaries :" << e.what();
135  LOG_ERROR << "Exiting...";
136  return EXIT_FAILURE;
137  }
138  }
139 
140  aktualizr.Initialize();
141 
142  // handle unix signals
143  SigHandler::get().start([&aktualizr]() {
144  aktualizr.Abort();
145  aktualizr.Shutdown();
146  });
147  SigHandler::signal(SIGHUP);
148  SigHandler::signal(SIGINT);
149  SigHandler::signal(SIGTERM);
150 
151  Json::Value hwinfo;
152  if (commandline_map.count("hwinfo-file") != 0) {
153  auto file = commandline_map["hwinfo-file"].as<boost::filesystem::path>();
154  hwinfo = Utils::parseJSONFile(file);
155  if (hwinfo.empty()) {
156  LOG_ERROR << file << " is not a valid JSON file";
157  return EXIT_FAILURE;
158  }
159  }
160 
161  std::string run_mode;
162  if (commandline_map.count("run-mode") != 0) {
163  run_mode = commandline_map["run-mode"].as<std::string>();
164  }
165  // launch the first event
166  if (run_mode == "campaign_check") {
167  aktualizr.CampaignCheck().get();
168  } else if (run_mode == "campaign_accept" || run_mode == "campaign_decline" || run_mode == "campaign_postpone") {
169  if (commandline_map.count("campaign-id") == 0) {
170  throw std::runtime_error(run_mode + " requires a campaign ID");
171  }
172  aktualizr.CampaignControl(commandline_map["campaign-id"].as<std::string>(), campaign::cmdFromName(run_mode))
173  .get();
174  } else if (run_mode == "check") {
175  aktualizr.SendDeviceData(hwinfo).get();
176  aktualizr.CheckUpdates().get();
177  } else if (run_mode == "download") {
178  result::UpdateCheck update_result = aktualizr.CheckUpdates().get();
179  aktualizr.Download(update_result.updates).get();
180  } else if (run_mode == "install") {
181  result::UpdateCheck update_result = aktualizr.CheckUpdates().get();
182  aktualizr.Install(update_result.updates).get();
183  } else if (run_mode == "once") {
184  aktualizr.SendDeviceData(hwinfo).get();
185  aktualizr.UptaneCycle();
186  } else {
187  boost::signals2::connection ac_conn =
188  aktualizr.SetSignalHandler(std::bind(targets_autoclean_cb, std::ref(aktualizr), std::placeholders::_1));
189 
190  try {
191  aktualizr.RunForever(hwinfo).get();
192  } catch (const std::exception &ex) {
193  LOG_ERROR << ex.what();
194  }
195 
196  LOG_DEBUG << "Aktualizr daemon exiting...";
197  }
198  r = EXIT_SUCCESS;
199  } catch (const std::exception &ex) {
200  LOG_ERROR << ex.what();
201  }
202 
203  return r;
204 }
result::UpdateCheck
Container for information about available updates.
Definition: results.h:38
Config
Configuration object for an aktualizr instance running on a Primary ECU.
Definition: config.h:74
Aktualizr
This class provides the main APIs necessary for launching and controlling libaktualizr.
Definition: aktualizr.h:20
event::DownloadProgressReport
A report for a download in progress.
Definition: events.h:71
event
Aktualizr status events.
Definition: events.h:18