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