Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
sqlstorage.cc
1 #include "sqlstorage.h"
2 
3 #include <sys/stat.h>
4 #include <sys/statvfs.h>
5 #include <iostream>
6 #include <map>
7 #include <memory>
8 #include <string>
9 #include <utility>
10 
11 #include "logging/logging.h"
12 #include "sql_utils.h"
13 #include "utilities/utils.h"
14 
15 // find metadata with version set to -1 (e.g. after migration) and assign proper version to it
16 void SQLStorage::cleanMetaVersion(Uptane::RepositoryType repo, const Uptane::Role& role) {
17  SQLite3Guard db = dbConnection();
18 
19  db.beginTransaction();
20 
21  auto statement = db.prepareStatement<int, int, int>(
22  "SELECT meta FROM meta WHERE (repo=? AND meta_type=? AND version=?);", static_cast<int>(repo), role.ToInt(), -1);
23 
24  int result = statement.step();
25 
26  if (result == SQLITE_DONE) {
27  LOG_TRACE << "meta with role " << role.ToString() << " in repo " << repo.toString() << " not present in db";
28  return;
29  } else if (result != SQLITE_ROW) {
30  LOG_ERROR << "Can't get meta: " << db.errmsg();
31  return;
32  }
33  std::string meta = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
34 
35  int version = Uptane::extractVersionUntrusted(meta);
36  if (version < 0) {
37  LOG_ERROR << "Corrupted metadata";
38  return;
39  }
40 
41  // in there is already metadata with such version delete it
42  statement = db.prepareStatement<int, int, int>("DELETE FROM meta WHERE (repo=? AND meta_type=? AND version=?);",
43  static_cast<int>(repo), role.ToInt(), version);
44 
45  if (statement.step() != SQLITE_DONE) {
46  LOG_ERROR << "Can't clear metadata: " << db.errmsg();
47  return;
48  }
49 
50  statement = db.prepareStatement<int, int, int, int>(
51  "UPDATE meta SET version = ? WHERE (repo=? AND meta_type=? AND version=?);", version, static_cast<int>(repo),
52  role.ToInt(), -1);
53 
54  if (statement.step() != SQLITE_DONE) {
55  LOG_ERROR << "Can't update metadata: " << db.errmsg();
56  return;
57  }
58 
59  db.commitTransaction();
60 }
61 
62 SQLStorage::SQLStorage(const StorageConfig& config, bool readonly)
63  : SQLStorageBase(config.sqldb_path.get(config.path), readonly, libaktualizr_schema_migrations,
64  libaktualizr_schema_rollback_migrations, libaktualizr_current_schema,
65  libaktualizr_current_schema_version),
66  INvStorage(config) {
67  try {
68  cleanMetaVersion(Uptane::RepositoryType::Director(), Uptane::Role::Root());
69  cleanMetaVersion(Uptane::RepositoryType::Image(), Uptane::Role::Root());
70  } catch (...) {
71  LOG_ERROR << "SQLite database metadata version migration failed";
72  }
73 }
74 
75 void SQLStorage::storePrimaryKeys(const std::string& public_key, const std::string& private_key) {
76  SQLite3Guard db = dbConnection();
77 
78  auto statement = db.prepareStatement<std::string>(
79  "INSERT OR REPLACE INTO primary_keys(unique_mark,public,private) VALUES (0,?,?);", public_key, private_key);
80  if (statement.step() != SQLITE_DONE) {
81  LOG_ERROR << "Can't set Primary keys: " << db.errmsg();
82  return;
83  }
84 }
85 
86 bool SQLStorage::loadPrimaryKeys(std::string* public_key, std::string* private_key) {
87  return loadPrimaryPublic(public_key) && loadPrimaryPrivate(private_key);
88 }
89 
90 bool SQLStorage::loadPrimaryPublic(std::string* public_key) {
91  SQLite3Guard db = dbConnection();
92 
93  auto statement = db.prepareStatement("SELECT public FROM primary_keys LIMIT 1;");
94 
95  int result = statement.step();
96  if (result == SQLITE_DONE) {
97  LOG_TRACE << "No public key in db";
98  return false;
99  } else if (result != SQLITE_ROW) {
100  LOG_ERROR << "Can't get public key: " << db.errmsg();
101  return false;
102  }
103 
104  auto pub = statement.get_result_col_str(0);
105  if (pub == boost::none) {
106  return false;
107  }
108 
109  if (public_key != nullptr) {
110  *public_key = std::move(pub.value());
111  }
112 
113  return true;
114 }
115 
116 bool SQLStorage::loadPrimaryPrivate(std::string* private_key) {
117  SQLite3Guard db = dbConnection();
118 
119  auto statement = db.prepareStatement("SELECT private FROM primary_keys LIMIT 1;");
120 
121  int result = statement.step();
122  if (result == SQLITE_DONE) {
123  LOG_TRACE << "No private key in db";
124  return false;
125  } else if (result != SQLITE_ROW) {
126  LOG_ERROR << "Can't get private key: " << db.errmsg();
127  return false;
128  }
129 
130  auto priv = statement.get_result_col_str(0);
131  if (priv == boost::none) {
132  return false;
133  }
134 
135  if (private_key != nullptr) {
136  *private_key = std::move(priv.value());
137  }
138 
139  return true;
140 }
141 
142 void SQLStorage::clearPrimaryKeys() {
143  SQLite3Guard db = dbConnection();
144 
145  if (db.exec("DELETE FROM primary_keys;", nullptr, nullptr) != SQLITE_OK) {
146  LOG_ERROR << "Can't clear Primary keys: " << db.errmsg();
147  return;
148  }
149 }
150 
151 void SQLStorage::saveSecondaryInfo(const Uptane::EcuSerial& ecu_serial, const std::string& sec_type,
152  const PublicKey& public_key) {
153  SQLite3Guard db = dbConnection();
154 
155  std::stringstream key_type_ss;
156  key_type_ss << public_key.Type();
157  std::string key_type_str;
158  key_type_str = key_type_ss.str();
159  key_type_str.erase(std::remove(key_type_str.begin(), key_type_str.end(), '"'), key_type_str.end());
160 
161  db.beginTransaction();
162 
163  auto statement =
164  db.prepareStatement<std::string>("SELECT count(*) FROM secondary_ecus WHERE serial = ?;", ecu_serial.ToString());
165  if (statement.step() != SQLITE_ROW) {
166  LOG_ERROR << "Can't get count of secondary_ecus table: " << db.errmsg();
167  return;
168  }
169 
170  const char* req;
171  if (statement.get_result_col_int(0) != 0) {
172  req = "UPDATE secondary_ecus SET sec_type = ?, public_key_type = ?, public_key = ? WHERE serial = ?;";
173  } else {
174  req =
175  "INSERT INTO secondary_ecus (serial, sec_type, public_key_type, public_key) SELECT "
176  "serial,?,?,? FROM ecus WHERE (serial = ? AND is_primary = 0);";
177  }
178 
179  statement = db.prepareStatement<std::string, std::string, std::string, std::string>(
180  req, sec_type, key_type_str, public_key.Value(), ecu_serial.ToString());
181  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
182  LOG_ERROR << "Can't save Secondary key: " << db.errmsg();
183  return;
184  }
185 
186  db.commitTransaction();
187 }
188 
189 void SQLStorage::saveSecondaryData(const Uptane::EcuSerial& ecu_serial, const std::string& data) {
190  SQLite3Guard db = dbConnection();
191 
192  db.beginTransaction();
193 
194  auto statement =
195  db.prepareStatement<std::string>("SELECT count(*) FROM secondary_ecus WHERE serial = ?;", ecu_serial.ToString());
196  if (statement.step() != SQLITE_ROW) {
197  LOG_ERROR << "Can't get count of secondary_ecus table: " << db.errmsg();
198  return;
199  }
200 
201  const char* req;
202  if (statement.get_result_col_int(0) != 0) {
203  req = "UPDATE secondary_ecus SET extra = ? WHERE serial = ?;";
204  } else {
205  req = "INSERT INTO secondary_ecus (extra, serial) VALUES (?,?);";
206  }
207 
208  statement = db.prepareStatement<std::string, std::string>(req, data, ecu_serial.ToString());
209  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
210  LOG_ERROR << "Can't save Secondary data: " << db.errmsg();
211  return;
212  }
213 
214  db.commitTransaction();
215 }
216 
217 bool SQLStorage::loadSecondaryInfo(const Uptane::EcuSerial& ecu_serial, SecondaryInfo* secondary) {
218  SQLite3Guard db = dbConnection();
219 
220  SecondaryInfo new_sec{};
221 
222  auto statement = db.prepareStatement<std::string>(
223  "SELECT serial, hardware_id, sec_type, public_key_type, public_key, extra FROM ecus LEFT JOIN secondary_ecus "
224  "USING "
225  "(serial) WHERE (serial = ? AND is_primary = 0);",
226  ecu_serial.ToString());
227  int statement_state = statement.step();
228  if (statement_state == SQLITE_DONE) {
229  LOG_TRACE << "Secondary ECU " << ecu_serial << " not found";
230  return false;
231  } else if (statement_state != SQLITE_ROW) {
232  LOG_ERROR << "Cannot load Secondary info: " << db.errmsg();
233  return false;
234  }
235 
236  try {
237  Uptane::EcuSerial serial = Uptane::EcuSerial(statement.get_result_col_str(0).value());
238  Uptane::HardwareIdentifier hw_id = Uptane::HardwareIdentifier(statement.get_result_col_str(1).value());
239  std::string sec_type = statement.get_result_col_str(2).value_or("");
240  std::string kt_str = statement.get_result_col_str(3).value_or("");
241  PublicKey key;
242  if (kt_str != "") {
243  KeyType key_type;
244  std::stringstream(kt_str) >> key_type;
245  key = PublicKey(statement.get_result_col_str(4).value_or(""), key_type);
246  }
247  std::string extra = statement.get_result_col_str(5).value_or("");
248  new_sec = SecondaryInfo{serial, hw_id, sec_type, key, extra};
249  } catch (const boost::bad_optional_access&) {
250  return false;
251  }
252 
253  if (secondary != nullptr) {
254  *secondary = std::move(new_sec);
255  }
256 
257  return true;
258 }
259 
260 bool SQLStorage::loadSecondariesInfo(std::vector<SecondaryInfo>* secondaries) {
261  SQLite3Guard db = dbConnection();
262 
263  std::vector<SecondaryInfo> new_secs;
264 
265  bool empty = true;
266 
267  int statement_state;
268  auto statement = db.prepareStatement(
269  "SELECT serial, hardware_id, sec_type, public_key_type, public_key, extra FROM ecus LEFT JOIN secondary_ecus "
270  "USING "
271  "(serial) WHERE is_primary = 0 ORDER BY ecus.id;");
272  while ((statement_state = statement.step()) == SQLITE_ROW) {
273  try {
274  Uptane::EcuSerial serial = Uptane::EcuSerial(statement.get_result_col_str(0).value());
275  Uptane::HardwareIdentifier hw_id = Uptane::HardwareIdentifier(statement.get_result_col_str(1).value());
276  std::string sec_type = statement.get_result_col_str(2).value_or("");
277  std::string kt_str = statement.get_result_col_str(3).value_or("");
278  PublicKey key;
279  if (kt_str != "") {
280  KeyType key_type;
281  std::stringstream(kt_str) >> key_type;
282  key = PublicKey(statement.get_result_col_str(4).value_or(""), key_type);
283  }
284  std::string extra = statement.get_result_col_str(5).value_or("");
285  new_secs.emplace_back(SecondaryInfo{serial, hw_id, sec_type, key, extra});
286  empty = false;
287  } catch (const boost::bad_optional_access&) {
288  continue;
289  }
290  }
291  if (statement_state != SQLITE_DONE) {
292  LOG_ERROR << "Can't load Secondary info" << db.errmsg();
293  }
294 
295  if (secondaries != nullptr) {
296  *secondaries = std::move(new_secs);
297  }
298 
299  return !empty;
300 }
301 
302 void SQLStorage::storeTlsCreds(const std::string& ca, const std::string& cert, const std::string& pkey) {
303  storeTlsCa(ca);
304  storeTlsCert(cert);
305  storeTlsPkey(pkey);
306 }
307 
308 void SQLStorage::storeTlsCa(const std::string& ca) {
309  SQLite3Guard db = dbConnection();
310 
311  db.beginTransaction();
312 
313  auto statement = db.prepareStatement("SELECT count(*) FROM tls_creds;");
314  if (statement.step() != SQLITE_ROW) {
315  LOG_ERROR << "Can't get count of tls_creds table: " << db.errmsg();
316  return;
317  }
318 
319  const char* req;
320  if (statement.get_result_col_int(0) != 0) {
321  req = "UPDATE OR REPLACE tls_creds SET ca_cert = ?;";
322  } else {
323  req = "INSERT INTO tls_creds(ca_cert) VALUES (?);";
324  }
325 
326  statement = db.prepareStatement<SQLBlob>(req, SQLBlob(ca));
327  if (statement.step() != SQLITE_DONE) {
328  LOG_ERROR << "Can't set ca_cert: " << db.errmsg();
329  return;
330  }
331 
332  db.commitTransaction();
333 }
334 
335 void SQLStorage::storeTlsCert(const std::string& cert) {
336  SQLite3Guard db = dbConnection();
337 
338  db.beginTransaction();
339 
340  auto statement = db.prepareStatement("SELECT count(*) FROM tls_creds;");
341  if (statement.step() != SQLITE_ROW) {
342  LOG_ERROR << "Can't get count of tls_creds table: " << db.errmsg();
343  return;
344  }
345 
346  const char* req;
347  if (statement.get_result_col_int(0) != 0) {
348  req = "UPDATE OR REPLACE tls_creds SET client_cert = ?;";
349  } else {
350  req = "INSERT INTO tls_creds(client_cert) VALUES (?);";
351  }
352 
353  statement = db.prepareStatement<SQLBlob>(req, SQLBlob(cert));
354  if (statement.step() != SQLITE_DONE) {
355  LOG_ERROR << "Can't set client_cert: " << db.errmsg();
356  return;
357  }
358 
359  db.commitTransaction();
360 }
361 
362 void SQLStorage::storeTlsPkey(const std::string& pkey) {
363  SQLite3Guard db = dbConnection();
364 
365  db.beginTransaction();
366 
367  auto statement = db.prepareStatement("SELECT count(*) FROM tls_creds;");
368  if (statement.step() != SQLITE_ROW) {
369  LOG_ERROR << "Can't get count of tls_creds table: " << db.errmsg();
370  return;
371  }
372 
373  const char* req;
374  if (statement.get_result_col_int(0) != 0) {
375  req = "UPDATE OR REPLACE tls_creds SET client_pkey = ?;";
376  } else {
377  req = "INSERT INTO tls_creds(client_pkey) VALUES (?);";
378  }
379 
380  statement = db.prepareStatement<SQLBlob>(req, SQLBlob(pkey));
381  if (statement.step() != SQLITE_DONE) {
382  LOG_ERROR << "Can't set client_pkey: " << db.errmsg();
383  return;
384  }
385 
386  db.commitTransaction();
387 }
388 
389 bool SQLStorage::loadTlsCreds(std::string* ca, std::string* cert, std::string* pkey) {
390  SQLite3Guard db = dbConnection();
391 
392  db.beginTransaction();
393 
394  auto statement = db.prepareStatement("SELECT ca_cert, client_cert, client_pkey FROM tls_creds LIMIT 1;");
395 
396  int result = statement.step();
397  if (result == SQLITE_DONE) {
398  LOG_TRACE << "Tls creds not present";
399  return false;
400  } else if (result != SQLITE_ROW) {
401  LOG_ERROR << "Can't get tls_creds: " << db.errmsg();
402  return false;
403  }
404 
405  std::string ca_v, cert_v, pkey_v;
406  try {
407  ca_v = statement.get_result_col_str(0).value();
408  cert_v = statement.get_result_col_str(1).value();
409  pkey_v = statement.get_result_col_str(2).value();
410  } catch (const boost::bad_optional_access&) {
411  return false;
412  }
413 
414  if (ca != nullptr) {
415  *ca = std::move(ca_v);
416  }
417  if (cert != nullptr) {
418  *cert = std::move(cert_v);
419  }
420  if (pkey != nullptr) {
421  *pkey = std::move(pkey_v);
422  }
423 
424  db.commitTransaction();
425 
426  return true;
427 }
428 
429 void SQLStorage::clearTlsCreds() {
430  SQLite3Guard db = dbConnection();
431 
432  if (db.exec("DELETE FROM tls_creds;", nullptr, nullptr) != SQLITE_OK) {
433  LOG_ERROR << "Can't clear tls_creds: " << db.errmsg();
434  return;
435  }
436 }
437 
438 bool SQLStorage::loadTlsCa(std::string* ca) {
439  SQLite3Guard db = dbConnection();
440 
441  auto statement = db.prepareStatement("SELECT ca_cert FROM tls_creds LIMIT 1;");
442 
443  int result = statement.step();
444  if (result == SQLITE_DONE) {
445  LOG_TRACE << "ca_cert not present";
446  return false;
447  } else if (result != SQLITE_ROW) {
448  LOG_ERROR << "Can't get ca_cert: " << db.errmsg();
449  return false;
450  }
451 
452  auto ca_r = statement.get_result_col_str(0);
453  if (ca_r == boost::none) {
454  return false;
455  }
456 
457  if (ca != nullptr) {
458  *ca = std::move(ca_r.value());
459  }
460 
461  return true;
462 }
463 
464 bool SQLStorage::loadTlsCert(std::string* cert) {
465  SQLite3Guard db = dbConnection();
466 
467  auto statement = db.prepareStatement("SELECT client_cert FROM tls_creds LIMIT 1;");
468 
469  int result = statement.step();
470  if (result == SQLITE_DONE) {
471  LOG_TRACE << "client_cert not present in db";
472  return false;
473  } else if (result != SQLITE_ROW) {
474  LOG_ERROR << "Can't get client_cert: " << db.errmsg();
475  return false;
476  }
477 
478  auto cert_r = statement.get_result_col_str(0);
479  if (cert_r == boost::none) {
480  return false;
481  }
482 
483  if (cert != nullptr) {
484  *cert = std::move(cert_r.value());
485  }
486 
487  return true;
488 }
489 
490 bool SQLStorage::loadTlsPkey(std::string* pkey) {
491  SQLite3Guard db = dbConnection();
492 
493  auto statement = db.prepareStatement("SELECT client_pkey FROM tls_creds LIMIT 1;");
494 
495  int result = statement.step();
496  if (result == SQLITE_DONE) {
497  LOG_TRACE << "client_pkey not present in db";
498  return false;
499  } else if (result != SQLITE_ROW) {
500  LOG_ERROR << "Can't get client_pkey: " << db.errmsg();
501  return false;
502  }
503 
504  auto pkey_r = statement.get_result_col_str(0);
505  if (pkey_r == boost::none) {
506  return false;
507  }
508 
509  if (pkey != nullptr) {
510  *pkey = std::move(pkey_r.value());
511  }
512 
513  return true;
514 }
515 
516 void SQLStorage::storeRoot(const std::string& data, Uptane::RepositoryType repo, Uptane::Version version) {
517  SQLite3Guard db = dbConnection();
518 
519  db.beginTransaction();
520 
521  auto del_statement =
522  db.prepareStatement<int, int, int>("DELETE FROM meta WHERE (repo=? AND meta_type=? AND version=?);",
523  static_cast<int>(repo), Uptane::Role::Root().ToInt(), version.version());
524 
525  if (del_statement.step() != SQLITE_DONE) {
526  LOG_ERROR << "Can't clear Root metadata: " << db.errmsg();
527  return;
528  }
529 
530  auto ins_statement = db.prepareStatement<SQLBlob, int, int, int>("INSERT INTO meta VALUES (?, ?, ?, ?);",
531  SQLBlob(data), static_cast<int>(repo),
532  Uptane::Role::Root().ToInt(), version.version());
533 
534  if (ins_statement.step() != SQLITE_DONE) {
535  LOG_ERROR << "Can't add metadata: " << db.errmsg();
536  return;
537  }
538 
539  db.commitTransaction();
540 }
541 
542 void SQLStorage::storeNonRoot(const std::string& data, Uptane::RepositoryType repo, const Uptane::Role role) {
543  SQLite3Guard db = dbConnection();
544 
545  db.beginTransaction();
546 
547  auto del_statement = db.prepareStatement<int, int>("DELETE FROM meta WHERE (repo=? AND meta_type=?);",
548  static_cast<int>(repo), role.ToInt());
549 
550  if (del_statement.step() != SQLITE_DONE) {
551  LOG_ERROR << "Can't clear " << role.ToString() << " metadata: " << db.errmsg();
552  return;
553  }
554 
555  auto ins_statement =
556  db.prepareStatement<SQLBlob, int, int, int>("INSERT INTO meta VALUES (?, ?, ?, ?);", SQLBlob(data),
557  static_cast<int>(repo), role.ToInt(), Uptane::Version().version());
558 
559  if (ins_statement.step() != SQLITE_DONE) {
560  LOG_ERROR << "Can't add " << role.ToString() << "metadata: " << db.errmsg();
561  return;
562  }
563 
564  db.commitTransaction();
565 }
566 
567 bool SQLStorage::loadRoot(std::string* data, Uptane::RepositoryType repo, Uptane::Version version) {
568  SQLite3Guard db = dbConnection();
569 
570  // version < 0 => latest metadata requested
571  if (version.version() < 0) {
572  auto statement = db.prepareStatement<int, int>(
573  "SELECT meta FROM meta WHERE (repo=? AND meta_type=?) ORDER BY version DESC LIMIT 1;", static_cast<int>(repo),
574  Uptane::Role::Root().ToInt());
575  int result = statement.step();
576 
577  if (result == SQLITE_DONE) {
578  LOG_TRACE << "Root metadata not present";
579  return false;
580  } else if (result != SQLITE_ROW) {
581  LOG_ERROR << "Can't get Root metadata: " << db.errmsg();
582  return false;
583  }
584  if (data != nullptr) {
585  *data = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
586  }
587  } else {
588  auto statement =
589  db.prepareStatement<int, int, int>("SELECT meta FROM meta WHERE (repo=? AND meta_type=? AND version=?);",
590  static_cast<int>(repo), Uptane::Role::Root().ToInt(), version.version());
591 
592  int result = statement.step();
593 
594  if (result == SQLITE_DONE) {
595  LOG_TRACE << "Root metadata not present";
596  return false;
597  } else if (result != SQLITE_ROW) {
598  LOG_ERROR << "Can't get Root metadata: " << db.errmsg();
599  return false;
600  }
601 
602  const auto blob = reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0));
603  if (blob == nullptr) {
604  LOG_ERROR << "Can't get Root metadata: " << db.errmsg();
605  return false;
606  }
607 
608  if (data != nullptr) {
609  *data = std::string(blob);
610  }
611  }
612 
613  return true;
614 }
615 
616 bool SQLStorage::loadNonRoot(std::string* data, Uptane::RepositoryType repo, const Uptane::Role role) {
617  SQLite3Guard db = dbConnection();
618 
619  auto statement = db.prepareStatement<int, int>(
620  "SELECT meta FROM meta WHERE (repo=? AND meta_type=?) ORDER BY version DESC LIMIT 1;", static_cast<int>(repo),
621  role.ToInt());
622  int result = statement.step();
623 
624  if (result == SQLITE_DONE) {
625  LOG_TRACE << role.ToString() << " metadata not present";
626  return false;
627  } else if (result != SQLITE_ROW) {
628  LOG_ERROR << "Can't get " << role.ToString() << " metadata: " << db.errmsg();
629  return false;
630  }
631  if (data != nullptr) {
632  *data = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
633  }
634 
635  return true;
636 }
637 
638 void SQLStorage::clearNonRootMeta(Uptane::RepositoryType repo) {
639  SQLite3Guard db = dbConnection();
640 
641  auto del_statement =
642  db.prepareStatement<int>("DELETE FROM meta WHERE (repo=? AND meta_type != 0);", static_cast<int>(repo));
643 
644  if (del_statement.step() != SQLITE_DONE) {
645  LOG_ERROR << "Can't clear metadata: " << db.errmsg();
646  }
647 }
648 
649 void SQLStorage::clearMetadata() {
650  SQLite3Guard db = dbConnection();
651 
652  if (db.exec("DELETE FROM meta;", nullptr, nullptr) != SQLITE_OK) {
653  LOG_ERROR << "Can't clear metadata: " << db.errmsg();
654  return;
655  }
656 }
657 
658 void SQLStorage::storeDelegation(const std::string& data, const Uptane::Role role) {
659  SQLite3Guard db = dbConnection();
660 
661  db.beginTransaction();
662 
663  auto statement = db.prepareStatement<SQLBlob, std::string>("INSERT OR REPLACE INTO delegations VALUES (?, ?);",
664  SQLBlob(data), role.ToString());
665 
666  if (statement.step() != SQLITE_DONE) {
667  LOG_ERROR << "Can't add delegation metadata: " << db.errmsg();
668  return;
669  }
670 
671  db.commitTransaction();
672 }
673 
674 bool SQLStorage::loadDelegation(std::string* data, const Uptane::Role role) {
675  SQLite3Guard db = dbConnection();
676 
677  auto statement =
678  db.prepareStatement<std::string>("SELECT meta FROM delegations WHERE role_name=? LIMIT 1;", role.ToString());
679  int result = statement.step();
680 
681  if (result == SQLITE_DONE) {
682  LOG_TRACE << "Delegations metadata not present";
683  return false;
684  } else if (result != SQLITE_ROW) {
685  LOG_ERROR << "Can't get delegations metadata: " << db.errmsg();
686  return false;
687  }
688  if (data != nullptr) {
689  *data = std::string(reinterpret_cast<const char*>(sqlite3_column_blob(statement.get(), 0)));
690  }
691 
692  return true;
693 }
694 
695 bool SQLStorage::loadAllDelegations(std::vector<std::pair<Uptane::Role, std::string>>& data) const {
696  bool result = false;
697 
698  try {
699  SQLite3Guard db = dbConnection();
700 
701  auto statement = db.prepareStatement("SELECT meta, role_name FROM delegations;");
702  auto statement_state = statement.step();
703 
704  if (statement_state == SQLITE_DONE) {
705  LOG_TRACE << "Delegations metadata are not present";
706  return true;
707  } else if (statement_state != SQLITE_ROW) {
708  LOG_ERROR << "Can't get delegations metadata: " << db.errmsg();
709  return false;
710  }
711 
712  do {
713  data.emplace_back(Uptane::Role::Delegation(statement.get_result_col_str(1).value()),
714  statement.get_result_col_blob(0).value());
715  } while ((statement_state = statement.step()) == SQLITE_ROW);
716 
717  result = true;
718  } catch (const std::exception& exc) {
719  LOG_ERROR << "Failed to fetch records from `delegations` table: " << exc.what();
720  }
721 
722  return result;
723 }
724 
725 void SQLStorage::deleteDelegation(const Uptane::Role role) {
726  SQLite3Guard db = dbConnection();
727 
728  auto statement = db.prepareStatement<std::string>("DELETE FROM delegations WHERE role_name=?;", role.ToString());
729  statement.step();
730 }
731 
732 void SQLStorage::clearDelegations() {
733  SQLite3Guard db = dbConnection();
734 
735  if (db.exec("DELETE FROM delegations;", nullptr, nullptr) != SQLITE_OK) {
736  LOG_ERROR << "Can't clear delegations metadata: " << db.errmsg();
737  }
738 }
739 
740 void SQLStorage::storeDeviceId(const std::string& device_id) {
741  SQLite3Guard db = dbConnection();
742 
743  auto statement = db.prepareStatement<std::string>(
744  "INSERT OR REPLACE INTO device_info(unique_mark,device_id,is_registered) VALUES(0,?,0);", device_id);
745  if (statement.step() != SQLITE_DONE) {
746  LOG_ERROR << "Can't set device ID: " << db.errmsg();
747  return;
748  }
749 }
750 
751 bool SQLStorage::loadDeviceId(std::string* device_id) {
752  SQLite3Guard db = dbConnection();
753 
754  auto statement = db.prepareStatement("SELECT device_id FROM device_info LIMIT 1;");
755 
756  int result = statement.step();
757  if (result == SQLITE_DONE) {
758  LOG_TRACE << "device_id not present in db";
759  return false;
760  } else if (result != SQLITE_ROW) {
761  LOG_ERROR << "Can't get device ID: " << db.errmsg();
762  return false;
763  }
764 
765  auto did = statement.get_result_col_str(0);
766  if (did == boost::none) {
767  LOG_ERROR << "Empty device ID" << db.errmsg();
768  return false;
769  }
770 
771  if (device_id != nullptr) {
772  *device_id = std::move(did.value());
773  }
774 
775  return true;
776 }
777 
778 void SQLStorage::clearDeviceId() {
779  SQLite3Guard db = dbConnection();
780 
781  if (db.exec("DELETE FROM device_info;", nullptr, nullptr) != SQLITE_OK) {
782  LOG_ERROR << "Can't clear device ID: " << db.errmsg();
783  return;
784  }
785 }
786 
787 void SQLStorage::storeEcuRegistered() {
788  SQLite3Guard db = dbConnection();
789 
790  db.beginTransaction();
791 
792  auto statement = db.prepareStatement("SELECT count(*) FROM device_info;");
793  if (statement.step() != SQLITE_ROW) {
794  throw std::runtime_error("Could not get device_info count");
795  }
796  if (statement.get_result_col_int(0) != 1) {
797  throw std::runtime_error("Cannot set ECU registered if no device_info set");
798  }
799 
800  std::string req = "UPDATE device_info SET is_registered = 1";
801  if (db.exec(req.c_str(), nullptr, nullptr) != SQLITE_OK) {
802  LOG_ERROR << "Can't set is_registered: " << db.errmsg();
803  return;
804  }
805 
806  db.commitTransaction();
807 }
808 
809 bool SQLStorage::loadEcuRegistered() {
810  SQLite3Guard db = dbConnection();
811 
812  auto statement = db.prepareStatement("SELECT is_registered FROM device_info LIMIT 1;");
813 
814  int result = statement.step();
815  if (result == SQLITE_DONE) {
816  return false;
817  } else if (result != SQLITE_ROW) {
818  LOG_ERROR << "Can't get is_registered in device_info " << db.errmsg();
819  return false;
820  }
821 
822  return statement.get_result_col_int(0) != 0;
823 }
824 
825 void SQLStorage::clearEcuRegistered() {
826  SQLite3Guard db = dbConnection();
827 
828  // note: if the table is empty, nothing is done but that's fine
829  std::string req = "UPDATE device_info SET is_registered = 0";
830  if (db.exec(req.c_str(), nullptr, nullptr) != SQLITE_OK) {
831  LOG_ERROR << "Can't set is_registered: " << db.errmsg();
832  return;
833  }
834 }
835 
836 void SQLStorage::storeNeedReboot() {
837  SQLite3Guard db = dbConnection();
838 
839  auto statement = db.prepareStatement<int>("INSERT OR REPLACE INTO need_reboot(unique_mark,flag) VALUES(0,?);", 1);
840  if (statement.step() != SQLITE_DONE) {
841  LOG_ERROR << "Can't set need_reboot: " << db.errmsg();
842  return;
843  }
844 }
845 
846 bool SQLStorage::loadNeedReboot(bool* need_reboot) {
847  SQLite3Guard db = dbConnection();
848 
849  auto statement = db.prepareStatement("SELECT flag FROM need_reboot LIMIT 1;");
850 
851  int result = statement.step();
852  if (result == SQLITE_DONE) {
853  if (need_reboot != nullptr) {
854  *need_reboot = false;
855  }
856  return true;
857  } else if (result != SQLITE_ROW) {
858  LOG_ERROR << "Can't get need_reboot: " << db.errmsg();
859  return false;
860  }
861 
862  auto flag = static_cast<bool>(statement.get_result_col_int(0));
863  if (need_reboot != nullptr) {
864  *need_reboot = flag;
865  }
866 
867  return true;
868 }
869 
870 void SQLStorage::clearNeedReboot() {
871  SQLite3Guard db = dbConnection();
872 
873  if (db.exec("DELETE FROM need_reboot;", nullptr, nullptr) != SQLITE_OK) {
874  LOG_ERROR << "Can't clear need_reboot: " << db.errmsg();
875  return;
876  }
877 }
878 
879 void SQLStorage::storeEcuSerials(const EcuSerials& serials) {
880  if (serials.size() >= 1) {
881  SQLite3Guard db = dbConnection();
882 
883  db.beginTransaction();
884 
885  if (db.exec("DELETE FROM ecus;", nullptr, nullptr) != SQLITE_OK) {
886  LOG_ERROR << "Can't clear ecus: " << db.errmsg();
887  return;
888  }
889 
890  // first is the Primary
891  std::string serial = serials[0].first.ToString();
892  std::string hwid = serials[0].second.ToString();
893  {
894  auto statement = db.prepareStatement<std::string, std::string>(
895  "INSERT INTO ecus(id, serial,hardware_id,is_primary) VALUES (0, ?,?,1);", serial, hwid);
896  if (statement.step() != SQLITE_DONE) {
897  LOG_ERROR << "Can't set ecu_serial: " << db.errmsg();
898  return;
899  }
900 
901  // update lazily stored installed version
902  auto statement_ivupdate = db.prepareStatement<std::string>(
903  "UPDATE installed_versions SET ecu_serial = ? WHERE ecu_serial = '';", serial);
904 
905  if (statement_ivupdate.step() != SQLITE_DONE) {
906  LOG_ERROR << "Can't set ecu_serial: " << db.errmsg();
907  return;
908  }
909  }
910 
911  for (auto it = serials.cbegin() + 1; it != serials.cend(); it++) {
912  auto statement = db.prepareStatement<int64_t, std::string, std::string>(
913  "INSERT INTO ecus(id,serial,hardware_id) VALUES (?,?,?);", it - serials.cbegin(), it->first.ToString(),
914  it->second.ToString());
915 
916  if (statement.step() != SQLITE_DONE) {
917  LOG_ERROR << "Can't set ecu_serial: " << db.errmsg();
918  return;
919  }
920  }
921 
922  db.commitTransaction();
923  }
924 }
925 
926 bool SQLStorage::loadEcuSerials(EcuSerials* serials) {
927  SQLite3Guard db = dbConnection();
928 
929  // order by auto-incremented Primary key so that the ECU order is kept constant
930  auto statement = db.prepareStatement("SELECT serial, hardware_id FROM ecus ORDER BY id;");
931  int statement_state;
932 
933  EcuSerials new_serials;
934  bool empty = true;
935  while ((statement_state = statement.step()) == SQLITE_ROW) {
936  try {
937  new_serials.emplace_back(Uptane::EcuSerial(statement.get_result_col_str(0).value()),
938  Uptane::HardwareIdentifier(statement.get_result_col_str(1).value()));
939  empty = false;
940  } catch (const boost::bad_optional_access&) {
941  return false;
942  }
943  }
944 
945  if (statement_state != SQLITE_DONE) {
946  LOG_ERROR << "Can't get ECU serials: " << db.errmsg();
947  return false;
948  }
949 
950  if (serials != nullptr) {
951  *serials = std::move(new_serials);
952  }
953 
954  return !empty;
955 }
956 
957 void SQLStorage::clearEcuSerials() {
958  SQLite3Guard db = dbConnection();
959 
960  db.beginTransaction();
961 
962  if (db.exec("DELETE FROM ecus;", nullptr, nullptr) != SQLITE_OK) {
963  LOG_ERROR << "Can't clear ECUs: " << db.errmsg();
964  return;
965  }
966 
967  if (db.exec("DELETE FROM secondary_ecus;", nullptr, nullptr) != SQLITE_OK) {
968  LOG_ERROR << "Can't clear Secondary ECUs: " << db.errmsg();
969  return;
970  }
971 
972  db.commitTransaction();
973 }
974 
975 void SQLStorage::storeCachedEcuManifest(const Uptane::EcuSerial& ecu_serial, const std::string& manifest) {
976  SQLite3Guard db = dbConnection();
977 
978  auto statement = db.prepareStatement<std::string, std::string>(
979  "UPDATE secondary_ecus SET manifest = ? WHERE (serial = ?);", manifest, ecu_serial.ToString());
980  if (statement.step() != SQLITE_DONE || sqlite3_changes(db.get()) != 1) {
981  LOG_ERROR << "Can't save Secondary manifest " << db.errmsg();
982  return;
983  }
984 }
985 
986 bool SQLStorage::loadCachedEcuManifest(const Uptane::EcuSerial& ecu_serial, std::string* manifest) {
987  SQLite3Guard db = dbConnection();
988 
989  std::string stmanifest;
990 
991  bool empty = false;
992 
993  auto statement = db.prepareStatement<std::string>("SELECT manifest FROM secondary_ecus WHERE (serial = ?);",
994  ecu_serial.ToString());
995 
996  if (statement.step() != SQLITE_ROW) {
997  LOG_WARNING << "Could not find manifest for ECU " << ecu_serial;
998  return false;
999  } else {
1000  stmanifest = statement.get_result_col_str(0).value_or("");
1001 
1002  empty = stmanifest == "";
1003  }
1004 
1005  if (manifest != nullptr) {
1006  *manifest = std::move(stmanifest);
1007  }
1008 
1009  return !empty;
1010 }
1011 
1012 void SQLStorage::storeMisconfiguredEcus(const std::vector<MisconfiguredEcu>& ecus) {
1013  if (ecus.size() >= 1) {
1014  SQLite3Guard db = dbConnection();
1015 
1016  db.beginTransaction();
1017 
1018  if (db.exec("DELETE FROM misconfigured_ecus;", nullptr, nullptr) != SQLITE_OK) {
1019  LOG_ERROR << "Can't clear misconfigured_ecus: " << db.errmsg();
1020  return;
1021  }
1022 
1023  std::vector<MisconfiguredEcu>::const_iterator it;
1024  for (it = ecus.begin(); it != ecus.end(); it++) {
1025  auto statement = db.prepareStatement<std::string, std::string, int>(
1026  "INSERT INTO misconfigured_ecus VALUES (?,?,?);", it->serial.ToString(), it->hardware_id.ToString(),
1027  static_cast<int>(it->state));
1028 
1029  if (statement.step() != SQLITE_DONE) {
1030  LOG_ERROR << "Can't set misconfigured_ecus: " << db.errmsg();
1031  return;
1032  }
1033  }
1034 
1035  db.commitTransaction();
1036  }
1037 }
1038 
1039 bool SQLStorage::loadMisconfiguredEcus(std::vector<MisconfiguredEcu>* ecus) {
1040  SQLite3Guard db = dbConnection();
1041 
1042  auto statement = db.prepareStatement("SELECT serial, hardware_id, state FROM misconfigured_ecus;");
1043  int statement_state;
1044 
1045  std::vector<MisconfiguredEcu> new_ecus;
1046  bool empty = true;
1047  while ((statement_state = statement.step()) == SQLITE_ROW) {
1048  try {
1049  new_ecus.emplace_back(Uptane::EcuSerial(statement.get_result_col_str(0).value()),
1050  Uptane::HardwareIdentifier(statement.get_result_col_str(1).value()),
1051  static_cast<EcuState>(statement.get_result_col_int(2)));
1052  empty = false;
1053  } catch (const boost::bad_optional_access&) {
1054  return false;
1055  }
1056  }
1057 
1058  if (statement_state != SQLITE_DONE) {
1059  LOG_ERROR << "Can't get misconfigured_ecus: " << db.errmsg();
1060  return false;
1061  }
1062 
1063  if (ecus != nullptr) {
1064  *ecus = std::move(new_ecus);
1065  }
1066 
1067  return !empty;
1068 }
1069 
1070 void SQLStorage::clearMisconfiguredEcus() {
1071  SQLite3Guard db = dbConnection();
1072 
1073  if (db.exec("DELETE FROM misconfigured_ecus;", nullptr, nullptr) != SQLITE_OK) {
1074  LOG_ERROR << "Can't clear misconfigured_ecus: " << db.errmsg();
1075  return;
1076  }
1077 }
1078 
1079 void SQLStorage::saveInstalledVersion(const std::string& ecu_serial, const Uptane::Target& target,
1080  InstalledVersionUpdateMode update_mode) {
1081  SQLite3Guard db = dbConnection();
1082 
1083  db.beginTransaction();
1084 
1085  // either adds a new entry or update the last one's status
1086 
1087  // empty serial: use Primary
1088  std::string ecu_serial_real = ecu_serial;
1089  if (ecu_serial_real.empty()) {
1090  auto statement = db.prepareStatement("SELECT serial FROM ecus WHERE is_primary = 1;");
1091  if (statement.step() == SQLITE_ROW) {
1092  ecu_serial_real = statement.get_result_col_str(0).value();
1093  } else {
1094  LOG_WARNING << "Could not find Primary ECU serial, set to lazy init mode";
1095  }
1096  }
1097 
1098  std::string hashes_encoded = Hash::encodeVector(target.hashes());
1099 
1100  // get the last time this version was installed on this ecu
1101  boost::optional<int64_t> old_id;
1102  bool old_was_installed = false;
1103  {
1104  auto statement = db.prepareStatement<std::string>(
1105  "SELECT id, sha256, name, was_installed FROM installed_versions WHERE ecu_serial = ? ORDER BY id DESC "
1106  "LIMIT 1;",
1107  ecu_serial_real);
1108 
1109  if (statement.step() == SQLITE_ROW) {
1110  int64_t rid = statement.get_result_col_int(0);
1111  std::string rsha256 = statement.get_result_col_str(1).value_or("");
1112  std::string rname = statement.get_result_col_str(2).value_or("");
1113  bool rwasi = statement.get_result_col_int(3) == 1;
1114 
1115  if (rsha256 == target.sha256Hash() && rname == target.filename()) {
1116  old_id = rid;
1117  old_was_installed = rwasi;
1118  }
1119  }
1120  }
1121 
1122  if (update_mode == InstalledVersionUpdateMode::kCurrent) {
1123  // unset 'current' and 'pending' on all versions for this ecu
1124  auto statement = db.prepareStatement<std::string>(
1125  "UPDATE installed_versions SET is_current = 0, is_pending = 0 WHERE ecu_serial = ?", ecu_serial_real);
1126  if (statement.step() != SQLITE_DONE) {
1127  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1128  return;
1129  }
1130  } else if (update_mode == InstalledVersionUpdateMode::kPending) {
1131  // unset 'pending' on all versions for this ecu
1132  auto statement = db.prepareStatement<std::string>(
1133  "UPDATE installed_versions SET is_pending = 0 WHERE ecu_serial = ?", ecu_serial_real);
1134  if (statement.step() != SQLITE_DONE) {
1135  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1136  return;
1137  }
1138  }
1139 
1140  if (!!old_id) {
1141  auto statement = db.prepareStatement<std::string, int, int, int64_t>(
1142  "UPDATE installed_versions SET correlation_id = ?, is_current = ?, is_pending = ?, was_installed = ? WHERE id "
1143  "= ?;",
1144  target.correlation_id(), static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent),
1145  static_cast<int>(update_mode == InstalledVersionUpdateMode::kPending),
1146  static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent || old_was_installed), old_id.value());
1147 
1148  if (statement.step() != SQLITE_DONE) {
1149  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1150  return;
1151  }
1152  } else {
1153  std::string custom = Utils::jsonToCanonicalStr(target.custom_data());
1154  auto statement = db.prepareStatement<std::string, std::string, std::string, std::string, int64_t, std::string,
1155  std::string, int, int>(
1156  "INSERT INTO installed_versions(ecu_serial, sha256, name, hashes, length, custom_meta, correlation_id, "
1157  "is_current, is_pending, was_installed) VALUES (?,?,?,?,?,?,?,?,?,?);",
1158  ecu_serial_real, target.sha256Hash(), target.filename(), hashes_encoded, static_cast<int64_t>(target.length()),
1159  custom, target.correlation_id(), static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent),
1160  static_cast<int>(update_mode == InstalledVersionUpdateMode::kPending),
1161  static_cast<int>(update_mode == InstalledVersionUpdateMode::kCurrent));
1162 
1163  if (statement.step() != SQLITE_DONE) {
1164  LOG_ERROR << "Can't set installed_versions: " << db.errmsg();
1165  return;
1166  }
1167  }
1168 
1169  db.commitTransaction();
1170 }
1171 
1172 static void loadEcuMap(SQLite3Guard& db, std::string& ecu_serial, Uptane::EcuMap& ecu_map) {
1173  // The Secondary only knows about itself and in its database it is considered
1174  // a Primary, for better or worse.
1175  if (ecu_serial.empty()) {
1176  auto statement = db.prepareStatement("SELECT serial FROM ecus WHERE is_primary = 1;");
1177  if (statement.step() == SQLITE_ROW) {
1178  ecu_serial = statement.get_result_col_str(0).value();
1179  } else if (statement.step() == SQLITE_DONE) {
1180  LOG_DEBUG << "No serial found in database for this ECU, defaulting to empty serial";
1181  } else {
1182  LOG_ERROR << "Error getting serial for this ECU, defaulting to empty serial: " << db.errmsg();
1183  }
1184  }
1185 
1186  if (!ecu_serial.empty()) {
1187  auto statement = db.prepareStatement<std::string>("SELECT hardware_id FROM ecus WHERE serial = ?;", ecu_serial);
1188  if (statement.step() == SQLITE_ROW) {
1189  ecu_map.insert(
1190  {Uptane::EcuSerial(ecu_serial), Uptane::HardwareIdentifier(statement.get_result_col_str(0).value())});
1191  } else if (statement.step() == SQLITE_DONE) {
1192  LOG_DEBUG << "No hardware ID found in database for ECU serial " << ecu_serial;
1193  } else {
1194  LOG_ERROR << "Error getting hardware ID for ECU serial " << ecu_serial << ": " << db.errmsg();
1195  }
1196  }
1197 }
1198 
1199 bool SQLStorage::loadInstallationLog(const std::string& ecu_serial, std::vector<Uptane::Target>* log,
1200  bool only_installed) {
1201  SQLite3Guard db = dbConnection();
1202 
1203  std::string ecu_serial_real = ecu_serial;
1204  Uptane::EcuMap ecu_map;
1205  loadEcuMap(db, ecu_serial_real, ecu_map);
1206 
1207  std::string query =
1208  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1209  "ecu_serial = ? ORDER BY id;";
1210  if (only_installed) {
1211  query =
1212  "SELECT id, sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1213  "ecu_serial = ? AND was_installed = 1 ORDER BY id;";
1214  }
1215 
1216  auto statement = db.prepareStatement<std::string>(query, ecu_serial_real);
1217  int statement_state;
1218 
1219  std::vector<Uptane::Target> new_log;
1220  std::map<int64_t, size_t> ids_map;
1221  size_t k = 0;
1222  while ((statement_state = statement.step()) == SQLITE_ROW) {
1223  try {
1224  auto id = statement.get_result_col_int(0);
1225  auto sha256 = statement.get_result_col_str(1).value();
1226  auto filename = statement.get_result_col_str(2).value();
1227  auto hashes_str = statement.get_result_col_str(3).value();
1228  auto length = statement.get_result_col_int(4);
1229  auto correlation_id = statement.get_result_col_str(5).value();
1230  auto custom_str = statement.get_result_col_str(6).value();
1231 
1232  // note: sha256 should always be present and is used to uniquely identify
1233  // a version. It should normally be part of the hash list as well.
1234  std::vector<Hash> hashes = Hash::decodeVector(hashes_str);
1235 
1236  auto find_sha256 =
1237  std::find_if(hashes.cbegin(), hashes.cend(), [](const Hash& h) { return h.type() == Hash::Type::kSha256; });
1238  if (find_sha256 == hashes.cend()) {
1239  LOG_WARNING << "No sha256 in hashes list";
1240  hashes.emplace_back(Hash::Type::kSha256, sha256);
1241  }
1242 
1243  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1244  if (!custom_str.empty()) {
1245  std::istringstream css(custom_str);
1246  std::string errs;
1247  Json::Value custom;
1248  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, nullptr)) {
1249  t.updateCustom(custom);
1250  } else {
1251  LOG_ERROR << "Unable to parse custom data: " << errs;
1252  }
1253  }
1254  new_log.emplace_back(t);
1255 
1256  ids_map[id] = k;
1257  k++;
1258  } catch (const boost::bad_optional_access&) {
1259  LOG_ERROR << "Incompleted installed version, keeping old one";
1260  return false;
1261  }
1262  }
1263 
1264  if (statement_state != SQLITE_DONE) {
1265  LOG_ERROR << "Can't get installed_versions: " << db.errmsg();
1266  return false;
1267  }
1268 
1269  if (log == nullptr) {
1270  return true;
1271  }
1272 
1273  *log = std::move(new_log);
1274 
1275  return true;
1276 }
1277 
1278 bool SQLStorage::loadInstalledVersions(const std::string& ecu_serial, boost::optional<Uptane::Target>* current_version,
1279  boost::optional<Uptane::Target>* pending_version) {
1280  SQLite3Guard db = dbConnection();
1281 
1282  std::string ecu_serial_real = ecu_serial;
1283  Uptane::EcuMap ecu_map;
1284  loadEcuMap(db, ecu_serial_real, ecu_map);
1285 
1286  auto read_target = [&ecu_map](SQLiteStatement& statement) -> Uptane::Target {
1287  auto sha256 = statement.get_result_col_str(0).value();
1288  auto filename = statement.get_result_col_str(1).value();
1289  auto hashes_str = statement.get_result_col_str(2).value();
1290  auto length = statement.get_result_col_int(3);
1291  auto correlation_id = statement.get_result_col_str(4).value();
1292  auto custom_str = statement.get_result_col_str(5).value();
1293 
1294  // note: sha256 should always be present and is used to uniquely identify
1295  // a version. It should normally be part of the hash list as well.
1296  std::vector<Hash> hashes = Hash::decodeVector(hashes_str);
1297 
1298  auto find_sha256 =
1299  std::find_if(hashes.cbegin(), hashes.cend(), [](const Hash& h) { return h.type() == Hash::Type::kSha256; });
1300  if (find_sha256 == hashes.cend()) {
1301  LOG_WARNING << "No sha256 in hashes list";
1302  hashes.emplace_back(Hash::Type::kSha256, sha256);
1303  }
1304  Uptane::Target t(filename, ecu_map, hashes, static_cast<uint64_t>(length), correlation_id);
1305  if (!custom_str.empty()) {
1306  std::istringstream css(custom_str);
1307  Json::Value custom;
1308  std::string errs;
1309  if (Json::parseFromStream(Json::CharReaderBuilder(), css, &custom, &errs)) {
1310  t.updateCustom(custom);
1311  } else {
1312  LOG_ERROR << "Unable to parse custom data: " << errs;
1313  }
1314  }
1315 
1316  return t;
1317  };
1318 
1319  if (current_version != nullptr) {
1320  auto statement = db.prepareStatement<std::string>(
1321  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1322  "ecu_serial = ? AND is_current = 1 LIMIT 1;",
1323  ecu_serial_real);
1324 
1325  if (statement.step() == SQLITE_ROW) {
1326  try {
1327  *current_version = read_target(statement);
1328  } catch (const boost::bad_optional_access&) {
1329  LOG_ERROR << "Could not read current installed version";
1330  return false;
1331  }
1332  } else {
1333  LOG_TRACE << "Cannot get current installed version: " << db.errmsg();
1334  *current_version = boost::none;
1335  }
1336  }
1337 
1338  if (pending_version != nullptr) {
1339  auto statement = db.prepareStatement<std::string>(
1340  "SELECT sha256, name, hashes, length, correlation_id, custom_meta FROM installed_versions WHERE "
1341  "ecu_serial = ? AND is_pending = 1 LIMIT 1;",
1342  ecu_serial_real);
1343 
1344  if (statement.step() == SQLITE_ROW) {
1345  try {
1346  *pending_version = read_target(statement);
1347  } catch (const boost::bad_optional_access&) {
1348  LOG_ERROR << "Could not read pending installed version";
1349  return false;
1350  }
1351  } else {
1352  LOG_TRACE << "Cannot get pending installed version: " << db.errmsg();
1353  *pending_version = boost::none;
1354  }
1355  }
1356 
1357  return true;
1358 }
1359 
1360 bool SQLStorage::hasPendingInstall() {
1361  SQLite3Guard db = dbConnection();
1362 
1363  auto statement = db.prepareStatement("SELECT count(*) FROM installed_versions where is_pending = 1");
1364  if (statement.step() != SQLITE_ROW) {
1365  LOG_ERROR << "Can't get tables count: " << db.errmsg();
1366  throw std::runtime_error("Could not count pending installations");
1367  }
1368 
1369  return statement.get_result_col_int(0) > 0;
1370 }
1371 
1372 void SQLStorage::getPendingEcus(std::vector<std::pair<Uptane::EcuSerial, Hash>>* pendingEcus) {
1373  SQLite3Guard db = dbConnection();
1374 
1375  auto statement = db.prepareStatement("SELECT ecu_serial, sha256 FROM installed_versions where is_pending = 1");
1376  int statement_result = statement.step();
1377  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1378  throw std::runtime_error("Failed to get ECUs with a pending target installation: " + db.errmsg());
1379  }
1380 
1381  std::vector<std::pair<Uptane::EcuSerial, Hash>> ecu_res;
1382 
1383  if (statement_result == SQLITE_DONE) {
1384  // if there are no any record in the DB
1385  return;
1386  }
1387 
1388  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1389  std::string ecu_serial = statement.get_result_col_str(0).value();
1390  std::string hash = statement.get_result_col_str(1).value();
1391  ecu_res.emplace_back(std::make_pair(Uptane::EcuSerial(ecu_serial), Hash(Hash::Type::kSha256, hash)));
1392  }
1393 
1394  if (pendingEcus != nullptr) {
1395  *pendingEcus = std::move(ecu_res);
1396  }
1397 }
1398 
1399 void SQLStorage::clearInstalledVersions() {
1400  SQLite3Guard db = dbConnection();
1401 
1402  if (db.exec("DELETE FROM installed_versions;", nullptr, nullptr) != SQLITE_OK) {
1403  LOG_ERROR << "Can't clear installed_versions: " << db.errmsg();
1404  return;
1405  }
1406 }
1407 
1408 void SQLStorage::saveEcuInstallationResult(const Uptane::EcuSerial& ecu_serial,
1410  SQLite3Guard db = dbConnection();
1411 
1412  auto statement = db.prepareStatement<std::string, int, std::string, std::string>(
1413  "INSERT OR REPLACE INTO ecu_installation_results (ecu_serial, success, result_code, description) VALUES "
1414  "(?,?,?,?);",
1415  ecu_serial.ToString(), static_cast<int>(result.success), result.result_code.toRepr(), result.description);
1416  if (statement.step() != SQLITE_DONE) {
1417  LOG_ERROR << "Can't set ECU installation result: " << db.errmsg();
1418  return;
1419  }
1420 }
1421 
1422 bool SQLStorage::loadEcuInstallationResults(
1423  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>>* results) {
1424  SQLite3Guard db = dbConnection();
1425 
1426  std::vector<std::pair<Uptane::EcuSerial, data::InstallationResult>> ecu_res;
1427 
1428  // keep the same order as in ECUs (start with Primary)
1429  auto statement = db.prepareStatement(
1430  "SELECT ecu_serial, success, result_code, description FROM ecu_installation_results INNER JOIN ecus ON "
1431  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1432  int statement_result = statement.step();
1433  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1434  LOG_ERROR << "Can't get ecu_installation_results: " << db.errmsg();
1435  return false;
1436  }
1437 
1438  if (statement_result == SQLITE_DONE) {
1439  // if there are no any record in the DB
1440  return false;
1441  }
1442 
1443  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1444  try {
1445  std::string ecu_serial = statement.get_result_col_str(0).value();
1446  auto success = static_cast<bool>(statement.get_result_col_int(1));
1447  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(2).value());
1448  std::string description = statement.get_result_col_str(3).value();
1449 
1450  ecu_res.emplace_back(Uptane::EcuSerial(ecu_serial), data::InstallationResult(success, result_code, description));
1451  } catch (const boost::bad_optional_access&) {
1452  return false;
1453  }
1454  }
1455 
1456  if (results != nullptr) {
1457  *results = std::move(ecu_res);
1458  }
1459 
1460  return true;
1461 }
1462 
1463 void SQLStorage::storeDeviceInstallationResult(const data::InstallationResult& result, const std::string& raw_report,
1464  const std::string& correlation_id) {
1465  SQLite3Guard db = dbConnection();
1466 
1467  auto statement = db.prepareStatement<int, std::string, std::string, std::string, std::string>(
1468  "INSERT OR REPLACE INTO device_installation_result (unique_mark, success, result_code, description, raw_report, "
1469  "correlation_id) "
1470  "VALUES (0,?,?,?,?,?);",
1471  static_cast<int>(result.success), result.result_code.toRepr(), result.description, raw_report, correlation_id);
1472  if (statement.step() != SQLITE_DONE) {
1473  LOG_ERROR << "Can't set device installation result: " << db.errmsg();
1474  return;
1475  }
1476 }
1477 
1478 bool SQLStorage::loadDeviceInstallationResult(data::InstallationResult* result, std::string* raw_report,
1479  std::string* correlation_id) {
1480  SQLite3Guard db = dbConnection();
1481 
1482  data::InstallationResult dev_res;
1483  std::string raw_report_res;
1484  std::string corrid_res;
1485 
1486  auto statement = db.prepareStatement(
1487  "SELECT success, result_code, description, raw_report, correlation_id FROM device_installation_result;");
1488  int statement_result = statement.step();
1489  if (statement_result == SQLITE_DONE) {
1490  LOG_TRACE << "No device installation result in db";
1491  return false;
1492  } else if (statement_result != SQLITE_ROW) {
1493  LOG_ERROR << "Can't get device_installation_result: " << db.errmsg();
1494  return false;
1495  }
1496 
1497  try {
1498  auto success = static_cast<bool>(statement.get_result_col_int(0));
1499  data::ResultCode result_code = data::ResultCode::fromRepr(statement.get_result_col_str(1).value());
1500  std::string description = statement.get_result_col_str(2).value();
1501  raw_report_res = statement.get_result_col_str(3).value();
1502  corrid_res = statement.get_result_col_str(4).value();
1503 
1504  dev_res = data::InstallationResult(success, result_code, description);
1505  } catch (const boost::bad_optional_access&) {
1506  return false;
1507  }
1508 
1509  if (result != nullptr) {
1510  *result = std::move(dev_res);
1511  }
1512 
1513  if (raw_report != nullptr) {
1514  *raw_report = std::move(raw_report_res);
1515  }
1516 
1517  if (correlation_id != nullptr) {
1518  *correlation_id = std::move(corrid_res);
1519  }
1520 
1521  return true;
1522 }
1523 
1524 void SQLStorage::saveEcuReportCounter(const Uptane::EcuSerial& ecu_serial, const int64_t counter) {
1525  SQLite3Guard db = dbConnection();
1526 
1527  auto statement = db.prepareStatement<std::string, int64_t>(
1528  "INSERT OR REPLACE INTO ecu_report_counter (ecu_serial, counter) VALUES "
1529  "(?,?);",
1530  ecu_serial.ToString(), counter);
1531  if (statement.step() != SQLITE_DONE) {
1532  LOG_ERROR << "Can't set ECU counter: " << db.errmsg();
1533  return;
1534  }
1535 }
1536 
1537 bool SQLStorage::loadEcuReportCounter(std::vector<std::pair<Uptane::EcuSerial, int64_t>>* results) {
1538  SQLite3Guard db = dbConnection();
1539 
1540  std::vector<std::pair<Uptane::EcuSerial, int64_t>> ecu_cnt;
1541 
1542  // keep the same order as in ECUs (start with Primary)
1543  auto statement = db.prepareStatement(
1544  "SELECT ecu_serial, counter FROM ecu_report_counter INNER JOIN ecus ON "
1545  "ecus.serial = ecu_serial ORDER BY ecus.id;");
1546  int statement_result = statement.step();
1547  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1548  LOG_ERROR << "Can't get ecu_report_counter: " << db.errmsg();
1549  return false;
1550  }
1551 
1552  if (statement_result == SQLITE_DONE) {
1553  // if there are no any record in the DB
1554  return false;
1555  }
1556 
1557  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1558  try {
1559  std::string ecu_serial = statement.get_result_col_str(0).value();
1560  int64_t counter = statement.get_result_col_int(1);
1561 
1562  ecu_cnt.emplace_back(Uptane::EcuSerial(ecu_serial), counter);
1563  } catch (const boost::bad_optional_access&) {
1564  return false;
1565  }
1566  }
1567 
1568  if (results != nullptr) {
1569  *results = std::move(ecu_cnt);
1570  }
1571 
1572  return true;
1573 }
1574 
1575 void SQLStorage::saveReportEvent(const Json::Value& json_value) {
1576  std::string json_string = Utils::jsonToCanonicalStr(json_value);
1577  SQLite3Guard db = dbConnection();
1578  auto statement = db.prepareStatement<std::string>(
1579  "INSERT INTO report_events SELECT MAX(id) + 1, ? FROM report_events", json_string);
1580  if (statement.step() != SQLITE_DONE) {
1581  LOG_ERROR << "Can't save report event: " << db.errmsg();
1582  return;
1583  }
1584 }
1585 
1586 bool SQLStorage::loadReportEvents(Json::Value* report_array, int64_t* id_max) {
1587  SQLite3Guard db = dbConnection();
1588  auto statement = db.prepareStatement("SELECT id, json_string FROM report_events;");
1589  int statement_result = statement.step();
1590  if (statement_result != SQLITE_DONE && statement_result != SQLITE_ROW) {
1591  LOG_ERROR << "Can't get report_events: " << db.errmsg();
1592  return false;
1593  }
1594  if (statement_result == SQLITE_DONE) {
1595  // if there are no any record in the DB
1596  return false;
1597  }
1598  *id_max = 0;
1599  for (; statement_result != SQLITE_DONE; statement_result = statement.step()) {
1600  try {
1601  int64_t id = statement.get_result_col_int(0);
1602  std::string json_string = statement.get_result_col_str(1).value();
1603  std::istringstream jss(json_string);
1604  Json::Value event_json;
1605  std::string errs;
1606  if (Json::parseFromStream(Json::CharReaderBuilder(), jss, &event_json, &errs)) {
1607  report_array->append(event_json);
1608  *id_max = (*id_max) > id ? (*id_max) : id;
1609  } else {
1610  LOG_ERROR << "Unable to parse event data: " << errs;
1611  }
1612  } catch (const boost::bad_optional_access&) {
1613  return false;
1614  }
1615  }
1616 
1617  return true;
1618 }
1619 
1620 void SQLStorage::deleteReportEvents(int64_t id_max) {
1621  SQLite3Guard db = dbConnection();
1622 
1623  db.beginTransaction();
1624 
1625  auto statement = db.prepareStatement<int64_t>("DELETE FROM report_events WHERE id <= ?;", id_max);
1626  if (statement.step() != SQLITE_DONE) {
1627  LOG_ERROR << "Can't delete report_events";
1628  }
1629 
1630  db.commitTransaction();
1631 }
1632 
1633 void SQLStorage::clearInstallationResults() {
1634  SQLite3Guard db = dbConnection();
1635 
1636  db.beginTransaction();
1637 
1638  if (db.exec("DELETE FROM device_installation_result;", nullptr, nullptr) != SQLITE_OK) {
1639  LOG_ERROR << "Can't clear device_installation_result: " << db.errmsg();
1640  return;
1641  }
1642 
1643  if (db.exec("DELETE FROM ecu_installation_results;", nullptr, nullptr) != SQLITE_OK) {
1644  LOG_ERROR << "Can't clear ecu_installation_results: " << db.errmsg();
1645  return;
1646  }
1647 
1648  db.commitTransaction();
1649 }
1650 
1651 bool SQLStorage::checkAvailableDiskSpace(const uint64_t required_bytes) const {
1652  struct statvfs stvfsbuf {};
1653  const int stat_res = statvfs(dbPath().c_str(), &stvfsbuf);
1654  if (stat_res < 0) {
1655  LOG_WARNING << "Unable to read filesystem statistics: error code " << stat_res;
1656  return true;
1657  }
1658  const uint64_t available_bytes = (static_cast<uint64_t>(stvfsbuf.f_bsize) * stvfsbuf.f_bavail);
1659  const uint64_t reserved_bytes = 1 << 20;
1660 
1661  if (required_bytes + reserved_bytes < available_bytes) {
1662  return true;
1663  } else {
1664  LOG_ERROR << "Insufficient disk space available to download target! Required: " << required_bytes
1665  << ", available: " << available_bytes << ", reserved: " << reserved_bytes;
1666  return false;
1667  }
1668 }
1669 
1670 boost::optional<std::pair<uintmax_t, std::string>> SQLStorage::checkTargetFile(const Uptane::Target& target) const {
1671  SQLite3Guard db = dbConnection();
1672 
1673  auto statement = db.prepareStatement<std::string>(
1674  "SELECT sha256, sha512, filename FROM target_images WHERE targetname = ?;", target.filename());
1675 
1676  int statement_state;
1677  while ((statement_state = statement.step()) == SQLITE_ROW) {
1678  auto sha256 = statement.get_result_col_str(0);
1679  auto sha512 = statement.get_result_col_str(1);
1680  auto filename = statement.get_result_col_str(2);
1681  if ((*sha256).empty() && (*sha512).empty()) {
1682  // Old aktualizr didn't save checksums, this could require to redownload old images.
1683  LOG_WARNING << "Image without checksum: " << target.filename();
1684  continue;
1685  }
1686  bool sha256_match = false;
1687  bool sha512_match = false;
1688  if (!(*sha256).empty()) {
1689  if (target.MatchHash(Hash(Hash::Type::kSha256, *sha256))) {
1690  sha256_match = true;
1691  }
1692  }
1693 
1694  if (!(*sha512).empty()) {
1695  if (target.MatchHash(Hash(Hash::Type::kSha512, *sha512))) {
1696  sha512_match = true;
1697  }
1698  }
1699  if (((*sha256).empty() || sha256_match) && ((*sha512).empty() || sha512_match)) {
1700  if (boost::filesystem::exists(images_path_ / *filename)) {
1701  return {{boost::filesystem::file_size(images_path_ / *filename), *filename}};
1702  } else {
1703  return boost::none;
1704  }
1705  }
1706  }
1707 
1708  if (statement_state == SQLITE_DONE) {
1709  return boost::none;
1710  }
1711  assert(statement_state != SQLITE_ROW); // from the previous loop precondition
1712  LOG_ERROR << "Statement step failure: " << db.errmsg();
1713 
1714  return boost::none;
1715 }
1716 
1718  public:
1719  SQLTargetWHandle(const SQLStorage& storage, Uptane::Target target)
1720  : db_path_(storage.dbPath()), target_(std::move(target)), storage_(&storage) {
1721  StorageTargetWHandle::WriteError exc("could not save file " + target_.filename() + " to the filesystem");
1722 
1723  std::string sha256Hash;
1724  std::string sha512Hash;
1725  for (const auto& hash : target_.hashes()) {
1726  if (hash.type() == Hash::Type::kSha256) {
1727  sha256Hash = hash.HashString();
1728  } else if (hash.type() == Hash::Type::kSha512) {
1729  sha512Hash = hash.HashString();
1730  }
1731  }
1732  std::string filename = (storage.images_path_ / target_.hashes()[0].HashString()).string();
1733  SQLite3Guard db = storage_->dbConnection();
1734  auto statement = db.prepareStatement<std::string, std::string, std::string>(
1735  "INSERT OR REPLACE INTO target_images (targetname, sha256, sha512, filename) VALUES ( ?, ?, ?, ?);",
1736  target_.filename(), sha256Hash, sha512Hash, target_.hashes()[0].HashString());
1737 
1738  if (statement.step() != SQLITE_DONE) {
1739  LOG_ERROR << "Statement step failure: " << db.errmsg();
1740  throw exc;
1741  }
1742  boost::filesystem::create_directories(storage.images_path_);
1743  stream_.open(filename);
1744  if (!stream_.good()) {
1745  LOG_ERROR << "Could not open image for write: " << storage.images_path_ / target_.filename();
1746  throw exc;
1747  }
1748  }
1749 
1750  ~SQLTargetWHandle() override {
1751  try {
1752  SQLTargetWHandle::wcommit();
1753  } catch (std::exception& ex) {
1754  LOG_ERROR << "Failed to commit to database: " << ex.what();
1755  } catch (...) {
1756  LOG_ERROR << "Failed to commit to database: unknown error";
1757  }
1758  }
1759 
1760  size_t wfeed(const uint8_t* buf, size_t size) override {
1761  stream_.write(reinterpret_cast<const char*>(buf), static_cast<std::streamsize>(size));
1762  written_size_ += size;
1763 
1764  return size;
1765  }
1766 
1767  void wcommit() override {
1768  if (stream_) {
1769  stream_.close();
1770  }
1771  }
1772 
1773  void wabort() noexcept override {
1774  if (stream_) {
1775  stream_.close();
1776  }
1777 
1778  if (storage_ != nullptr) {
1779  SQLite3Guard db = storage_->dbConnection();
1780  auto statement =
1781  db.prepareStatement<std::string>("DELETE FROM target_images WHERE targetname=?;", target_.filename());
1782  if (statement.step() != SQLITE_DONE) {
1783  LOG_ERROR << "could not delete " << target_.filename() << " from sql storage";
1784  }
1785  }
1786  }
1787 
1788  friend class SQLTargetRHandle;
1789 
1790  private:
1791  SQLTargetWHandle(const boost::filesystem::path& db_path, Uptane::Target target,
1792  const boost::filesystem::path& image_path, const uintmax_t& start_from = 0)
1793  : db_path_(db_path), target_(std::move(target)) {
1794  stream_.open(image_path.string(), std::ofstream::out | std::ofstream::app);
1795  if (!stream_.good()) {
1796  LOG_ERROR << "Could not open image for write: " << image_path;
1797  throw StorageTargetWHandle::WriteError("could not open file for write: " + image_path.string());
1798  }
1799 
1800  written_size_ = start_from;
1801  }
1802  boost::filesystem::path db_path_;
1803  Uptane::Target target_;
1804  std::ofstream stream_;
1805  const SQLStorage* storage_ = nullptr;
1806 };
1807 
1808 std::unique_ptr<StorageTargetWHandle> SQLStorage::allocateTargetFile(const Uptane::Target& target) {
1809  return std::unique_ptr<StorageTargetWHandle>(new SQLTargetWHandle(*this, target));
1810 }
1811 
1813  public:
1814  SQLTargetRHandle(const SQLStorage& storage, Uptane::Target target)
1815  : db_path_(storage.dbPath()), target_(std::move(target)), size_(0) {
1816  StorageTargetRHandle::ReadError exc("could not read file " + target_.filename() + " from sql storage");
1817 
1818  auto exists = storage.checkTargetFile(target_);
1819  if (!exists) {
1820  LOG_ERROR << "File " << target_.filename() << " with expected hash not found in the database!";
1821  throw exc;
1822  }
1823 
1824  size_ = exists->first;
1825  partial_ = size_ < target_.length();
1826  image_path_ = storage.images_path_ / exists->second;
1827  stream_.open(image_path_.string());
1828  if (!stream_.good()) {
1829  LOG_ERROR << "Could not open image: " << storage.images_path_ / target_.filename();
1830  throw exc;
1831  }
1832  }
1833 
1834  ~SQLTargetRHandle() override { SQLTargetRHandle::rclose(); }
1835 
1836  uintmax_t rsize() const override { return size_; }
1837 
1838  size_t rread(uint8_t* buf, size_t size) override {
1839  stream_.read(reinterpret_cast<char*>(buf), static_cast<std::streamsize>(size));
1840  return static_cast<size_t>(stream_.gcount());
1841  }
1842 
1843  void rclose() noexcept override {
1844  if (stream_.is_open()) {
1845  stream_.close();
1846  }
1847  }
1848 
1849  bool isPartial() const noexcept override { return partial_; }
1850  std::unique_ptr<StorageTargetWHandle> toWriteHandle() override {
1851  return std::unique_ptr<StorageTargetWHandle>(new SQLTargetWHandle(db_path_, target_, image_path_, size_));
1852  }
1853 
1854  private:
1855  boost::filesystem::path db_path_;
1856  Uptane::Target target_;
1857  uintmax_t size_;
1858  bool partial_{false};
1859  boost::filesystem::path image_path_;
1860  std::ifstream stream_;
1861 };
1862 
1863 std::unique_ptr<StorageTargetRHandle> SQLStorage::openTargetFile(const Uptane::Target& target) {
1864  return std_::make_unique<SQLTargetRHandle>(*this, target);
1865 }
1866 
1867 std::vector<Uptane::Target> SQLStorage::getTargetFiles() {
1868  SQLite3Guard db = dbConnection();
1869 
1870  auto statement = db.prepareStatement<>("SELECT targetname, filename, sha256, sha512 FROM target_images;");
1871 
1872  std::vector<Uptane::Target> v;
1873 
1874  int result = statement.step();
1875  while (result != SQLITE_DONE) {
1876  if (result != SQLITE_ROW) {
1877  LOG_ERROR << "Statement step failure: " << db.errmsg();
1878  throw std::runtime_error("Error getting target files");
1879  }
1880 
1881  auto tname = statement.get_result_col_str(0).value();
1882  auto fname = statement.get_result_col_str(1).value();
1883  auto tsize = boost::filesystem::file_size(images_path_ / fname);
1884  auto sha256 = statement.get_result_col_str(2).value();
1885  auto sha512 = statement.get_result_col_str(3).value();
1886 
1887  std::vector<Hash> hashes;
1888  if (!sha256.empty()) {
1889  hashes.emplace_back(Hash::Type::kSha256, sha256);
1890  }
1891  if (!sha512.empty()) {
1892  hashes.emplace_back(Hash::Type::kSha512, sha512);
1893  }
1894  v.emplace_back(tname, Uptane::EcuMap{}, hashes, tsize);
1895 
1896  result = statement.step();
1897  }
1898 
1899  return v;
1900 }
1901 
1902 void SQLStorage::removeTargetFile(const std::string& target_name) {
1903  SQLite3Guard db = dbConnection();
1904 
1905  db.beginTransaction();
1906 
1907  auto statement =
1908  db.prepareStatement<std::string>("SELECT filename FROM target_images WHERE targetname = ?;", target_name);
1909 
1910  if (statement.step() != SQLITE_ROW) {
1911  LOG_ERROR << "Statement step failure: " << db.errmsg();
1912  throw std::runtime_error("Could not find target file");
1913  }
1914 
1915  std::string filename = statement.get_result_col_str(0).value();
1916 
1917  statement = db.prepareStatement<std::string>("DELETE FROM target_images WHERE targetname=?;", target_name);
1918 
1919  if (statement.step() != SQLITE_DONE) {
1920  LOG_ERROR << "Statement step failure: " << db.errmsg();
1921  throw std::runtime_error("Could not remove target file");
1922  }
1923  try {
1924  boost::filesystem::remove(images_path_ / filename);
1925  } catch (std::exception& e) {
1926  LOG_ERROR << "Could not remove target file";
1927  throw;
1928  }
1929 
1930  db.commitTransaction();
1931 }
1932 
1933 void SQLStorage::cleanUp() { boost::filesystem::remove_all(dbPath()); }
Hash
The hash of a file or Uptane metadata.
Definition: crypto.h:65
data::ResultCode
Definition: types.h:125
data::InstallationResult
Definition: types.h:182
Uptane::Version
Metadata version numbers.
Definition: tuf.h:119
SQLBlob
Definition: sql_utils.h:17
StorageConfig
Definition: storage_config.h:15
data
General data structures.
Definition: types.cc:55
Uptane::HardwareIdentifier
Definition: tuf.h:146
StorageTargetWHandle::WriteError
Definition: invstorage.h:38
Uptane::RepositoryType
Definition: tuf.h:20
Uptane::EcuSerial
Definition: tuf.h:177
SecondaryInfo
Definition: invstorage.h:106
PublicKey
Definition: crypto.h:26
StorageTargetRHandle
Definition: invstorage.h:61
SQLTargetRHandle
Definition: sqlstorage.cc:1812
result
Results of libaktualizr API calls.
Definition: results.h:13
SQLite3Guard
Definition: sql_utils.h:125
SQLiteStatement
Definition: sql_utils.h:28
SQLTargetWHandle
Definition: sqlstorage.cc:1717
Uptane::Role
TUF Roles.
Definition: tuf.h:60
Uptane::Target
Definition: tuf.h:210
SQLStorageBase
Definition: sqlstorage_base.h:33
StorageTargetWHandle
Definition: invstorage.h:36
SQLStorage
Definition: sqlstorage.h:18
INvStorage
Definition: invstorage.h:126
StorageTargetRHandle::ReadError
Definition: invstorage.h:63