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