Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
main.cc
1 #include <iostream>
2 #include <string>
3 #include <vector>
4 
5 #include <boost/filesystem.hpp>
6 #include <boost/program_options.hpp>
7 
8 #include "libaktualizr/packagemanagerfactory.h"
9 
10 #include "aktualizr_info_config.h"
11 #include "logging/logging.h"
12 #include "storage/invstorage.h"
13 #include "storage/sql_utils.h"
14 #include "utilities/aktualizr_version.h"
15 
16 namespace bpo = boost::program_options;
17 
18 static int loadAndPrintDelegations(const std::shared_ptr<INvStorage> &storage) {
19  std::vector<std::pair<Uptane::Role, std::string> > delegations;
20  bool delegations_fetch_res = storage->loadAllDelegations(delegations);
21 
22  if (!delegations_fetch_res) {
23  std::cout << "Failed to load delegations" << std::endl;
24  return EXIT_FAILURE;
25  }
26 
27  if (!delegations.empty()) {
28  for (const auto &delegation : delegations) {
29  std::cout << delegation.first << ": " << delegation.second << std::endl;
30  }
31  } else {
32  std::cout << "Delegations are not present" << std::endl;
33  }
34  return EXIT_SUCCESS;
35 }
36 
37 void checkInfoOptions(const bpo::options_description &description, const bpo::variables_map &vm) {
38  if (vm.count("help") != 0) {
39  std::cout << description << '\n';
40  exit(EXIT_SUCCESS);
41  }
42  if (vm.count("version") != 0) {
43  std::cout << "Current aktualizr-info version is: " << aktualizr_version() << "\n";
44  exit(EXIT_SUCCESS);
45  }
46 }
47 
48 int main(int argc, char **argv) {
49  bpo::options_description all("aktualizr-info command line options");
50  bpo::options_description description("aktualizr-info command line options");
51  bpo::options_description hidden("deprecated options");
52  // clang-format off
53  description.add_options()
54  ("help,h", "print usage")
55  ("version,v", "Current aktualizr version")
56  ("config,c", bpo::value<std::vector<boost::filesystem::path> >()->composing(), "configuration file or directory")
57  ("loglevel", bpo::value<int>(), "set log level 0-5 (trace, debug, info, warning, error, fatal)")
58  ("name-only", "Only output device name (intended for scripting). Cannot be used in combination with other arguments.")
59  ("tls-creds", "Outputs TLS credentials")
60  ("tls-root-ca", "Outputs TLS Root CA")
61  ("tls-cert", "Outputs TLS client certificate")
62  ("tls-prv-key", "Output TLS client private key")
63  ("ecu-keys", "Outputs Uptane keys")
64  ("ecu-pub-key", "Outputs Uptane public key")
65  ("ecu-prv-key", "Outputs Uptane private key")
66  ("image-root", "Outputs root.json from Image repo")
67  ("image-timestamp", "Outputs timestamp.json from Image repo")
68  ("image-snapshot", "Outputs snapshot.json from Image repo")
69  ("image-targets", "Outputs targets.json from Image repo")
70  ("delegation", "Outputs metadata of Image repo Targets' delegations")
71  ("director-root", "Outputs root.json from Director repo")
72  ("director-targets", "Outputs targets.json from Director repo")
73  ("allow-migrate", "Opens database in read/write mode to make possible to migrate database if needed")
74  ("wait-until-provisioned", "Outputs metadata when device already provisioned");
75  // Support old names and variations due to common typos.
76  hidden.add_options()
77  ("images-root", "Outputs root.json from Image repo")
78  ("images-timestamp", "Outputs timestamp.json from Image repo")
79  ("images-snapshot", "Outputs snapshot.json from Image repo")
80  ("images-target", "Outputs targets.json from Image repo")
81  ("images-targets", "Outputs targets.json from Image repo")
82  ("image-target", "Outputs targets.json from Image repo")
83  ("director-target", "Outputs targets.json from Director repo");
84  // clang-format on
85 
86  try {
87  all.add(description).add(hidden);
88  bpo::variables_map vm;
89  bpo::basic_parsed_options<char> parsed_options = bpo::command_line_parser(argc, argv).options(all).run();
90  bpo::store(parsed_options, vm);
91  checkInfoOptions(description, vm);
92  bpo::notify(vm);
93  std::vector<std::string> unregistered_options =
94  bpo::collect_unrecognized(parsed_options.options, bpo::include_positional);
95  if (vm.count("help") == 0 && !unregistered_options.empty()) {
96  std::cout << description << "\n";
97  exit(EXIT_FAILURE);
98  }
99 
100  logger_init();
101  if (vm.count("loglevel") == 0U) {
102  logger_set_enable(false);
103  }
104 
105  AktualizrInfoConfig config(vm);
106 
107  bool secondary_db = false;
108 
109  bool readonly = true;
110  if (vm.count("allow-migrate") != 0U) {
111  readonly = false;
112  }
113 
114  bool wait_provisioning = false;
115  if (vm.count("wait-until-provisioned") != 0) {
116  wait_provisioning = true;
117  }
118 
119  std::shared_ptr<INvStorage> storage;
120  bool cmd_trigger = false;
121  std::string device_id;
122 
123  bool registered = false;
124  bool has_metadata = false;
125  std::string director_root;
126  if (wait_provisioning) {
127  while (!registered || !has_metadata) {
128  try {
129  storage = INvStorage::newStorage(config.storage, readonly);
130 
131  registered = storage->loadEcuRegistered();
132  has_metadata = storage->loadLatestRoot(&director_root, Uptane::RepositoryType::Director());
133  } catch (std::exception &e) {
134  // ignore storage exceptions here which are common as this is intended
135  // to run while aktualizr sets up the storage
136  }
137  sleep(1);
138  }
139  } else {
140  storage = INvStorage::newStorage(config.storage, readonly);
141  }
142 
143  bool deviceid_loaded = false;
144  if (storage->loadDeviceId(&device_id)) {
145  deviceid_loaded = true;
146  // Early return if only printing device ID.
147  if (vm.count("name-only") != 0U) {
148  std::cout << device_id << std::endl;
149  return EXIT_SUCCESS;
150  }
151  }
152 
153  registered = registered || storage->loadEcuRegistered();
154  has_metadata = has_metadata || storage->loadLatestRoot(&director_root, Uptane::RepositoryType::Director());
155 
156  bool tlscred_loaded = false;
157  {
158  std::string ca;
159  std::string cert;
160  std::string pkey;
161 
162  storage->loadTlsCreds(&ca, &cert, &pkey);
163  if (!ca.empty() || !cert.empty() || !pkey.empty()) {
164  tlscred_loaded = true;
165  }
166  // TLS credentials
167  if (vm.count("tls-creds") != 0U) {
168  std::cout << "Root CA certificate:" << std::endl << ca << std::endl;
169  std::cout << "Client certificate:" << std::endl << cert << std::endl;
170  std::cout << "Client private key:" << std::endl << pkey << std::endl;
171  cmd_trigger = true;
172  }
173  }
174 
175  if (vm.count("tls-root-ca") != 0U) {
176  std::string ca;
177  storage->loadTlsCa(&ca);
178  std::cout << ca << std::endl;
179  cmd_trigger = true;
180  }
181 
182  if (vm.count("tls-cert") != 0U) {
183  std::string cert;
184  storage->loadTlsCert(&cert);
185  std::cout << cert << std::endl;
186  cmd_trigger = true;
187  }
188 
189  if (vm.count("tls-prv-key") != 0U) {
190  std::string key;
191  storage->loadTlsPkey(&key);
192  std::cout << key << std::endl;
193  cmd_trigger = true;
194  }
195 
196  // ECU credentials
197  bool ecukeys_loaded = false;
198  std::string priv;
199  std::string pub;
200 
201  storage->loadPrimaryKeys(&pub, &priv);
202  if (!pub.empty() && !priv.empty()) {
203  ecukeys_loaded = true;
204  }
205  if (vm.count("ecu-keys") != 0U) {
206  std::cout << "Public key:" << std::endl << pub << std::endl;
207  std::cout << "Private key:" << std::endl << priv << std::endl;
208  cmd_trigger = true;
209  }
210 
211  if (vm.count("ecu-pub-key") != 0U) {
212  std::string key;
213  storage->loadPrimaryPublic(&key);
214  std::cout << key << std::endl;
215  return EXIT_SUCCESS;
216  }
217 
218  if (vm.count("ecu-prv-key") != 0U) {
219  std::string key;
220  storage->loadPrimaryPrivate(&key);
221  std::cout << key << std::endl;
222  cmd_trigger = true;
223  }
224 
225  // An arguments which depend on metadata.
226  std::string msg_metadata_fail = "Metadata is not available";
227  if (vm.count("image-root") != 0U || vm.count("images-root") != 0U) {
228  if (!has_metadata) {
229  std::cout << msg_metadata_fail << std::endl;
230  } else {
231  std::string images_root;
232  storage->loadLatestRoot(&images_root, Uptane::RepositoryType::Image());
233  std::cout << images_root << std::endl;
234  }
235  cmd_trigger = true;
236  }
237 
238  if (vm.count("image-targets") != 0U || vm.count("image-target") != 0U || vm.count("images-targets") != 0U ||
239  vm.count("images-target") != 0U) {
240  if (!has_metadata) {
241  std::cout << msg_metadata_fail << std::endl;
242  } else {
243  std::string images_targets;
244  storage->loadNonRoot(&images_targets, Uptane::RepositoryType::Image(), Uptane::Role::Targets());
245  std::cout << images_targets << std::endl;
246  }
247  cmd_trigger = true;
248  }
249 
250  if (vm.count("delegation") != 0U) {
251  if (!has_metadata) {
252  std::cout << msg_metadata_fail << std::endl;
253  } else {
254  loadAndPrintDelegations(storage);
255  }
256  cmd_trigger = true;
257  }
258 
259  if (vm.count("director-root") != 0U) {
260  if (!has_metadata) {
261  std::cout << msg_metadata_fail << std::endl;
262  } else {
263  std::cout << director_root << std::endl;
264  }
265  cmd_trigger = true;
266  }
267 
268  if (vm.count("director-targets") != 0U || vm.count("director-target") != 0U) {
269  if (!has_metadata) {
270  std::cout << msg_metadata_fail << std::endl;
271  } else {
272  std::string director_targets;
273  storage->loadNonRoot(&director_targets, Uptane::RepositoryType::Director(), Uptane::Role::Targets());
274  std::cout << director_targets << std::endl;
275  }
276  cmd_trigger = true;
277  }
278 
279  if (vm.count("image-snapshot") != 0U || vm.count("images-snapshot") != 0U) {
280  if (!has_metadata) {
281  std::cout << msg_metadata_fail << std::endl;
282  } else {
283  std::string snapshot;
284  storage->loadNonRoot(&snapshot, Uptane::RepositoryType::Image(), Uptane::Role::Snapshot());
285  std::cout << snapshot << std::endl;
286  }
287  cmd_trigger = true;
288  }
289 
290  if (vm.count("image-timestamp") != 0U || vm.count("images-timestamp") != 0U) {
291  if (!has_metadata) {
292  std::cout << msg_metadata_fail << std::endl;
293  } else {
294  std::string timestamp;
295  storage->loadNonRoot(&timestamp, Uptane::RepositoryType::Image(), Uptane::Role::Timestamp());
296  std::cout << timestamp << std::endl;
297  }
298  cmd_trigger = true;
299  }
300 
301  if (cmd_trigger) {
302  return EXIT_SUCCESS;
303  }
304 
305  if (!deviceid_loaded && !tlscred_loaded && ecukeys_loaded) {
306  secondary_db = true;
307  }
308 
309  // Print general information if user does not provide any argument.
310  if (!secondary_db) {
311  if (!deviceid_loaded) {
312  std::cout << "Couldn't load device ID" << std::endl;
313  } else {
314  std::cout << "Device ID: " << device_id << std::endl;
315  }
316  }
317 
318  std::string ecu_name = secondary_db ? "Secondary" : "Primary";
319  EcuSerials serials;
320  if (!storage->loadEcuSerials(&serials)) {
321  std::cout << "Couldn't load ECU serials" << std::endl;
322  } else if (serials.empty()) {
323  std::cout << ecu_name << " serial is not found" << std::endl;
324  } else {
325  std::cout << ecu_name << " ECU serial ID: " << serials[0].first << std::endl;
326  std::cout << ecu_name << " ECU hardware ID: " << serials[0].second << std::endl;
327  }
328 
329  if (serials.size() > 1) {
330  auto it = serials.begin() + 1;
331  std::cout << "Secondaries:\n";
332  int secondary_number = 1;
333  for (; it != serials.end(); ++it) {
334  std::cout << secondary_number++ << ") serial ID: " << it->first << std::endl;
335  std::cout << " hardware ID: " << it->second << std::endl;
336 
337  boost::optional<Uptane::Target> current_version;
338  boost::optional<Uptane::Target> pending_version;
339 
340  auto load_installed_version_res =
341  storage->loadInstalledVersions((it->first).ToString(), &current_version, &pending_version);
342 
343  if (!load_installed_version_res || (!current_version && !pending_version)) {
344  std::cout << " no details about installed nor pending images\n";
345  } else {
346  if (!!current_version) {
347  std::cout << " installed image hash: " << current_version->sha256Hash() << "\n";
348  std::cout << " installed image filename: " << current_version->filename() << "\n";
349  }
350  if (!!pending_version) {
351  std::cout << " pending image hash: " << pending_version->sha256Hash() << "\n";
352  std::cout << " pending image filename: " << pending_version->filename() << "\n";
353  }
354  }
355  }
356  }
357 
358  std::vector<MisconfiguredEcu> misconfigured_ecus;
359  storage->loadMisconfiguredEcus(&misconfigured_ecus);
360  if (!misconfigured_ecus.empty()) {
361  std::cout << "Removed or unregistered ECUs (deprecated):" << std::endl;
362  std::vector<MisconfiguredEcu>::const_iterator it;
363  for (it = misconfigured_ecus.begin(); it != misconfigured_ecus.end(); ++it) {
364  std::cout << " '" << it->serial << "' with hardware_id '" << it->hardware_id << "' "
365  << (it->state == EcuState::kOld ? "has been removed from config" : "not registered yet") << std::endl;
366  }
367  }
368 
369  if (!secondary_db) {
370  std::cout << "Provisioned on server: " << (registered ? "yes" : "no") << std::endl;
371  }
372  std::cout << "Fetched metadata: " << (has_metadata ? "yes" : "no") << std::endl;
373 
374  auto pacman = PackageManagerFactory::makePackageManager(config.pacman, config.bootloader, storage, nullptr);
375 
376  Uptane::Target current_target = pacman->getCurrent();
377 
378  if (current_target.IsValid()) {
379  std::cout << "Current " << ecu_name << " ECU running version: " << current_target.sha256Hash() << std::endl;
380  } else {
381  std::cout << "No currently running version on " << ecu_name << " ECU" << std::endl;
382  }
383 
384  std::vector<Uptane::Target> installed_versions;
385  boost::optional<Uptane::Target> pending;
386  storage->loadPrimaryInstalledVersions(nullptr, &pending);
387 
388  if (!!pending) {
389  std::cout << "Pending " << ecu_name << " ECU version: " << pending->sha256Hash() << std::endl;
390  }
391  } catch (const bpo::error &o) {
392  std::cout << o.what() << std::endl << description;
393  return EXIT_FAILURE;
394 
395  } catch (const std::exception &exc) {
396  std::cerr << "Error: " << exc.what() << std::endl;
397  return EXIT_FAILURE;
398  }
399 
400  return EXIT_SUCCESS;
401 }
402 // vim: set tabstop=2 shiftwidth=2 expandtab:
AktualizrInfoConfig
Definition: aktualizr_info_config.h:15
Uptane::Target
Definition: types.h:379