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